关于动态调用COM组件的问题

现在还是人类 2010-04-11 12:39:54
在VB中,可以通过 CreateObject 函数通过类名动态创建出COM组建对象来使用,
如我有一个 COM 组件,注册名为:"AObject.Demo",里面有一个方法,名为 "Show"
在VB中通过这两个信息,可以这样调用这个对象

Sub Main()
Dim DemoObj As Object
Set DemoObj = CreateObject("AObject.Demo")
DemoObj.Show
End Sub

但是在VC里我就不知道具体的该怎么做了,看了一下网上的资料,好像需要使用
CLSIDFromProgID 和 CoCreateInstance 来创建对象,我这样尝试了一下

#include "stdafx.h"
#pragma comment(lib,"Ole32.lib")
#include "Objbase.h"

int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
CLSID clsid;
CLSIDFromProgID(L"AObject.Demo", &clsid);

IUnknown *pUnk = NULL;
CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER,
IID_IUnknown, (void **)&pUnk);
//不知道下面该怎么写了,还请高手帮一下忙
//...
return 0;
}
...全文
380 17 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
现在还是人类 2010-04-12
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 sgzwiz 的回复:]
不懂的东西先自己读书,不要一遇到问题就问别人。否则别人说出正解,你也不会明白。
而14楼的内容,正好说明了楼主根本看不懂别人再说些什么。
[/Quote]
你从何看出我是一遇到问题就问别人?还有别人说出正解在哪?
我问

//这里之后该如何调用 Show 方法呢?
//...

正解在哪呢?
我是一直在找资料,一直在放代码上来,可能是我想得过于简单,我提问的部分可能不止
一两行代码才可以实现,但这并不表示我没有尝试学习和研究呀。起码这方面我的态度是
很认真的。就是因为看了没搞懂才到这里来问问看的。


[Quote=引用 16 楼 arong1234 的回复:]
难道3楼的话很冒犯你?不管怎么说,怎样对你才是“真”掌握,我相信对别人是无所谓的,你自己去体会吧
[/Quote]
一开始你就没打算认真回答问题,当然,到 CSDN 这种地方答题回帖是大家的自由,不想答
就不答,即使乱答也无所谓,只是你的处事方式我实在不敢苟同。
就你#3答的东西,可以说是“点”,当然,我还没到那层面你点不透是常有的事,这种回答方式
在CSDN中经常有,我也常用,所以在后面我也表示感谢,但是你除了点之外,还多余加了点“贬”的意思。
就你这一句:“即使真的让你程序跑起来,你也不可能真掌握的。”就是在“贬”。
你怎么知道我弄得我的程序跑起来后就不可能掌握?难道我不会继续找资料继续学习?还是你认为
我是属猪的这辈子都不可能了解这些问题?
就算是这样我也没怎么多说你把,最后还表示了感谢
怎知你后面还直接说我是个“不合理的人”和说话“偏极端”,你这已经不是在讨论什么技术,根本
就是人身攻击,而且从开始就是,也怪不得我后面说你的话带刺。

不要说我见谁咬谁,我只是道出事实。我本很有诚意的提出问题,但却遇到题不怎么答,却爱没事贬人
的人,像这种情况任谁看了都会看不下去。
arong1234 2010-04-11
  • 打赏
  • 举报
回复
难道3楼的话很冒犯你?不管怎么说,怎样对你才是“真”掌握,我相信对别人是无所谓的,你自己去体会吧
[Quote=引用 14 楼 supermanking 的回复:]
引用 12 楼 arong1234 的回复:
我无意冒犯,你的意思说我是不合理的人啰?

对于不同的开发语言来说,开发技术的理念与实现方法都不同,说到 COM 组件,在VB的开发当中,
真正接触到IUnknown,IDispatch,IConnectionPtr的并不多,但不可否认同样有很多人弄出很多很
优秀的 COM 组件,但开发这些组件的人未必对你所说的这些东西有多深的了解。你那句:
“难道IUnknown,IDispatch,IConnectionPtr之类得接口不知道,也能把COM程写好?”
过于武断了吧,而且我不是在VC里写 COM 组件,我只想调用而已。

[/Quote]
sgzwiz 2010-04-11
  • 打赏
  • 举报
回复
不懂的东西先自己读书,不要一遇到问题就问别人。否则别人说出正解,你也不会明白。
而14楼的内容,正好说明了楼主根本看不懂别人再说些什么。
现在还是人类 2010-04-11
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 arong1234 的回复:]
我相信任何一个合理的人都不会把“掌握COM”理解成Ring3/Ring0和WIn32子系统的,如果这样,没有任何人敢说“掌握”什么!楼主就是一个说话偏极端的人。

