【发布时间】:2015-03-06 03:27:10
【问题描述】:
在我为我的公司工作的一个项目中,出现了跨语言 DLL 通信问题。库提供者用 C++ 制作 DLL,我的公司将在 C# 中使用这个 DLL。
我在网上看到,如果 C++ DLL 是在 COM(组件对象模型)中创建的,Visual Studio 可以将此 DLL 作为引用添加到 C# 项目中并在代码中使用。
因此,我制作了非常简单的 DLL,并尝试按照 MSDN 文章“从 CPP 到 COM”来使这个 DLL 与 COM 兼容,这样我就可以将它与 C# 项目一起使用。但是,即使我可以编译 DLL 并且在构建时没有错误,我也无法设法让 C# 项目引用它,并且当我想将此 DLL 作为引用添加时,Visual Studio 会给出“没有有效的 COM 组件”的错误。
我为此制作了两个文件。一个“头”文件:
#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
这使得编译器说“这个函数声明必须是私有的”。
我在这里走错路了吗?还是只是我,在写DLL时犯了一个错误。
谢谢。
PS:我没有调用 regsvr32.exe 之类的。我已经读到 Windows XP 和更高版本的操作系统不再严格要求了,我认为尝试在 Visual Studio 中添加作为参考可以为我解决这个问题。
【问题讨论】:
-
您是否使用
regsvr32注册了COM dll? -
我没有,我只是尝试使用 Visual Studio 添加 -> 项目(右键单击)-> 添加参考页面并尝试使用“浏览”按钮添加参考。当我尝试将 regsrv32.exe 与 DLL 一起使用时,它显示“已加载 DLL,但未找到 DllRegisterServer”。
-
据我所知,regsvr32 必须成功才能在 .NET 中使用 DLL。我可能是错的。
-
你用Visual C++ ATL项目模板试过了吗?
-
不,但你确定我需要它吗? ATL 对我来说似乎是一个完全不同的故事,而且我以前从未使用过它。我现在需要做的就是让“库提供商公司”确保编写 C++ COM DLL 可以用于 C# 客户端代码。