I have been provided with a DLL which is to be called by C# et al. The DLL contains two methods as follows
extern "C" {
__declspec(dllexport) BSTR GroupInit(LPCTSTR bstrIniFile, bool bDiagErr, bool bProcErr);
__declspec(dllexport) void G();
}
class GrouperServer {
public:
BSTR GroupInit(LPCTSTR bstrIniFile, bool bDiagErr, bool bProcErr);
void G();
}
BSTR GrouperServer::GroupInit(LPCTSTR bstrIniFile, bool bDiagErr, bool bProcErr) {
CString strResult = "";
char* sz;
SetVars(bDiagErr, bProcErr);
if (sz = ::GroupInit((char*)bstrIniFile, 1))
strResult = sz;
return strResult.AllocSysString();
}
void G() {
MessageBox(0, "And text here", "MessageBox caption", MB_OK);
}
I am attempting to call these DLLs from C# by first defining the class:
public class GrouperServer {
[DllImport("GrouperServer.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void G();
[DllImport("GrouperServer.dll", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.BStr)]
public static extern string GroupInit(
string strCmdFile, bool bAllowBadDiagCodes, bool bAllowBadProcCodes);
}
and doing
this.strCommandFilePath = "C:\\MyDir\\MyCommandFile.txt";
Grouper.GrouperServer.G();
Grouper.GrouperServer.GroupInit(this.strCommandFilePath, true, true);
The call to method G()
works and I get a message box, but for the call to GroupInit()
, I get
An unhandled exception of type 'System.EntryPointNotFoundException' occurred in DrGroupIN.exe. Additional information: Unable to find an entry point named 'GroupInit' in DLL 'GrouperServer.dll'.
How can I call the second method GrouInit(...)
with the correct parameters in this case?
Edit 1.
I have also tried
[DllImport("GrouperServer.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr GroupInit(
string strCmdFile, bool bAllowBadDiagCodes, bool bAllowBadProcCodes);
where this is called via:
IntPtr ptr = Grouper.GrouperServer.GroupInit(this.strCommandFilePath, true, true);
string strString = Marshal.PtrToStringBSTR(ptr);
Marshal.FreeBSTR(ptr);
But this too throws the error above.
Edit 2.
I have also tried
[DllImport("GrouperServer.dll", CallingConvention = CallingConvention.Cdecl, CharSet=CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.BStr)]
public static extern string GroupInit(
[MarshalAs(UnmanagedType.LPTStr)]string strCmdFile,
bool bAllowBadDiagCodes,
bool bAllowBadProcCodes);
But this too throws the error above.
It looks to me as though you cannot call this DLL using C#. The DLL exports member functions of a class. And you cannot instantiate that class.
I can see the following options:
That said, these declarations seem to be in conflict:
extern "C" {
__declspec(dllexport) BSTR GroupInit(LPCTSTR bstrIniFile, bool bDiagErr, bool bProcErr);
__declspec(dllexport) void G();
}
class GrouperServer {
public:
BSTR GroupInit(LPCTSTR bstrIniFile, bool bDiagErr, bool bProcErr);
void G();
}
The first pair of declarations seem to be non-member functions. But they are followed by a class with member functions having the same names. You do need to be clear which functions you are attempting to call.
Perhaps the DLL already contains non-member functions that wrap up the member functions. In which case you just need to find out the names by which they are exported. Use Dependency Walker to do that.
So, how to declare the p/invoke. You need to know the character set in use, and the name by which the function is exported. Let's assume Unicode. The p/invoke would be:
[DllImport("GrouperServer.dll", CallingConvention = CallingConvention.Cdecl,
EntryPoint = "<exported name goes here>")]
[return: MarshalAs(UnmanagedType.BStr)]
public static extern string GroupInit(
[MarshalAs(UnmanagedType.LPWStr)]
string strCmdFile,
bool bAllowBadDiagCodes,
bool bAllowBadProcCodes
);