掌握COM,你至少对一些基本的使用方法得了解,即使你不打算非常深入得了解,不打算脱离普通得开发,几个COM最基本得东西你总得知道,难道IUnknown,IDispatch,IConnectionPtr之类得接口不知道,也能把COM程……
[/Quote]
我无意冒犯,你的意思说我是不合理的人啰?

对于不同的开发语言来说,开发技术的理念与实现方法都不同,说到 COM 组件,在VB的开发当中,
真正接触到IUnknown,IDispatch,IConnectionPtr的并不多,但不可否认同样有很多人弄出很多很
优秀的 COM 组件,但开发这些组件的人未必对你所说的这些东西有多深的了解。你那句:
“难道IUnknown,IDispatch,IConnectionPtr之类得接口不知道,也能把COM程写好?”
过于武断了吧,而且我不是在VC里写 COM 组件,我只想调用而已。

我对 VC 是个新手,接触时间并不是很长,所以很多开发习惯和理念都还是按 VB 的模式思考问题。
虽然有时候并不一定正确,但起码我知道,把复杂的东西弄出来,封装后让他使用起来更简单的做法
肯定没错。因为这样会解放程序员的思路,不要被工具所制约,是人玩程序,不是程序玩人。即使我
现在不是很了解这些技术,但相信今后肯定会慢慢接触,慢慢弄清楚。

我的说法其实也并不是偏极端,因为我也接触过下位机的开发和驱动开发,每一个层面要了解的东西
可以说太多太多了,如果真的每一个东西都去刨根问底,那不知道那一年我才能做出一个完整的程序,
所以我才会只想知道怎么使用先,至于以后如果有这方面的需要或是有多余时间的时候在慢慢了解也
不晚。在我的概念里,如果要做到“真掌握”,我认为从计算机结构和操作系统的结构及COM在系统中
扮演什么角色乃至他具体的工作方式及实现函数都要了如执掌这才叫“真掌握”。难道了解计算机结构
就不要清楚什么是Ring3和Ring0?了解COM在Win32子系统扮演什么样的角色就不需要了解操作系统?
我只是因为要么接触的是比较高级的应用,要么就是弄比较底层的应用,所以看起问题来会看到另一个
层面的东西也不奇怪。

我只是没按你的理解“真掌握”的意思去理解这个词而已,你理解的“真掌握”是了解 IUnknown,IDispatch,IConnectionPtr 就叫做“真掌握”。早知道这么简单就“真掌握”你直说不
就好了,还把我弄成个“不合理的人”。
ljz888666555 2010-04-11
  • 打赏
  • 举报
回复
http://www.vckbase.com/document/viewdoc/?id=1493
看这个了解一下,就行了,
arong1234 2010-04-11
  • 打赏
  • 举报
回复
我相信任何一个合理的人都不会把“掌握COM”理解成Ring3/Ring0和WIn32子系统的,如果这样,没有任何人敢说“掌握”什么!楼主就是一个说话偏极端的人。

掌握COM,你至少对一些基本的使用方法得了解,即使你不打算非常深入得了解,不打算脱离普通得开发,几个COM最基本得东西你总得知道,难道IUnknown,IDispatch,IConnectionPtr之类得接口不知道,也能把COM程序写好?

[Quote=引用 4 楼 supermanking 的回复:]
引用 3 楼 arong1234 的回复:
所谓真掌握是指什么呢?从底层了解Ring 0\Ring 3 还有 Win32 子系统和 COM/COM+ 结构体系?
没必要吧,我只是想做这方面的普通开发而已,不是研发这方面的架构作更底层的运用,而且我目前
的应用也没涉及到那么深,能用就好了,就像在VB里使用CreateObject函数,谁会去管他是怎么做的,
知道怎么用就可以了。[/Quote]
arong1234 2010-04-11
  • 打赏
  • 举报
回复
这是需要使用支持IDispatch接口的COM对象才行(VB只支持这种对象),这种接口是支持根据名字进行访问和参数调用的。
[Quote=引用 9 楼 supermanking 的回复:]
引用 7 楼 firmbird 的回复:
注意,这种方法的前提是没有引用任何的库文件,是直接通过字符串变量的类名创建出对象来使用的
但是楼上几位的说法都是以先知道或先引用为基础,这样就有点难办了[/Quote]
现在还是人类 2010-04-11
  • 打赏
  • 举报
