1. 程式人生 > >Javascript通過WebBrowser呼叫C++方法

Javascript通過WebBrowser呼叫C++方法

  折騰了一天還是沒有能用MFC裡面的webbrowser控制元件實現js呼叫C++的方法,後來多方參考還是選擇了直接用CAxWindow建立的辦法。

  首先需要新增兩個標頭檔案

  #include <atlbase.h>
  #include <atlwin.h> // 因為CAxWindow是atl的類

  再需要生成一個物件CComModule _Module;   這個是什麼用處,我不知道,不過沒有他,webbrowser不能工作。

   剩下的就是主體實現了

   派生自IDsipatch 實現一個類,這個類是供CAxWindow物件來呼叫的。主要實現的幾個方法是:

   AddRef , Release, QueryInterface, GetIDsOfNames, Invoke。 順便也把 GetTypeInfoCount, GetTypeInfo實現了,因為這倆是純虛擬函式,不實現這個類無法例項化。

  貼一個程式碼:

  class CExternal : public IDispatch
{
private:
long m_dwRef;
public:
CExternal()
{
m_dwRef = 0;
}
~CExternal()
{


}
STDMETHOD(GetTypeInfoCount)(UINT* pctinfo)  
{  
return E_NOTIMPL;  
}  


STDMETHOD(GetTypeInfo)(/* [in] */ UINT iTInfo,  
/* [in] */ LCID lcid,  
/* [out] */ ITypeInfo** ppTInfo)  
{  
return E_NOTIMPL;  
}

STDMETHOD_(ULONG, AddRef)()  
{  
return InterlockedIncrement(&m_dwRef);  
}  


STDMETHOD_(ULONG, Release)()  
{  
unsigned long l = InterlockedDecrement(&m_dwRef);  
if(l == 0)  
delete this;  
return l;  
}  
STDMETHOD(QueryInterface)(REFIID iid, LPVOID far* ppvObject)  
{  
HRESULT hrRet = S_OK;  
*ppvObject = NULL;  
if(IsEqualIID(iid, IID_IDispatch))  
*ppvObject = (IDispatch*)this;  
else  
hrRet = E_NOINTERFACE;  
if (S_OK == hrRet)  
((IUnknown*)*ppvObject)->AddRef();  
return hrRet;  
}  
STDMETHOD(GetIDsOfNames)(  
/* [in] */ REFIID riid,  
/* [size_is][in] */ LPOLESTR *rgszNames,  
/* [in] */ UINT cNames,  
/* [in] */ LCID lcid,  
/* [size_is][out] */ DISPID *rgDispId)  
{  
HRESULT hr = S_OK;  
for (int i = 0; i < (int)cNames; i++)   
{  
CString cszName = CString(rgszNames[i]);  
if(cszName == L"callone")  
{  
rgDispId[i] = 1;  
break;  
}  
else  
{  
// One or more are unknown so set the return code accordingly  
hr = ResultFromScode(DISP_E_UNKNOWNNAME);  
rgDispId[i] = DISPID_UNKNOWN;  
}  


}  
return hr;  


}  


STDMETHOD(Invoke)(  
/* [in] */ DISPID dispIdMember,  
/* [in] */ REFIID riid,  
/* [in] */ LCID lcid,  
/* [in] */ WORD wFlags,  
/* [out][in] */ DISPPARAMS  *pDispParams,  
/* [out] */ VARIANT  *pVarResult,  
/* [out] */ EXCEPINFO *pExcepInfo,  
/* [out] */ UINT *puArgErr)  
{  
if (!pDispParams)  
return E_INVALIDARG;  


if(wFlags & DISPATCH_METHOD)  
{    
switch(dispIdMember)  
{  
case 1:  
{  
MessageBox(NULL,"Hello JS!", "",NULL);  
return S_OK;  
}  
break;  
default:  
return DISP_E_MEMBERNOTFOUND;  
break;  
}  
}  
return DISP_E_MEMBERNOTFOUND;  
}  
};

   然後定義CAxWindow m_Ax; 呼叫create方法建立視窗,m_Ax.Create(...) 。這裡需要注意的是標題字串一定要為NULL,否則網頁無法顯示在AxWindow中。

   利用AxWindow的SetExternalDispatch方法將派生的distpatch類物件指標傳入。這樣就可以獲得到這個物件了。

   現在AxWindow還只是個空殼,我們需要給裡面加入WebBrowser這個東西,利用一下程式碼

    m_Ax.CreateControl(OLESTR("shell.Explorer.2"));

    然後載入網頁

   IWebBrowser2* iWeb;
m_Ax.QueryControl(__uuidof(IWebBrowser2), (void**)&iWeb);
iWeb->put_Silent(VARIANT_TRUE);
CComVariant url = "D:\\net.html", VTEmpty;
iWeb->Navigate2(&url,&VTEmpty,&VTEmpty,&VTEmpty,&VTEmpty);

   這樣net.html中的js就可以呼叫自己在dispatch派生類中的callone函數了。