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函數了。