C++ calling managed COM object can't find dependent assemblies - c#

I've created and registered a managed COM library in C# on my development machine. I've successfully registered it and created a .tlb file with regasm, and successfully imported the tlb into a c++ console app used for testing.
My COM assembly is called "efcAPI.dll" and it references another assembly that has not been set up for COM or registered in anyway called "efcServerDiscovery.dll". This second dll contains some code used by my COM dll and exists in the same folder as efcAPI.dll.
Everything concerning loading the COM assembly works fine. I can create instances of my classes defined in the COM and call methods from them. However when I call certain methods that use the code defined in efcServerDiscovery.dll I get a _com_error which reports that it could not load file or assembly 'efcServerDiscovery'.
I've verified that everywhere on my hard drive where efcAPI.dll exists there's a copy of efcServerDiscovery.dll (which is just the location I built and registered efcAPI.dll from). I've also attempted to place efcAPI.dll and efcServerDiscovery.dll in the same directory as the c++ app with no success.
Any suggestions as to where the c++ app is looking for the assembly or how to discover where it's looking would be great!

Yes, this is a problem with COM components having non-COM dependencies. Windows doesn't consider the location of the COM DLL when it searches for dependent DLLs. The normal search rules are in effect, the folder that contains the EXE first, Windows directories, current working directory, PATH environment. The location of the COM server does not play a role.
Assuming you don't want to deploy to the EXE folder, none of these are good places to store your DLL, although plenty of installers made the desperation move of storing it in c:\windows\system32 or modify the system PATH environment variable.
One thing you could do is P/Invoke SetDllDirectory() in your C# code before running any code in the DLL. Using Assembly.GetExecutingAssembly().Location will do it. That is however not a safe thing to do though, it might alter the search rules for the app that uses your component.
The only real fix is to install the DLL in the Windows side-by-side cache (WinSxS) and to include a manifest in your C# executable. Given the state of the documentation, I can only wish you the best of luck.

In these situations i always start with Dependency Walker verifying that what & where its trying to load is what i think it is.

fuslogvw will tell you where the CLR is looking for assemblies

Or use GAC.
(here are your characters, stackoverflow)

Related

Registration free activation of native COM (activex) component from .NET

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.

windows service Can't call C++ Native Methods [DllImpor("myDLL")]

I tried to use this way:
DLLImport a variable MFC dll
It works.
The problem is the C++ dll "myDLL" needs another DLL "XDLL",
I found that
the service current fodler when services started is the system32, not where the assemble are !!!
In this case, if I put "XDLL" in system32 it would work...
What I need is away to run it without copying anything to System32 or anyway else
Is it C# windows service issue ? or C++ ? what should I do ?
Thanks
If DLLs are specified by name only, that is without a complete path, then the Dynamic-Link Library Search Order comes into play.
There are lots of ifs and buts with this, but the bottom line is that if you put all the DLLs that your executable needs in the same directory as the executable, then the loader will be able to find the DLLs. That is the best practice because it requires no configuration, and you can be certain of which version of the DLL is to be loaded.

dll not found (non COM object)

I made an application in vs2010 (.net 4.0). I published it, both using publisher and InstallShield LE.
But when I run application, I get error that a dll is not found. I know which dll is missing. This is a non-COM object and I can't add it to my project in vs2010. I am using a wrapper library which invokes this dll.
If I paste that dll in syswow64, my application works fine. But I want a cleaner way of doing it. I already had a look at Hans's answer here. But I have no clue what is side-by-side cache.
Adding path to environment variables works fine too.
I am not sure if updating registry and adding a path value will work or not. I would like to know if I can update registry for my application and direct the path where it searches for particular dlls.
Thanks.
Modifying the user's PATH variable is a very heavyweight solution, and you should avoid that. Likewise, do not put the DLL in the system directory. That belongs to the system and is private to you.
The recommended way to solve the problem is simply to put the DLL in the same directory as the executable. The directory in which the executable lives is searched first when the loaded tries to locate DLLs. It is the safest place to put your native DLLs.
If for some reason you cannot put the DLL in the executable directory, there are other options:
Call SetDllDirectory with the directory of your DLL before making your first p/invoke call. When that call returns, call SetDllDirectory passing NULL to restore the default DLL search order.
Make an explicit call to LoadLibrary with the full path of your DLL before making your first p/invoke call. Once the DLL has been loaded, future p/invoke calls will use the module that has been loaded.
If you know the DLL name in advance, there is a simple way.
You can simply use LoadLibrary to load the DLL from its known location (based on for example a configuration file entry).
As long as you successfully call LoadLibrary before any of the DLL methods are used, this will succeed as the DLL is already loaded.
This works because you can LoadLibrary with a full path, and once that is done, subsequent calls to LoadLibrary with just the filename will succeed immediately, since the library is already loaded.

