.NET COM Interop with references to other libraries - com

I'm up against a problem when loading a class in a managed library from a COM Interop library.
basically I have some Unmanaged C++ code and a COM Interop library written in C#. And finally a 3rd library which is referenced by the COM Interop library which contains a class:
public class MyClass{
public MyClass(){}
}
What I'd like to do is from my unmanaged c++ code, call a function in the Interop library
The C++ code doesn't need to know of the existence of the third library, it's only used within the Interop.
Init(){
MyClass _class = new MyClass();
}
for some reason this line in Init fails "MyClass _class = new MyClass();", and I don't get very usefull error messages, all I have to go on is a few of these in my output window:
"First-chance exception at 0x7c812afb in DotNet_Com_Call.exe: Microsoft C++ exception: [rethrow] at memory location 0x00000000.."
and the HRESULT of the "HRESULT hr = pDotNetCOMPtr->Init();" line in my C++ code is "The system cannot find the specified file"
I'm new to COM so if anyone has any ideas or pointer to get me going the right direction, I'd appreciate it,
Thanks

Nevermind, I think I just figured it out on my own. It looks like the Interop DLL and the third DLL referenced by the interop need to be located in the same directory.

Related

Replace COM DLL with new managed COM Callable assembly

Is there a smart way to scaffold a COM callable .NET class library from an existing native COM DLL?
Scenario
Suppose you have a COM based C++ Win32 application and you want to replace one of the COM DLLs with something written from scratch.
Constraints
The new library shall be written in C#, targeting the .NET Framework (4.x)
No modifications to the rest of the existing unmanaged application shall be required.
No recompilation of the unmanaged code shall be required.
What I already know
You can create .NET assemblies which are COM callable.
You can import the type library IDL from an existing COM DLL.
Based on this question, what I want should be possible, even if arduous.
Question
Is there a smart / efficient way to generate the scaffolding code for a COM callable .NET class library with the exact same signature as an existing unmanaged COM DLL so I can replace the DLLs?
There does not need to be any implementation at first, every method could just throw a NotImplementedException for example.

Calling c# code from managed c++ crashes

I have an unmanaged c++ DLL that calls c# code through a managed c++ wrapper. The unmanaged c++ DLL is a plug-in for some application (outside my control). When this application calls the unmanaged c++ DLL everything works fine until the managed c++ code tries to use the c# code. Then it crashes.
I have written a test application that does the same thing as the application, that is, it calls the unmanaged c++ DLL. This works fine.
The code is as simple as it could be:
unmanaged c++:
extern "C" __declspec(dllexport) void UnmanagedMethodCalledUponByApplication()
{
new Bridge();
}
managed c++:
Bridge::Brigde()
{
gcnew Managed(); // This line crashes
}
c#:
public class Managed
{
}
I have tried to add a try-catch (...) block around the problematic line but it doesn't catch the error.
If I replace the gcnew Managed(); line with MessageBox::Show("Alive!"); it works fine. So my guess is that something is wrong with my c# project settings.
I have tried to compile it with different platforms (Any CPU and x86). I have tried to change target framework. I have tried to call a static method in Managed instead of using gcnew. Still crashing.
Any ideas what might be the problem?
Update:
After advise in comments and answer, I attached the debugger. Now I see that I get a System.IO.FileNotFoundException saying that the managed DLL (or one of its dependencies) can't be found.
Here's a guess: The DLLs are placed together, but they are not located in the current directory. The unmanaged c++ DLL is loaded correctly since the main application specifies the path to it. The managed c++ is actually a lib, so that code works fine as well. But when the managed c++ tries to load the c# DLL it looks for it in the wrong directory.
Update:
The way to fix this is to load the c# DLL dynamically, using reflection.
extern "C" __declspec(dllexport)
Yes, that's a cheap and easy way to get the compiler to generate the required stub that loads and initializes the CLR so it can execute managed code. Problem is, it doesn't do anything reasonable to deal with exceptions thrown by managed code. And managed code likes throwing exceptions, they are a terrific trouble-shooting tool. That stops being terrific when there's no way for you to retrieve the exception information.
The best you could possibly do from native code is use the __try/__except keywords to catch the managed exception. Exception code is 0xe0434f4d. But that still doesn't give you access to the information you need, the exception message and the holy stack trace.
You can debug it. Project + Properties, Debugging, change the Debugger Type to "Mixed". Then Debug + Exceptions, tick the Thrown checkbox for CLR Exceptions. The debugger stops when the exception is thrown so you can see what's wrong.
Getting decent diagnostics after you shipped your code requires a better interop mechanism. Like using COM interop or hosting the CLR yourself.

.NET class as callback object in COM DLL

