当前位置: 首页 > news >正文

Win32编程点滴3 - 简单ActiveX控件的使用

虽然这里一片的.net气氛,到处充斥着像MVC、WPF、WorkFlow、LINQ等各种niubility的术语。但我们使用的Windows还是由COM技术主宰着;我们在选择日常使用的软件时,也会避免使用.net开发的软件。即便是.net的桌面程序,也会经常使用ActiveX控件。这篇文章就让我们用最原始的方式来使用ActiveX,不使用任何MFC,ATL等框架,也不使用编译器提供的#import之类的指令,也不使用任何ide提供的向导。

像OLE、ActiveX等COM的术语,即便是微软也说不清它们的关系,所以下面说的我也这样模棱两可下去,只要明白意思即可。

首先,要了解一下的是ActiveX技术是为了做“嵌入”这样的功能而诞生的,比如:在Word中插入一张Bitmap图片,双击此图片,Word会调用画笔程序的功能来编辑图片,整个Word的菜单栏也会变成画笔程序的菜单栏。所以,ActiveX控件相当的复杂,有着几十个相关的接口。简单的说来,ActiveX控件的父窗口被称为“容器”,所以作为ActiveX控件的使用者来说,要实现的接口基本上都是IOleXXXXContainer或IOleXXXXSite之类的;而ActiveX则实现了IOleXXXXObject等接口。在这些接口中,大多有“InPlace”这个术语,指的是“InPlace edit”,也就是Word通过双击图片调用画笔编辑图片就称为“InPlace edit”(仅仅了解一下,和这篇文章说的使用AcitveX控件无关)。

在这样一篇文章中,我并不想讲很多COM或者AcitveX的知识,只是讲使用ActiveX所必须涉及的接口,然后你就可以去查MSDN中的其他一些可选的接口来一步步对这个ActiveX加强控制。

作为一个最简单的程序,我们需要实现的接口有:IOleClientSite和IOleInPlaceSite。使用到的AcitveX提供的接口有:IOleObject和IOleInPlaceObject。创建ActiveX控件的步骤:

  1. 创建一个类,实现IOleClientSite和IOleInPlaceSite。
  2. 使用CoCreateInstance创建相应ActiveX控件的实例,并获取它的IOleObject接口指针。
  3. 调用IOleObject::SetClientSite传入第一步中的类的指针。
  4. 调用IOleObject::DoVerb完成ActiveX控件的创建。
  5. 之后,可以调用ActiveX控件的IOleInPlaceObject::SetObjectRects调整控件的大小和位置。

根据以上步骤,创建如下函数:

HRESULT CreateAxControl(HWND hWnd,const wchar_t * ProgId,IUnknown ** ppControlUnknown,IUnknown ** ppContainerUnknown);

第一个参数hWnd是父窗口句柄。ProgId是ActiveX控件的ProgId,因为我们不使用编译器的#import,一般不知道所要创建控件的CLSID。ppControlUnknown是用来返回ActiveX控件的IUnknown指针。ppContainerUnknown是用来返回用来代表父窗口的IUnknown指针。

代码如下(这里的代码去除了出错的处理):

复制代码
复制代码
HRESULT CreateAxControl(HWND hWnd,const wchar_t * ProgId,IUnknown ** ppControlUnknown,IUnknown ** ppContainerUnknown)
{
HRESULT hr;
CLSID cls;
IOleObject * pObject = NULL;
CControlContainer * pContainer = NULL;

//通过ProgId得到CLSID CLSIDFromProgID(ProgId,&cls); //创建ActiveX控件的对象,顺便得到IOleObject指针 CoCreateInstance(cls,NULL,CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER|CLSCTX_LOCAL_SERVER, IID_IOleObject,(void**)&pObject); //CControlContainer是实现了IOleClientSite和IOleInPlaceSite接口的类 pContainer = new CControlContainer(hWnd); //调用IOleObject::SetClientSite,传入容器指针 pObject->SetClientSite(pContainer); //调用IOleObject::DoVerb,显示控件 pObject->DoVerb(OLEIVERB_SHOW,0,pContainer,0,hWnd,0); //一些返回的参数 pObject->QueryInterface(IID_IUnknown,(void**)ppControlUnknown); pContainer->QueryInterface(IID_IUnknown,(void**)ppContainerUnknown); if (pObject) pObject->Release(); if (pContainer) pContainer->Release(); return S_OK; }
复制代码
复制代码

CControlContainer类的实现非常简单,基本上IOleClientSite和IOleInPlaceSite接口大部分的方法都只要简单的返回S_OK或E_NOTIMPLE即可。唯一需要实现的是IUnknown的方法,还有IOleWindow接口(IOleInPlaceSite继承于IOleWindow)的GetWindow(返回父窗口的句柄)。代码如下:

复制代码
复制代码
class CControlContainer:public IOleClientSite,public IOleInPlaceSite
{
HWND m_hWnd;
ULONG m_refCnt;
public:
CControlContainer(HWND hWnd)
{
m_hWnd = hWnd;
m_refCnt = 1;
}
~CControlContainer()
{
}
.... IUnknown的实现
//IOleControlSite
STDMETHOD(SaveObject()) { return E_NOTIMPL; } STDMETHOD(GetMoniker(DWORD,DWORD,IMoniker**)) { return E_NOTIMPL; } STDMETHOD(GetContainer(IOleContainer **ppContainer)) { return E_NOINTERFACE; } STDMETHOD(ShowObject()) { return S_OK; } STDMETHOD(OnShowWindow(BOOL bShow)) { return S_OK; } STDMETHOD(RequestNewObjectLayout()) { return E_NOTIMPL; } //IOleWindow STDMETHOD(GetWindow(HWND * pHwnd)) { *pHwnd = m_hWnd; return S_OK; } STDMETHOD(ContextSensitiveHelp(BOOL bEnterMode)) { return S_OK; } //IOleInPlaceSite STDMETHOD(CanInPlaceActivate()) { return S_OK; } STDMETHOD(OnInPlaceActivate()) { return S_OK; } STDMETHOD(OnUIActivate()) { return S_OK; } STDMETHOD(GetWindowContext(/* [out] */ IOleInPlaceFrame **ppFrame,
/* [out] */ IOleInPlaceUIWindow **ppDoc,
/* [out] */ LPRECT lprcPosRect,
/* [out] */ LPRECT lprcClipRect,
/* [out][in] */ LPOLEINPLACEFRAMEINFO lpFrameInfo))
{
return E_NOTIMPL;
}
STDMETHOD(Scroll(SIZE scrollSize))
{
return S_OK;
}
STDMETHOD(OnUIDeactivate(BOOL bUndoable))
{
return S_OK;
}
STDMETHOD(OnInPlaceDeactivate())
{
return S_OK;
}
STDMETHOD(DiscardUndoState())
{
return S_OK;
}
STDMETHOD(DeactivateAndUndo())
{
return S_OK;
}
STDMETHOD(OnPosRectChange(LPCRECT lprcPosRect))
{
return S_OK;
}
};
复制代码
复制代码

