怎样得知COM对象的IID及VC中如何创建和使用COM对象

韦翔罂 2008-08-21 11:12:46

正在COM入门,试验中遇到难题--
我用Visual FoxPro9.0将一个项目Project1中的类TEST(类中只有一个自定义方法opentable)编译成一个COM,生成的COM部件名是Project1.TEST,并且在Visual FoxPro9.0中测试,调用类TEST的方法opentable运行正确。
但是,用VC编写的客户程序里不知该怎么创建这个COM对象,好像需要调用API:
WINOLEAPI CoCreateInstance(REFCLSID rclsid, LPUNKNOWN pUnkOuter,
DWORD dwClsContext, REFIID riid, LPVOID FAR* ppv);
其中有一项参数‘REFIID riid’应该是‘方法opentable’所对应的接口IID吧,那么,如何得到呢?尝试了下面的途径:
首先通过注册表查找:打开注册表,只看到Project1.TEST的接口CLSID,却没有标出其中的‘方法opentable’的接口IID;
然后用VC6的OLE/COM Object View查看:打开VC6的OLE/COM Object View,找到COM部件Project1.TEST,双击打开,内容如下
// Generated .IDL file (by the OLE/COM Object Viewer)
// typelib filename: Project1.dll
[uuid(3472BE1C-760A-4309-B3E6-A64503420B27),
version(1.0),
helpstring("\xFFFFFFCF\xFFFFFFEE目1 Type Libra")]
library \xFFFFFFCF\xFFFFFFEE?
{
// TLib : // TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
importlib("stdole2.tlb");
// Forward declare all types defined in this typelib
interface Itest;
[odl,
uuid(B39D2C1A-B151-45E5-89C8-82BF55E7869B),
helpstring("Project1.test"),
hidden,
dual,
nonextensible,
oleautomation ]
interface Itest : IDispatch {
[id(00000000), propget, helpstring("指定用户自定义类库的文件名,该类库包含对象的类。")]
HRESULT ClassLibrary([out, retval] BSTR* ClassLibrary);
[id(0x00000001)]
HRESULT opentable([out, retval] VARIANT* RetVal);
[id(0x00000002), propget, helpstring("指定在代码中用以引用对象的名称。")]
HRESULT Name([out, retval] BSTR* Name);
[id(0x00000002), propput, helpstring("指定在代码中用以引用对象的名称。")]
HRESULT Name([in] BSTR Name);
······//有很多类似的,在这里我就省略了。
HRESULT SetAll(
BSTR cProperty,
VARIANT Value,
BSTR cClass,
[out, retval] VARIANT* RetVal); };
[uuid(5CB425B4-DD80-4750-AE5E-D757EAF56947),
helpstring("Project1.test") ]
coclass test {
[default] interface Itest; };};

