JS和C++之间的相互访问

      最近,工作需要,实现了JS与C++之间的相互访问。核心思想是通过一个隐藏域作为中转。JS发送数据给C++时,将数据写往某个隐藏域,同时C++每隔一段时间(如40ms)检测一次此域可有数据,有的话取出进行相关操作后清空。C++发送数据给JS时,将数据写往另外一个隐藏域后,直接使用COM触发某个隐藏Button的click事件,由它进行相关的操作。具体代码如下:

//File: WebNativeCall.js
var g_strInCommPortId = null;
var g_strOutCommPortId = null;
var g_strInCommCmdId = null;
var g_funcCallIn = null;

var funcOnLoad = function() {
    if (g_strInCommPortId != null && g_strOutCommPortId != null
    && g_strInCommCmdId != null && g_funcCallIn != null) {
        var txtInCommPort = document.createElement("input");
        txtInCommPort.setAttribute("type", "hidden");
        txtInCommPort.setAttribute("id", g_strInCommPortId);
        txtInCommPort.setAttribute("name", g_strInCommPortId);
        txtInCommPort.setAttribute("value", "");
        document.body.appendChild(txtInCommPort);

        var txtOutCommPort = document.createElement("input");
        txtOutCommPort.setAttribute("type", "hidden");
        txtOutCommPort.setAttribute("id", g_strOutCommPortId);
        txtOutCommPort.setAttribute("name", g_strOutCommPortId);
        txtOutCommPort.setAttribute("value", "");
        document.body.appendChild(txtOutCommPort);

        var btnInCommCmd = document.createElement("input");
        btnInCommCmd.setAttribute("type", "button");
        btnInCommCmd.style.setAttribute("display", "none");
        btnInCommCmd.setAttribute("id", g_strInCommCmdId);
        btnInCommCmd.setAttribute("name", g_strInCommCmdId);
        btnInCommCmd.onclick = function() {
            var data = document.getElementById(g_strInCommPortId).value;
            if (data != null && data != "") {
                g_funcCallIn(document.getElementById(g_strInCommPortId).value);
            }
        };
        document.body.appendChild(btnInCommCmd);
    };
};

if (window.addEventListener) {
    window.addEventListener("load", funcOnLoad, false);
}
else if (window.attachEvent) {
    window.attachEvent("onload", funcOnLoad);
}

function funcCallOut(strData)
{
    document.getElementById(g_strOutCommPortId).value = strData;
}


//File: Test.html
<html>
    <head>
        <title>Test the Commucation between C++ and JS</title>
        <script type="text/javascript" language="javascript" src="WebNativeCall.js"></script>
        <script type="text/javascript" language="javascript">
            g_strInCommPortId = "txtInCommPort";
            g_strOutCommPortId = "txtOutCommPort";
            g_strInCommCmdId = "btnInCommCmd";
           
            g_funcCallIn = function(CommData) {
                alert("Web Receive Data: " + CommData);
            }

            function TestCallOut() {
                funcCallOut(document.getElementById("txtOutData").value);
            }
        </script>
    </head>
    <body>
        <input type="text" id="txtOutData" name="txtOutData" value="" />
        <input type="button" id="btnCallOut" name="btnCallOut" value="CallOut" οnclick="TestCallOut();" />   
    </body>
</html>


//File: VisitHtmlTool.h
/***************************************************************************

* 功能  : 网页本地访问类
* 输入参数 : 无
* 输出参数 : 无
* 返回值 : 无

***************************************************************************/
class CVisitHtmlTool               //网页本地访问类
{
public:
 typedef void (* Func_CallOut)(LPCTSTR lpszData);

 CVisitHtmlTool(CHtmlView *pHtmlView, LPCTSTR lpszInCmdTagId
  , LPCTSTR lpszInDataTagId, LPTSTR lpszOutDataTagId
  , Func_CallOut pCallOut);
 ~CVisitHtmlTool(void);

 BOOL CallIn(LPCTSTR lpszData);            //向网页发数据
 VOID StartReceive();              //开始自动接收数据
 VOID StopReceive();               //停止自动接收数据
 
protected:
 static DWORD WINAPI ReceiveThread(LPVOID lpThreadParameter);
 static LRESULT CALLBACK WindowSubSolve(HWND hWnd, UINT iMsg, WPARAM wParam
  , LPARAM lParam);

