最近在给银行做一个项目,使用ocx 来做,显示视频,和获取数据,如果一个接口阻塞,会造成视频卡顿,网页无响应等,原以为是cpu占用过高问题,但cpu 降下来后也无效,怀疑是刷新问题;最终确认是 接口不能阻塞时间超过5秒,否则就会出出这种问题;解决方案只能采用异步的方式来解决; 把业务逻辑的执行放到多线程下,通过 ocx 的事件 吐给 js。
一、建立MFC ActiveX Control
CJavaScriptActiviXCtrl
在ClassWizard automation 类视图 页添加方法invoke
Invoke函数代码如下:
void CJavaScriptActiviXCtrl::invoke()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
_beginthread(dealwith, 0, (void*)(this));
// TODO: 在此添加调度处理程序代码
}
在上面的invoke方法中调用了线程函数 dealwith ,在dealwith函数中要调用界面控件CforthCtrl,所以必须进行线程同步,我们使用了PostMessage 异步发送消息 。
dealwith 函数 :
#define WM_THREADFIREEVENT WM_USER + 10002
void dealwith(void * r)
{
CJavaScriptActiviXCtrl* p = (CJavaScriptActiviXCtrl*)r;
Sleep(10000);
MessageBoxA(0, "fff", "algInit", 3);
PostMessage(p->m_hWnd, WM_THREADFIREEVENT, (WPARAM)NULL, (LPARAM)NULL);
return;
}
在类视图页 ClassWizard ActiveX Events 添加事件callbackjs,事件的参数为BSTR类型的参数,用于将结果传递到JavaScript中去。
5. 添加WM_THREADFIREEVENT消息的消息映射
ON_MESSAGE(WM_THREADFIREEVENT, &CJavaScriptActiviXCtrl::OnFireEventForThread)
LRESULT CJavaScriptActiviXCtrl::OnFireEventForThread(WPARAM wParam, LPARAM lParam)
{
MessageBoxA(0, "OnFire11", "algInit", 3);
this->callbackjs(" from ocx callback");
MessageBoxA(0, "OnFire22", "algInit", 3);
return TRUE;
}
void CJavaScriptActiviXCtrl::callbackjs(LPCTSTR result)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
FireEvent(dispidcallbackjs, EVENT_PARAM(VTS_BSTR), result);
// TODO: 在此添加调度处理程序代码
}
二、测试 html 页面
<HTML>
<HEAD>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<TITLE>New Page</TITLE>
</HEAD>
<BODY>
<SCRIPT LANGUAGE="JavaScript" FOR="Forth1" EVENT="calljs(param)">
alert(param);
</SCRIPT>
<script LANGUAGE="JavaScript">
function test()
{
alert("aa");
Forth1.invoke();
}
</script>
<OBJECT ID="Forth1" WIDTH=100 HEIGHT=51
CLASSID="CLSID:A0942C4E-2442-4FAC-ABDC-87D735FEAE9D">
<PARAM NAME="_Version" VALUE="65536">
<PARAM NAME="_ExtentX" VALUE="2646">
<PARAM NAME="_ExtentY" VALUE="1323">
<PARAM NAME="_StockProps" VALUE="0">
</OBJECT>
<input type="button" value="test" onclick="javascrypt: test()" />
</BODY>
</HTML>
注意 :测试页 CLSID 一定要和 ocx 的 CLSID 一致;
CLSID:A0942C4E-2442-4FAC-ABDC-87D735FEAE9D
脚本调用OCX控件是根据其classid调用, 要修改控件的classid。,假设工程名为xxx.ocx步逐如下:
(1) 在xxx.odl中将
// Class information for CXXXCtrl
// CMfcActiveXCtrl 的类信息
[
//uuid(DA9B5351-B039-4BBE-BCB5-9D58A3CA0ABF)
uuid(FC3899CF-1DDA-4F3D-917C-AA7A7385320A)
]
中的uuid修改为你要改的classid。
(2) 在xxxCtr.cpp中
// Initialize class factory and guid
IMPLEMENT_OLECREATE_EX(CMfcActiveXCtrl, "MFCACTIVEX.MfcActiveXCtrl.1",
//0xda9b5351, 0xb039, 0x4bbe, 0xbc, 0xb5, 0x9d, 0x58, 0xa3, 0xca, 0xa, 0xbf)
0xFC3899CF, 0x1DDA, 0x4F3D, 0x91, 0x7C, 0xAA, 0x7A, 0x73, 0x85, 0x32, 0x0A)
(3) 反注册原来控件。
(4) 注册控件。