回复
我顶 我顶 我顶 我顶 我顶 我顶 我顶
现在还是人类 2010-04-11
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 firmbird 的回复:]
你得知道定义这个show方法的接口,
pDisp->QueryInterface(IID_IXXXX,(LVOID*)&pInterface)
pInterface->show(...)
或者这个方法的dispid以及调用参数个数与类型,
pDisp->Invoke(...)
[/Quote]
问题是我调用对象的先决条件是通过字符串类型的“类名”创建出对象。
这个需求其实很平常,我有一个程序,是个框架式的,他通过读取脚本文件
得到要调用的COM组件名称,当然,COM组件的接口都一样,比如脚本是这样的

用户窗口="AObject.Demo1"
客户窗口="AObject.Demo2"
供应商窗口="AObject.Demo3"
而每一个都是一个程序员开发的单独 COM 组件,但他们都有一个 Show 方法
如果在VB里,可以这样调用

Sub Main()
InfObj.LoadInfoFile(App.path & "\Option.ini")
Dim DemoObj As Object
Set DemoObj = CreateObject(InfObj.Item("用户窗口").Value)
DemoObj.Show
End Sub


注意,这种方法的前提是没有引用任何的库文件,是直接通过字符串变量的类名创建出对象来使用的
但是楼上几位的说法都是以先知道或先引用为基础,这样就有点难办了
lsupper 2010-04-11
  • 打赏
  • 举报
回复
1.创建myCom.dll,该COM只有一个组件,两个接口:
IGetRes--方法Hello(),
IGetResEx--方法HelloEx()

2.在工程中导入组件或类型库
#import "组件所在目录myCom.dll" no_namespace

#import "类型库所在目录myCom.tlb"
using namespace MYCOM;

方法一:
CoInitialize(NULL);
CLSID clsid;
CLSIDFromProgID(OLESTR("myCom.GetRes"),&clsid);
CComPtr<IGetRes> pGetRes;//智能指针
pGetRes.CoCreateInstance(clsid);
pGetRes->Hello();
pGetRes.Release();//小心哦!!请看最后的“注意”
CoUninitialize();

方法二:
CoInitialize(NULL);
CLSID clsid;
HRESULT hr=CLSIDFromProgID(OLESTR("myCom.GetRes"),&clsid);
IGetRes *ptr;
hr=CoCreateInstance(clsid,NULL,CLSCTX_INPROC_SERVER,
__uuidof(IGetRes),(LPVOID*)&ptr);
ptr->Hello();
CoUninitialize();

方法三:
CoInitialize(NULL);
HRESULT hr;
CLSID clsid;
hr=CLSIDFromProgID(OLESTR("myCom.GetRes"),&clsid);
IGetRes* ptr;
IGetResEx* ptrEx;
//使用CoCreateClassObject创建一个组件(特别是mutilThreads)的多个对象的
时候,效率更高.
IClassFactory* p_classfactory;
hr=CoGetClassObject(clsid,CLSCTX_INPROC_SERVER,
NULL,IID_IClassFactory,
(LPVOID*)&p_classfactory);
p_classfactory->CreateInstance(NULL,__uuidof(IGetRes),
(LPVOID*)&ptr);
p_classfactory->CreateInstance(NULL,__uuidof(IGetResEx),
(LPVOID*)&ptrEx);
ptr->Hello();
ptrEx->HelloEx();
CoUninitialize();

方法四:
直接从dll中得到DllGetClassObject,接着生成类对象及类实例(这方法可以
使组件不用在注册表里注册,这是最原始的方法,但这样做没什么意义,至少失去了COM
对用户的透明性),不推荐使用.
typedef HRESULT (__stdcall * pfnHello)(REFCLSID,REFIID,void**);
pfnHello fnHello= NULL;
HINSTANCE hdllInst = LoadLibrary("组件所在目录myCom.dll");
fnHello=(pfnHello)GetProcAddress(hdllInst,"DllGetClassObject");
if (fnHello != 0)
{
IClassFactory* pcf = NULL;
HRESULT hr=(fnHello)(CLSID_GetRes,IID_IClassFactory,(void**)&pcf);
if (SUCCEEDED(hr) && (pcf != NULL))
{
IGetRes* pGetRes = NULL;
hr = pcf->CreateInstance(NULL, IID_IFoo, (void**)&pGetRes);
if (SUCCEEDED(hr) && (pFoo != NULL))
{
pGetRes->Hello();
pGetRes->Release();
}
pcf->Release();
}
}
FreeLibrary(hdllInst);

