开启辅助访问 切换到宽版

精易论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

用微信号发送消息登录论坛

新人指南 邀请好友注册 - 我关注人的新帖 教你赚取精币 - 每日签到


求职/招聘- 论坛接单- 开发者大厅

论坛版规 总版规 - 建议/投诉 - 应聘版主 - 精华帖总集 积分说明 - 禁言标准 - 有奖举报

查看: 2581|回复: 9
收起左侧

[分享] E COM研究笔记 / 挂接事件

[复制链接]
结帖率:33% (3/9)
发表于 2015-9-14 18:04:08 | 显示全部楼层 |阅读模式   四川省成都市
本帖最后由 Modify 于 2015-9-14 18:21 编辑

为COM挂接一个回调接口,在如C++,C#中可以调用AtlAdvise或从
IConnectionPointContainer挂接(Sink必须具象继承接口的全部成员)
易语言则不同,易语言在COM支持上一直存在缺陷,易语言是一个
强类型语言,而“Object / 对象”似乎很类似IDispatch*但似乎又不是
而易语言本身则未提供任何可以具备事件点对点的方法 需要挂接的话
着实令人头疼不已
// IDispatch* pdisp = NULL;
// if(SUCCEEDED(CoInitialize(NULL)) != FALSE)
// {
//  CoCreateInstance(__uuidof(CLSID_ScriptControl), NULL, CLSCTX_INPROC_SERVER, __uuidof(IDispatch), (void**)&pdisp);
// }

// UINT pctinfo;
// IDispatch* pdisp;
// pdisp->GetTypeInfoCount(&pctinfo);
//  mov         esi,esp  
//  lea         eax,dword ptr [pctinfo]  
//  push        eax

//  mov         ecx,dword ptr [pdisp]  
//  mov         edx,dword ptr [ecx]  
//  mov         eax,dword ptr [pdisp]  
//  push        eax  

//  mov         ecx,dword ptr [edx+0Ch]  
//  call        ecx  

上面是一个调用IDispatch::GetTypeInfoCount的代码及内联汇编
可以得到下述内容:
// express: *((int*)(*((int*)pdisp) + 0xC))

上图则为易语言的部分,实际上易语言对象内包含的是IUnknown*
如果调用“Object::QueryInterface”则会返回IID所对应的指针,但
内部会被以IDispatch*表示、



上面则是一段PB(Power Basic)的代码,先把CLSID与IID压入变
量后创建COM实例,在从中得到“虚函数指针”具体参照下文
CALL DWORD 调用函数地址(四字节),综合上述与下述代码可以

得到关于COM类结构形式、倒不如说是一个类与接口的结构形式、
上面的易语言代码很简单,复制并构建一个IDispatch接口类但是
它是一个具象类,该类是由汇编代码进行复制并构造
typedef class IUnknown
{
public:
  virtual int AddRef() = 0;
  virtual int Release() = 0;
} *LPIUnknown;

typedef class IDispatch : public IUnknown
{

public:
  int AddRef() override
  {
   return 2;
  }

int Release() override
  {
   return 1;
  }
} *LPIDispatch;

上面是一个类与一个接口的结构、仔细观察与思考上述代码
int _tmain(int argc, _TCHAR* argv[])
{
  IDispatch* idisp = new IDispatch;
int x = idisp->AddRef();
  int y = *((int*)(*((int*)idisp) + 4)); // Release
  _asm
  {
   call dword ptr[y]
   mov dword ptr[y], eax
   pop eax
  }
  printf("{x=%d, y=%d}", x, y); // {x=2, y=1}
  getchar();
  return 0;
}
接口中所有成员都是抽象的,具象由实体重写成员

仔细看看上图,在一般类情况下父类不存在 “__vfptr / 虚函数指针”
它用于寄存被重写的父类成员地址链表、
那么回到正题,由于此处研究易语言COM事件挂接的问题,那么
需要知道Sink的结构是什么,上述已经提到事件接受器(EventSink)
Sink必须具象继承接口的全部成员、
COM内部托管被挂接的Sink,共有一份与Sink相同接口协yi公约、
它们所有的一切都惊人的类似
但是Sink是具象方而COM只是抽象调用方,那么需要知道常规类
函数(方法)是静态固定的、
正常情况下只可以获取到静态类函数的地址,而不可获取类成员
函数地址,但是可以通过union或inline-asm获取它的地址 不过需
要提到一点,即使虚函数是以一个虚函数指针寄存但不可否认它
包含值是静态的、所谓函数皆静态可不是闹着玩的 要是托管代码
我倒也无话可说,代码是静态的运行时是动态(JIT Auto Complie)
但是会被优化,何时为动态我举个小例子一旦获取函数指针那么
则会重新构建该函数但只针对托管代码(.NET) 一般只编译一次

上面是在易语言中被挂接的COM IDispatch Sink 那么需要知道
COM中IDispatch::Invoke的作用,它是一个整个COM互调用的
核心部分,当COM调用函数或属性时都会最终由该函数处理
在COM中拥有举足轻重的地位、如果没它COM则会变得无意义

该部分是必须的,每次COM接口调用函数时都会先调用该函数
获取对应COM接口的指针 如果ppvObject远过程返回无效 那么
最终结果不是软体停止工作那么就是没有任何反应、

在易语言中有一个与VARIANT相同的类型、及“变体型” 上述代码
表示侦听dispid 0x66及响应DWebBrowserEvents2::StatusTextChange
由于COM传递参数全部以VARIANT所以在这里编写一个函数
PTR_TO_VARIANT 方便调用 方法倒也很简单,使用汇编交换两者地址
然后再返回 不然则需要使用API去绕过易语言的类型检查 没办法的事

