sample p/invoke VS.NET 2003 solution

Microsoft includes a sample of language-interop via p/invoke with Visual Studio .NET 2003, but it's only set up as a makefile project. I do most of my Windows coding from inside VS.NET, so I wanted to learn how to create a dll from C++ code, then call it from C#, all from within the IDE. I built a VS.NET 2003 solution which builds the Microsoft sample code from within the IDE. Just posting it in the hope someone else might find it useful.

What I learned is that there's a very particular set of compiler options which must be set, and some very specific keywords/tags/attributes in both the C++ and the C-sharp code.

To set up the dll to have exported functionality:


  1. Set the compiler options so they look like this: /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_USRDLL" /D "PINVOKELIB_EXPORTS" /D "_WINDLL" /D "_MBCS" /FD /EHsc /RTC1 /MTd /Yc"stdafx.h" /Fp".\Debug/PinvokeLib.pch" /Fo".\Debug/" /Fd".\Debug/" /W3 /nologo /c /Gz /TP. To do this, edit the Property Pages for the project. Go through each of the C/C++ subcategories and set the options to get exactly this command line listed in the "Command Line" subcategory. skoolLIB.vcproj has these settings already, if you want to copy from there. This seems to do a whole bunch of things, including generating precompiled headers and a dll.

  2. Tag the declaration functions you wish to export with a macro -- this is too insane to describe; see the first comment in skoolLIB/PinvokeLib.h for details.

  3. Export the data structures:
    extern "C" PINVOKELIB_API int TestArrayOfStructs( MYPOINT* pPointArray, int size );
    typedef struct _MYPERSON
    {
    char* first;
    char* last;

To use the exported API from C#:


  1. Use the StructLayout attribute to describe the layout of datatypes to import:
    [ StructLayout( LayoutKind.Sequential, CharSet=CharSet.Ansi )]
    public struct MyPerson
    {
    public String first;
    public String last;
    }


  2. Declare the functions to import, and indicate where to find the library from which to load them:

    public class LibWrap
    {
    ....
    [ DllImport( "..\\skoolLIB\\Debug\\skoolLIB.dll") ]
    public static extern int TestStructInStruct( ref MyPerson2 person2 );
    ....
    }

  3. Call the imported functions as if they were normal functions:

    int res = LibWrap.TestStructInStruct( ref personAll );

Compiling the c# files doesn't need any special options, because the complicated part -- finding and loading the DLL -- is done at runtime. You've compiled a relative path into your code, though, which will probably complicate distribution.

I'm interested if anyone has insight into this process, or can point me at better documentation than what I've just written. There's way too much documentation; I guess I've just compounded the problem.