TLI file throwing exception - c#

I am using COM component in C++/CLI, one of the method of COM, takes 'void *' as parameter. My code compiles fine but throws 'System.Accessviolation' exception at runtime
following is the code snippet. What could be reason for this exception.
// C++ managed Code
void ManagedWrapper::InitializeConfig(ManagedConfigruation ^objConfiguration)
{
objConfiguration->SetConfigurationValue();
IntPtr p = objConfiguration->GetObjectPtr();
m_objCameraConfig->InitializeNetworkConfig(p.ToPointer());
}
//COM signature for InitializeNetworkConfig in IDL file
[helpstring("method InitializeCameraConfig")] HRESULT InitializeNetworkConfig([in] void *configparam);

How old is the COM object and do it need administrator priviliges? I know that some core functionality got the UAC leash on them when Windows moved from XP to Vista and 7.
It maybe totally wrong but hopefully that gives you a pointer in the right direction...

Related

C# wrapper (pinvoke) for Debian apt library libapt-pkg

I need to retrieve package information in my C# application running on Linux.
I've tried to use Python.NET which wrap python-apt which wrap libapt-pkg.so, and it works but I would prefer to go more direct by pinvoke libapt-pkg.
But I need help on my DLLImport statement.
When using python-apt I first initialize the apt module, then instantiat the Cache() class and then called the Cache.keys() function which retrieve all package-names as a string array.
If I can get this to work using pinvoke I believe I have a good chance getting the rest working too (retrieve the more advanced stuff)
Just to show some code which doesn't work, but just to get started:
[DllImport("libapt-pkg")]
public static extern dynamic GetPkgCache();
dynamic AptCache = GetPkgCache();
I get the error:
System.Runtime.InteropServices.MarshalDirectiveException: 'Cannot
marshal 'return value': Invalid managed/unmanaged type combination
(Marshaling to and from COM VARIANTs isn't supported).'
I've been looking in the header file cachefile.h of the apt project. Maybe these lines are useable for my DllImport statement?
..
inline operator pkgCache &() const {return *Cache;};
inline operator pkgCache *() const {return Cache;};
..
inline pkgCache* GetPkgCache() { BuildCaches(NULL, false); return Cache; };
..
But I'm new to C/C++ so it doesn't make much sense for me at present.
UPDATE:
Thanks for the feedback.
[DllImport("libapt-pkg")]
public static extern IntPtr GetPkgCache();
Now I get the error
System.EntryPointNotFoundException: 'Unable to find an entry point
named 'GetPkgCache' in shared library 'libapt-pkg'.'

C# COM object and CreateDispatch

First of all: There is existing Code using CreateDispatch. The maintainer doesn't want to change the code for compatibility/convenience reasons (except for using a new TLB/GUID).
So I have to create COM object which works with this restrictions. Preferabbly in C# (but C++ is also fine).
Problem is: I have absolutely no experience with COM.
That's how far I got: I created a COM object in C#, registered it and got a tlb. I checked the Registry, there is an entry: HKEY_CLASSES_ROOT\Wow6432Node\CLSID{36E6BC94-308C-4952-84E6-109041990EF7}
Seems fine. Next step: creating a test program (C++). I created a C++ console project with MFC enabled, imported the tlb. Then I added the following lines to the main:
CInterface01 server;
COleException* pe = new COleException;
LPTSTR m = new TCHAR[255];
CoInitialize(NULL);
server.CreateDispatch(L"{36E6BC94-308C-4952-84E6-109041990EF7}", pe);
pe->GetErrorMessage(m, 255);
Somehow the CreateDispatch didn't work. In the Exception it reads: "Class not registered"(what?! it's in the registry). Even worse: It crashes the Visual Studio when I'm running the same program again.
It feels like the solution is near, but I have no idea whats going wrong.
You need code like this:
//interface wrapper method implementations for
#import "YouTlbModule.tlb" no_namespace
//function
CoInitializeEx ( NULL, COINIT_MULTITHREADED);
IYouTlbModulePtr ptrYouTlbModule;
HRESULT hResult = ptrYouTlbModule.CreateInstance(OLESTR("Your.Component.Name"));
//test hResult
//Others function call
hResult = ptrYouTlbModule.Other(122, L"AAA");
//Call
int ret = ptrYouTlbInput.GetErrorMessage(m, 255);

Java JNI call to C# COM fails, when COM is registered without codebase option of regasm

