如何使用正确的参数类型从 C# 正确调用C++ DLL
本文关键字:调用 C++ DLL 参数 何使用 类型 | 更新日期: 2023-09-27 17:56:02
我得到了一个DLL,由C#等人调用。DLL 包含两个方法,如下所示
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);
}
我尝试通过首先定义类从 C# 调用这些 DLL:
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);
}
和做
this.strCommandFilePath = "C:''MyDir''MyCommandFile.txt";
Grouper.GrouperServer.G();
Grouper.GrouperServer.GroupInit(this.strCommandFilePath, true, true);
对方法G()
的调用有效,我收到一个消息框,但是对于对GroupInit()
的调用,我得到
DrGroupIN.exe 中发生了类型为"System.EntryPointNotFoundException"的未处理异常。其他信息:无法在 DLL "GrouperServer.dll"中找到名为"GroupInit"的入口点。
在这种情况下,如何使用正确的参数调用第二种方法GrouInit(...)
?
编辑 1.
我也试过
[DllImport("GrouperServer.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr GroupInit(
string strCmdFile, bool bAllowBadDiagCodes, bool bAllowBadProcCodes);
这称为通过:
IntPtr ptr = Grouper.GrouperServer.GroupInit(this.strCommandFilePath, true, true);
string strString = Marshal.PtrToStringBSTR(ptr);
Marshal.FreeBSTR(ptr);
但这也抛出了上面的错误。
编辑 2.
我也试过
[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);
但这也抛出了上面的错误。
在我看来
,您似乎无法使用 C# 调用此 DLL。DLL 导出类的成员函数。并且您无法实例化该类。
我可以看到以下选项:
- 要求 DLL 供应商导出静态成员函数或非成员函数。然后应该可以使用 p/invoke 访问这些。
- 围绕 DLL 编写混合模式 C++/CLI 包装器。此包装器可以轻松使用非托管 DLL。反过来,它可以公开包装功能的托管 ref 类。然后,可以将 C++/CLI 包装器添加为 C# 项目的引用。
也就是说,这些声明似乎相互冲突:
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();
}
第一对声明似乎是非成员函数。但是它们后面跟着一个具有相同名称的成员函数的类。您确实需要清楚您尝试调用哪些函数。
也许 DLL 已包含包装成员函数的非成员函数。在这种情况下,您只需要找出导出它们的名称。使用依赖沃克来做到这一点。
那么,如何声明 p/invoke。您需要知道正在使用的字符集以及导出函数的名称。让我们假设 Unicode。p/调用将是:
[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
);