我已经获得了一个由 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
.
最重要的是,你正在抛弃 const。我猜是因为您调用的函数接受一个可修改的缓冲区,用于它不修改的参数。最好的解决方案是修复错误接受 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
会发生什么.谁应该解除分配?它甚至需要被释放吗?只有您才能回答这些问题。
关于c# - 字符串参数未正确编码到 C++ DLL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22809189/