3

I have a mixed mode dll with native dll dependencies.

I am loading the mixed mode dll from a C# exe using Assembly.Load. However, the location of the mixed mode dll is not in the application bin directory, therefore it fails because it only looks for the native C++ dll's in the bin and the folders in the PATH environment variable.

I thought using the option /assemblylinkresource was suppose to stop this and force the native dll's to be found in the alternate directory alongside the deployed mixed mode dll. This is proving to be not correct.

Is there a way to create a multi-file assembly with native dll's using an existing C++/CLI mixed mode dll? The only examples (http://msdn.microsoft.com/en-us/library/xawyf94k(v=vs.100).aspx) I've seen are using .netmodules coupled with a native dll.

Therefore, the solution is to either:

a) some how force the application to search for native dependencies in a directory of your choosing; or b) package the native dll's into the one managed mixed mode assembly (is this even possible??) - given statically linking the dependencies is not an option.

Seth
  • 8,213
  • 14
  • 71
  • 103

2 Answers2

5

Normal Windows DLL searching rules apply. So yes, there's no hope it will ever find those DLLs. A "multi-file assembly" isn't going to work either, you cannot merge native code. Options you have, roughly in preferred order:

  • Call SetDllDirectory() to add the path that contains the DLLs to the set of directories where Windows will look. May fail if the external code uses it as well.
  • Use Environment.SetEnvironmentVariable() to append the path to the PATH environment variable. This only changes the process' copy of the PATH so is a reasonable approach. May fail on machines that have a bloated PATH that is reaching the limit.
  • Set Enviroment.CurrentDirectory to the path with the DLLs. May fail if the external code tinkers with it as well.
  • Record the path for each DLL at install time in the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs registry key.
  • Install the DLLs in the Windows side-by-side cache and use a manifest to tell Windows about it. This is hard to get right.
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Great thanks! What do you mean 'May fail if the external code uses it as well' in your first solution? The SetDllDirectory doco, http://msdn.microsoft.com/en-us/library/ms686203%28v=vs.85%29.aspx, states "Adds a directory to the search path used to locate DLLs for the application." So even if external code uses it - won't it just add an additional path to the search? – Seth Jul 16 '13 at 22:34
  • Thanks for 4th solution. But this is not an option in our specific case as it is a boostrap application and the implementation is not known (dll dependencies) when the bootstr application is installed. – Seth Jul 16 '13 at 22:37
  • No, as documented: "Each time the SetDllDirectory function is called, it replaces the directory specified in the previous SetDllDirectory call." AddDllDirectory() is better but it was a very late addition to Windows. – Hans Passant Jul 16 '13 at 22:37
  • I think I will use option 2 and fallback on option 1 if there is a PATH environment variable bloat. – Seth Jul 16 '13 at 22:45
2

Potential candidate for a solution, not tested with MMA: This is probably not the optimal solution you were hoping for, but I thought I would add it as it could help you along the way to achieve solution a). In c++ you could control loading path and path search order by either manually setting the directory to be searched using SetDllDirectory (only available from XP SP1) or by manually loading the dll using LoadLibraryEx.

I guess one could use P/invokes to get access to these calls in C#

[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
private static extern void SetDllDirectory(string lpPathName);
kamjagin
  • 3,614
  • 1
  • 22
  • 24
  • This could work. So I am using Ninject to late bind - so all I have to do is make a call to `SetDllDirectory` before I do a `_kernel.Get`? – Seth Jul 16 '13 at 22:29
  • I don't think the link you provided in your edit will work with native dll dependencies. – Seth Jul 16 '13 at 22:32
  • @Seth: Try it, I think either of `SetDllDirectory` or `LoadLibrary` before getting to the p/invoke call should work. – Ben Voigt Jul 16 '13 at 22:33
  • @Seth: Sorry, I felt that my solution was a bit hacky and uncertain and started scouting for better solutions, (and missed that the link was not for native DLLs; removed it now.) – kamjagin Jul 16 '13 at 22:40
  • @BenVoigt was referring to a link that has now been removed. – Seth Jul 16 '13 at 22:42
  • @Seth: Ah, for mixed-mode assemblies, there is no p/invoke call. You'd need to preconfigure search path or preload the native DLLs before loading the mixed-mode assembly that depends on them. Different timing, same approach. – Ben Voigt Jul 16 '13 at 22:42
  • @BenVoigt: Thanks for your comment. I wasn't very clear in my question. But the managed exe is in C# so the p/invoke should work I have a C# Interface that is implemented by a C# class. The C# class wraps the C++/CLI ref class. This allows me to use ninject and late bind the interface. So I should be able to use SetDllDirectory before I call `_kernel.Get`. – Seth Jul 16 '13 at 22:47