字符串参数未正确编组到C ++ DLL

时间:2014-04-02 10:53:16

标签: 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;
   ::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)
{
   ...
}

1 个答案:

答案 0 :(得分:1)

在此处使用TCHAR及相关类型是错误的。 TCHAR的用例是针对需要为没有Unicode支持的Windows 9x和Windows NT进行编译的代码。那些日子早已过去,TCHAR掩盖了这个问题。更重要的是,底层代码使用char*,因此假装您的包装器代码可以执行任何其他操作是没有意义的。所以切换到char

最重要的是你要扔掉const。我想因为你调用的函数接受一个不可修改的参数的可修改缓冲区。最佳解决方案是修复错误接受char*的原始库代码并使其接受const char*。如果你不能这样做那么你需要抛弃const。但是用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会发生什么。谁应该解除分配呢?它甚至需要被解除分配吗?只有你能回答这些问题。