ado中的IUnknown和IDispatch有什么区别?

tcige 2012-10-16 11:12:32
比如_RecordsetPtr::Open的第一个参数传_CommandPtr,第二个参数用vtMissing

用(IUnknown*)_CommandPtr和(IDispatch*)_CommandPtr都可以转换成_variant_t,有什么区别?

IUnknown的话,是不是Open内部是通过QueryInterface,然后用虚函数表来执行_CommandPtr方法?

IDispatch的话,Open内部是通过Invoke来执行_CommandPtr方法?
...全文
245 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
bsnry 2012-10-20
  • 打赏
  • 举报
回复
昨天看了自动化接口

这个接口就是用来对付诸多语言的, 一般我们用 com,都用了这个接口

bsnry 2012-10-17
  • 打赏
  • 举报
回复
源码是 多连接点对象, vcbase的例子,我发代码, 你也可以自己去下载,看看

包含头文件d:\Program Files\Microsoft SDKs\Windows\v7.0\Include\OAIdl.h


pragma once
#include "oaidl.h"

class CSink :
public IDispatch
{
public:
CSink(void);
~CSink(void);
private:
CEdit *m_pEdit;
public:
void SetResultWnd(CEdit * pEdit);
// IUnknown
STDMETHOD(QueryInterface)(const struct _GUID &iid,void ** ppv);
ULONG __stdcall AddRef(void);
ULONG __stdcall Release(void);
// IDispatch
STDMETHOD(GetTypeInfoCount)(unsigned int *);
STDMETHOD(GetTypeInfo)(unsigned int,unsigned long,struct ITypeInfo ** );
STDMETHOD(GetIDsOfNames)(const IID &,LPOLESTR *,UINT,LCID,DISPID *);
STDMETHOD(Invoke)(long dispID,const struct _GUID &,unsigned long,unsigned short,struct tagDISPPARAMS * pParams,struct tagVARIANT *,struct tagEXCEPINFO *,unsigned int *);
};






[Quote=引用 5 楼 的回复:]

楼上贴点代码上来看看?
MFC导入生成的包装类多从COleDispatchDriver派生,且这些类都不是智能指针,只能使用调度接口进行调用。
ATL项目导入生成的包装类都是从_com_ptr_t<>派生的,都是智能指针,可直接转换到原始接口指针,且生成的包装方法中对参数类型进行了再包装(默认是这样)。当然如果原始接口指针本身也是IDispatch,它必然也是IDispatch的派生类,可以……
[/Quote]
I_ask_who 2012-10-17
  • 打赏
  • 举报
回复
IUnknown只能获取指定IID的对象指针
IDispatch不光可以通过Invoke还可以通过获取ITypeInfo指针来操作
_variant_t只是一个指针包装,没有区别

COM内部可以通过传进来的指针来获得其想要的任何接口,IDispatch继承IUnknown,同样也能QueryInterface

我估计:
不管是IUnknown*还是IDispatch,ado首先会检查QueryInterface有没有它要的知名接口(假设为ICommand),如果找不到,如果是IDispatch,ado还有了一个获得ITypeInfo的机会,这样就可以按照名字查找函数了。比如Command应该支持Excute()方法,那么ITypeInfo就可以查找有没有叫Excute的方法,方法参数是否匹配,找到后直接调用,如果还是找不到就失败。
tcige 2012-10-17
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 的回复:]
ITypeInfo可以直接查找函数名,BSTR形式
IDispatch只能查id

MSDN上open接口只是规定Command是一个
Source Optional. A Variant that evaluates to a valid Command object, an SQL statement, a table name, a stored procedure call, a ……
[/Quote]

我的意思是,用了ITypeInfo,那IDispatch::Invoke内部不就是调用的ITypeInfo::Invoke?
tcige 2012-10-17
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 的回复:]
ado怎么实现谁也不知道,如果你自己编写一套Command组件,调用自己开发的新型数据库,也似乎是可以的
[/Quote]

逆向了下,确实没有调用Invoke

csdn上难得碰到个讨论问题的,你再看看我其他的问题吧
I_ask_who 2012-10-17
  • 打赏
  • 举报
回复
ITypeInfo可以直接查找函数名,BSTR形式
IDispatch只能查id

MSDN上open接口只是规定Command是一个
Source Optional. A Variant that evaluates to a valid Command object, an SQL statement, a table name, a stored procedure call, a URL, or the name of a file or Stream object containing a persistently stored Recordset.

神马叫做valid Command object,MSDN只是做了描述,并且没有要求它继承自任何已知接口
原文就不贴了,只是一大堆必须要有的property和method,只有一个办法查名字匹配

