在我为公司工作的项目中,存在语际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中添加作为参考可以为我管理。
答案 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内容。