C# 字符串参数未正确编组到C++;动态链接库
我已经被提供了一个由C#调用的DLL。DLL包含以下两种方法C# 字符串参数未正确编组到C++;动态链接库,c#,c++,parameters,pinvoke,C#,C++,Parameters,Pinvoke,我已经被提供了一个由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;
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);
编辑以处理评论
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*
。如果你不能做到这一点,那么你需要扔掉常量。但是C++的方式是用<代码> COSTOSTCAST < < /P>
<>所以,我会有这样的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();
}
现在,我们想知道sz
会发生什么。谁会被期望解除分配呢?它甚至需要被解除分配吗?只有你才能回答这些问题。你这里一团糟。出于某种原因,您正在使用TCHAR
。你为什么这么做?您确实需要确定正在使用的字符集TCHAR
会让您感到困惑,根本不会给您带来任何好处。我也非常怀疑这个演员。你为什么这么做?另外,你100%确定你发布了真实的代码吗?您确定p/invoke中没有CharSet.Unicode
吗?您好,大卫,不幸的是,我刚刚继承了这个损坏的代码。我不知道是谁写的。我只是想让底层C代码能够(快速)从C#调用。所以我把旧的C++包装代码(写为COM库),你在代码> GROUP PNIT 方法中看到的东西,并把它放在我的“包装器方法”里面。我没有改变以前的类型。我有旧的C++包装代码和底层C代码,所以可以改变类型,但是另一个要求是这个C++代码可以在Linux的盒子上运行(还没有完成这个部分!),这并没有什么帮助。您需要了解什么是TCHAR
。以及你为什么要这样做。你说的TCHAR
是指使用LPCTSTR
;嗯,我相信这是你需要为不同的C++编译器做互操作的。我不是C++开发者,所以我承认我在这里挣扎,为什么要做的事情,当它完成了。我很高兴看到改变的类型,但我需要再次与许多不同的C++编译器,所以我不知道这里需要什么。就GroupInit(…)
方法中的代码而言,我确信它是可以更改的,因为我不知道为什么要进行转换,甚至不知道如果是按原样使用的话为什么要进行。。注意,之所以要进行字符转换,是因为::GroupInit
调用调用的是一个C方法,它采用字符*
。我们正在寻找重写整个东西,但要通过今年我必须启用从.NET使用。我讨厌这种垃圾,但我别无选择。
[DllImport("GrouperServer.dll", CallingConvention = CallingConvention.Cdecl,
CharSet = CharSet.Ansi)]
[return: MarshalAs(UnmanagedType.BStr)]
public static extern string GroupInit(
string strCmdFile,
bool bAllowBadDiagCodes,
bool bAllowBadProcCodes
);