不知为什么编写一个CALL COM接口函数的汇编时在易语言中无法使用 倒
是在C++中内嵌时没问题 倒是很让我有些头疼 不过幸好有一种替代方案
汇编 虽然不是我写的、呵呵

差不多了、剩下的还需要靠大家自己理解了 不可说,不可言 一朵相似之花
项目源代码: http://pan.baidu.com/s/1hqgyRPy
版权声明:本文为博主原创文章,未经博主允许不得转载。
原帖处处:http://blog.csdn.net/u012395622/article/details/48431049

结帖率:82% (9/11)
发表于 2015-9-15 08:42:13 | 显示全部楼层   广东省深圳市
Modify 发表于 2015-9-15 06:59
嗯、但你似乎有些错误 易语言的类是实体(具象)而不是抽象
而COM对象是具象需要抽象才可以两者之间交换地 ...

喔,是你错了。自己dump观察,易语言类调度接口是:
[变量指针]->[类指针]-[成员函数指针]->方法N

则如果将类指针替换为对象指针,那么调用将得到一样的效果。
[变量指针]->[对象指针]-[成员函数指针]->方法N
回复 支持 反对

使用道具 举报

结帖率:33% (3/9)
 楼主| 发表于 2015-9-15 06:59:58 | 显示全部楼层   四川省成都市
秋雨怜心 发表于 2015-9-14 23:00
不需要噢,这里的强制继承的意思并不是一个 类->对象 的过程,而是把对象当做类。即 类.方法1() 的实质就是 ...

嗯、但你似乎有些错误 易语言的类是实体(具象)而不是抽象
而COM对象是具象需要抽象才可以两者之间交换地址指针、
简单的说易语言的类函数是静态固定的 不论你怎么递交指针
调用AddRef函数也不会是执行COM的AddRef函数、
回复 支持 反对

使用道具 举报

结帖率:82% (9/11)
发表于 2015-9-14 23:00:11 | 显示全部楼层   广东省深圳市
Modify 发表于 2015-9-14 22:37
这倒是一个办法、可以理解为接口对称 类与对象本身差距并不大
不过还需要考虑实际情况 易语言的类没有与 ...

不需要噢,这里的强制继承的意思并不是一个 类->对象 的过程,而是把对象当做类。即 类.方法1() 的实质就是 对象.方法1() 。 所以这里的类本身就是虚的,你只需声明而已,不需要在方法里写任何代码。
回复 支持 反对

使用道具 举报

结帖率:33% (3/9)
 楼主| 发表于 2015-9-14 22:37:12 | 显示全部楼层   四川省成都市
秋雨怜心 发表于 2015-9-14 22:18
实际上还有更简单的,对象的本质还是类(那么就可以:对象指针≈类指针)
则:声明与对象相同的类(成员函数的 ...

这倒是一个办法、可以理解为接口对称 类与对象本身差距并不大
不过还需要考虑实际情况 易语言的类没有与COM接口对称 因为
易语言不存在虚函数这个概念 所以需要构建一个包含虚函数的类
不然我也没必要那么麻烦、
回复 支持 反对

使用道具 举报

结帖率:82% (9/11)
发表于 2015-9-14 22:18:33 | 显示全部楼层   广东省深圳市
实际上还有更简单的,对象的本质还是类(那么就可以:对象指针≈类指针)
则:声明与对象相同的类(成员函数的声明位置需要一致),然后通过强制继承来获得对象的全部控制权:

  
子程序名返回值类型公开备 注
强制继承对象  
参数名类 型参考可空数组备 注
对象指针_整数型
类指针_与对象声明一致的类
__asm (“push ebx”)
__asm (“mov eax,[ebp+0c]”)
__asm (“mov ebx,[ebp+8]”)
__asm (“mov [eax],ebx”)
__asm (“pop ebx”)


i支持库列表   支持库注释   
TianSin(未知支持库)


之后就可以实现:

类.方法1() =  对象.方法()


回复 支持 反对

使用道具 举报

结帖率:92% (190/207)

签到天数: 10 天

发表于 2015-9-14 21:47:47 | 显示全部楼层   广东省汕头市
我是说你以往的帖子 不是说你这个帖子
回复 支持 反对

使用道具 举报

结帖率:92% (190/207)

签到天数: 10 天

发表于 2015-9-14 18:25:27 | 显示全部楼层   广东省汕头市
这是易论坛,楼住怎么发那么多  其他语言的   

点评

可惜你没看懂 我为什么要贴其他语言的代码   四川省成都市  发表于 2015-9-14 18:36
回复 支持 反对

使用道具 举报

结帖率:100% (15/15)
发表于 2015-9-14 18:20:02 | 显示全部楼层   浙江省杭州市
表示全没看懂。。。就路过一下吧
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 致发广告者

关闭

精易论坛 - 有你更精彩上一条 /2 下一条

发布主题 收藏帖子 返回列表

sitemap| 易语言源码| 易语言教程| 易语言论坛| 易语言模块| 手机版| 广告投放| 精易论坛
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表精易立场!
论坛帖子内容仅用于技术交流学习和研究的目的,严禁用于非法目的,否则造成一切后果自负!如帖子内容侵害到你的权益,请联系我们!
防范网络诈骗,远离网络犯罪 违法和不良信息举报QQ: 793400750,邮箱:wp@125.la
网站简介:精易论坛成立于2009年,是一个程序设计学习交流技术论坛,隶属于揭阳市揭东区精易科技有限公司所有。
Powered by Discuz! X3.4 揭阳市揭东区精易科技有限公司 ( 粤ICP备2025452707号) 粤公网安备 44522102000125 增值电信业务经营许可证 粤B2-20192173

快速回复 返回顶部 返回列表