由于一些原因,居然开始 MFC OCX 的开发,这都是淘汰了多久的玩意了啊,心塞。
MFC 如何进行 OCX 开发不在本文讨论之内,可以参考一下这些内容:MFC ActiveX (ocx)控件的开发, MFC .ocx控件开发,mfc 开发ocx
OCX 加载失败问题
如果 OCX 莫名其妙加载失败,主要表现为,在 ie
无论调用那个函数,都会提示 没有该方法,则很有可能 OCX 加载失败了,可以检查一下两个方面:
- 是否注册:
regsvr32 OCX路径
(卸载命令:regsvr32 /u OCX路径
) - 依赖的 dll 是否完整。
OCX 事件回调
有些情况下,我们需要OCX 进行一些耗时间的操作,但是又不想卡死UI,这时候我们可以注册事件回调,等处理好之后,再通过事件回调进行通知UI:这里有几个地方需要注意的:
需要添加消息映射
1
2
3
4
5
6// 事件映射
BEGIN_EVENT_MAP(CVideoShowOCXCtrl, COleControl)
EVENT_STOCK_READYSTATECHANGE()
// 注册 onComplete 的事件映射
EVENT_CUSTOM_ID("onComplete", eventidComplete, Complete, VTS_BSTR)
END_EVENT_MAP()调用方式
通过
FireEvent
进行触发事件映射1
FireEvent(eventidComplete, EVENT_PARAM(VTS_BSTR), data);
开放端口
如果只是进行了1、2步骤,那么事件是无法触发的,还需要对
*.idl : ActiveX 控件项目的类型库源
进行编辑,增加暴露1
2
3
4
5
6
7
8
9
10
11
12
13
14// CVideoShowOCXCtrl 的事件调度接口
[
uuid(*******-****-****-****-***********)
]
dispinterface _DVideoShowOCXEvents
{
properties:
// 事件接口没有任何属性
methods:
// 增加 onComplete 的暴露
[id(1)] void onComplete(char*);
};在IE中的使用方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17<!--回调函数-->
<script language='javascript' for="object_id" event="onComplete(data)">
// 参数为 data
// Works on IE11
Complete(data);
</script>
<script>
// 使用统一的函数进行处理
function Complete(data) {
}
// IE 11 以下
try {
object_id.attachEvent("onComplete", Complete, false);
} catch (e) {
}
</script>需要注意的是,这玩意在
IE
不一样的版本下面还有区别;最好将两种方式都进行实现。
多线程进行事件回调
就像前面说的,通过 FireEvent
进行触发事件映射,但是问题是,多线程的情况下,这个是也是无效的,所以需要想办法使用主线程(UI线程)通过 FireEvent
进行触发事件映射,比较简单的方式就是消息通知的方式,可以通过PostMessage
发送消息给主线程,让主线程进行操作,数据的话,可以通过全局变量(记得加锁读写)进行共享。
这玩意也需要进行注意:
继承函数
1
2
3
4
5
6
7
8
9
10// 要使用消息推送,必须使用继承该函数
void *Ctrl::OnSetClientSite()
{
// It doesn't matter who the parent window is or what the size of
// the window is because the control's window will be reparented
// and resized correctly later when it's in-place activated.
if (m_pClientSite)
VERIFY(CreateControlWindow(::GetDesktopWindow(), CRect(0, 0, 0, 0), CRect(0, 0, 0, 0)));
COleControl::OnSetClientSite();
}使用消息推送,必须继承
OnSetClientSite
函数,否则还是无效,emmmmmm。注册消息推送处理函数
1
2
3
4
5
6
7
8// 消息映射
BEGIN_MESSAGE_MAP(CVideoShowOCXCtrl, COleControl)
ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
// 注册消息 id = WM_USER + 100 使用 OnFinishPublic 处理
ON_MESSAGE(WM_USER + 100, OnFinishPublic)
END_MESSAGE_MAP()
// OnFinishPublic 定义可以参考以下
afx_msg LRESULT OnFinishPublic(WPARAM wParam, LPARAM lParam);PostMessage 参数
使用消息推送的时候,第一个参数可以使用 内部变量
m_hWnd
或者使用:1
2
3
4if (cWnd == nullptr) {
cWnd = GetActiveWindow();
hWnd = cWnd->GetSafeHwnd();
}或者,看需求情况自己选择。
总结
目前发现的坑就是这些,其它的如果有的话,以后再说吧。