我想,其中有一句‘opentable([out, retval] VARIANT* RetVal);[id(0x00000002)’中的id(0x00000002)是不是‘方法opentable’的接口IID呢?怎么用呢?我试着将它加上Project1.TEST的接口CLSID作为‘方法opentable’的接口IID放到CoCreateInstance调用,程序如下
#include "windows.h"
#include <stdio.h>
#include <comutil.h>
void main()
{
CoInitialize(NULL);
static const GUID TESTclsid={0x3472be1c,0x760a,0x4309,
{0xb3,0xe6,0xa6,0x45,0x03,0x42,0x0b,0x27}};
//Project1.TEST的接口CLSID
static const GUID TESTopeniid={0x3472be1e,0x760a,0x4309,
{0xb3,0xe6,0xa6,0x45,0x03,0x42,0x0b,0x27}};
//我是用那个id(0x00000002)加上上面的Project1.TEST的接口CLSID,得到TESTopeniid,作为Project1.TEST的‘方法opentable’的接口IID,不知对不?

IUnknown *pUnknown;

CoCreateInstance(TESTclsid, NULL, CLSCTX_INPROC_SERVER,TESTopeniid, (void **)&pUnknown);

printf("%s",pUnknown->opentable );
}
结果有错误提示 error C2039: 'opentable' : is not a member of 'IUnknown'


由于时间较紧张,COM方面的学习只想面向应用,即主要着重于掌握如何在客户程序中创建和使用COM对象,而不是掌握如何开发一个COM组件,很多COM的书都是大篇幅介绍如何开发COM组件,而对创建和使用COM对象的叙述显得有些散乱,特别是VC++中创建和使用COM对象很复杂,要求客户程序中首先#include接口类定义文件,可是Visual FoxPro9.0生成COM部件时只生成了两个文件,一个是Project1.dll,一个是Project1.tlb,哪里有什么接口类定义文件哟,没有接口类定义文件,VC中好像就无法创建COM对象了,
不像VB、VFP那样创建一个COM对象只需一句CREATEOBJECT就搞掂了,所以希望大家在这一方面给予热心指点,非常感谢!
...全文
504 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
韦翔罂 2008-09-25
  • 打赏
  • 举报
回复
非常感谢大家,由于比较忙,过段时间再回来结贴派分.
lake_cx 2008-09-01
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 huangyinghua 的回复:]
谢谢大家,我也做了试验,使用组件封装类的方法,但不成功,如下
Ivfpoper oper;// Ivfpoper是封装类名
int a=oper. test ();//这里调用组件的内部所实现的方法函数test (),它只是简单的返回一个整数5.
编译报错:第二句代码error C2440: 'initializing' : cannot convert from 'struct tagVARIANT' to 'int'
于是改为
Ivfpoper oper;
VARIANT var;
var=oper. test ();
int a=var.lVal;
顺利通过编译,但是…
[/Quote]
记得AttachDispatch,用CoCreateInstance创建你这个CLSID的对象,然后用QueryInterface查询Ivfpoper接口
然后用AttachDispatch把查询到的接口附加到上面
美丽海洋 2008-08-30
  • 打赏
  • 举报
回复
需要把你的com导
进来
韦翔罂 2008-08-30
  • 打赏
  • 举报
回复
谢谢大家,我也做了试验,使用组件封装类的方法,但不成功,如下
Ivfpoper oper;// Ivfpoper是封装类名
int a=oper. test ();//这里调用组件的内部所实现的方法函数test (),它只是简单的返回一个整数5.
编译报错:第二句代码error C2440: 'initializing' : cannot convert from 'struct tagVARIANT' to 'int'
于是改为
Ivfpoper oper;
VARIANT var;
var=oper. test ();
int a=var.lVal;
顺利通过编译,但是,在调试器中跟踪,发现,运行到最后,变量a中的值是空的(-858993460),并不是组件所返回的5.
为此,再次调试跟踪,发现执行var=oper. test ();后,var中根本没有得到组件所返回的5.
打开封装类Ivfpoper的test(),代码如下
VARIANT Ivfpoper::test()
{
VARIANT result;
InvokeHelper(0x1, DISPATCH_METHOD, VT_VARIANT, (void*)&result, NULL);
return result;
}
于是单步跟踪进入oper. test ()中,发现,它返回的VARIANT类型的变量result确实什么数据都没有,难道是这个组件没有实现“返回5”的功能?可是,这个组件在visual foxpro中测试,确实实现了“返回5”这个功能,那么,为什么在VC中这个功能没有实现呢?
paerxiushi 2008-08-30
  • 打赏
  • 举报
回复
1.使用__uuidof(expression),这个宏可以根据导入的类型库,组件,接口的类型,来获得它们的uuid。
导入语句:#import "msxml4.dll"

2.如果你的组件没有实现IDisptach接口:
可以使用
CoCreateInstance得查询接口,然后使用QueryInterface接口查询当前组件的其它。

