如何使用正确的参数类型从C#正确调用C ++ DLL

时间:2014-04-02 09:24:43

标签: c# c++ dll pinvoke dllimport

我已经提供了一个由C#等人调用的DLL。 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);

但这也引发了上述错误。

1 个答案:

答案 0 :(得分:2)

它看起来好像你不能使用C#调用这个DLL。 DLL导出类的成员函数。而你无法实例化那个类。

我可以看到以下选项:

  1. 要求DLL供应商导出静态成员函数或非成员函数。然后可以使用p / invoke访问它们。
  2. 围绕DLL编写混合模式C ++ / CLI包装器。这个包装器可以很容易地使用非托管DLL。然后,它可以公开一个包装功能的托管ref类。然后可以添加C ++ / CLI包装器作为对C#项目的引用。

  3. 尽管如此,这些声明似乎存在冲突:

    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已经包含了包含成员函数的非成员函数。在这种情况下,您只需要找出导出它们的名称。使用Dependency Walker来做到这一点。

    那么,如何声明p / invoke。您需要知道正在使用的字符集以及导出函数的名称。我们假设是Unicode。 p / invoke将是:

    [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
    );