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" {
endif
_declspec(dllexport) int WINAPI PassString(char *pIn, char *pOut)
{
strcpy(pOut, pIn);
return strlen(pIn);
}
#ifdef __cplusplus
}
#endif
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.