Function calls from Java to C# through JNI-C++/CLI are failing when the C# COM is not registered using regasm with the codebase option. I've built a sample following the instructions in P2: Calling C# from Java with some changes.
Numero uno: C#
Change the C# dll into a COM by creating an interface, IRunner, and making the library assembly COM-visible.
namespace RunnerCOM
{
public interface IRunner
{
String ping();
}
public class Runner:IRunner
{
static void Main(string[] args)
{
}
public Runner() { }
public String ping()
{
return "Alive (C#)";
}
}
}
Numero due: Java
No changes made to the Java section.
Numero tre: C++
This part was changed to create a new instance of the RunnerCOM.Runner class and use that result. Here is a good tutorial on how to call managed code from unmanaged code: http://support.microsoft.com/kb/828736
#include "stdafx.h"
#include "Runner.h"
#pragma once
#using <mscorlib.dll>
#import "RunnerCOM.tlb"
JNIEXPORT jstring JNICALL Java_Runner_ping(JNIEnv *env, jobject obj){
RunnerCOM::IRunnerPtr t = RunnerCOM::IRunnerPtr("RunnerCOM.Runner");
BSTR ping = t->ping();
_bstr_t temp(ping, true);
char cap[128];
for(unsigned int i=0;i<temp.length();i++){
cap[i] = (char)ping[i];
}
return env->NewStringUTF(cap);
}
Now to my questions,
The code above fails with a _com_error exception, Class not registered (0x80040154) unless the codebase option is enabled during regsitration of RunnerCOM.dll, with regasm.exe. Why is this? If the code is not ran from JNI, I tested it as an exe, it works fine. The RunnerCOM.dll is simply found in the working directory.
Type casting _bstr_t temp to char* fails. For example, char *out = (char*) temp; Similar to the issue above, it works fine when it's built and executed as an exe but crashes the JVM when it's a JNI call.
By the way this is what I used to run it as an executable:
int main(){
RunnerCOM::IRunnerPtr t = RunnerCOM::IRunnerPtr("RunnerCOM.Runner");
BSTR ping = t->ping();
_bstr_t temp(ping, false);
printf(temp);
return 0;
}
Codebase creates a Codebase entry in the registry. The Codebase entry specifies the file path for an assembly that is not installed in the global assembly cache, so when you specify the codebase, the system will find the DLL based on the path. If not, it will try to locate the dll in the GAC and current working directory. In JNI, I think the current working directory is not the folder where the DLL is. You can use process explorer to find what is the current working directory, also, you can use process monitor to find out which directories the exe is looking into to find the dll.
The code converting _bstr_t to char*, the char* string cap is not ended with '\0', I think this might cause problem in JNI. Uses the _bstr_t operator (char *), you can obtain a null terminated string from the _bstr_t object. Please check the msdn example for details.
You mentioned C++/CLI, C++/Cli and COM warpper are two different ways to interop with C# code. If you're using C++/CLI as a bridge, you doesn't need to register C# DLL as COM, please see this: Calling .Net Dlls from Java code without using regasm.
If you're using COM, you should call CoInitialize() to init COM first in your code.

Error when invoking a method through .NET COM interop