3.如果你的组件实现了IDispatch接口,可以这么来使用接口:
OleInitialize(NULL); //这个必须的,这样一来,当前的线程只能套间,而不是自由线程。
IDispatch* pIDispatch=NULL;
CLSID clsID;
//将组件的ProgID转化成它的CLSID
HRESULT hr=CLSIDFromProgID(_T("Aggregate221.CA"),&clsID);
if(FAILED(hr))
{
cout<<"could not find the prog ID"<<endl;
return -1;
}
//查询IDispatch接口
hr=CoCreateInstance(clsID,NULL,CLSCTX_LOCAL_SERVER,IID_IDispatch,(void**)&pIDispatch);
if(SUCCEEDED(hr))
{
//方法名称
OLECHAR* szMethodName1=L"FxInString";

//得到方法的DISPID
hr=pIDispatch->GetIDsOfNames(IID_NULL,&szMethodName1,1,GetUserDefaultLCID(),&dispID);
if(FAILED(hr))
{
cout<<"could not find FxInString method"<<endl;
pIDispatch->Release();
return -4;
}

WCHAR szHello[100]=L"My life for this";
BSTR bstrHello=SysAllocString(szHello);
VARIANTARG variant1;
VariantInit(&variant1);
variant1.vt=VT_BSTR;
variant1.bstrVal=bstrHello;
DISPPARAMS params;
params.cArgs=1;
params.cNamedArgs=0;
params.rgdispidNamedArgs=NULL;
params.rgvarg=&variant1;
//调用调度方法
hr=pIDispatch->Invoke(dispID,IID_NULL,GetUserDefaultLCID(),DISPATCH_METHOD,¶ms,NULL,NULL,NULL);
if(FAILED(hr))
{
cout<<"could not invoke FxInString method"<<endl;
SysFreeString(bstrHello);
pIDispatch->Release();
return -5;
}
SysFreeString(bstrHello);
}
OleUninitialize();
return 0;

5.使用__uuid宏可以偷赖一下:
#import "msxml.dll"
::CoInitialize(NULL);
MSXML2::IXMLDOMDocument2Ptr xml;
xml.CreateInstance(__uuidof(MSXML2::DOMDocument));
if(!xml->load(_bstr_t(m_sFilePath)))
return false;

int i= 1;
bool bNode = TRUE;
MSXML2::IXMLDOMNodePtr node;
node = xml->selectSingleNode(_bstr_t(strRoot));
::CoUninitialize();
其中:MSXML2是命名空间
jameshooo 2008-08-21
  • 打赏
  • 举报
回复
TESTopeniid 应该等于 B39D2C1A-B151-45E5-89C8-82BF55E7869B,这是接口ID(IID),跟类型库ID(CLSID)是完全不同的,两者没有任何关联,也不能进行算术操作
吹泡泡的小猫 2008-08-21
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 lake_cx 的回复:]

用COM其实很简单的:
Class Wizard->Add Class->From a type library
它就会生成相…
[/Quote]

正确
lake_cx 2008-08-21
  • 打赏
  • 举报
回复
提醒一下,包装类使用之前记得先调用AttachDispatch
lake_cx 2008-08-21
  • 打赏
  • 举报
回复
CLSID是Class ID,就是表示一个COM对象
IID是Interface ID,表示一个COM接口
因此可以某一个CLSID1的对象实现了IID1,CLSID2也实现了IID1
也可以CLSID1实现了IID1,同时也实现了IID2
所以CLSID跟IID没什么关系,体现其关系的仅仅是利用CLSID调用了CoCreateInstance拿到IUnkown接口后,QueryInterface一次就知道它有没有实现IID了没有。

用COM其实很简单的:
Class Wizard->Add Class->From a type library
它就会生成相应的包装类,你直接用就可以了
yawer 2008-08-21
  • 打赏
  • 举报
回复
B39D2C1A-B151-45E5-89C8-82BF55E7869B应该是接口ID。5CB425B4-DD80-4750-AE5E-D757EAF56947是你的clsid,good luck.有些知识还是需要补充的。即使你解决了这个问题。

3,245

社区成员

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

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