I am a relative newcomer to Windows programming and VB.net. What we are trying to do is call a function in an existing, 3rd party COM dll. This function requires a callback parameter, whose type is an interface also defined in the dll.
In our VB.net application, we have added the dll as a COM reference, and created a class that implements the interface in the DLL. We then send an object of that type as the callback parameter. This compiles fine. However, when we run the application, we receive an error stating that the program is unable to cast the object from our existing type to the interface type.
I suspect that there is a simple fix, but so far, my efforts to find a solution have come up short. If anyone could point me in the right direction, I'd be very grateful.
Thanks very much.
I suggest you to check whether the COM interface which you are implementing has a registerd proxy/stub or a correspondent typelibrary (tlb). You may check this by searching the interface's IID (this is a guid assossiated with this interface) in the registry:
Proxy/stub case:
HKEY_CLASSES_ROOT
Interface
{iid}
(Default) = ICustomInterfaceName
ProxyStubClsid32 = {clsid}
Typelibrary case:
HKEY_CLASSES_ROOT\TypeLib\{F37C8060-4AD5-101B-B826-00DD01103DE1}
HKEY_CLASSES_ROOT\TypeLib\{F37C8060-4AD5-101B-B826-00DD01103DE1}\2.0 = Automation Hello 2.0 Type Library.
HKEY_CLASSES_ROOT\TypeLib\{F37C8060-4AD5-101B-B826-00DD01103DE1}\2.0\HELPDIR =
; U.S. English.
HKEY_CLASSES_ROOT\TypeLib\{F37C8060-4AD5-101B-B826-00DD01103DE1}\2.0\9\win32 = hello.tlb
Replace {F37C8060-4AD5-101B-B826-00DD01103DE1} with a guid assossiated with your typelibrary.
In case if the typelibrary is registered. Check if its file is present on your PC

How to manage .Net's RCW COM object creation paramets (namely requested interface)?

I'm using an external native COM component in my C# .NET application.
This COM DLL doesn't have a type library, so I had to write the interop code myself, and having include/idl files I did it like TlbImp does.
But the worst thing is that the object creation fails with:
Creating an instance of the COM component with CLSID {40700425-0080-11D2-851F-00C04FC21759} from the IClassFactory failed due to the following error: 80040111
The class is finally created if I use the native CoCreateInstance and specify class_id and one of the implemented interface IIDs.
As it turned out the problem lies in that the COM object's IClassFactory::CreateInstance doesn't support IID_IUnknown passed as the riid parameter, and therefore returns CLASS_E_CLASSNOTAVAILABLE (I identified it with disassembler and debugger). The component is MS SQL VDI.
Is there any way to force the .NET RCW to pass a different interface ID into the CreateInstance method rather than IID_IUnknown?
I searched the net a lot, but didn't find a solution for this.
As a workaround I'm using C++/CLI now to create the object, requesting the proper interface instead of IID_IUnknown for this purpose now; but I would like to have code in C#, because C++/CLI requires me to build a different DLL for each platform.
Thanks
I repro. Brr, painful. You could pinvoke CoCreateInstance:
[return: MarshalAs(UnmanagedType.Interface)]
[DllImport("ole32.dll", ExactSpelling=true, PreserveSig=false)]
public static extern object CoCreateInstance(ref Guid clsid,
[MarshalAs(UnmanagedType.Interface)] object punkOuter, int context, ref Guid iid);

How to write a class library for OLE Automation?

I have Excel add-in which I add so many class modules that it is now very bulky. I want to convert it into a type library or a COM package so that I can re-use it for the other apps in the MS Office suite.
I ported the add-in to Visual Studio as a class library project but Excel Automation doesn't recognize the classes in the compiled .dll file. Intuitively I think I would need a manifest, an interface or the something like that in my code.
What do I need to know in order to expose a class's methods and properties for use in OLE Automation?
I am assuming since you used the phrase manifest, you are assembling this DLL using a .net development platform VS2003, VS2005 or VS2008 as compared to a VS 6.0
This link provides a detailed set of steps required to register a .NET assembly for use as COM component.
The one thing the article doesn't mention that I routinely do is create my own GUIDs. Use the Create GUID item in the Tools menu then insert them above the classes, interfaces, and enums you want exposed for COM.
[Guid("3838ADC1-E901-4003-BD0C-A889A7CF25A1")]
public interface IMyCOMClass {
void MyMethod();
}
[Guid("476BDEB6-B933-4ed5-8B86-7D9330A59356"),
ClassInterface(ClassInterfaceType.None)]
public class MyCOMClass : IMyCOMClass {
public void MyMethod() {
//implementation here
}
}
The second thing I do is use a separate interface for the COM portion that is implemented by the class. The reasoning for doing this has to do with the breakability of COM when the interface changes, think DLL Hell.
Hope this helps,
Bill.
(Assuming it's a .NET project)
Besides having to add the Guids to your interfaces and classes, you also need to mark them with the ComVisible attribute (unless you've marked the whole assembly with it). Also, you need to use the tlbexp.exe to export the metadata as a COM typelibrary for referencing in unmanaged clients.