Register a dll that references multiple dlls

Ok I have 2 questions and I'm in a pickle here and have been for a week.
Important - No application will build this or run it. It will be a single client side dll (that references several other dll's) that will be placed in specific folder and I will need to register this dll using regasm or something.
OverView:
So I have a c# COM ScannerController.dll written. ScannerController references five 3rd party dll's that will already be installed and registered in folders throughout c:\Program Features\etc.... (the locations will change depending on the version of the software that they are on, but the dll will be the same.)
This one dll (integration.ActiveX (it's an assembly)) has a method called InstalledPath. InstalledPath returns the actual location of the executing assembly. When I finished the dll I ran it through IExplorer and it was returning the correct "../program features/....".
Then, in order to set it up on another computer I unregistered it and then ran some regasms and registered the dll at "Scanner/bin/debug/integration.ActiveX" (which oleview says it can't find it's dependencies) So I unregistered it, built it in vs2012 and now when I run it from IExplorer, the InstalledPath is "../bin/debug/". I created a new projecte, built it which auto registered it, and ran it from iexplorer and the InstalledPath is "..Scanner-fake/bin/debug/". I've unregistered it a million times in cmd and no matter what I do, it is now always pointing at the debug folder of the registered ScannerController.
Question 1:
How in the world do i register my COM ScannerController.dll, using something like regasm, and also point it to the five 3rd party dlls that ScannerController references?
Question 2:
I tried fixing it to where Integration.dll wouldn't exists in the local path on my computer (since i'm building it) so I set the copy local to false. When I build it, view it in oleview, it says that its dependencies cannot be loaded or found. How can I set the project up so that, with the copy local = false, the references can find the other 3rd party dlls?
Sorry for the lengthy question but thank you so much for reading and attempting to help me out. I have searched high and low for this and I am just mentally exhausted now.
1) ScannerController.dll
COM registration using regasm ScannerController.dll
2) 3rd Party ActiveX dll
Assuming it's already registered: No action required. (Otherwise register with regsvr32)
3) 3rd Party Managed Libraries (no com types/libsexposed)
Use one of the following 2 option to guarantie that your ScannerController Libraray can access these managed libraries:
Copy them to the folder where your ScannerController.dll or maybe (I am not 100% sure, you have to test it) to the folder where the ScannerController.dll host - the exe / the process calling ScannerController.dll - resides
Register these libs in the global assembly cache (the registry pendant for managed libraries) to make them globally available to other applications

iis7 hosted wcf service : avoid placing dll in system32 folder

I have a wcf service referencing a dll. Only way it works is by placing the dll in %windir%/system32 folder.
Things I have tried
tried switching between iis express, development server and iis (but this is irrelevant)
placing the dll in the bin folder and/or other application folders
trying to use the "regsvr32" util but the dll is not a com dll so it does not work.(no ddl entry point)
It is not a .NET dll so I don't think GAC can be manipulated to work with this
played with the system path variable without any success
What I actually want
A simpler method to access the dlls so I do not have to place the dll in system32 but contain it in an application folder and access it from there.
What am I missing?
EDIT:
I did find this post interesting and similar but again, it also uses the system32 method which is not the way to go.
If this is a win32 native library, you can "preload" it from a known location using pinvoked LoadLibrary passing a full path of your library as a parameter, somewhere early in your processing pipeline.
When any method from the library decorated with DllImport is called, the runtime will try to load the library (and would fall because the dll cannot be found) but since you preloaded it eariler, loading will succeed (loader checks the library file name, doesn't pay any attention to the directory the library is loaded from).

Categories

Resources