I need to late bind to a 3rd party VB6 COM object in a 3.5 C# application (to avoid version dependencies that we currently have). The dll that was provided is not consumable in most non-latebound ways due to some bug that causes errors when we try to consume it normally. Currently, we are using a custom VB6 wrapper that makes things VERY version specific, however I have found that I can use late-binding to access properties and methods. Now, I am trying to late-bind to events, however everything I have read says that I need to inherit from the COM wrapper's interface to create the event sinks that are needed. Here is one such article.
So, my question is whether it is possible to perform late-bound event handling without having any reference to the dll at compile time?
UPDATE
Here are the errors I have with the VB6 wrapper (Which is still being actively updated).
In OleViewer, I get
Could not decompile selected item Error loading type library/DLL.
TYPE_E_CANTLOADLIBRARY ($80029C4A)
In Visual Studio I get:
Could not determine the dependencies of the COM reference
"3rdPartyDLL". Error loading type library/DLL. (Exception from
HRESULT: 0x80029C4A (TYPE_E_CANTLOADLIBRARY))
From here:
I found that the problem is caused when the IDL contains an importlib
to another project's .tlb typelib.
This seems to create a dependency between one dll and the other.
If dependant dll is missing OLEView refuses to display the dependent
dll, which also manifests itself by not allowing #import from C++
code.
Therefore I would look carefully at the COM dependencies of the DLL in question and make sure they are all registered as well.
It also goes on to add:
...because both dlls are co-dependent,
components from each interact (via interface declarations on method
signatures) and use #import from each others typelib.
Therefore, unless both target dlls are present, neither can be
rebuilt. As you can imagine, this causes a terrible problem when you
try to completely rebuild the project's from scratch.
I've experimented with separating the interface definitions into
smaller IDL files...
Edit: here's a recent example of this problem coming about (I believe). I had a C# library exported to COM. Modifications to that library were made which changed the interface of several classes, but the library GUID was not changed. Also see here about risks of AutoDual which was in use.
Here's the odd part - the VB6 DLL was rebuilt referencing the modified C# DLL. It compiled fine. no errors. But its typelib was corrupt - OleView couldn't open it, failing with TYPE_E_CANTLOADLIBRARY. Changing the C# DLL GUID was necessary to get the VB6 DLL recompiled successfully.
Clearly a pitfall of VB6 / C# interop.
The problem is most probably caused by the platform you are using. I just had a similar problem yesterday. Make sure that you are setting your project platform to x86 / x64 when you are late binding a x86/x64 COM type library.
The same applies to oleview. Use the x86/x64 version to view x86/x64 type libraries. (Possibly you need to install the x64 Windows SDK if you are on an x64 system to get the correct executeable).
Related
I have a native dll (which is an activex control) that I need use with my .NET application without having to register the dll in the registry.
I have read several in depth posts about registration free activation, some of the better ones are
A lengthy one from Steve White and Leslie Muller
This one from samuel jack
And another from Mike Makarov
and from what I can see it is possible. However several hours and hundreds of tests later I just cant get it to work. I've done a bit of PInvoking and even less with ActiveX controls in .NET in my career, so would appreciate any input from anyone whom might have kicked goals on this before.
So far I'm following Steves advice, in terms of building an application that works and then trying to formulate the winning manifest file syntax via repeatedly running the regsvr32 command to add and remove the unmanaged dll's from the registry. Just a bog simple .Net console application with about 10 lines of code...
One part that I am confused about is the interop. The native dll's I have are also accompanied with managed runtime callable wrappers (RCW's). In my .NET application I add reference to these RCW's and then can consume the respective classes and functionality provided for by the unmanaged dll's. I'm not PInvoking via dllimport.
In creating the manifest files I'm unsure if I need to worry about these RCW's and how they work in a registration free scenario, or even if if they need to be in the compiled output?
I've also tried several tools such as (OLE/COM object viewer, Mt.exe from the windows sdk, and regsvr42 from codeproject). But the manifest structure and necessary GUID's all vary between tools and posts.
Current status is that I receive a InvalidCastException "Unable to cast COM object of type System.__ComObject to interface type MyFunkyDllLib.FunkyDllControl. This operation failed because the QueryInterface call on the COM component for the interface with IID '{some guid}' failed due to the following error: Library not registered.
Can anyone confirm the correct syntax for the application and dll manifest files ? Online posts even vary on the name with some using sxs in the name....
Update1:
Whilst Joe's answer below did not work it did give me some better insights into reg free COM. In the properties of the Interop dll (the one that that is added to the project reference from the list of installed COM components on the dev machine) I changed the Isolated Property to True. This has the effect of making VS dump a copy of the COM dll (not the interop, it is embeded in the exe) to the bin\debug folder. VS also then creates a myapplication.exe.manifest.
In this manifest file is supposedly sufficent information for reg free com. I found other posts indicating success with this method but in my case I still ended up with the same InvalidCastException.
Reading over Samuel Jacks post again, I tried his method of creating both a manifest for the exe and the COM dll using the clsid information from the VStudio output manifest when Isolated=true. (I also deleted the <file/> section created by VS from the exe.manifest). After unregistering the COM from the registry I now have success ! The application starts and does not error.
Why this approach works and not the Isolated=true I have no idea because it is beyond my knowledge of manifests and assemblies.
However we are still not at the wizards castle yet Toto.
Now I'm back at the same issue I posted on this SO thread. However in this scenario unit tests are not involved. Just a plain console application with 10 lines of code. Works fine when in normal registered COM mode, but not in reg free mode.
After many hours of trial and error I finally got a solution to how to successfully implement RegFree COM.
Here is a full explanation incase it helps someone else.
I create a new .NET class library in VS
Right click references and select the COM components of interest.
(Note: for the COM to be visible in the list they must be registered
on the development machine. This can be acheived by using the
Regsvr32.exe tool included with windows. Calling "regsvr32
mycomdll.dll" registers it in the windows registry)
Right click the COM reference, goto properties, and then set Isolated=True. This has the effect of causing VS to output a .manifest file supposedly containing all the registry details necessary for a consuming .exe to know what resources to load instead of querying the registry. However in my case it was incomplete. Calls to Interop methods would work, but events from the COM component would not. See step 5 for my solution)
Build the project. The .manifest should appear in the build output.
Open the manifest in notepad or similar. Within the <assembly /> tag I needed to add a <comInterfaceExternalProxyStub /> tag with appropriate IID, tlbid and proxyStubClsid32 GUID elements. Elements of the manifest are documented on msdn. In my case the proxy/stub was proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"/> which is the built in windows proxy. The iid and tlbid I originally discovered via Process Monitor whilst calling regsvr32. An easier and more reliable option I later discovered was to use a tool like SxS manifest maker as it added a second <comInterfaceExternalProxyStub /> that I originally did not have.
Create an exe project in VS and reference the previously built library.
Build the exe project.
Run regsvr32 /u mycomdll.dll. To remove all registry associations.
Run the exe. In my case calls to and events from the COM component in the class library worked perfectly.
Caveats: I dont know why VS does not include the <comInterfaceExternalProxyStub /> element automatically in the .manifest. At the time of writing the only way to automatically update the manifest was to add a post build Task in VS. In my case I copied the entire XML manifest into an XML in the class library project and then just overwrote the .manifest file in the build output.
Unit (integration) testing of the COM is inconsistent. Currently in my case calls to Interop methods work, but events do not. It has something to do with the fact that the Test Runner is not compiled with knowledge of the dependencies and therefore such are not present in the activation context.
You are probably missing a typelib declaration...but ignore that for now... Instead, do the following...
After playing with this on and off for a while, I decided that the easiest way to do it is using MSBuild and a GenerateApplicationManifest task. I've been using it with a unmanaged app, but I don't see why it would not work with a managed app. I say "app" ... because my app is managed but I have both COM libraries and .NET assemblies with ComVisible classes in them.
From your description it sounds like you are dealing with having COM and don't have to worry about consuming .NET assemblies from COM. You can google for MSBUILD and GenerateApplicationManifest to get an example MSBuild file.
So, I assume you will not need to populate the "Dependencies" attribute of the task. You will need to populate the "IsolatedComReferences" attribute with a list of your COM DLLs. They can be a simple semi-colon delimited list, but usually they are in "ItemGroup" declarations in the MSBuild project file. The COM DLLs need to be registered at the time you generate the manifest.
As for your RCW, there is nothing special you need to do. IMO, they don't need to be in the manifest. .NET has a way of finding them as long as they are in the same directory as your app/DLLs.
If you use MSBuild, you won't have to generate manifests for your COM DLLs... They probably already have manifests already... Usually, the wizards automatically generate manifests and embed them. The only manifest that will need the COM type information is the manifest you generate with MSBuild.
The whole point of the manifests used in this manner is to populate the manifest space with all the COM information that would be in the registry.
I'm trying to add Windows/System32/Shell32.dll DLL to my project. The issue is, it copies the reference to the directory! Since this is a windows file, it shouldn't have to come with me if I were to deploy my application.
I have tried stopping it from copying to the directory, tried looking for how to embed the resource in the application and even added reference paths to System32. It seems so much more challenging than the program just using the local DLL from the system...
What can I do?
Shell32.dll is a COM component. You should not get a copy of it in your project. What you get instead is Interop.Shell32.dll. Which is a .NET assembly, not a copy of Shell32.dll. It contains the COM interface and class declarations, converted from the type library definition inside Shell32.dll to friendly .NET declarations that the CLR knows how to easily handle.
This is an optimization, it avoids having to make the conversion at runtime. Which is expensive, subject to various options (check the MSDN docs for Tlbimp.exe) and may easily fail because there is no general requirement that the type library is also available on the target machine.
You must deploy Interop.Shell32.dll to the target machine, just like you do with any .NET class libraries you'd use.
Do note that this interop library is no longer needed on .NET 4 and VS2010. Which acquired the "Embed Interop Types" feature. In other words, instead of keeping the interop types in a separate assembly, the C# and VB.NET compilers can now embed them in your program. Very highly recommended, just set the option to True in the Properties window view of the Shell32 reference.
This question is a sequel of this question
We're creating a dll, written in C++, providing access to some hardware. This dll implements and is accessed using COM interfaces. We also have a C# program that uses this dll through the COM objects.
We're having an issue with the versions. Indeed, when running the C# program, it absolutely wants to use the exact COM/C++ dll version it used when compiling. I.e. if the C# program was compiled using COM/C++ dll 1.2.3.4, then the program will refuse to run with COM/C++ dll 1.2.3.5.
Unhandled Exception: System.TypeInitializationException: The type initializer for 'MyDllVerify.App' threw an exception. ---> System.IO.FileNotFoundException: Could not load file or assembly 'MyCorp.MyDll.Interop, Version=1.2.3.4, Culture
=neutral, PublicKeyToken=ced78d295d1e0f2b' or one of its dependencies. The system cannot find the file specified.
File name: 'MyCorp.MyDll.Interop, Version=1.2.3.4, Culture=neutral, PublicKey Token=ced78d295d1e0f2b' at MyDllVerify.App..cctor()
I'd like to instruct the C# program to use any COM/C++ dll with version 1.2.anything.
Where can I configure this in the C# project?
I would suggest you to not directly reference to the COM-dll in your C# project. If you do that, at build time there is always a new COM-interop-dll generated. This can lead to a lot of problems.
It would be a better approach to create a COM-interop-dll, store it in your library folder and reference this library in your C# project. Keep this COM-interop-dll as static as possible. If you do it like that, you can replace the used COM-dll as much as you want, as long as your interfaces do not change.
You could try to manipulate this interop assembly and make the version checking for 1.2.* there, if you realy want that (I would not recommend to that, it could cause serious confusion).
Explanation:
The COM-interop-dll is a regular .NET assembly. It works like a wrapper between your C# code and the COM-C++-code you want to use in the C# code.
The COM-interop-dll don't have to be registered for COM. You can install this assembly so many times you like. But it requires that your COM-dll is registered for COM.
Useful tools:
tlbimp
regasm
sn
Nothing is different from the way I documented it in your previous question. You still use <bindingRedirect> to allow the wrong version of the interop assembly to be loaded.
It is fairly unlikely to work in practice, messing with DLL Hell when you use COM is extremely unwise. If you use early binding then COM has no way to verify that you are calling the correct method. Very unlike .NET where the jitter can make checks like these at runtime from the metadata in the assembly. If the C++ programmer did it right then he changed the guids of the types that he changed. Which will make your code bomb with E_NOINTERFACE since you'll use the guid of the old version.
If he didn't, unfortunately way too common, then your program is liable to crash with something nasty like an AccessViolationException. Or worse, it won't crash but will call the completely wrong method.
The failure mode is more benign when you use late binding, you'll get one of the IDispatch errors when the method doesn't exist or if its arguments have changed. Not that this ultimately solves anything, you still have a program that doesn't work. Mess with DLL Hell like this only if you like to live dangerously.
I am wondering how I would go about correctly setting up a C++/CLI library that wraps native c++ code that has several dependencies. I have tried both statically and dynamically linking the native library to its dependent libraries with no luck.
The Managed C++/CLI dll builds just fine and can be added as a reference to a C# project. However when I attempt to use any of the defined classes i receive either a BadImageFormatException or FileNotFoundException depending how i linked. I believe I need to specify the dependent libraries in the CLI library so it is loaded in the manifest but I am unsure of the process. Also because i know it will come up, I have verified that all of the libraries involved are built on the x86 architecture.
I figured out the problem and everything is working correctly now. It was a combination of several incorrect things all happening together.
If anyone has the same issue, I resolved it by setting up the following:
1) The Boost libraries that were referenced (specifically boost_thread) needed to be compiled with BOOST_THREAD_USE_DLL preprocessor (other boost libraries may need BOOST_ALL_DYN_LINK to just dynamically link everything). This is apparently a common issue.
2) I verified that all dependencies were in system Path (like R Ubben reiterated)
3) I used the DependencyWalker (depends.exe from sourceforge) to analyze my compiled managed DLL. It turned out that the libpq.lib library being used actually referenced additional DLLs that were not included in the lib folder but in the bin folder. So that need to be added to the Path.
4) Part of my wrapper was using the #include header for lists. This forced my library to link against 2.0 framework dependent libraries. This was not compatible with my 4.0 client targeted C# application. This was only made known by parsing through the Warnings from compiling (previously hidden due to C++ generating too many..foolish i know). However this was resulting in a System.BadImageFormateException being thrown despite everything targeting the same x86 architecture.
Hope that helps anyone else who has the same problem. The BadImageFormateException and FileNotFoundException were entirly too vague and unhelpful.
You should make the C++ dll in release mode and use extern "C" for public static things.
I have gotten that error when the dependent libraries were not in the path. The wrapper library is found because of the reference, but the reference does not also take care of the dependent libraries. Try placing them explicitly where the program is executing.
I have a .Net 2 C# application I am developing which uses a VB 6 generated COM DLL. The VB DLL is updated frequently any my application crashes with a System.Runtime.InteropServices.COMException (0x80040154). The part of the COM DLL I use does not change but the version (and CLSID) will.
The "Specific Version" option for the reference is false. The WrapperTool is tlbimp.
How do I tell my application not to worry about changes in the DLL? Is there any way of checking just the functions I am using?
It is one of the most common COM errors, "Class not registered". It starts at VB6, it has an option to control binary compatibility. I forgot exactly what that looks like, it's been too long. If you don't control this, VB6 is going to create a new COM server with different CLSID values. That requires re-registering the DLL with Regsvr32.exe. And re-generating the interop library with Tlbimp.exe. The latter step is probably the one you missed.
Note that using different CLSID values is a hard requirement for COM, it must be done when the public interface changes. But not when only the implementation changes.