Referencing a non-CLR DLL

2010-01-18

In my last post, I mentioned that I configured the C++ DLL to compile with the /clr option. I found this to be necessary in order to use the Visual Studio Add Reference command, so that the C# app could find the DLL at runtime. For some reason, Add Reference failed unless I used /clr. But strangely, I found that if I compiled without /clr and copied the DLL into my bin/Debug folder, everything still worked. And that isn’t too surprising: P/Invoke lets you call plain old Win32 DLLs.

But why wasn’t Add Reference working? Well, it turns out that Add Reference only lets you reference assemblies, and a win32 dll is not an assembly; you need CLR support for that. I had assumed Add Reference was some kind of generic build dependency, but I guess it’s something more specific. This is kind of disappointing. Who ever heard of an IDE without some way of managing project dependencies?

At first I thought my only option was to use Pre- and Post-Build commands. If you go to the Build Events tab of the C# properties window, you can see spaces for defining DOS commands that run before and after your build. VS supplies a bunch of macros you can use for important paths of other bits of information. So one way of solving my problem is to copy the DLL by hand. In the pre-build box, I entered this command:

copy "$(SolutionDir)$(Configuration)/MathDll.dll" "$(TargetDir)"

But that seems sort of like a hack. It leaves Visual Studio completely innocent of the project dependency. Later I found a slightly better (but still not so great) way of doing it. I got rid of this pre-build step, and under the C# project I used the Add Existing Item command. Then I navigated to the dll and added it to the C# project. I set its Copy to Output Directory property to Copy if newer. I left the Build Action property as Content, which seems to mean that Visual Studio just leaves it untouched. So now, as long as I’ve set up the dll portion to run first, the dll gets copied properly. This seems a little better than the DOS way, because at least Visual Studio is somewhat aware of that the C# project uses the dll, and that fact is also less hidden from developers (i.e. me, six months later).

UPDATE: On second thought, my first approach seems better. Because of the $(Configuration) macro, it works whether I’m building a Debug or Release version. But the Add Existing Item approach forces me to point to a dll in either the Debug or Release directory.

Perhaps the best solution is simply to compile with /clr. But I wanted to get both ways working, because I want to try both versions to see if either will resolve another error I’m getting, to be explained later. . . .

UPDATE 2: One problem I’ve found with the Pre-Build shell code is that even with $(Configuration), one line doesn’t work for all configurations. This is because if you set up, say, an “x64” configuration in addition to the default “Any CPU” one, then the folder structure isn’t parallel. The default configuration has a bin/Debug folder, whereas the x64 configuration has a bin/x64/Debug folder. This difference is not captured in the $(Configuration) macro. You can work around this because Visual Studio maintains separate property values for each configuration, so you can set up different pre-build shell commands for different configurations. But this is sort of annoying.

blog comments powered by Disqus Prev: Choose Folder Dialog Box Next: Hello world!