ATL COM开发入门(二)(ActiveX/COM组件回调JS)

清泛原创

本文代码基于上篇《ATL COM开发入门(一)(JS调用ActiveX/COM组件)》。

完成的需求:后台ATL代码回调前台js函数,后台ATL启动定时器完成前台计数。截图如下:

分析:完成此需求有两个难点,一是如何回调前台js代码?二是ATL是无窗口的如何使用定时器(MFC一般的定时器SetTimer、OnTimer都是CWnd的成员)?

MSDN提供了ATL直接获取前台IHTMLDocument2对象的方法,但是写得很不够详细,详见《获得ActiveX控件所在网页的对象模型》,不过笔者没有调试成功,有兴趣的读者可以深入研究下。这里笔者提供另外一种更加简便的方式:前台传入浏览器窗口对象的IDispatch指针(js中this便是),然后通过它就可以在ATL中任意获取网页元素,进行Invoke调用。

定时器采用Win32 API的SetTimer,在回调函数中回调前台js函数,显示计数。

一、ATLDemo.idl 中添加一个新的接口:


BeginTiming函数体:
STDMETHODIMP CAtlDemoIf::BeginTiming(IDispatch* pIDispatch)
{
	gIDispatch = pIDispatch;

	UINT nRet = SetTimer(NULL,      // handle to main window 
			ID_TIMER,				// 定时器标识 
             1000,					// 1 秒间隔 
             (TIMERPROC)TimerProc); // 回调函数

	return S_OK;
}
TimerProc回调函数:
IDispatch* gIDispatch = NULL;

#define ID_TIMER 1
VOID CALLBACK TimerProc( 
    HWND hwnd,        // 定时器消息的窗口句柄
    UINT message,     // WM_TIMER 消息 
    INT_PTR idTimer,     // 定时器标志
    DWORD dwTime)     // 当前系统启动计时
{
	if (!gIDispatch)
		return;

	CComQIPtr<IHTMLWindow2> spHtmlWin;
	CComQIPtr<IHTMLDocument2> spHtmlDoc2;
	gIDispatch->QueryInterface(IID_IHTMLWindow2, (void **)&spHtmlWin);
	spHtmlWin->get_document(&spHtmlDoc2);

	DISPPARAMS param = {0};
	VARIANT vtRet;
	CallJSFunction(spHtmlDoc2, _T("TimingCallbackFunc"), param, &vtRet, NULL, NULL);
}
CallJSFunction:
HRESULT CallJSFunction(IHTMLDocument2* pDoc2,
					   CString strFunctionName,
					   DISPPARAMS dispParams,
					   VARIANT* varResult,
					   EXCEPINFO* exceptInfo,
					   UINT* nArgErr )
{
	IDispatch *pDispScript = NULL;
	HRESULT hResult;
	hResult = pDoc2->get_Script(&pDispScript);
	if(FAILED(hResult))
	{
		return S_FALSE;
	}

	DISPID   dispid;   
	CComBSTR objbstrValue = strFunctionName;
	BSTR bstrValue = objbstrValue.Copy();
	OLECHAR *pszFunct = bstrValue ; 
	hResult = pDispScript->GetIDsOfNames(IID_NULL, 
				&pszFunct, 
				1,
				LOCALE_SYSTEM_DEFAULT, 
				&dispid);
	if (FAILED(hResult))   
	{ 
		pDispScript->Release();
		return hResult;
	}  

	varResult->vt = VT_VARIANT;
	hResult = pDispScript->Invoke(dispid,
				IID_NULL, LOCALE_USER_DEFAULT,
				DISPATCH_METHOD,
				&dispParams,
				varResult,
				exceptInfo,
				nArgErr);  
	pDispScript->Release();

	return hResult;
}
二、前台代码:
<HTML>
<HEAD>
<TITLE>COM接口测试页</TITLE>
<script type="text/javascript">
//...

function BeginTiming(){
	AtlDemoObj.BeginTiming(this);
}
function TimingCallbackFunc(){
	var obj = document.getElementById('timing');
	var num = parseInt(obj.innerText);
	obj.innerText = ++num;
}
</script>
</HEAD>
<BODY>
<object id="AtlDemoObj" classid="clsid:B0DA2962-C4C3-48CD-BFBC-4F43F9D03C56" width=0 height=0></object>
...
<input type="button" value="Begin Timing " onclick = "javascript:BeginTiming();"/>
<span id="timing">0</span>

</BODY>
</HTML>
拓展:
ATL中回调js函数并传参的例子,参见《ATL创建的ActiveX(COM组件)实现JS回调》。

源码点此下载,如有问题请点此</</</a>a>a>。

ATL COM ActiveX 入门 JS回调

分享到:
评论加载中,请稍后...
创APP如搭积木 - 创意无限,梦想即时!
回到顶部