2

I have a .NET application which relies on a COM dll which is loaded with Registry-Free activation (Side By Side) and then accessed via P/Invoke. The COM dll additionally needs a few database files to work correctly.

Now I'm trying to merge all files in to one exe, and I don't know how.

ILMerge and similar will not work, as the COM dll is a native (unmanaged).

A possibility would be to hold the dll and its files as embedded resources and write them to the file system on startup. (As in the answers to this Stackoverflow question).

However, I would rather not have the application do this at startup.

Does anybody know how to easily add the COM dll and its files to the application and then load it by Registry-Free activation?

Btw: obviously I also could just register the COM dll separately (in the registry) and then use it from the application, however, this is not an option for me.

Community
  • 1
  • 1
Daniel
  • 471
  • 5
  • 28
  • 2
    There's no way. Either you distribute with the DLLs (the easiest), or you unpack them somewhere (e.g. a subdirectory of the TEMP directory; check for errors on creation) you can load them from without a full pathname (e.g. `AllDllDirectory`, `SetDllDirectory` or prepend to `PATH`). – acelent Aug 08 '14 at 11:34
  • @Daniel please review this question, and if my answer is sufficient, vote and close. It could help others in the future. – David Watts Sep 19 '14 at 09:57
  • @DavidWatts thanks very much for your answer, but it seems as if it is not possible to do exactly what I wanted to do. Paulo Madeira seems to be right (and is suggesting a similar approach). In my question I hinted at the possibility to add the files as resources and then write them to disk at startup, thereafter loading them separately (possibly with SetDllDirectory). However, as the files are big this would lead to a to large DLL and starting time. The problem is more a Deployment problem, with me actually wanting a single exe for the complete application... – Daniel Sep 19 '14 at 11:43
  • @PauloMadeira If you want to make your comment to an answer I will accept it (mainly because of the "There's no way" part) otherwise I will just make an answer myself and accept it (while referencing the solution outlined by you and David Watts). – Daniel Sep 19 '14 at 11:45
  • http://stackoverflow.com/questions/8836093/how-can-i-specify-a-dllimport-path-at-runtime/8861895#8861895 – Cody Gray - on strike Sep 24 '14 at 09:08
  • @CodyGray Not really a duplicate in my oppinion, the part about the DLLs having to be actual files the real answer. But yes, the rest is already contained in other answers. – Daniel Sep 25 '14 at 06:10
  • Had it been a duplicate, I would have marked it as such. They are just related, someone wondering about this is 99% guaranteed to want to read the other answer. – Cody Gray - on strike Sep 25 '14 at 06:42
  • @CodeGray Ah ok, now I see why you posted the link. In that case thanks for improving the question. – Daniel Sep 25 '14 at 06:45

2 Answers2

1

The way I have done this is to store the DLL in a path within the project and use the SetDllDirectory method to tell my application where to look for the DLL.

Here is my example:

PInvoke Signature for SetDllDirectory()

 [DllImport("kernel32.dll", SetLastError = true)]
  static extern bool SetDllDirectory(string lpPathName);

Constructor for the class that contains the DllImport

 public ClassName()
 {
     var currentWorkingDirectory = AppDomain.CurrentDomain.BaseDirectory;
     string path = Path.Combine(cwd, @"HereGoesYourRelativeFilepath");
     SetDllDirectory(path);
 }

On the properties of my DLL I have the "Copy To Output Directory" property set to "Copy Always" so I know that it will always be in the relevant folder in my bin directory after a build, so my relative filepath points to there and all is well.

Hope this helps

David Watts
  • 2,249
  • 22
  • 33
1

You can't do what you want directly, your DLLs must be actual files.

However, you can extract DLLs from resources into a temporary directory, and then use one of the following techniques to affect the DLL search:

  • Call SetDefaultDllDirectories with at least LOAD_LIBRARY_SEARCH_USER_DIRS or LOAD_LIBRARY_SEARCH_DEFAULT_DIRS, and then call AddDllDirectory to add your temporary directory to the DLL search path

  • If you can't find the previous functions with GetProcAddress (e.g. pre-Win7 with KB 2533623 or SP1), call SetDllDirectory to add your temporary directory to the DLL search path

  • If you can't find the previous function with GetProcAddress (e.g. pre-WinXP SP1), either set the current directory to the temporary directory (I don't recommend this one) or prepend it to the list of directories in the PATH environment variable

The reason why I don't recommend changing the current directory is because some DLL initialization might capture the current directory for some reason, and it'll be the temporary DLL directory instead of the intended one.

Adding a directory to the PATH may have its consequences if you also extract executable files.

The reason why I included this last option is because it works for limited environments where you can't call arbitrary Win32 functions, but you can either change the PATH environment variable or change the current directory.

acelent
  • 7,965
  • 21
  • 39