方法五:
通过ClassWizard利用类型库生成包装类,不过前提是com组件的接口必须是派
生自IDispatch,具体方法:
调出添加类向导(.NET中),选择类型库中MFC类,打开,选择"文件",选择
"myCom.dll"或"myCom.tlb",接下来会出来该myCom中的所有接口,选择你想
生成的接口包装类后,向导会自动生成相应的.h文件.这样你就可以在你的MFC中
像使用普通类那样使用组件了.(CreateDispatch("myCom.GetRes") 中的参数就是ProgID通过Clsid在注册表中可以查询的到)
CoInitialize(NULL);
CGetRes getRest;
if (getRest.CreateDispatch("myCom.GetRes") != 0)
{
getRest.Hello();
getRest.ReleaseDispatch();
}
CoUninitialize();
注意:
COM中的智能指针实际上是重载了->的类,目的是为了简化引用记数,几不需要程序
员显示的调用AddRef()和Release(),但是为什么我们在Method 1中
pGetRes.Release(),问题在与,我们的智能指针pGetRes生命周期的结束是在
CoUninitialize()之后,CoInitialize所开的套间在CoUninitialize()后已经被
关闭,而pGetRes此时发生析构,导致了程序的崩溃,解决这个问题的另一个方法是
CoInitialize(NULL);
CLSID clsid;
CLSIDFromProgID(OLESTR("myCom.GetRes"),&clsid);
{
CComPtr<IGetRes> pGetRes;//智能指针
pGetRes.CoCreateInstance(clsid);
pGetRes->Hello();
}
CoUninitialize();

以上就是COM的5中方法,当然具体怎么使用还是在于程序的环境,加以琢磨....

源文档 <http://cache.baidu.com/c?m=9f65cb4a8c8507ed4fece76310478921494380147a8a92542c81c45f93130a1c187ba5e167754352c4c50a6200a84f5de1e73604341420c198df883d87fdcd763bcd7a742613d70145805ff89d1d648373d60bb3b81996ad803284dfa5c4ae2744be25&p=c37b8b0685cc45dd08e297794a48&user=baidu>
firmbird 2010-04-11
  • 打赏
  • 举报
回复
你得知道定义这个show方法的接口,
pDisp->QueryInterface(IID_IXXXX,(LVOID*)&pInterface)
pInterface->show(...)
或者这个方法的dispid以及调用参数个数与类型,
pDisp->Invoke(...)
现在还是人类 2010-04-11
  • 打赏
  • 举报
回复
我又重新更改了一下程序

#include "stdafx.h"
#pragma comment(lib,"Ole32.lib")
#include "Objbase.h"
HRESULT ComInit();

int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
ComInit();
CLSID clsid;
CLSIDFromProgID(L"AObject.Demo", &clsid);

IUnknown *pUnk = NULL;
CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
IID_IUnknown, (void **)&pUnk);

IDispatch *pDisp = NULL;
pUnk->QueryInterface(IID_IDispatch,(void **)&pDisp);
//这里之后该如何调用 Show 方法呢?
//...
pUnk->Release();
CoFreeUnusedLibraries();
return 0;
}
HRESULT ComInit()
{
HRESULT hr = S_OK; // 默认返回值
if FAILED(CoInitialize(NULL)) // COM 初始化调用
{
CoUninitialize();
hr = E_UNEXPECTED;
}
return hr;
}
现在还是人类 2010-04-11
  • 打赏
  • 举报
回复
不过还是谢谢,我起马知道了CoCreateInstance相当于VB中new 对象
现在还是人类 2010-04-11
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 arong1234 的回复:]
CoCreateInstance相当于VB中new 对象,底下你需要QueryInterface得到指定接口,然后调用呗
个人觉得这种东西还是系统学习一下比较好,什么都不知道指望靠网络上问几个问题就会,即使真的让你程序跑起来,你也不可能真掌握的。
[/Quote]
所谓真掌握是指什么呢?从底层了解Ring 0\Ring 3 还有 Win32 子系统和 COM/COM+ 结构体系?
没必要吧,我只是想做这方面的普通开发而已,不是研发这方面的架构作更底层的运用,而且我目前
的应用也没涉及到那么深,能用就好了,就像在VB里使用CreateObject函数,谁会去管他是怎么做的,
知道怎么用就可以了。
arong1234 2010-04-11
  • 打赏
  • 举报
回复
CoCreateInstance相当于VB中new 对象,底下你需要QueryInterface得到指定接口,然后调用呗
个人觉得这种东西还是系统学习一下比较好,什么都不知道指望靠网络上问几个问题就会,即使真的让你程序跑起来,你也不可能真掌握的。
现在还是人类 2010-04-11
  • 打赏
  • 举报
回复
路过的也帮忙顶一下呀,拜托
现在还是人类 2010-04-11
  • 打赏
  • 举报
回复
高手们帮帮忙呀

3,248

社区成员

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

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