zoukankan      html  css  js  c++  java
  • JavaScript Interactive with ActiveX Control

    1.在COM组件中调用JavaScript函数
    // 连接点方式页面javascript脚本
    <object classid="CLSID:B568F111-DFE4-4944-B67F-0728AB2AB30F" id="testCom" VIEWASTEXT></object>
    <script language="JavaScript" for="testCom" event="staTe(s)">
    alert("State(" + s + ")");
    return 123;
    </script>
    <script language="JavaScript">
    testCom.FireStateEvent("Hello");
    </script>
     
    // 事件属性方式页面javascript脚本
    function onState(s){
    alert("onState(" + s + ")");
    return 456;
    }
    var o = new ActiveXObject("TestATL.TestCom");
    o.onstaTe=onState;
    o.FireStateEvent("Hello");
     
    // Com组件VC7.1 ATL代码
    __interface _ITestComEvents{
    [id(1), helpstring("State事件")] HRESULT State([in] BSTR str);
    };
    __event __interface _ITestComEvents;
    IDispatchPtr m_onState;        // 事件属性
    STDMETHOD(get_onState)(IDispatch** pVal) {
    *pVal = m_onState;
    return S_OK;
    };
    STDMETHOD(put_onState)(IDispatch* newVal) {
    m_onState = newVal;
    return S_OK;
    };
    STDMETHOD(FireStateEvent)(BSTR str) {
    __raise State(str);        // 激发连接点事件
    CComVariant result;
    CComVariant avarParams[1] = {str};
    DISPPARAMS dispParams = {avarParams, NULL, 1, 0};
    EXCEPINFO excepInfo;
    memset(&excepInfo, 0, sizeof excepInfo);
    UINT nArgErr = (UINT)-1;      // initialize to invalid arg
    if (m_onState)        // 激发属性事件
    HRESULT hr = m_onState->Invoke(0, IID_NULL, LOCALE_USER_DEFAULT,
    DISPATCH_METHOD, &dispParams, &result, &excepInfo, &nArgErr);
    return S_OK;
    }
    参见:
    How To Call a Script Function from a VC WebBrowser Application
    如何在COM object中使用 Javascript function object?
    在COM组件中调用JavaScript函数
     
    2.从页面javascript向Com组件传递结构数组
    // 页面脚本
    var o = new ActiveXObject("TestATL.TestCom");
    o.onstaTe=onState;
    o.Put("array", {0: 123, 1: "abc"});
    o.Put("array", [456, "def"]);
    o.Put("array", [{name: "tom", age: 8}, {name: "jack", age: 10}]);
    var a = new Array(789, "ghi"); // has "length" property
    o.Put("array", a);
     
    // Com组件VC7.1 ATL代码
    STDMETHODIMP CTestCom::Put(BSTR key, VARIANT value)
    {
    WCHAR output[4096] = L"";
    if(0 == wcsicmp(key, L"array") && VT_DISPATCH == value.vt)
    {
    IDispatchPtr spDisp = value.pdispVal;
    DISPID dispID = 0;
    DISPPARAMS dispParams = {NULL, NULL, 0, 0};
    CComVariant result;
    EXCEPINFO excepInfo;
    memset(&excepInfo, 0, sizeof excepInfo);
    UINT nArgErr = (UINT)-1; // initialize to invalid arg
    unsigned int length = 0; // 数组长度 或 属性 个数
     
         LPOLESTR func = L"length";
    HRESULT hr = spDisp->GetIDsOfNames(GUID_NULL, &func, 1, LOCALE_SYSTEM_DEFAULT, &dispID);
    if(S_OK == hr){       // 如果有"length"属性
    hr = spDisp->Invoke(dispID, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispParams, &result, &excepInfo, &nArgErr);
    if(S_OK == hr && VT_I4 == result.vt)
    length = result.intVal;       // 直接读取数组长度
    }else{
    unsigned int nTypeInfo = 0;
    hr = spDisp->GetTypeInfoCount(&nTypeInfo);
    ATLASSERT(1 == nTypeInfo);
    ITypeInfoPtr spTypeInfo;
    hr = spDisp->GetTypeInfo(0, 0, &spTypeInfo);
    TYPEATTR *pTypeAttr = NULL;
    hr = spTypeInfo->GetTypeAttr(&pTypeAttr);
    //ATLASSERT("{C59C6B12-F6C1-11CF-8835-00A0C911E8B2}" == pTypeAttr->guid);     // JScript: 
    length = pTypeAttr->cVars;       // 从类型信息读取数组长度
    spTypeInfo->ReleaseTypeAttr(pTypeAttr);
    }
    for(unsigned int i=0; i<length; i++)
    {
    WCHAR buf[32];
    _itow(i, buf, 10);
    func = buf;
    hr = spDisp->GetIDsOfNames(GUID_NULL, &func, 1, LOCALE_SYSTEM_DEFAULT, &dispID);
    hr = spDisp->Invoke(dispID, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispParams, &result, &excepInfo, &nArgErr);
    if(S_OK != hr)
    continue;
    if(VT_DISPATCH == result.vt){
    IDispatchPtr spItem = result.pdispVal;
    func = L"name";
    hr = spItem->GetIDsOfNames(GUID_NULL, &func, 1, LOCALE_SYSTEM_DEFAULT, &dispID);
    hr = spItem->Invoke(dispID, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispParams, &result, &excepInfo, &nArgErr);
    if(S_OK == hr && VT_BSTR == result.vt)
    swprintf(output + wcslen(output), L"name=%s", result.bstrVal);
    func = L"age";
    hr = spItem->GetIDsOfNames(GUID_NULL, &func, 1, LOCALE_SYSTEM_DEFAULT, &dispID);
    hr = spItem->Invoke(dispID, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispParams, &result, &excepInfo, &nArgErr);
    if(S_OK == hr && VT_I4 == result.vt)
    swprintf(output + wcslen(output), L" age=%d\n", result.intVal);
    }else if(VT_BSTR == result.vt)
    swprintf(output + wcslen(output), L"BSTR:%s\n", result.bstrVal);
    else if(VT_I4 == result.vt)
    swprintf(output + wcslen(output), L"I4:%d\n", result.intVal);
    else
    swprintf(output + wcslen(output), L"item.vt=%d\n", result.vt);
    }
    }
    FireStateEvent(output);
    return S_OK;
    }
     
    3.枚举IE窗口的内容,并调用其中的脚本
    #import <mshtml.tlb>       // Internet Explorer 5
    #import <shdocvw.dll> 
    SHDocVw::IShellWindowsPtr spSHWinds; 
    spSHWinds.CreateInstance(__uuidof(SHDocVw::ShellWindows));
    long nCount = spSHWinds->GetCount();
    IDispatchPtr spDisp;
    for (long i = 0; i < nCount; i++)
    {
    _variant_t va(i, VT_I4);
    spDisp = spSHWinds->Item(va);
    SHDocVw::IWebBrowser2Ptr spBrowser(spDisp);
    if (spBrowser != NULL)
    {
    _bstr_t location = spBrowser->GetLocationName();
    if(_bstr_t(L"Test DapCtrl") == location)       // 找指定IE窗口
    {
    IHTMLDocument2Ptr spDoc(spBrowser->GetDocument());
    if (spDoc != NULL)
    {
    _bstr_t exp = m_onState;
    IDispatch *pdis = NULL;
    hr = spDoc->get_Script(&pdis);
    if(pdis){
    DISPID tmpDispID = 0;
    LPOLESTR func = L"Test"; // javascript 函数名
    hr = pdis->GetIDsOfNames(GUID_NULL, &func, 1, LOCALE_SYSTEM_DEFAULT, &tmpDispID);
    if(S_OK == hr)
    hr = pdis->Invoke(tmpDispID, IID_NULL, LOCALE_USER_DEFAULT,
    DISPATCH_METHOD, &dispParams, &result, &excepInfo, &nArgErr);
    }
    }
    }
    }
    }
    参见:
    HOWTO: Connect to a Running Instance of Internet Explorer
    ActiveX组件与JavaScript交互
    ActiveX组件控制其所在的IE窗口
     
    4.在VC中执行脚本
    #import <msscript.ocx>       // msscript.ocx 
    using namespace MSScriptControl;
    IScriptControlPtr pScriptControl(__uuidof(ScriptControl));
    LPSAFEARRAY psa;
    SAFEARRAYBOUND rgsabound[]       = { 1, 0 }; // 1 elements, 0-based
    int i;
    psa = SafeArrayCreate(VT_VARIANT, 1, rgsabound);
    if (!psa)
    {
    return E_OUTOFMEMORY;
    }
    VARIANT vFlavors[1];
    for (i = 0; i < 1; i++)
    {
    VariantInit(&vFlavors[i]);
    V_VT(&vFlavors[i]) = VT_BSTR;
    }
    V_BSTR(&vFlavors[0]) = SysAllocString(bstr);
    long lZero = 0;
    hr = SafeArrayPutElement(psa, &lZero,&vFlavors[0]);
    for(i=0;i<1;i++)
    {
    SysFreeString(vFlavors[i].bstrVal);
    }
    pScriptControl->Language = "JScript";
    pScriptControl->AllowUI = TRUE;
    _bstr_t exp = L"1+2+3";
    _variant_t outpar = pScriptControl->Eval(exp);
    //_variant_t outpar = pScriptControl->ExecuteStatement(exp);
    //_variant_t outpar = pScriptControl->Run("MyStringFunction", &psa);
    _bstr_t bstrReturn = (_bstr_t)outpar;
    char *pResult = (char *)bstrReturn;
    SafeArrayDestroy(psa);
    参见:
    How To Call Run() Method of the Microsoft Script Control in C++


    本文研究如何在JS等脚本语言与ActiveX控件之间通信,如何传递各种类型的参数,以及COMIDispatch接口。使用类似的方法,可以推广到其他所有脚本型语言,如LUAAutoCad等。
    本文将研究以下几个方面:

    1. 整形数组传参

    2. 字符串参数,字符串返回值

    3. 修改传入字符串内容

    4. 数组参数

    5. IDispatch接口介绍

    6. 修改输入数组内容

    7. 增加数组内容

    8. 以数组传参方式,JS调用S4Execute( )

    (一)整形参数

    1. 整形参数,可直接传递。整形返回值需要以 [retVal] Long *方式声明
    2.
    COMc++接口定义

    STDMETHODIMP CJsAtl::IntSum(LONG a, LONG b, LONG* retVal)

    {

    *retVal = a + b;

    return S_OK;

    }

    3. Js中调用

    <object id="obj" classid="CLSID:AD694878-......"> </object>

    function test_int()

    {

    var a = 1;

    var b = 2;

    try {

    var obj = document.getElementByIdx_xx_x("obj");

    var retVal = obj.IntSum(a, b);

    Alert("RetVal: " + retVal);

    } catch (e) {

    Alert( "Js error: " + e.message);

    }

    }

    (二)字符串参数,字符串返回值

    1. COM中,字符串使用BSTR表示,BSTR实际是UNICODE 字符数组(WCHAR[]

    2. COM字符串传参规范中规定:

    a) 生成字符串变量时,需要SysAllocString/SysAllocStringByteLen分配空间。

    b) 函数结束前,分配的空间需要释放,SysFreeString

    c) 若函数中分配的空间作为返回值,则不释放。而由外部调用者负责释放。

    3. COMc++函数定义

    STDMETHODIMP CJsAtl::StringAdd(BSTR str1, BSTR str2, BSTR* retVal)

    {

    int len = SysStringLen(str1);

    len += SysStringLen(str2);

    len += 4; // 保证有'\0'结尾

    BSTR result = SysAllocStringLen(NULL, len);

    memset(result, 0, len * 2); // 双字节字符

    StrCat(result, str1);

    StrCat(result, str2);

    *retVal = result; // 设置返回值指针。注:不释放内存

    return S_OK;

    }

    4. JS中调用

    function test_str_cat()

    {

    var a = "123";

    var b = "abc";

    try {

    var obj = document.getElementByIdx_xx_x("obj");

    var retVal = obj.StringAdd(a, b);

    alert("RetVal: " + retVal);

    } catch (e) {

    alert("JS ERROR: " + e.message);

    }

    }

    (三)修改传入字符串内容

    1. 原则上,不应修改传入字符串的内存数据,否则可能破坏数据,造成js端异常。

    2. 使用中,可通过修改传入字符串缓冲区内容的方法,实现参数传递。

    3. 不能使用SysFreeString破坏传入的BSTR参数,否则会破坏js内存结构

    4. COMC++定义

    STDMETHODIMP CJsAtl::StrModify(BSTR str)

    {

    int len = SysStringLen(str); // 注:此方法修改BSTR,不能破坏原占用内存,不能越界访问

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

    str[i] = '0' + i;

    return S_OK;

    }

    5. JS调用

    function test_str_modify()

    {

    var str = "abcdefghijklmn";

    try {

    var obj = document.getElementByIdx_xx_x("obj");

    obj.StrModify(str);

    alert("After modify: " + str);

    } catch (e) {

    alert("JS ERROR: " + e.message);

    }

    }

    6. 测试执行

    原字符串: abcdefghijklmn

    调用后: 0123456789:;<=

    (四)数组参数

    1. 在使用时,有时需要使用数组传参,如S4Execute( )inBuff/ outBuff

    2. JS中整形数据不分Byte/ Short/ Int等,因此数组元素类型都为int COM中的VT_I4,其中I表示整形、4表示4字节)

    3. JS中的ArrayCOM中是一个实现了IDispatch的对象,可通过IDispatch接口api进行操作。关于IDispatch请看下一节介绍。

    4. COMC++定义

    下面代码中定义了两个函数 GetArrayNumberOfIndexGetArrayLength两个函数,功能分别获取数组长度和获取指定序号元素

    以下代码含义,请参考下一节 IDispatch接口介绍”

    JS数组在COM中是一个IDispatch对象,获取长度,实际是获取其中名为“length”的属性值。

    而获取最后一个数组,实际是获取名为“4”的属性值(假设5个元素)

    STDMETHODIMP CJsAtl::GetLastElement(VARIANT vArray, LONG* retVal)

    {

    int len = 0;

    HRESULT hr = GetArrayLength(vArray.pdispVal, &len);

    if (FAILED(hr))

    return hr;

    hr = GetArrayNumberOfIndex(vArray.pdispVal, len - 1, retVal);

    return S_OK;

    }

    // ***

    // 获取Javascript数组长度

    // Javascript中的数组length只计算列表中下标为数字的部分

    // ***

    HRESULT GetArrayLength(IDispatch* pDisp, int* pLength)

    {

    BSTR varName = L"length";

    VARIANT varValue;

    DISPPARAMS noArgs = {NULL, NULL, 0, 0};

    DISPID dispId;

    HRESULT hr = 0;


    hr = pDisp->GetIDsOfNames(IID_NULL, &varName, 1, LOCALE_USER_DEFAULT, &dispId);

    if (FAILED(hr))

    return hr;

    hr = pDisp->Invoke(dispId, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &noArgs, &varValue, NULL, NULL);

    if (SUCCEEDED(hr))

    {

    *pLength = varValue.intVal;

    return hr;

    }

    else

    {

    return hr;

    }

    }

    // ***

    // 获取Javascript数组中指定位置的整数元素值

    // ***

    HRESULT GetArrayNumberOfIndex(IDispatch* pDisp, int index, int * pValue)

    {

    CComVariant varName(index, VT_I4); // 数组下标

    DISPPARAMS noArgs = {NULL, NULL, 0, 0};

    DISPID dispId;

    VARIANT varValue;

    HRESULT hr = 0;

    varName.ChangeType(VT_BSTR); // 将数组下标转为数字型,以进行GetIDsOfNames

    //

    // 获取通过下标访问数组的过程,将过程名保存在dispId

    //

    hr = pDisp->GetIDsOfNames(IID_NULL, &varName.bstrVal, 1, LOCALE_USER_DEFAULT, &dispId);

    if (FAILED(hr))

    return hr;

    //

    // 调用COM过程,访问指定下标数组元素,根据dispId 将元素值保存在varValue

    //

    hr = pDisp->Invoke(dispId, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTY GET , &noArgs, &varValue, NULL, NULL);

    if (SUCCEEDED(hr))

    {

    *pValue = varValue.intVal; // 将数组元素按int类型取出

    return hr;

    }

    else

    {

    return hr;

    }

    }

    5. JS中调用

    function test_get_last()

    {

    var array = new Array(0, 1, 2, 3); // 定义数组

    try {

    var obj = document.getElementByIdx_xx_x("obj");

    var lastElement = obj.GetLastElement(array); // 获取数组最后一个元素

    alert("lastElement: " + lastElement);

    } catch (e) {

    alert("JS ERROR: " + e.message);

    }

    }

    6. 测试执行

    数组定义:{0,1,2,3}

    最后元素:3

    (五)IDispatch接口介绍

    1. C程序调用时,调用者必须预先知道接口规范(如,参数类型、参数字节长度、参数顺序等)。由于不同语言这些规范有所不同,COM未解决不同语言之间调用,提供了IDispatch接口。

    2. IDispatch要求其实例必须自我描述,即拿到一个对象后,可从对象中直接获取调用方式,而无须预先明确。

    3. IDispatch中通过VT_TYPE来指定相关类型,如 VT_I44字节整形、VT_BSTRunicode字符串,VT_DISPATCH表示是一个IDispatch对象

    4. 给对象中每一属性或函数(Method)分配一个整形Id和一个字符串name,调用者可以通过name字符串确定如何调用。如,若name"length"的属性,调用者就理解为长度。由于这里通常是根据name来理解相应属性,因此name描述应足够准确。如,以"length()"为名称的函数实现整数相加功能就是不恰当的。

    5. 使用IDispatch对象时,首相调用 IDispatch::GetIDsOfNames()将属性、函数名称作为参数,获取对应的属性、函数id

    6. 再调用IDispatch::Invoke() id作为参数,实际调用功能。

    7. 若为获取属性值,则 Invoke()调用时,传入 Dispatch_PropertyGet标志。

    8. 若为设置属性值,则Invoke()调用时,传入 Dispatch_PropertyPut标志。并在 DispParams参数中指定修该属性改为何值。DispParams结构说明见后。

    9. 若为调用函数,则 Invoke()调用时,传入 Dispatch_Method标志。若该Method需要参数,则通过IDispatch::Invoke()DispParams参数指定。

    10. DispParams结构使用举例:

    DISPPARAMS dispparams;

    dispparams.rgdispidNamedArgs = &dispidOfNamedArgs;

    dispparams.cArgs = 1;

    dispparams.cNamedArgs = 1;

    dispparams.rgvarg = new VARIANTARG[1];

    dispparams.rgvarg[0].vt = VT_I4;

    dispparams.rgvarg[0].intVal = 123;

    a. 上面代码是一个用于给Method传参的简单例子,先创建一个DispParams对象

    b. cArgs指定Method中的参数个数。

    c. cNamedArgs指定Method中已经命名的参数个数。(命名参数是对应无名参数的概念。有些语言可定义不定参数,此时IDispatch的描述中不会给参数分配名称,而是调用时以无名参数存在。如,JSArray对象的push()方法,可支持不定个数的参数)

    d. rgvarg 为实际参数数组,每一元素表示一个参数,其中.vt表明此元素的数据类型,intVal项是一个C++联合结构,如vt == VT_I4时,应以intVal = xxx方式赋值;若 vt == VT_BSTR,则应以 bstrVal = xxx方式赋值

    11. 举例:两个参数,都是无名称参数,第一个为整形,第二个为BSTR

    DISPPARAMS dispparams;

    dispparams.rgdispidNamedArgs = NULL;

    dispparams.cArgs = 2;

    dispparams.cNamedArgs = 0;

    dispparams.rgvarg = new VARIANTARG[2]; // 2个参数,分配2个空间

    dispparams.rgvarg[0].vt = VT_I4; // 整形

    dispparams.rgvarg[0].intVal = 123;

    dispparams.rgvarg[1].vt = VT_BSTR; // 字符串型

    dispparams.rgvarg[1].bstrVal = L"abcd";

    (六)修改输入数组内容

    1. 第五节介绍了如何从JSCOM传递数组参数,以及如何在COM中获取参数。本节介绍如何在COM中修改JS传入的数组。

    2. 修改JS数组值时,首先通过GetIDsOfNames获取指定序号元素的dispid;然后调用Invoke(),传入Dispatch_PropertyPut标志表明写操作,并在DispParams结构中指明此元素类型和元素值。

    3. COMC++定义

    STDMETHODIMP CJsAtl::ArrayModiy(VARIANT vArray)

    {

    SetArrayNumberOfIndex(vArray.pdispVal, 0, 123); // 修改数组第[0]个元素,值为

    return S_OK;

    }

    // ***

    // 设置Javascript数组中指定位置的整数元素值

    // ***

    HRESULT SetArrayNumberOfIndex(IDispatch* pDisp, int index, int value)

    {

    CComVariant varName(index, VT_I4);

    DISPID dispId;

    CComVariant varValue;

    HRESULT hr = 0;

    varName.ChangeType(VT_BSTR); // 将数组下标转为数字型,以进行GetIDsOfNames

    hr = pDisp->GetIDsOfNames

    (IID_NULL, &varName.bstrVal, 1, LOCALE_USER_DEFAULT, &dispId);

    if (FAILED(hr))

    return hr;

    DISPID dispidPut = DISPID_PROPERTYPUT; // put操作

    DISPPARAMS dispparams;

    dispparams.rgvarg = new VARIANTARG[1]; // 初始化rgvarg

    dispparams.rgvarg[0].vt = VT_I4; // 数据类型

    dispparams.rgvarg[0].intVal = value; // 更新值

    dispparams.cArgs = 1; // 参数数量

    dispparams.cNamedArgs = 1; // 参数名称

    dispparams.rgdispidNamedArgs = &dispidPut; // 操作DispId,表明本参数适用于put操作

    hr = pDisp->Invoke(dispId, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTY PUT, &dispparams, NULL, NULL, NULL);

    return hr;

    }

    4. JS调用

    function test_set_first()

    {

    var array = new Array(0, 1, 2, 3);

    try {

    var obj = document.getElementByIdx_xx_x("obj");

    obj.ArrayModiy(array);

    alert("first element: " + array[0]);

    } catch (e) {

    alert("JS ERROR: " + e.message);

    }

    }

    5. 测试执行

    原数组:{0, 1,2,3}

    修改后:{123,1,2,3}


    (七)增加数组内容

    1. COM中无法向JS中一样,直接增加数组元素。只能使用属性、方法的方式访问数组对象,并以此产生增加数组元素的效果。

    2. JSArray中包含push( ) pop( )两个方法,用于在数组尾部增减元素。在COM中需要增减元素时,可通过IDispatch:: Invoke( )接口调用 "push""pop"方法来实现。

    3. COMC++定义

    STDMETHODIMP CJsAtl::AddNewElement(VARIANT vArray)

    {

    AddArrayElement(vArray.pdispVal, 123); // 增加元素,值为 123

    return S_OK;

    }

    // ****************************************************

    // js数组中增加元素

    // ****************************************************

    HRESULT AddArrayElement(IDispatch* pDisp, int value)

    {

    HRESULT hr = 0;

    DISPID dispid[2] = {0};

    CComBSTR funcName(L"push");

    hr = pDisp->GetIDsOfNames(IID_NULL, &funcName, 1, LOCALE_USER_DEFAULT, dispid);

    if (FAILED(hr))

    return hr;

    DISPID dispidNamed = DISPID_UNKNOWN;

    DISPPARAMS params;

    params.rgdispidNamedArgs = NULL;

    params.cArgs = 1;

    params.cNamedArgs = 0;

    params.rgvarg = new VARIANTARG[1];

    params.rgvarg[0].vt = VT_I4;

    params.rgvarg[0].intVal = value;

    hr = pDisp->Invoke(dispid[0], IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);

    return hr;

    }

    4. JS调用

    function test_add_element()

    {

    var array = new Array(0, 1, 2, 3);

    try {

    var obj = document.getElementByIdx_xx_x("obj");

    obj.AddNewElement(array);

    alert("length: [" + array.length + "] " + array[array.length - 1]);

    } catch (e) {

    alert("JS ERROR: " + e.message);

    }

    }

    5. 测试执行

    原数组:{0,1,2,3}

    增加后:{0,1,2,3,123}

    (八)以数组传参方式,JS调用S4Execute( )

    1. 本例展示如何在JS中执行精锐4锁内程序,且以数组方式处理参数。

    2. 本例在Execute传参时,直接以整形数组表示字节数组,而不再需要Hex字符串形式,使得JS端接口更加直观。

    3. JS代码

    var obj = document.getElementByIdx_xx_x("obj");

    var deviceID = "123";

    var userPin = "12345678";

    var fileID = "0001";

    var inBuff = new Array(1, 2, 3, 4);

    var outBuff = new Array(0, 0, 0, 0);

    var ret = 0;

    try {

    ret = obj.OpenLock(deviceID);

    ret = obj.ChangeDir("\\");

    ret = obj.VerifyPin(userPin);

    ret = obj.Execute(fileID, inBuff, outBuff);

    ret = obj.Close();

    } catch (e) {

    alert("JS Exception: " + e.message);

    }

    // JS数组操作,打印结果

    var str = "";

    for (var i = 0; i < outBuff.length; i++)

    str += " " + outBuff[i];

    alert(str);

    4. ActiveX代码

    SENSE4_CONTEXT g_ctx = {0}; //全局变量保存当前打开的ctx

    // 打开设备,以设备ID作为筛选条件,若设备ID指定为空串,则打开第一把锁

    STDMETHODIMP CS4ActiveX::OpenLock(BSTR deviceID, LONG* retVal)

    {

    SENSE4_CONTEXT * pctx = NULL;

    unsigned long ret = 0;

    unsigned long size = 0;

    unsigned long devCount= 0;

    unsigned long i = 0;

    char bDeviceID[9] = {0};

    char bUserPin[9] = {0};

    S4Enum(NULL, &size);

    if (size == 0)

    {

    *retVal = S4_NO_LIST;

    goto cleanup;

    }

    pctx = (SENSE4_CONTEXT*) malloc(size);

    ret = S4Enum(pctx, &size);

    if (ret != S4_SUCCESS)

    {

    *retVal = ret;

    goto cleanup;

    }

    // 获取ascii格式的设备ID

    WideCharToMultiByte(CP_ACP, 0, deviceID, SysStringLen(deviceID), bDeviceID, 9, NULL, NULL);

    // 遍历,寻找deviceID为指定值的设备

    devCount = size / sizeof(SENSE4_CONTEXT);

    for (i = 0; i < devCount; i++)

    {

    if (strlen(bDeviceID) == 0) // 未指定设备ID,返回第一把锁

    {

    break;

    }

    if (0 == memcmp(bDeviceID, pctx[i].bID, 8))

    {

    break;

    }

    }

    // 没有找到

    if (i == devCount)

    {

    *retVal = S4_NO_LIST;

    goto cleanup;

    }

    memcpy(&g_ctx, &pctx[i], sizeof(SENSE4_CONTEXT));

    ret = S4Open(&g_ctx);

    if (ret != S4_SUCCESS)

    {

    *retVal = ret;

    goto cleanup;

    }

    *retVal = S4_SUCCESS;

    cleanup:

    if (pctx)

    {

    free(pctx);

    pctx = NULL;

    }

    return S_OK;

    }

    STDMETHODIMP CS4ActiveX::ChangeDir(BSTR dir, LONG* retVal)

    {

    char bDir[20] = {0};

    WideCharToMultiByte(CP_ACP, 0, dir, SysStringLen(dir), bDir, 20, NULL, NULL);

    *retVal = S4ChangeDir(&g_ctx, bDir);

    return S_OK;

    }

    STDMETHODIMP CS4ActiveX::Execute(BSTR fileID, VARIANT inBuff, VARIANT outBuf, LONG* retVal)

    {

    char bFileID[5] = {0};

    BYTE * bInBuff = NULL;

    BYTE * bOutBuff = NULL;

    int inBuffSize = 0;

    int outBuffSize = 0;

    unsigned long size = 0;

    unsigned long ret = 0;

    int i = 0;

    int tmp = 0;

    GetArrayLength(inBuff.pdispVal, &inBuffSize);

    GetArrayLength(outBuf.pdispVal, &outBuffSize);

    if (inBuffSize > 0)

    bInBuff = (BYTE*) malloc(inBuffSize);

    if (outBuffSize > 0)

    bOutBuff = (BYTE*) malloc(outBuffSize);

    for (i = 0; i < inBuffSize; i++)

    {

    GetArrayNumberOfIndex(inBuff.pdispVal, i, &tmp);

    bInBuff[i] = (BYTE)tmp;

    }

    WideCharToMultiByte(CP_ACP, 0, fileID, SysStringLen(fileID), bFileID, 5, NULL, NULL);

    ret = S4Execute(&g_ctx, bFileID, bInBuff, inBuffSize, bOutBuff, outBuffSize, &size);

    if (ret != S4_SUCCESS)

    {

    *retVal = ret;

    return S_FALSE;

    }

    for (i = 0; i < size; i++)

    {

    SetArrayNumberOfIndex(outBuf.pdispVal, i, bOutBuff[i]);

    }

    return S_OK;

    }

    STDMETHODIMP CS4ActiveX::VerifyPin(BSTR userPin, LONG* retVal)

    {

    unsigned char bUserPin[9] = {0};

    WideCharToMultiByte(CP_ACP, 0, userPin, SysStringLen(userPin), (char*)bUserPin, 9, NULL, NULL);

    *retVal = S4VerifyPin(&g_ctx, bUserPin, 8, S4_USER_PIN);

    return S_OK;

    }

    STDMETHODIMP CS4ActiveX::Close(LONG* retVal)

    {

    *retVal = S4Close(&g_ctx);

    return S_OK;

    }


  • 相关阅读:
    Hibernate save, saveOrUpdate, persist, merge, update 区别
    Eclipse下maven使用嵌入式(Embedded)Neo4j创建Hello World项目
    Neo4j批量插入(Batch Insertion)
    嵌入式(Embedded)Neo4j数据库访问方法
    Neo4j 查询已经创建的索引与约束
    Neo4j 两种索引Legacy Index与Schema Index区别
    spring data jpa hibernate jpa 三者之间的关系
    maven web project打包为war包,目录结构的变化
    创建一个maven web project
    Linux下部署solrCloud
  • 原文地址:https://www.cnblogs.com/yefengmeander/p/2887553.html
Copyright © 2011-2022 走看看