博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Win32编程点滴3 - 简单ActiveX控件的使用
阅读量:6625 次
发布时间:2019-06-25

本文共 5430 字,大约阅读时间需要 18 分钟。

虽然这里一片的.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加强控制。

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

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

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

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事件。

转载地址:http://rhtpo.baihongyu.com/

你可能感兴趣的文章
Linux下tomcat修改成的80端口无法访问
查看>>
Kubernetes 集群日志管理 - 每天5分钟玩转 Docker 容器技术(180)
查看>>
redis实现对账(集合比较)功能
查看>>
为了好好看球,学霸们用深度学习重建整个比赛3D全息图
查看>>
浅谈持续集成
查看>>
【ZH奶酪】如何用textgenrnn处理中文
查看>>
CentOS双机中Docker下安装Mysql并配置互为主从模式
查看>>
OkHttp3源码详解(六) Okhttp任务队列工作原理
查看>>
这样做,轻松在Word中使用MathType
查看>>
VS Code非英语版本连接TFS错误解决方案
查看>>
angular5中使用jsonp请求页面
查看>>
sql in not in 案例用 exists not exists 代替
查看>>
使用newtonjson解决Json日期格式问题
查看>>
WEB前端资源代码:学习篇
查看>>
Nginx安装及配置详解【转】
查看>>
vue2.0 :style :class样式设置
查看>>
测不准原理主要指向微观
查看>>
排序算法java版,速度排行:冒泡排序、简单选择排序、直接插入排序、折半插入排序、希尔排序、堆排序、归并排序、快速排序...
查看>>
Android之ExpandableList扩展用法(基于BaseExpandableListAdapter)
查看>>
解决注册表映像劫持
查看>>