2014-04-02 87 views
1

我已经提供了一个由C#等人调用的DLL。该DLL包含两个方法如下如何使用正确的参数类型从C#正确调用C++ 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); 

然而,这也引发上述错误。

回答

2

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

我可以看到以下选项:

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

这就是说,这些声明似乎是在冲突:

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 
); 
+0

感谢您的回复大卫。我昨天获得了源代码C++代码。核心库是用C编写的,在给出这个代码之前,它有一个COM C++包装类。当从C#调用时,这是非常缓慢的(尽可能快地请求1,000个呼叫)。所以作者给了我C代码,所以我可以用某种方式来包装它。我从来没有这样做过,所以会感谢您可能支付我的任何进一步的建议? '混合模式C++/CLI包装'是什么意思?非常感谢您的时间...... Ps。 'G()'方法调用好吗? – MoonKnight

+0

在VS中创建一个C++ CLR类库项目。这将编译为.net托管程序集。您可以使用C++/CLI代码来使用本地DLL。将其头文件和链接包含到其导入库中。一些网络搜索应该会让你回家。 –

+0

由于你的答案是正确的,我不会发布一个新的,但我认为这个错误是由于代码声明(和导出)一个名为'GroupInit'的外部函数但没有定义它的事实。所以该方法不在DLL中,因此是例外。它与类成员函数无关。 –