We program our tools in C# almost exclusively now which saves us a lot of time.  However, we have a considerable amount of code in C/C++.  This code is something we don’t wish to rewrite and maintain 2 versions of.   The solution was to use a DLL and call it from C#.

The difference between a standard .NET DLL and a standard DLL is that C# cannot easily get a reference to the functions.  To get around this you need to do a bit of extra work within your C# program.

To get started, here is a function in my standard Win32 dll.  This function just counts the string length and returns it again with no error checking:

#ifdef __cplusplus
extern "C" {
_declspec(dllexport) int WINAPI PassString(char *pIn, char *pOut)
strcpy(pOut, pIn);
return strlen(pIn);
#ifdef __cplusplus

Breaking the function down:

  • It is made an extern “C” to stop the C++ compiler mangling the name.  The WINAPI forces the function to be a _stdcall type as well.
  • The declspec(dllexport) tells the compiler to expose this function.
  • The rest should be self explanatory.

That is your DLL sorted.  To use this inside a C# application requires the use of DllImport.

To use our function from C# we need to add this code to a class. Anywhere else gives lots of errors that are not too helpful.

public class cFoo

[DllImport(".dll", EntryPoint = "PassString", PreserveSig = true)] 
static extern int PassString ([In] [MarshalAs(UnmanagedType.LPStr)] string In, [Out] StringBuilder Out);

It is that simple.  Using it is then as easy as any other function:

StringBuilder builder = new StringBuilder(255);
int x = PassString (“Hi AltDevADay”, builder);

We use this extensively for internal tools and Goldfish, the tool that comes with Elephant.  It has saved us many hours for relatively little work.

Note: I am led to believe there is a fairly large performance penalty crossing from .NET to a standard DLL but haven’t noticed any issues with this. This is most likely because the calls we perform are not that frequent so it has never become a problem.

Edit: Fixed code cut and paste error.  Also corrected to stdcall.  Thanks to jdhardy for pointing that out.