接下来,在父窗口的窗口过程中,调用上面实现的函数,创建一个Flash控件:

复制代码
复制代码
IUnknown * g_pControl = NULL;//控件的指针
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
....
switch(message)
{
case WM_CREATE:
//Flash控件
hr = CreateAxControl(hWnd,L"ShockwaveFlash.ShockwaveFlash",&pControl,&pContainer);
if (SUCCESSED(hr))
{
VARIANT src;
src.vt = VT_BSTR;
src.bstrVal = SysAllocString(L"http://www.google.com/intl/en_ALL/images/logo.gif");
DispSetProperty(pControl,L"movie",&src);//这个函数的实现,请下载源代码
}
break;
case WM_SIZE:
{
//调整控件的大小
RECT rcClient;
GetClientRect(hWnd,&rcClient);
IOleInPlaceObject * pInPlaceObject;
if (g_pControl &&
SUCCEEDED(g_pControl->QueryInterface(IID_IOleInPlaceObject,(void**)&pInPlaceObject)))
{
pInPlaceObject->SetObjectRects(&rcClient,&rcClient);
pInPlaceObject->Release();
}
}
break;
}
....
}
复制代码
复制代码

下载源代码

在下一篇,可能会写如何响应ActiveX的Dispatch事件。

相关文章:

  • 禁止鼠标选中文字
  • HDU2553 N皇后问题
  • [转]给年轻工程师的十大忠告
  • Flutter 安装
  • CYQ.Data V5 批量插入与批量更新示例
  • Java知识点总结(JavaIO-打印流)
  • 在Java中使用Lua脚本语言
  • python正则
  • [HEOI2013]ALO
  • 20172304 2017-2018-2 《程序设计与数据结构》第七周学习总结
  • 【语言处理与Python】4.2序列
  • 关于iOS网络访问权限的问题
  • Repository设计模式
  • Launcher中Shortcut的创建流程简析
  • thymeltesys-基于Spring Boot Oauth2的扫码登录框架
  • [PHP内核探索]PHP中的哈希表
  • 2017前端实习生面试总结
  • CSS相对定位
  • EOS是什么
  • Java 多线程编程之:notify 和 wait 用法
  • Javascripit类型转换比较那点事儿,双等号(==)
  • JS专题之继承
  • mysql_config not found
  • Promise初体验
  • uni-app项目数字滚动
  • Vue2.0 实现互斥
  • Yeoman_Bower_Grunt
  • 阿里云前端周刊 - 第 26 期
  • 从伪并行的 Python 多线程说起
  • 等保2.0 | 几维安全发布等保检测、等保加固专版 加速企业等保合规
  • 机器学习学习笔记一
  • 基于遗传算法的优化问题求解
  • 聊聊flink的TableFactory
  • 七牛云假注销小指南
  • 物联网链路协议
  • #LLM入门|Prompt#1.8_聊天机器人_Chatbot
  • #在线报价接单​再坚持一下 明天是真的周六.出现货 实单来谈
  • (2009.11版)《网络管理员考试 考前冲刺预测卷及考点解析》复习重点
  • (附源码)springboot“微印象”在线打印预约系统 毕业设计 061642
  • (附源码)springboot宠物医疗服务网站 毕业设计688413
  • (附源码)springboot人体健康检测微信小程序 毕业设计 012142
  • (附源码)ssm高校实验室 毕业设计 800008
  • (牛客腾讯思维编程题)编码编码分组打印下标(java 版本+ C版本)
  • (十)DDRC架构组成、效率Efficiency及功能实现
  • (原創) 如何讓IE7按第二次Ctrl + Tab時,回到原來的索引標籤? (Web) (IE) (OS) (Windows)...
  • (转)GCC在C语言中内嵌汇编 asm __volatile__
  • (转)LINQ之路
  • (转)关于多人操作数据的处理策略
  • ******之网络***——物理***
  • .CSS-hover 的解释
  • .NET CORE 2.0发布后没有 VIEWS视图页面文件
  • .net6解除文件上传限制。Multipart body length limit 16384 exceeded
  • .NET项目中存在多个web.config文件时的加载顺序
  • [100天算法】-每个元音包含偶数次的最长子字符串(day 53)
  • [383] 赎金信 js