I am writing a C# COM+ drop in for another COM+ dll. It has a very simple interface and I have successfully tested the drop in.
I am using 'component services' partly because the old system did and partly because it feel right.
Problem I have is when I register the legacy dll the path to the dll in the properties is the ACTUAL dll, also it just works.
When I register my drop in the path to the dll is mscoree.dll not my dll, and it seems hit and miss as to whether I have to add my dll to the GAC? I have tried code to add it to a cache automatically but it doesn't work?
Also, as I am using a WCF call with my COM+ call I am running into an issue as to where the configuration dll is currently it appears to be looking for settings in C:\Windows\system32\dllhost.exe.config
What I'd like is for it to look along side the actual dll? Am I missing something?
COM/COM+ is an unmanaged technology. It knows nothing about .NET managed code, so registering your .NET assembly directly in the COM registry could not possibly work. mscoree.dll is the .NET hosting library which loads the managed runtime and presents the unmanaged interfaces to COM which the COM registry requires. When an instance of the COM coclass that your assembly implements is activated, COM+ loads mscoree first, then mscoree has to load your assembly to hook up your implementation to the COM-callable wrapper which mscoree presents to COM+.
Where mscoree looks for your assembly in order to load it depends on how you registered it. It follows the normal path probing rules of the .NET Fusion loader, which means it will usually be looking in the GAC unless you have specified a codebase during registration (e.g. using the regasm command line argument /codebase).
Configuration settings for managed code are scoped by AppDomain, and by default the configuration file name for an AppDomain is obtained by adding the suffix .config to the path of the executable of the process hosting the AppDomain. Your component is hosted in COM+, so will execute in process which is an instance of DllHost.exe. So by default the configuration file for your component's AppDomain is going to be DllHost.exe.config. However, if you specify an Application Root directory for the COM+ application this will change the location where the AppDomain looks for its configuration, to [COM+ Application Root Directory]\[COM+ Application Name].config.
Related
I'm implementing a plugin system which allows them to be reloaded without restarting the host process. Everything works flawlessly in .NET 4.5 but when running in Mono 3.2.7 the plugin assembly gets leaked into the host AppDomain and the plugin can not be changed.
The assembly gets loaded into the host AppDomain when calling AppDomain.CreateInstanceFromAndUnwrap to create an instance of a type in the plugin assembly. This shouldn't cause problems because the type inherits MarshalByRefObject and shares a common interface.
You can see my code here: https://github.com/Rohansi/PluginTest The line which causes the assembly to leak is here.
I found a workaround for this issue. I've updated the Github repo with the fixes but I'll sum it up here.
To prevent leaking the assembly into the host AppDomain the assembly must not be in one of the locations the runtime will search for it. You either need to load it in a subdirectory or load it under a different file name. The assembly will no longer be automatically loaded into the host AppDomain but it started crashing when reloading.
I fixed this crash by replacing CreateInstanceFromAndUnwrap calls with this method. The PluginBridge instance is still created with CreateInstanceFromAndUnwrap.
After all this it seems I have working plugin reloading in both .NET and Mono (tested in 3.4).
I have a question concerning a COM C# component being created from a native C++ application.
The C# component is referencing an assembly which contains the COM interface.
So project A(.dll) contains the COM interface, project B(.dll) contains the COM class that implements this interface.
This C# COM component is then registered using regasm from some folder on my system, say for example:
C:\TestComponent which contains A.dll & B.dll, B being the one registered using regasm.
When my native C++ application (COM server), which is installed in another path, is trying to create an instance of the C# COM class from project B this fails complaining that A.dll can not be found.
If I copy (only) A.dll to the installation directory of my native C++ app, everything works perfectly.
Any ideas on how to tell my native C++ app that it needs to find the A.dll in a specified directory or in the directory where B.dll resides?
Kind regards,
Dwight
Having dependencies in a COM server is always a problem, whether it is an unmanaged server or one written in C#. Just like Windows, the CLR will only look in a few select places for a DLL. Which are the GAC and the directory where the EXE resides. With an option to also look in subdirectories of the EXE directory by using a app.exe.config file.
Knocking off the candidates here: you'll want to avoid giving the client EXE a .config file, you don't control its location nor configuration, it is somebody else's program. Same problem with the EXE directory.
Which leaves the GAC.
Also the location that Regasm.exe prefers, just omit the /codebase option when you register after you put the assemblies in the GAC. And a very good way to solve the DLL Hell problem that's so strongly associated with COM, the GAC can store different versions of your DLLs.
As far as I understand, you only registered B.dll. That is the reason, the COM System has no knowledge, where A.dll reside. I do not know a way to tell the application where it can found a, except of changing the workingdirectory or add the path to the A.dll to the system path variable or last but not least copy the A.dll into the system32 directory (but I hate that).
By the way, having a DLL proxy, like A.dll is, reside in the same directory as your application seems totally fine to me.
Ah one more thing. You can, if you now the path of the A.dll but did not want any of the above solutions, you can have a look into Loadlibrary.
I wrote a dll c++/cli library which uses my other c# dll library. C++/cli library works fine when I've got c# dll in the same folder as application which calls it. This library will be finally loaded to many applications and a C# dll must not be copied into directory with application. It has to be in the same folder as c++/cli library, but in that cases I've got System.IO.FileNotFoundException.
My suggestion is to load c# library manually or to change path where f.ex. firefox is looking for dependencies, but I tried with LoadLibrary() and Assembly::LoadFrom() methods to force loading from right directory. Of course I added directory path with dll to system PATH.
I work on VS2010.
You don't change the default directory where an application will look for dlls.
At design time put your dll in some well know location, the one you are going to deploy to. Add a reference to it, make sure it's set to Don't copy ever, otherwise it will end up in the bin folder. You have to do this otherwise it won't compile.
When you deploy, you'll need one package to deploy common dlls, and one for each application. Careful you don't create your own version of dll hell, if appA needs an older or new version of the common dll, compared to AppB
Add an AppDomain.AssemblyResolve event to main (for windows app). At run time the event handler will get fired when you reference a type in your dll, and the assembly has not yet been loaded.
In there you load it from the well known location. That usually in config, or in a relative path.
E.g.
AllMyApps
CommonDLLS
MyFirstApp
So the path you load the required common dll from would be "..\CommonDlls\MyCommondll.dll".
NB you will want to secure the dlls in some way, otherwise a bad guy might be able to inject their version of one in to your app, which would be bad...
You can use this mechanism to get the dll from a remote server or a database blob as well.
The simplest case is only a few lines of code, just look the event up. Took me about 15 minutes to get this going in a similar scenario.
Not on this machine though, otherwise I'd have pasted in the code.
I have an application written in C# which interfaces with some custom hardware using a vendor supplied .Net assembly. The .Net assembly in turn loads another DLL at run time. I can add the vendor supplied assembly to my project but when I run it, the vendor assembly complains that it can't load the required DLL. I can work around this for the moment by copying the DLL to the bin\Debug and bin\Release folder.
The problem is that I will need to distribute this application to clients at some point and they will not have this DLL in place. I can't see how I can make the solution require it; I can't add it as a reference since I get the error "A reference to foo.dll could not be added. Please make sure that the file is accessible, and that it is a valid assembly or COM component."
I can't convert the DLL to a .Net assembly using TlbExp, it gives an error "The module was expected to contain an assembly manifest."
I thought if I published the application via "click once" that I could declare the dependency there but I don't see any way for this either. I also tried adding it as a file resource but this didn't seem to help.
I can see other questions on SO relating to how to invoke functionality in an external DLL but in this case, I just need a way to bundle the DLL with the project.
Thanks.
Indicates that the attributed method is exposed by an unmanaged dynamic-link library (DLL)
The DllImportAttribute attribute provides the information needed to call a function exported from an unmanaged DLL. As a minimum requirement, you must supply the name of the DLL containing the entry point.
For further reference go here
Link to Review
You could add the dll as a resource, write it out as a byte[] to a file on loading, and do an Assembly.Load() at runtime for deployment.
You might have to use an AppDomain.AssemblyResolve Event to make sure the assembly resolves in case of multiple versions.
you could add both (all) of the dlls in your project as references and mark them as "copy local". That should do it unless the first DLL expects the second DLL in a specific place.
We have a plugin for IE based on spicIE, the purpose is to connect to some external devices.
To connect to those external devices, another company developed their token & DLLs. We need to have some ActiveX's and DLL's to do authentication by token.
The problem is that the plugin we developed for IE, in final part have a install.bat file, that runs a RegAsm and registers the DLL and after that plugin (or its changes) is viewable in IE.
When running the plugin from IE, our code can not find some DLL, required for authentication (name it x.dll).
Where is registered DLL copied? Is it really copied? I need to have x.dll in the folder where my plugin's DLL exists.
In a nutshell, RegAsm registers your .NET assembly to be COM-viewable. From MSDN: Once a class is registered, any COM client can use it as though the class were a COM class. The class is registered only once, when the assembly is installed. Instances of classes within the assembly cannot be created from COM until they are actually registered.
Without seeing your code in ActiveX, if I understand you correctly, your ActiveX is dependent on some COM DLLs, which is why you are running RegAsm against a .NET DLL.
Run RegDllView to find the details of what is registered and then check if you are indeed instantiating that object which was in fact registered.
Also, if you still have problems, try instantiating the object in VB6/Visual Studio 2010 etc. or equivalent in early binding to see if you have any problems. Examine the error on instantiation.