用于C#的C ++ COM DLL

时间:2014-05-22 14:00:20

标签: c# c++ .net dll com

在我为公司工作的项目中,存在语际DLL通信问题。库提供程序使用C ++生成DLL,我的公司将在C#中使用此DLL。

我在互联网上读到,如果在COM(组件对象模型)中创建C ++ DLL,Visual Studio可以将此DLL添加为C#项目中的引用,并在代码中使用它。

由于这个原因,我制作了非常简单的DLL并尝试遵循MSDN文章"从CPP到COM"使这个DLL COM兼容,所以我可以将它与C#项目一起使用。但是,即使我可以编译DLL并且在构建时没有错误,我也无法让C#项目引用它,并且Visual Studio会给出错误#34;没有有效的COM组件"当我想添加这个DLL作为参考。

我为此制作了两个文件。一个"标题"文件:

#include "stdafx.h"
// 467B2143-85CC-404E-9050-4A754EF1DF01
static const GUID IID_Test = { 0x467B2143, 0x85CC, 0x404E , { 0x90, 0x50, 0x4A,0x75,0x4E,0xF1,0xDF,0x01} };
// 5D4EEEE9-9BE4-4DE9-B36D-86B96400F0F1
static const GUID CLSID_Test = { 0x5D4EEEE9, 0x9BE4, 0x4DE9, {0xB3, 0x6D, 0x86, 0xB9, 0x64, 0x00, 0xF0, 0xF1} };

#define DEF_EXPORT _declspec(dllexport) 

interface ITest: public IUnknown
{
    public: 

    virtual HRESULT __stdcall MultiplyNumbers( double n1, double n2, double& result) = 0;

};

实现接口的文件(header-impl.cpp)

#include "stdafx.h" 
#include "Header.h"

ULONG g_dwRefCount = 0;

class Test : public ITest
{
protected:
    ULONG m_dwRefCount;

public:
    Test(): m_dwRefCount(0) {   }

    virtual HRESULT __stdcall MultiplyNumbers( double n1, double n2, double& result)
    {
        result = n1 * n2;
        return NO_ERROR;
    }

    virtual HRESULT __stdcall QueryInterface(  REFIID riid, void  **ppvObject)
    {
        if (riid==IID_IUnknown || riid==IID_Test) {
            *ppvObject= this;
        } else {
            return E_NOINTERFACE;
        }
        AddRef();
        return NO_ERROR;
    }

    virtual ULONG __stdcall AddRef( void)
    {
        g_dwRefCount++; 
        m_dwRefCount++; 
        return m_dwRefCount;
    }

    virtual ULONG __stdcall Release( void)
    {
        g_dwRefCount--; 
        m_dwRefCount--; 
        if (m_dwRefCount==0) {
            delete this; 
            return 0; 
        } 
        return m_dwRefCount;
    }

};

class TestFactory : public IClassFactory {
protected:
    ULONG m_dwRefCount;

public:

    TestFactory(): m_dwRefCount(0){ }

    HRESULT __stdcall CreateInstance(IUnknown *pUnkOuter, REFIID riid, void** ppObject)  
    {
        if (pUnkOuter!=NULL) {
            return CLASS_E_NOAGGREGATION;
        }

        Test *pobj = new Test();

        if (FAILED(pobj->QueryInterface(riid, ppObject))) {
            delete pobj;
            *ppObject=NULL;
            return E_NOINTERFACE;
        }
        return NO_ERROR;
    }

    HRESULT   __stdcall LockServer(BOOL fLock)
    {
        if (fLock) {
            g_dwRefCount++;
        } else {
            g_dwRefCount--;
        }

        return NO_ERROR;
    }

    virtual HRESULT __stdcall QueryInterface(  REFIID riid, void  **ppvObject)
    {
        if (riid==IID_IUnknown || riid==IID_IClassFactory) {
            *ppvObject=  this;
        } else {
            return E_NOINTERFACE;
        }
        AddRef();
        return NO_ERROR;
    }

    virtual ULONG __stdcall AddRef( void)
    {
        g_dwRefCount++;
        m_dwRefCount++;
        return m_dwRefCount;
    }


    virtual ULONG  __stdcall Release()
    {
        g_dwRefCount--;
        m_dwRefCount--;
        if (m_dwRefCount==0) {
            delete this;
            return 0;
        }
        return m_dwRefCount;


    }
};

STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID * ppObject)
{
    if (rclsid!= CLSID_Test) { // Is this the number of our class?
        return CLASS_E_CLASSNOTAVAILABLE;
    }

    TestFactory *pFactory= new TestFactory;

    if (FAILED(pFactory->QueryInterface(riid, ppObject))) {
        delete pFactory;
        *ppObject=NULL;
        return E_INVALIDARG;
    }
    return NO_ERROR;

}

现在,我知道我要求的有点太多了,但有人能指出这个问题吗?我还有一个" Source.def"文件中包含一些内容:

LIBRARY DLLTEST
EXPORTS
    DllGetClassObject

这使得编译器说"这个函数声明必须是PRIVATE"。

我在错误的道路上吗?或者只是我,在编写DLL时犯了错误。

谢谢。

PS:我没有进行regsvr32.exe调用等。我已经读过Windows XP和更高版本的操作系统不再严格要求了,我认为尝试在Visual Studio中添加作为参考可以为我管理。

1 个答案:

答案 0 :(得分:1)

SO上的人曾经比较过写作和旧式的#39; COM到汇编编程。我认为这样说是公平的。人们正在逃避COM,而不是相反。要将COM组件正确添加到VS,必须在注册表中正确注册包含COM服务器的DLL(假设您需要inproc server)。这是使用regsvr32.exe程序完成的。但是regsvr32。 exe需要一个入口点 - 即DllRegisterServer() - http://msdn.microsoft.com/en-us/library/windows/desktop/ms682162(v=vs.85).aspx。 (也是DllUnregisterServer())我建议使用活动模板库来创建COM服务器,因为它启用了一些有用的抽象(IDL和许多宏)。

至于正常的' C ++ DLL - 您可以使用C#中可用的P / Invoke功能,并在不使用任何COM的情况下访问DLL内容。