字符串参数未正确封送到 DLL C++
本文关键字:DLL C++ 参数 字符串 | 更新日期: 2023-09-27 17:56:13
我得到了一个由C#调用的DLL。DLL 包含两个方法,如下所示
extern "C" {
__declspec(dllexport) BSTR GroupInit(LPCTSTR bstrIniFile, bool bDiagErr, bool bProcErr);
}
BSTR 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();
}
我尝试通过首先定义类从 C# 调用这些 DLL:
[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";
string s = Grouper.GrouperServer.GroupInit(this.strCommandFilePath, true, true);
但是 DLL 返回错误:"找不到命令文件:"C"(仅路径的第一个字符,我已经在C++ DLL 中检查过)。由于某种原因,字符串this.strCommandFilePath
未正确传递到 C++ 方法中。
上面的电话有什么问题?
编辑以解决评论。
在 if (sz = ::GroupInit((char*)bstrIniFile, 1))
语句中调用的方法在 .c 文件中定义,并具有签名
char *GroupInit(char *szCmd, int iType)
{
...
}
在这里使用TCHAR
和相关类型是错误的。TCHAR
的用例是针对需要为不支持Unicode的Windows 9x和不支持Unicode的Windows NT编译的代码。那些日子早已一去不复返了,TCHAR
掩盖了这个问题。更重要的是,底层代码使用char*
所以假装你的包装器代码可以做任何其他事情是没有意义的。所以切换到 char
.
最重要的是,你正在抛弃康斯特。我猜是因为您调用的函数接受它不会修改的参数的可修改缓冲区。最好的解决方案是修复错误接受char*
的原始库代码,并使其接受const char*
。如果你做不到这一点,那么你就需要抛弃常量。但是用const_cast<>
C++的方式做到这一点.
所以,我会有这样的C++代码:
BSTR GroupInit(const char* szIniFile, bool bDiagErr, bool bProcErr) {
CString strResult = "";
char* sz;
::SetVars(bDiagErr, bProcErr);
if (sz = ::GroupInit(const_cast<char*>(szIniFile), 1))
strResult = sz;
return strResult.AllocSysString();
}
C# 代码应该是:
[DllImport("GrouperServer.dll", CallingConvention = CallingConvention.Cdecl,
CharSet = CharSet.Ansi)]
[return: MarshalAs(UnmanagedType.BStr)]
public static extern string GroupInit(
string strCmdFile,
bool bAllowBadDiagCodes,
bool bAllowBadProcCodes
);
现在,人们想知道sz
会发生什么.谁应该释放它?它甚至需要解除分配吗?只有你能回答这些问题。