 CHtmlView *m_pHtmlView;              //HtmlView指针
 LPCTSTR m_lpszInCmdTagId;             //Web端数据接收触发器标识
 LPCTSTR m_lpszInDataTagId;             //Web端接收数据保存控件标志
 LPTSTR m_lpszOutDataTagId;             //Web端发送数据保存控件标志
 
 IHTMLElement* m_pEle;              //CallOut的数据结点

 Func_CallOut m_pCallOut;             //本地端接收数据回调函数

private:
 HANDLE m_hLock;

 BOOL m_bStarted;
 WNDPROC m_pOldProc;
 LONG m_pUserData;
};


//File: VisitHtmlTool.cpp
#include "StdAfx.h"
#include "VisitHtmlTool.h"

#define WM_PUMPCALLOUTDATA (WM_USER+1)

CVisitHtmlTool::CVisitHtmlTool(CHtmlView *pHtmlView,
          LPCTSTR lpszInCmdTagId ,
          LPCTSTR lpszInDataTagId,
          LPTSTR lpszOutDataTagId,
          Func_CallOut pCallOut)
{
 m_pOldProc = NULL;
 m_pUserData = NULL;
 m_hLock = ::CreateEvent(NULL, FALSE, TRUE, NULL);

 m_bStarted = FALSE;
 m_pCallOut = pCallOut;

 m_pHtmlView = pHtmlView;
 m_lpszInCmdTagId = lpszInCmdTagId;
 m_lpszInDataTagId = lpszInDataTagId;
 m_lpszOutDataTagId = lpszOutDataTagId;
 m_pEle = NULL;
}

CVisitHtmlTool::~CVisitHtmlTool(void)
{
 StopReceive();
 ::CloseHandle(m_hLock);

 if(m_pEle)
 {
  m_pEle->Release();
  m_pEle = NULL;
 }
}

BOOL CVisitHtmlTool::CallIn(LPCTSTR lpszData)
{
 IDispatch* pDis = NULL;
 IHTMLElement* pEle = NULL;
 IHTMLElement* pEleBody = NULL; 
 IHTMLDocument2 *pDoc = NULL;
 IHTMLElementCollection* pAllCollection = NULL;
 IHTMLElementCollection* pBodyCollection = NULL;

 LONG lLength = 0;
 BSTR bstrTmp;

 WaitForSingleObject(m_hLock, INFINITE);

 if((pDoc=(IHTMLDocument2 *)m_pHtmlView->GetHtmlDocument()) == NULL)
 {
  SetEvent(m_hLock);
  return FALSE;
 }

 pDoc->get_body(&pEleBody);
 if (pEleBody == NULL)
 {
  SetEvent(m_hLock);
  return FALSE;
 }

 BOOL bRet = FALSE;
 pEleBody->get_children(&pDis);
 pDis->QueryInterface(IID_IHTMLElementCollection, (void**)&pBodyCollection);
 pDis->Release();
 pEleBody->Release();
 pBodyCollection->get_length(&lLength);

 for (int i = 0; i < lLength; i++)
 {
  pBodyCollection->item(_variant_t(i), _variant_t(0), &pDis);
  pDis->QueryInterface(IID_IHTMLElement, (void**)&pEle);
  pDis->Release();
  pEle->get_id(&bstrTmp);
  
  if(!lstrcmp(m_lpszInDataTagId, bstrTmp))
  {
   pEle->setAttribute(BSTR(TEXT("value")), _variant_t(lpszData));
   ::SysFreeString(bstrTmp);
   pEle->Release();
   bRet = TRUE;
  }
  else if(!lstrcmp(m_lpszInCmdTagId, bstrTmp))
  {
   pEle->click();
   break;
  }
  else
  {
   pEle->Release();
   ::SysFreeString(bstrTmp);
  }
 }

 pBodyCollection->Release();
 SetEvent(m_hLock);
 return bRet;
}

VOID CVisitHtmlTool::StartReceive()
{
 if(m_bStarted)
 {
  return;
 }

 m_bStarted = TRUE;
 m_pUserData = ::SetWindowLong(m_pHtmlView->GetSafeHwnd(), GWL_USERDATA, (LONG)this);
 m_pOldProc = (WNDPROC)::SetWindowLong(m_pHtmlView->GetSafeHwnd(), GWL_WNDPROC, (LONG)WindowSubSolve);

 ::CreateThread(NULL, 0, ReceiveThread, this, 0, NULL);
}

