如何用纯C++写一个进程外的COM?搞不定了!!

dawei_sun 2010-12-25 03:37:52
首先,用纯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();
...全文
361 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
clingingboy 2011-05-12
  • 打赏
  • 举报
回复
解决没,我也遇到同样的问题
hh_xj 2011-01-13
  • 打赏
  • 举报
回复
我也在学COM。
楼主看我最近的几个帖子。

进程外组件需要注册 proxy/stub dll的,楼主是不是没注册这步。
返回的E_NOINTERFACE其实不是你定义的Interface, 可能是跨进程通信时的IMarshal什么的的。
nodiebirdcomeback 2011-01-10
  • 打赏
  • 举报
回复
跨进程处理参数是需要代理的,没有代理是没有办法实现的。
简单的产生代理的代码可以通过使用IDL编写接口然后IDL
编译机器编译自动生成代理代码。
dawei_sun 2010-12-29
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 leechiyang 的回复:]
如果用户量很大,进程外com尽量避免使用,创建进程的时候,容易被杀毒软件拦截,可能会起不来(类似360等弱智的安全软件,真的是不分青红皂白就拦截了,他不知道是不是病毒,就让用户选择,用户更不知道啊,知道的用360吗!)。
[/Quote]
谢谢,但是我现在就想知道如何用纯C++写一个进程外的COM。
ThinkiCode 2010-12-29
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 leechiyang 的回复:]
如果用户量很大,进程外com尽量避免使用,创建进程的时候,容易被杀毒软件拦截,可能会起不来(类似360等弱智的安全软件,真的是不分青红皂白就拦截了,他不知道是不是病毒,就让用户选择,用户更不知道啊,知道的用360吗!)。
[/Quote]
谢谢,但是我现在就想知道如何用纯C++写一个进程外的COM。
leechiyang 2010-12-29
  • 打赏
  • 举报
回复
如果用户量很大,进程外com尽量避免使用,创建进程的时候,容易被杀毒软件拦截,可能会起不来(类似360等弱智的安全软件,真的是不分青红皂白就拦截了,他不知道是不是病毒,就让用户选择,用户更不知道啊,知道的用360吗!)。
ThinkiCode 2010-12-28
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 nodiebirdcomeback 的回复:]
使用纯粹C++编写进程外的COM组件需要编写很多代码的。建议不要怎么做了,
不过有个方法可以减少你的麻烦,可以使用idl编写脚本,然后使用idl的编译
器,会自动编译出代理和存根的代码。包括接口声明代码。不过编译出来的代码
可读性很差。
[/Quote]
如果我没有写存根和代理什么的?那COM库不会使用默认的吗?
我看ATL生成的进程外COM,它也没有相应的存根和代码DLL呀,那它就是可以正常。
不过我通过QueryInterface发现,它的接口实现了IMarshal接口,按照书上说,这个接口如果不实现,COM库也会有默认的实现呀。。。我实在是搞不明白了。。。
wshcdr 2010-12-26
  • 打赏
  • 举报
回复
? 楼上说的属实?

那我得多注意点儿他
jameshooo 2010-12-26
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 gw_net 的回复:]

你可以把代码发过来给我,我看看为什么不行,帮你补一下
gw_net@163.com
[/Quote]

这个家伙回答所有人的问题都是同一句话,从来没有任何技术回答的。
dawei_sun 2010-12-26
  • 打赏
  • 举报
回复
已经发到你邮箱了,谢谢你啊
nodiebirdcomeback 2010-12-26
  • 打赏
  • 举报
回复
使用纯粹C++编写进程外的COM组件需要编写很多代码的。建议不要怎么做了,
不过有个方法可以减少你的麻烦,可以使用idl编写脚本,然后使用idl的编译
器,会自动编译出代理和存根的代码。包括接口声明代码。不过编译出来的代码
可读性很差。
nodiebirdcomeback 2010-12-26
  • 打赏
  • 举报
回复
进程外的组件如果是使用纯粹的C++编写的话,和进程内的很多特性不一样的。
因为不同进程是不能共享地址的,所以必须委托操作系统来进行它们之间的互动,
这个互动就需要使用到代理和存根dll,COM里面还有个套间的概念,不同套间的
接口使用需要封送操作的。
gw_net 2010-12-25
  • 打赏
  • 举报
回复
你可以把代码发过来给我,我看看为什么不行,帮你补一下
gw_net@163.com
nodiebirdcomeback 2010-12-25
  • 打赏
  • 举报
回复
需要代理和存根的
hankcs 2010-12-25
  • 打赏
  • 举报
回复
COM不熟,关注

3,245

社区成员

发帖
与我相关
我的任务
社区描述
ATL,Active Template Library活动(动态)模板库,是一种微软程序库,支持利用C++语言编写ASP代码以及其它ActiveX程序。
社区管理员
  • ATL/ActiveX/COM社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