`
buliedian
  • 浏览: 1259634 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

ActiveX异步回调JavaScript

阅读更多

版权声明

请尊重原创作品。转载请保持文章完整性,并以超链接形式注明原始作者“tingsking18”和主站点地址,方便其他朋友提问和指正。

ActiveX异步回调JavaScript

开发环境:VC6.0

背景知识:COM/ActiveX/JavaScript/MFC/Thread

想必用过Ajax的童鞋们都知道xmlhttp这个东西吧,通过设定onreadystatechange属性,我们就可以指定他状态改变的回调函数,当状态改变时,ActiveX控件就会调用我们通过onreadystatechange属性制定的回调函数。从而就出现了Ajax给我们带来的精彩。关于Ajax的技术我们这里不做讨论,我们的目的就是实现像xmlhttp这样具有异步回调JavaScript功能的ocx控件来。

Let’s go!

1. 建立MFC ActiveX Control(方法略)

2. ClassWizard中添加属性callbackfunction属性,并为该属性生成getset方法。我们将在ActiveX控件中开启线程,线程执行完后将调用通过该属性执行的JavaScript函数。在该实例中,通过callbackfunction属性指定的JavaScript函数必须是返回值是void的,并且含有一个short类型的参数的函数。

3. 我们需要一个方法来触发回调函数,添加方法Invoke包含一个short类型的参数param。在这个函数里将开启一个线程进行运算,然后返回计算结果。并把结果以回调函数的形式调用JavaScript的函数。

4. Invoke方法中开启线程。进行计算。线程同步的方法采用PostMessage自定义消息。这个很重要,否则的话,我们在线程中操作界面控件是不正确的。(我就是忘记了进行线程同步才多走了好多弯路)

#define WM_THREADFIREEVENT WM_USER+101

void f(void * r)

{

CThirdCtrl* p = (CThirdCtrl*)r;

Sleep(5000);

p->m_param +=10;

PostMessage(p->m_hWnd,WM_THREADFIREEVENT,(WPARAM)NULL,(LPARAM)NULL);

return;

}

void CThirdCtrl::invoke(short param)

{

m_param = param;

_beginthread(f, 0, (void*)(this));

}

5. 添加THREADFIREEVENT 消息的消息映射函数:

ON_MESSAGE(WM_THREADFIREEVENT,OnFireEventForThread)

6. 实现函数OnFireEventForThread

LRESULT CThirdCtrl::OnFireEventForThread(WPARAM wParam, LPARAM lParam)

{

//FireLengthyProcessDone();

InvokeScript ();

return TRUE;

}

7. 在实现InvokeScript前,先说一个重要的东西,就是OnSetClientSite这是一个CThirdCtrl 的父类ColeControl的一个虚方法。我们需要重写他来获得IWebBrowser2指针,有了IWebBrowser2我们就可以为所欲为了。比方说获得document对象,获得html中的elements,设定他们的属性,调用方法。也可以执行页面中的JavaScript函数。

为获得顶层IWebBrowser2 引用, 从客户站点获取IServiceProvider接口并且执行一个QueryService操作获取IID_IServiceProvider服务:SID_STopLevelBrowser (这在Shlguid.h中定义);对第二个IServiceProvider,执行一个QueryService 获取IID_IWebBrowser2 服务:SID_SWebBrowserApp.

上代码:

void CThirdCtrl::OnSetClientSite()

{

IOleClientSite* pClientSite = GetClientSite();

HRESULT hr = S_OK;

IServiceProvider *isp, *isp2 = NULL;//用于导航DHTML对象层次,作用就是提供服务

if (!pClientSite)

{

if(browser!=NULL)

{

browser->Release();

browser = NULL;

}

return;// !S_OK;

}

else

{

hr = pClientSite->QueryInterface(IID_IServiceProvider, reinterpret_cast<void **>(&isp));

if (FAILED(hr))

{

hr = S_OK;

goto cleanup;

}

hr = isp->QueryService(SID_STopLevelBrowser, IID_IServiceProvider, reinterpret_cast<void **>(&isp2));

if (FAILED(hr))

{

hr = S_OK;

goto cleanup;

}

//获得浏览器

hr = isp->QueryService(SID_SWebBrowserApp, IID_IWebBrowser2, reinterpret_cast<void **>(&browser));

if (FAILED(hr))

{

hr = S_OK;

goto cleanup;

}

cleanup:

// Free resources.

if(isp!=NULL)

{

isp->Release();

isp = NULL;

}

if(isp2!=NULL)

{

isp2->Release();

isp2 = NULL;

}

return;// hr;

}

return;// hr;

}

同样的道理,如果我们是ATL做的ActiveX,则需要重写

STDMETHODIMP CThirdCtrl::SetClientSite()

这个方法。

8. 下面就是最关键的InvokeScript函数的实现,我们在这里使用上面获取到的IWebBrowser2指针来获取document对象,然后获取Idispatch接口的script对象,然后调用Idispatch接口的Invoke方法。就可以调用JavaScript了。Idispatch接口真是强大啊。

废话少说,上代码:

void CThirdCtrl::InvokeScript()

{

if(!browser)

{

if(browser!=NULL)

{

browser->Release();

browser = NULL;

}

return;

}

CComPtr<IHTMLDocument2> m_spDoc;

HRESULT hr = browser->get_Document((IDispatch**)&m_spDoc);

if(FAILED(hr))

throw("");

CComPtr<IDispatch> pScript;

hr = m_spDoc->get_Script(&pScript);

if(FAILED(hr))

throw("");

CComBSTR bstrMember(m_callbackfunction);

DISPID dispid;

hr=pScript->GetIDsOfNames(IID_NULL,&bstrMember,1,LOCALE_SYSTEM_DEFAULT,&dispid);

// 设置函数参数

DISPPARAMS dispparams;

memset(&dispparams,0,sizeof(dispparams));

dispparams.cArgs = 1;//表示参数的计数。

dispparams.rgvarg = new VARIANT[dispparams.cArgs];//表示对参数数组的引用。

for(int i = 0; i < 1; i++)

{

//CComBSTR bstr = "111"; // back reading

//bstr.CopyTo(&dispparams.rgvarg[i].bstrVal);

dispparams.rgvarg[i].iVal = m_param;

dispparams.rgvarg[i].vt = VT_I2;

}

dispparams.cNamedArgs =0;//表示命名参数的计数。

EXCEPINFO excepInfo;

memset(&excepInfo,0,sizeof(excepInfo));

CComVariant vaResult;

UINT nArgErr = (UINT)-1; // initialize to invalid arg

hr = pScript->Invoke(dispid, IID_NULL,0,DISPATCH_METHOD,&dispparams,&vaResult,&excepInfo,&nArgErr);

}

这样,ActiveX控件就完成了。

9. 编写html页面代码。打开Microsoft ActiveX Control Pad,插入控件。然后编写JavaScript代码。

<HTML>

<HEAD>

<TITLE>New Page</TITLE>

</HEAD>

<BODY>

<SCRIPT LANGUAGE="JavaScript" >

function invoke()

{

Third1.callbackfunction = "callback";

Third1.invoke(2);

alert("begin invoke");

}

function callback(param)

{

alert(param);

}

</SCRIPT>

<OBJECT ID="Third1" WIDTH=100 HEIGHT=51

CLASSID="CLSID:E9D38528-0F4E-468B-858D-69905F16942F">

<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="invoke();" />

</BODY>

</HTML>

10. 测试:打开浏览器,打开test.html页面。点击“test“按钮,将会先显示对话框begin invoke,然后过5秒钟再显示对话框12

11. 调试方法:我们可以直接调试浏览器。浏览器加载了控件,然后我们调用控件的方法,这时会自动触发我们在工程中设置的断点。在

project---settings---debug---executable for debug sessions设置浏览器的exe文件的路径。我用的世界之窗浏览器。所以值设置为:C:\Program Files\TheWorld\TheWorld.exe

如果你用IE浏览器,可设置为:C:\Program Files\Internet Explorer\iexplore.exe

说明:

1. 上述控件与xmlhttp不同的地方是callbackfunction我传的是一个字符串,而xmlhttp传的是一个JavaScript的函数指针。

2. COM中的线程模型不在本文讨论范围之内。还有浏览器安全问题和打包CAB的问题也不在本文讨论范围之内。

参考:

http://vcfaq.mvps.org/com/1.htm

http://vcfaq.mvps.org/com/11.htm

http://support.microsoft.com/kb/q157437/

分享到:
评论

相关推荐

    JavaScriptActiviX.zip

    "ActiveX异步回调JavaScript(通过事件方式)"指的是通过事件模型实现的通信方式。在ActiveX控件中定义一个事件,当特定条件满足(如任务完成)时,触发该事件。JavaScript端注册事件监听器,当事件发生时,监听器的...

    USB-ID通用免动动读卡器JavaScript示例源码.rar

    - 异步编程:RFID读卡器操作可能是异步的,需要理解回调函数、Promise或async/await语法。 - 安全性:ActiveX控件在现代Web开发中的安全问题,以及为什么它主要限于IE浏览器。 在实际应用中,由于ActiveX控件的安全...

    JavaScript中文手册+核心手册

    此外,还包括了作用域、闭包、原型链、异步编程(回调函数、Promise、async/await)等高级主题。理解这些内容能帮助开发者编写出高效且易于维护的代码。 2. **JavaScript核心参考手册**: 核心参考手册通常会更...

    JavaScript全集

    4. **异步编程**:回调函数、Promise、async/await,这些是解决JavaScript中回调地狱问题的关键技术。 5. **DOM操作**:通过JavaScript访问和修改HTML元素,包括选择元素(getElementById, getElementsByClassName,...

    javascript api 手册

    9. **异步编程**:包括回调函数、Promise、async/await,用于处理非阻塞I/O操作,是现代JavaScript开发的核心技能。 10. **错误处理**:通过try...catch块处理运行时错误,以及使用throw语句抛出自定义错误。 11. ...

    Javascript以及JScript帮助文档(chm格式)

    2. **函数**:函数定义、参数传递、回调函数、立即执行函数表达式。 3. **对象与原型**:对象创建、原型链、对象属性操作。 4. **DOM操作**:获取和修改HTML元素、事件处理、DOM遍历。 5. **AJAX**:XMLHttpRequest...

    js 访问dotnet control

    在JavaScript中,可以使用`setTimeout`或`setInterval`来模拟异步回调,但这种方式并不理想,因为它们可能会导致性能问题。更好的做法是使用.NET控件提供事件支持,当.NET执行完某个操作后触发事件,JavaScript端...

    javascript对象参考手册

    19. **异步编程**:包括事件循环、回调函数、async/await等处理异步任务的方式。 20. **模块系统**:讲解CommonJS、AMD、ES6模块以及它们在不同场景下的应用。 这本手册将是你掌握JavaScript对象和相关技术的宝贵...

    JavaScript中三种异步上传文件方式_.docx

    // 上传完成后的回调 function uploadFinished(fileName) { addToFlist(fileName); loading(false); } // 添加文件列表 function addToFlist(fname) { var temp = [", fname, "(\"" + fname + "\");'&gt;...

    JavaScript与JScript从入门到精通

    6. **异步编程**:JavaScript中的异步编程主要涉及回调函数、Promise和async/await。它们处理耗时操作,如网络请求,以避免阻塞主线程。 JScript与JavaScript的主要区别在于,JScript默认开启严格模式,而...

    html调用python,python回调结果给html.zip

    总结来说,这个示例展示了如何通过HTML使用JavaScript调用Python脚本,然后让Python将处理结果回调给HTML。虽然ActiveX技术在现代Web开发中已较少使用,但通过Ajax或者Web框架如Flask、Django等,我们可以实现安全、...

    JavaScriptHelp中文

    2. 高级特性:闭包、原型链、作用域、异步编程(回调、Promise、async/await)。 3. BOM(Browser Object Model)和DOM操作:如何访问和操作浏览器窗口、文档、以及页面元素。 4. AJAX(异步JavaScript和XML):实现...

    javascript手册

    手册中可能还涵盖了变量作用域、闭包、异步编程(回调函数、Promise、async/await)、事件监听、AJAX请求、模板字符串、模块化(CommonJS、ES6模块)、正则表达式、数据类型与类型转换等JavaScript基础和高级主题。...

    原生javascript实现的ajax异步封装功能示例

    示例中定义了一个名为`ajax`的函数,它接受四个参数:请求的URL地址、成功回调函数`fnSucc`、选择器ID和失败回调函数`fnFaild`。这个函数能够处理GET请求,并在请求成功或失败时执行相应的回调函数。 在`ajax`函数...

    javascript跨域请求包装函数与用法示例.docx

    这会触发一个异步请求,并且服务器需要响应一个带有指定回调函数名称的JSON字符串。 - **处理 AJAX 请求**:设置请求头、打开连接并发送请求。 ##### 3.3 回调函数 `_setRandomFun()` 此函数用于生成一个随机的...

    FoxitPDF SDK ActiveX 5.2 开发文档 中文版 Chinese

    7. 事件:事件是指控件在执行某些操作时触发的回调,开发者可以在这些事件发生时执行特定的代码。文档中列出的事件包括BeforeDraw(绘制前)、AfterDraw(绘制后)、OnZoomChange(缩放改变时)等。 8. IPDFPrinter...

    JavaScript中三种异步上传文件方式

    然后,可以通过某种机制,比如JavaScript回调函数,来从iframe中获取上传结果并反馈到主页面上。这种方法的优点是可以兼容大多数现代浏览器,且不需要额外的插件支持。然而,由于使用iframe,所以在与主页面进行数据...

    Vc++编写ocx异步调用dll

    本文将详细讲解如何使用VC++编写一个OCX控件,以实现异步调用DLL,并通过回调函数来防止网页卡死。 首先,我们需要了解OCX和DLL的基本概念。OCX是ActiveX控件的一种形式,它是可重用的软件组件,可以在不同的应用...

    ActiveQtServer

    5. **AJAX异步请求回调**:在Web端,使用JavaScript的AJAX技术向C++服务器发送异步请求,服务器端接收到请求后,通过回调函数返回结果,实现页面的无刷新更新。 这些回调机制的实现,都基于ActiveQtServer中的...

    ajax异步调用

    2. **设置回调函数** - 当服务器响应状态发生变化时,`onreadystatechange`事件会被触发。通常情况下,只有当`readyState`为4(表示请求完成)且`status`为200(表示成功获取到数据)时,才会处理服务器返回的数据...

Global site tag (gtag.js) - Google Analytics