VOID CVisitHtmlTool::StopReceive()
{
 if(!m_bStarted)
 {
  return;
 }

 m_bStarted = FALSE;
 while(!m_bStarted)
 {
  SleepEx(100, TRUE);
 }
 ::SetWindowLong(m_pHtmlView->GetSafeHwnd(), GWL_WNDPROC, (LONG)m_pOldProc);
 ::SetWindowLong(m_pHtmlView->GetSafeHwnd(), GWL_USERDATA, m_pUserData);
 m_bStarted = FALSE;
}

DWORD WINAPI CVisitHtmlTool::ReceiveThread(LPVOID lpThreadParameter)
{
 CVisitHtmlTool *pThis = reinterpret_cast<CVisitHtmlTool *>(lpThreadParameter);

 while(pThis->m_bStarted)
 {
  SleepEx(40, TRUE);
  pThis->m_pHtmlView->PostMessage(WM_PUMPCALLOUTDATA);
 }

 pThis->m_bStarted = TRUE;
 return 0;
}

LRESULT CALLBACK CVisitHtmlTool::WindowSubSolve(HWND hWnd,
            UINT iMsg,
            WPARAM wParam,
            LPARAM lParam)
{
 CComVariant varData;
 CVisitHtmlTool *pThis = reinterpret_cast<CVisitHtmlTool *>(::GetWindowLong(
  hWnd, GWL_USERDATA));

 if(iMsg != WM_PUMPCALLOUTDATA)
 {
  return CallWindowProc(pThis->m_pOldProc, hWnd, iMsg, wParam, lParam);
 }

 if(WaitForSingleObject(pThis->m_hLock, 0) == WAIT_TIMEOUT)
 {
  return 0;
 }

 if(pThis->m_pEle==NULL
  || pThis->m_pEle->getAttribute(CComBSTR(TEXT("value")), 0, &varData)!=S_OK)
 {
  IDispatch* pDis = NULL;       
  IHTMLElement* pEle = NULL;
  IHTMLElement* pEleBody = NULL; 
  IHTMLDocument2 *pDoc = NULL;
  IHTMLElementCollection* pAllCollection = NULL;
  IHTMLElementCollection* pBodyCollection = NULL;

  LONG lLength = 0;
  BSTR  bstrTmp;

  if((pDoc=(IHTMLDocument2 *)pThis->m_pHtmlView->GetHtmlDocument()) == NULL)
  {
   SetEvent(pThis->m_hLock);
   return 0;
  }

  pDoc->get_body(&pEleBody);
  if (pEleBody == NULL)
  {
   SetEvent(pThis->m_hLock);
   return 0;
  }

  pEleBody->get_children(&pDis);
  pDis->QueryInterface(IID_IHTMLElementCollection, (void**)&pBodyCollection);
  pDis->Release();
  pEleBody->Release();
  pBodyCollection->get_length(&lLength);
  pThis->m_pEle = NULL;

  for (int i = 0; i < lLength; i++)
  {
   pBodyCollection->item(_variant_t(i), _variant_t(0), &pDis);
   pDis->QueryInterface(IID_IHTMLElement, (void**)&pEle);
   pDis->Release();
   pEle->get_id(&bstrTmp);

   if(!lstrcmp(pThis->m_lpszOutDataTagId, bstrTmp))
   {
    pThis->m_pEle = pEle;    
    ::SysFreeString(bstrTmp);
    break;
   }
   else
   {
    pEle->Release();
    ::SysFreeString(bstrTmp);
   }
  }

  pBodyCollection->Release();
 }

 if(pThis->m_pEle && pThis->m_pEle->getAttribute(CComBSTR(TEXT("value")), 0, &varData)==S_OK)
 {
  if(varData.vt!=VT_NULL && varData.bstrVal!=NULL && lstrcmp(varData.bstrVal, TEXT("")))
  {
   pThis->m_pEle->setAttribute(CComBSTR(TEXT("value")), _variant_t(""));

   if(pThis->m_pCallOut)
   {
    pThis->m_pCallOut(varData.bstrVal);
   }
  }
 }

 SetEvent(pThis->m_hLock);
 return 1;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值