当然不排除微软自己内部有一个ICommandXXX接口,首先查这个接口,使自己的SQL-server最快。查不到的情况再查名字找函数。
tcige 2012-10-17
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 的回复:]
以 xxxxPtr 形式封装的智能指针,生成包装方法的同时也包装了参数和返回类型,内部是通过虚表方式调用原始方法(原始方法通常以 raw_Open 命名)实现的。指针类型转换取决于原始方法的参数类型,原始参数类型是什么,就转换成什么。

ado的这些智能指针是通过#import生成的,可以在导入选项里设置是否也生成包装方法(默认是生成),如果不生成,Open就是原始方法,没有包装方法。
[/Quote]


麻烦仔细看看,不要想当然,你说的用raw_interfaces_only就可以了

我说的是_RecordsetPtr::Open内部的实现,肯定会调用传过来的_CommandPtr方法

无非就两种,虚函数表和Invoke

没源码,不清楚,感觉我说的和1楼说的都有可能
tcige 2012-10-17
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 的回复:]
IUnknown只能获取指定IID的对象指针
IDispatch不光可以通过Invoke还可以通过获取ITypeInfo指针来操作
_variant_t只是一个指针包装,没有区别

COM内部可以通过传进来的指针来获得其想要的任何接口,IDispatch继承IUnknown,同样也能QueryInterface

我估计:
不管是IUnknown*还是IDispatch,ado首先会……
[/Quote]


用了ITypeIfno,那IDispatch::Invoke和ITypeInfo::Invoke有什么区别?

先QueryInterface也是有可能的,这样的话_variant_t分两种是为了处理ambiguous?
redui 2012-10-17
  • 打赏
  • 举报
回复
楼上贴点代码上来看看?
MFC导入生成的包装类多从COleDispatchDriver派生,且这些类都不是智能指针,只能使用调度接口进行调用。
ATL项目导入生成的包装类都是从_com_ptr_t<>派生的,都是智能指针,可直接转换到原始接口指针,且生成的包装方法中对参数类型进行了再包装(默认是这样)。当然如果原始接口指针本身也是IDispatch,它必然也是IDispatch的派生类,可以使用调度接口方式调用方法。

在不同框架下生成的包装类是完全不同的。具体是什么方式,可以直接查看生成的包装类代码,是驴是马,是虚表还是调度方式,一眼就看出来了。
bsnry 2012-10-17
  • 打赏
  • 举报
回复

不敢苟同啊, 貌似我的demo里有IDispatch接口的派生类,


控制台工程。





[Quote=引用 3 楼 的回复:]

BTW: 只有MFC导入类型库生成的包装类和包装方法才使用IDispatch方式调用
[/Quote]
redui 2012-10-17
  • 打赏
  • 举报
回复
BTW: 只有MFC导入类型库生成的包装类和包装方法才使用IDispatch方式调用
redui 2012-10-17
  • 打赏
  • 举报
回复
以 xxxxPtr 形式封装的智能指针,生成包装方法的同时也包装了参数和返回类型,内部是通过虚表方式调用原始方法(原始方法通常以 raw_Open 命名)实现的。指针类型转换取决于原始方法的参数类型,原始参数类型是什么,就转换成什么。

ado的这些智能指针是通过#import生成的,可以在导入选项里设置是否也生成包装方法(默认是生成),如果不生成,Open就是原始方法,没有包装方法。
I_ask_who 2012-10-17
  • 打赏
  • 举报
回复
ado怎么实现谁也不知道,如果你自己编写一套Command组件,调用自己开发的新型数据库,也似乎是可以的
I_ask_who 2012-10-17
  • 打赏
  • 举报
回复
我看了一下Inside OLE,里面chapter14是关于IDispatch的
IDispatch的存在的唯一意义是支持OLE Automation,可以广泛支持翻译型语言
IDispatch其中一个功能是支持late binding
IDispatch还有一个功能是支持sink-event-source通知

我认为ado需要依赖IDispatch,从Command参数名Source就可以发现Recordset可以接受Command对象的callback也就是FireEvent

还有IDispatch的执行函数只有通过Invoke(),但是Invoke需要Dispid变量,ado不可能事先得知,必须要调用GetIDsOfNames(),Command对象创建者有多种实现IDispatch接口的可能,书中给了5种方法
比如GetIDsOfNames(),设计者可以通过比较传入的字符串返回dispid,找不到就返回DISP_E_UNKNOWNLCID;也可以查找TypeInfo,后者最常用。
redui 2012-10-17
  • 打赏
  • 举报
回复
两个问题都是想当然的问题,没毛病的东西都被你搞出病来,这牛角尖钻得够深

_variant_t是选择IUnknown*还是IDispatch*,这个问题看起来都蛋疼,看来你是完全不理会编译器动态CAST原则了
Open都是ado自己实现的,只有傻子才会在内部实现中还去调用Invoke

4,011

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 数据库
社区管理员
  • 数据库
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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