I am trying to use the IOfficeAntiVirus COM interface to invoke a scan using the Microsoft security essentials virus scanner.
I am doing early binding because the documentation says that IOfficeAntiVirus interface inherits from IUknown and does not support IDispatch.
[Guid("56FFCC30-D398-11d0-B2AE-00A0C908FA49"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)
]
public interface IOfficeAntiVirus
{
void Scan(IntPtr info);
}
[ComImport, Guid("2781761E-28E1-4109-99FE-B9D127C57AFE")]
class SecurityEssentialsAntiVirus
{
}
The parameter for the scan method is a type that comes from this example. That example does the opposite of what I want because it implements the IOfficeAntiVirus interface using a .NET class rather than invoking the scan method. The marshalling and types in the example seem to match the documentation as far as I can tell.
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct MSOAVINFO
{
public int cbsize;
[MarshalAs(UnmanagedType.U4)]
public uint uFlags;
public IntPtr hwnd;
[MarshalAs(UnmanagedType.LPWStr)]
public string pwzFullPath;
[MarshalAs(UnmanagedType.LPWStr)]
public string pwzHostname;
[MarshalAs(UnmanagedType.LPWStr)]
public string pwzOrigURL;
}
This is the code I'm trying to use to invoke the scan method:
var antivirus = (IOfficeAntiVirus)new SecurityEssentialsAntiVirus();
var file = new MSOAVINFO();
file.pwzFullPath = #"test.txt";
IntPtr lParam = Marshal.AllocHGlobal(Marshal.SizeOf(file));
Marshal.StructureToPtr(file, lParam, false);
antivirus.Scan(lParam);
It fails on the call to the scan method. I get an exception that says:
"Attempted to read or write protected memory. This is often an
indication that other memory is corrupt."
I'm running this from a 32 bit command line app on a 64 bit system. I have experimented with running the command line program in both 32 bit and 64 bit with no success.
I am sure that the IOfficeAntiVirus guid is correct because I got it from the documentation. Also trying a random GUID that isn't a COM interface causes an error when I try to cast the object to the interface.
I am sure that the SecurityEssentialsAntiVirus guid implements the IOfficeAntiVirus because when I tried casting a different type of COM object to that interface I got an error.
I think the problem might be that the Scan method on the interface hasn't been correctly declared (declaring a random method on the interface gives the same error). I am not working from documentation for the security essentials assembly so it might not implement the interface in the way I imagine (or at all). Does anyone have any idea how to check that?
I can see a MpOAv.dll file in its directory and that is the same name as the header file in the IOfficeAntiVirus documentation, I know that's not a lot to go on. I can't open that dll up in ole-com object viewer to see what is inside. I get a message saying:
IMoniker::BindToObject failed on the file moniker created from (
"C:\Program Files\Microsoft Security Client\MpOAv.dll" ). Bad
extension for file
MK_E_INVALIDEXTENSION ($800401E6)
It also could be that I'm not passing the struct correctly to the Scan method. I have tried about a hundred variations without any luck including using AllocCoTaskMem() and passing the struct by reference.
I'm really not had much experience doing interop (learnt a heap today trying to figure this out!) so I'd really appreciate a push in the right direction. :)
I'm was also spent a couple of days on the same problem but without any results. The maximum what I was able to do it run check without any errors but even for malware it returns OK status, in my case
So, I continued research and found that Mozilla uses IAttachmentExecute antivirus API for checks. And Save method, of it, doing same job like
Scan of IOfficeAntiVirus
IAttachmentExecute::Save may run virus scanners or other trust
services to validate the file before saving it. Note that these
services can delete or alter the file.
and implementation of it on codeples http://antivirusscanner.codeplex.com/
One thing I notice is that you didn't set cbsize. file.cbsize=Marshal.SizeOf(file);

Exception details lost when thrown from C++ to C# through COM interop?

I am consuming a cpp COM object from c# code.
My c# code looks like this:
try
{
var res = myComServer.GetSomething();
}
catch (Exception e) { }
However the exception never contains any of the details I set in cpp, in particular my error message.
In my cpp side I have followed several examples I have found on the web:
...
ICreateErrorInfo *pcerrinfo;
IErrorInfo *perrinfo;
HRESULT hr;
hr = CreateErrorInfo(&pcerrinfo);
pcerrinfo->SetDescription(L"C++ Exception");
hr = pcerrinfo->QueryInterface(IID_IErrorInfo, (LPVOID FAR*) &perrinfo);
if (SUCCEEDED(hr))
{
SetErrorInfo(0, perrinfo);
perrinfo->Release();
}
pcerrinfo->Release();
return E_FAIL; // E_FAIL or other appropriate failure code
...
Am I missing anything?
Is there anything else that could affect this, like marshaling, the interop creation or attributes of the com server itself?
Does your COM class support ISupportErrorInfo ?
Assuming that your class does implement ISupportErrorInfo, did you by any chance add the support AFTER you imported the library into your C# project from Visual Studio?
Visual Studio generates the gunk that it needs to talk to a COM library only once, when you import the library. For this purpose, it builds a special translation DLL called "originalDllName.Interop.dll", based on the information available in the TypeLib of the DLL at the time of the import.
You can make implementation changes as often as you want without trouble; but if you changed the library in any way (added new classes, changed the interface definitions, changed the iterfaces implemented by your classes...), you will have to remove the COM DLL from your References, and then re-import it, for the Interop DLL to be refreshed.
I was facing the exact same issue. I had implemented ISupportErrorInfo and the InterfaceSupportsErrorInfo method in my COM module.Still, In C# exception I was not getting the error description I had set in perrorinfo on the C++ side. In my case, the entry of COM_INTERFACE_ENTRY(ISupportErrorInfo) was missing in the header file.
Instead of catching the Exception type, catch COMException type like this ...
try
{
// COM call
}
catch( COMException cEx )
{
// Check HRESULT here
}

Categories

Resources