首先,用纯C++写一个进程内的COM已经搞定了,理论上只要把DLL导出的那几个接口变成主动注册类厂(CoRegisterClassObject)就应该OK了,现在的情况是客户端在创建接口的时候COM库也正确把进程拉起来,类厂也注册成功了,但是创建接口老是返回E_NOINTERFACE。我调试运行COM进程发现我我已经正确返回了对应接口的指针了,也返回了S_OK,但是客户端那边就是返回E_NOINTERFACE,搞了几天了。。麻烦高手帮看看。
我在网上找了半天,都是说用纯C++实现的进程内的例子,没有一个说进程外的,如果哪位有写好的发给我参考更是感谢,不要给我ATL和MFC之类框架代码。先谢谢了。下面是接口定义import "unknwn.idl";[object, uuid(e1893788-31b1-4a20-8e5a-c765c8272e75)]
interface ICalc : IUnknown
{
HRESULT Add(int a, int b, int* result);
HRESULT Sub(int a, int b, int* result);
}[
uuid(3ab7610a-a3eb-4101-822e-0557aef8de14),
version(1.0),
helpstring("Math Library")
]
library MathLib
{
importlib("stdole32.tlb");
[uuid(4994511e-a14d-4192-a1ff-9c4259c95bcd)]
coclass Math
{
interface ICalc;
}
}
下面是类实现部分的头文件:extern const IID IID_ICalc;
class ICalc : public IUnknown
{
public:
virtual HRESULT __stdcall Add( int a, int b, int *result) = 0;
virtual HRESULT __stdcall Sub( int a, int b, int *result) = 0;
};class Calc : public ICalc
{
protected:
long m_lRef;
public:
Calc();
virtual HRESULT __stdcall QueryInterface( REFIID riid, void **ppvObject );
virtual ULONG __stdcall AddRef( void);
virtual ULONG __stdcall Release( void);
virtual HRESULT __stdcall Add( int a, int b, int *result);
virtual HRESULT __stdcall Sub( int a, int b, int *result);
};class Math : public IClassFactory
{
public:
virtual HRESULT __stdcall QueryInterface( REFIID riid, void **ppvObject );
virtual ULONG __stdcall AddRef( void);
virtual ULONG __stdcall Release( void);
virtual HRESULT __stdcall CreateInstance( IUnknown *pUnkOuter, REFIID riid, void **ppvObject);
virtual HRESULT __stdcall LockServer( BOOL fLock);
};extern const IID LIBID_MathLib;
extern const CLSID CLSID_Math;
下面是类实现的部分代码:...HRESULT __stdcall Calc::QueryInterface( REFIID riid, void **ppvObject )
{
printf("Calc::QueryInterface\n");
if ( riid == IID_ICalc || riid == IID_IUnknown )
{
AddRef();
*ppvObject = this;
return S_OK;
} return E_NOINTERFACE;
}...HRESULT __stdcall Math::CreateInstance( IUnknown *pUnkOuter, REFIID riid, void **ppvObject )
{
printf("Math::CreateInstance\n");
Calc* p = new Calc();
HRESULT hr = p->QueryInterface(riid, ppvObject);
if ( SUCCEEDED(hr) )
{
return S_OK;
} delete p;
p = NULL;
return E_NOINTERFACE;
}...
HRESULT __stdcall Math::QueryInterface( REFIID riid, void **ppvObject )
{
printf("Math::QueryInterface\n");
if ( riid == IID_IClassFactory || riid == IID_IUnknown )
{
*ppvObject = this;
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}...下面是类厂注册实现代码:CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); Math oMath; printf("begin register class object...");
DWORD dwRegister = 0;
HRESULT hr = CoRegisterClassObject(CLSID_Math, &oMath, CLSCTX_LOCAL_SERVER, REGCLS_MULTI_SEPARATE, &dwRegister );
if (FAILED(hr))
{
printf("register failed, HR=%X\n", hr);
getch();
return 0;
} MSG msg;
while (GetMessage(&msg,0,0,0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
CoRevokeClassObject(dwRegister); ::CoUninitialize();
我在网上找了半天,都是说用纯C++实现的进程内的例子,没有一个说进程外的,如果哪位有写好的发给我参考更是感谢,不要给我ATL和MFC之类框架代码。先谢谢了。下面是接口定义import "unknwn.idl";[object, uuid(e1893788-31b1-4a20-8e5a-c765c8272e75)]
interface ICalc : IUnknown
{
HRESULT Add(int a, int b, int* result);
HRESULT Sub(int a, int b, int* result);
}[
uuid(3ab7610a-a3eb-4101-822e-0557aef8de14),
version(1.0),
helpstring("Math Library")
]
library MathLib
{
importlib("stdole32.tlb");
[uuid(4994511e-a14d-4192-a1ff-9c4259c95bcd)]
coclass Math
{
interface ICalc;
}
}
下面是类实现部分的头文件:extern const IID IID_ICalc;
class ICalc : public IUnknown
{
public:
virtual HRESULT __stdcall Add( int a, int b, int *result) = 0;
virtual HRESULT __stdcall Sub( int a, int b, int *result) = 0;
};class Calc : public ICalc
{
protected:
long m_lRef;
public:
Calc();
virtual HRESULT __stdcall QueryInterface( REFIID riid, void **ppvObject );
virtual ULONG __stdcall AddRef( void);
virtual ULONG __stdcall Release( void);
virtual HRESULT __stdcall Add( int a, int b, int *result);
virtual HRESULT __stdcall Sub( int a, int b, int *result);
};class Math : public IClassFactory
{
public:
virtual HRESULT __stdcall QueryInterface( REFIID riid, void **ppvObject );
virtual ULONG __stdcall AddRef( void);
virtual ULONG __stdcall Release( void);
virtual HRESULT __stdcall CreateInstance( IUnknown *pUnkOuter, REFIID riid, void **ppvObject);
virtual HRESULT __stdcall LockServer( BOOL fLock);
};extern const IID LIBID_MathLib;
extern const CLSID CLSID_Math;
下面是类实现的部分代码:...HRESULT __stdcall Calc::QueryInterface( REFIID riid, void **ppvObject )
{
printf("Calc::QueryInterface\n");
if ( riid == IID_ICalc || riid == IID_IUnknown )
{
AddRef();
*ppvObject = this;
return S_OK;
} return E_NOINTERFACE;
}...HRESULT __stdcall Math::CreateInstance( IUnknown *pUnkOuter, REFIID riid, void **ppvObject )
{
printf("Math::CreateInstance\n");
Calc* p = new Calc();
HRESULT hr = p->QueryInterface(riid, ppvObject);
if ( SUCCEEDED(hr) )
{
return S_OK;
} delete p;
p = NULL;
return E_NOINTERFACE;
}...
HRESULT __stdcall Math::QueryInterface( REFIID riid, void **ppvObject )
{
printf("Math::QueryInterface\n");
if ( riid == IID_IClassFactory || riid == IID_IUnknown )
{
*ppvObject = this;
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}...下面是类厂注册实现代码:CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); Math oMath; printf("begin register class object...");
DWORD dwRegister = 0;
HRESULT hr = CoRegisterClassObject(CLSID_Math, &oMath, CLSCTX_LOCAL_SERVER, REGCLS_MULTI_SEPARATE, &dwRegister );
if (FAILED(hr))
{
printf("register failed, HR=%X\n", hr);
getch();
return 0;
} MSG msg;
while (GetMessage(&msg,0,0,0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
CoRevokeClassObject(dwRegister); ::CoUninitialize();
lz可以参考一下ATL的ComModule,如何实现一个Windows 服务程序
也可以参考以下文字,如何实现Window服务
http://www.vckbase.com/document/viewdoc/?id=1474
为什么自己写一个简单的COM进程外服务麻烦?麻烦指点一下,谢谢
但是没有实现双接口的ATL进程外COM如果没有代理DLL也会报找不到接口的错误。
比较了一下,在加载实现了双接口的ATL进程外COM时,服务进程和客户进程有都会加载一个SXS.dll。
而我自己实现IDispatch接口不实现代理DLL时,却根本没用。一样会报找不到接口的错误。能不能答一下。谢谢
最近在看atl开发指南,代理存根还没有认真看,能否讲一下为什么需要代理存根吗?
谢谢
是不是本地的话,代理存根只需要在com服务器的exe文件生成就可以了。
对于远程服务器的话,服务器和客户端的机器都要有一份代理存根。
是这样吗?
1. 可以自己实现,MIDL在编译IDL文件时已经生成了代码,编译一下即可,这样会多出一个DLL。
2. 如果接口继承于IDispatch,那么可以使用通用列集器:CLSID:{00020424-0000-0000-C000-000000000046}。
3. 如果接口是继承于IUnknown且成员的参数和返回值是Automation-compatible(具体请查MSDN),那么可以在IDL接口描述上添加oleautomation属性,这样也可以使用通用列集器