分3步:
一》实现IDispatch 接口
#ifndef _IDISPIMP_H_ #define _IDISPIMP_H_ // idispimp.h class CImpIDispatch : public IDispatch { protected: ULONG m_cRef; public: CImpIDispatch(void); ~CImpIDispatch(void); STDMETHODIMP QueryInterface(REFIID, void **); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); //IDispatch STDMETHODIMP GetTypeInfoCount(UINT* pctinfo); STDMETHODIMP GetTypeInfo(/* [in] */ UINT iTInfo, /* [in] */ LCID lcid, /* [out] */ ITypeInfo** ppTInfo); STDMETHODIMP GetIDsOfNames( /* [in] */ REFIID riid, /* [size_is][in] */ LPOLESTR *rgszNames, /* [in] */ UINT cNames, /* [in] */ LCID lcid, /* [size_is][out] */ DISPID *rgDispId); STDMETHODIMP 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); }; #endif
#include "StdAfx.h" #include "testDlg.h" // 这个是MFC对话框的头文件,在后面用于调用函数的 #include "Idispimp.h" #include <atlbase.h> #include <mmsystem.h> #include <shlwapi.h> #pragma comment(lib ,"shlwapi.lib") CString javaScriptName="JavaScriptCallCpp"; // javascript 传入的函数名 #define DISPID_CallCppFromJs 1 //与函数名绑定的ID CImpIDispatch::CImpIDispatch( void ) { m_cRef = 0; } CImpIDispatch::~CImpIDispatch( void ) { ASSERT( m_cRef == 0 ); } STDMETHODIMP CImpIDispatch::QueryInterface( REFIID riid, void **ppv ) { *ppv = NULL; if ( IID_IDispatch == riid ) { *ppv = this; } if ( NULL != *ppv ) { ((LPUNKNOWN)*ppv)->AddRef(); return NOERROR; } return E_NOINTERFACE; } STDMETHODIMP_(ULONG) CImpIDispatch::AddRef(void) { return ++m_cRef; } STDMETHODIMP_(ULONG) CImpIDispatch::Release(void) { return --m_cRef; } //IDispatch STDMETHODIMP CImpIDispatch::GetTypeInfoCount(UINT* /*pctinfo*/) { return E_NOTIMPL; } STDMETHODIMP CImpIDispatch::GetTypeInfo( /* [in] */ UINT /*iTInfo*/, /* [in] */ LCID /*lcid*/, /* [out] */ ITypeInfo** /*ppTInfo*/) { return E_NOTIMPL; } STDMETHODIMP CImpIDispatch::GetIDsOfNames( /* [in] */ REFIID riid, /* [size_is][in] */ OLECHAR** rgszNames, /* [in] */ UINT cNames, /* [in] */ LCID lcid, /* [size_is][out] */ DISPID* rgDispId) { HRESULT hr; UINT i; // Assume some degree of success hr = NOERROR; for ( i=0; i < cNames; i++) { CString cszName; cszName = rgszNames[i]; if (cszName == javaScriptName)//这里判断是否是JS传入的参数名 { rgDispId[i] = DISPID_CallCppFromJs;//将ID绑定,用于Invoke } else { // One or more are unknown so set the return code accordingly hr = ResultFromScode(DISP_E_UNKNOWNNAME); rgDispId[i] = DISPID_UNKNOWN; } } return hr; } STDMETHODIMP CImpIDispatch::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) { CtestDlg* pDlg = (CtestDlg*) AfxGetMainWnd(); /* 参数wFlags有下面若干值---- Value Description DISPATCH_METHOD 表示将调用方法。如果属性名称和方法名称相同,则和DISPATCH_PROPERTYGET标志一起设置。 DISPATCH_PROPERTYGET 获得属性 DISPATCH_PROPERTYPUT 设置属性 DISPATCH_PROPERTYPUTREF 通过引用设置属性 */ if (dispIdMember == DISPID_CallCppFromJs)// { if (wFlags & DISPATCH_PROPERTYGET)//获取属性 { if (pVarResult != NULL) { VariantInit(pVarResult); V_VT(pVarResult)=VT_BOOL; V_BOOL(pVarResult)=true; } } if (wFlags & DISPATCH_METHOD)//这里进行调用 { CString cszArg1; cszArg1 = pDispParams->rgvarg[0].bstrVal;//这里是传入参数 pDlg->TestHtml();// 调用测试的函数 } } return S_OK; }
二》改成COleControlSit
// Custsite.h #ifndef __CUSTOMSITEH__ #define __CUSTOMSITEH__ #include "Idispimp.h" #include <afxocc.h> #include <Mshtmhst.h> class CCustomControlSite:public COleControlSite { public: CCustomControlSite(COleControlContainer *pCnt):COleControlSite(pCnt){} BEGIN_INTERFACE_PART(DocHostShowUI, IDocHostShowUI) INIT_INTERFACE_PART(CDocHostSite, DocHostShowUI) STDMETHOD(ShowHelp)( /* [in ] */ HWND hwnd, /* [in ] */ LPOLESTR pszHelpFile, /* [in ] */ UINT uCommand, /* [in ] */ DWORD dwData, /* [in ] */ POINT ptMouse, /* [out] */ IDispatch __RPC_FAR *pDispatchObjectHit); STDMETHOD(ShowMessage)( /* [in ] */ HWND hwnd, /* [in ] */ LPOLESTR lpstrText, /* [in ] */ LPOLESTR lpstrCaption, /* [in ] */ DWORD dwType, /* [in ] */ LPOLESTR lpstrHelpFile, /* [in ] */ DWORD dwHelpContext, /* [out] */ LRESULT __RPC_FAR *plResult); END_INTERFACE_PART(DocHostShowUI) protected: DECLARE_INTERFACE_MAP(); BEGIN_INTERFACE_PART(DocHostUIHandler, IDocHostUIHandler) STDMETHOD(ShowContextMenu)(/* [in] */ DWORD dwID, /* [in] */ POINT __RPC_FAR *ppt, /* [in] */ IUnknown __RPC_FAR *pcmdtReserved, /* [in] */ IDispatch __RPC_FAR *pdispReserved); STDMETHOD(GetHostInfo)( /* [out][in] */ DOCHOSTUIINFO __RPC_FAR *pInfo); STDMETHOD(ShowUI)( /* [in] */ DWORD dwID, /* [in] */ IOleInPlaceActiveObject __RPC_FAR *pActiveObject, /* [in] */ IOleCommandTarget __RPC_FAR *pCommandTarget, /* [in] */ IOleInPlaceFrame __RPC_FAR *pFrame, /* [in] */ IOleInPlaceUIWindow __RPC_FAR *pDoc); STDMETHOD(HideUI)(void); STDMETHOD(UpdateUI)(void); STDMETHOD(EnableModeless)(/* [in] */ BOOL fEnable); STDMETHOD(OnDocWindowActivate)(/* [in] */ BOOL fEnable); STDMETHOD(OnFrameWindowActivate)(/* [in] */ BOOL fEnable); STDMETHOD(ResizeBorder)( /* [in] */ LPCRECT prcBorder, /* [in] */ IOleInPlaceUIWindow __RPC_FAR *pUIWindow, /* [in] */ BOOL fRameWindow); STDMETHOD(TranslateAccelerator)( /* [in] */ LPMSG lpMsg, /* [in] */ const GUID __RPC_FAR *pguidCmdGroup, /* [in] */ DWORD nCmdID); STDMETHOD(GetOptionKeyPath)( /* [out] */ LPOLESTR __RPC_FAR *pchKey, /* [in] */ DWORD dw); STDMETHOD(GetDropTarget)( /* [in] */ IDropTarget __RPC_FAR *pDropTarget, /* [out] */ IDropTarget __RPC_FAR *__RPC_FAR *ppDropTarget); STDMETHOD(GetExternal)( /* [out] */ IDispatch __RPC_FAR *__RPC_FAR *ppDispatch); STDMETHOD(TranslateUrl)( /* [in] */ DWORD dwTranslate, /* [in] */ OLECHAR __RPC_FAR *pchURLIn, /* [out] */ OLECHAR __RPC_FAR *__RPC_FAR *ppchURLOut); STDMETHOD(FilterDataObject)( /* [in] */ IDataObject __RPC_FAR *pDO, /* [out] */ IDataObject __RPC_FAR *__RPC_FAR *ppDORet); END_INTERFACE_PART(DocHostUIHandler) }; class CCustomOccManager :public COccManager { public: CCustomOccManager(){} COleControlSite* CreateSite(COleControlContainer* pCtrlCont) { CCustomControlSite *pSite = new CCustomControlSite(pCtrlCont); return pSite; } }; #endif
#include "StdAfx.h" #include "Custsite.h" #include "test.h" // 主要用到 theApp (261行) BEGIN_INTERFACE_MAP(CCustomControlSite, COleControlSite) INTERFACE_PART(CCustomControlSite, IID_IDocHostShowUI, DocHostShowUI) INTERFACE_PART(CCustomControlSite, IID_IDocHostUIHandler, DocHostUIHandler) END_INTERFACE_MAP() ULONG CCustomControlSite::XDocHostShowUI::AddRef() { METHOD_PROLOGUE(CCustomControlSite, DocHostShowUI); return pThis->ExternalAddRef(); } ULONG CCustomControlSite::XDocHostShowUI::Release() { METHOD_PROLOGUE(CCustomControlSite, DocHostShowUI); return pThis->ExternalRelease(); } HRESULT CCustomControlSite::XDocHostShowUI::QueryInterface(REFIID riid, void ** ppvObj) { METHOD_PROLOGUE(CCustomControlSite, DocHostShowUI); return pThis->ExternalQueryInterface( &riid, ppvObj ); } HRESULT CCustomControlSite::XDocHostShowUI::ShowHelp(HWND hwnd, LPOLESTR pszHelpFile, UINT nCommand, DWORD dwData, POINT ptMouse, IDispatch * pDispatchObjectHit) { METHOD_PROLOGUE(CCustomControlSite, DocHostShowUI); return S_OK; } HRESULT CCustomControlSite::XDocHostShowUI::ShowMessage(HWND hwnd, LPOLESTR lpstrText, LPOLESTR lpstrCaption, DWORD dwType, LPOLESTR lpstrHelpFile, DWORD dwHelpContext, LRESULT * plResult) { METHOD_PROLOGUE(CCustomControlSite, DocHostShowUI); MessageBox(hwnd, (CString)lpstrText, _T("Cpp & JavaScript"), /*dwType*/MB_ICONWARNING); return S_OK; } ULONG FAR EXPORT CCustomControlSite::XDocHostUIHandler::AddRef() { METHOD_PROLOGUE(CCustomControlSite, DocHostUIHandler) return pThis->ExternalAddRef(); } ULONG FAR EXPORT CCustomControlSite::XDocHostUIHandler::Release() { METHOD_PROLOGUE(CCustomControlSite, DocHostUIHandler) return pThis->ExternalRelease(); } HRESULT FAR EXPORT CCustomControlSite::XDocHostUIHandler::QueryInterface(REFIID riid, void **ppvObj) { METHOD_PROLOGUE(CCustomControlSite, DocHostUIHandler) HRESULT hr = (HRESULT)pThis->ExternalQueryInterface(&riid, ppvObj); return hr; } // * CImpIDocHostUIHandler::GetHostInfo // * // * Purpose: Called at initialization // * HRESULT FAR EXPORT CCustomControlSite::XDocHostUIHandler::GetHostInfo( DOCHOSTUIINFO* pInfo ) { METHOD_PROLOGUE(CCustomControlSite, DocHostUIHandler) pInfo->dwFlags = DOCHOSTUIFLAG_NO3DBORDER; pInfo->dwDoubleClick = DOCHOSTUIDBLCLK_DEFAULT; return S_OK; } // * CImpIDocHostUIHandler::ShowUI // * // * Purpose: Called when MSHTML.DLL shows its UI // * HRESULT FAR EXPORT CCustomControlSite::XDocHostUIHandler::ShowUI( DWORD dwID, IOleInPlaceActiveObject * /*pActiveObject*/, IOleCommandTarget * pCommandTarget, IOleInPlaceFrame * /*pFrame*/, IOleInPlaceUIWindow * /*pDoc*/) { METHOD_PROLOGUE(CCustomControlSite, DocHostUIHandler) // We've already got our own UI in place so just return S_OK return S_OK; } // * CImpIDocHostUIHandler::HideUI // * // * Purpose: Called when MSHTML.DLL hides its UI // * HRESULT FAR EXPORT CCustomControlSite::XDocHostUIHandler::HideUI(void) { METHOD_PROLOGUE(CCustomControlSite, DocHostUIHandler) return S_OK; } // * CImpIDocHostUIHandler::UpdateUI // * // * Purpose: Called when MSHTML.DLL updates its UI // * HRESULT FAR EXPORT CCustomControlSite::XDocHostUIHandler::UpdateUI(void) { METHOD_PROLOGUE(CCustomControlSite, DocHostUIHandler) // MFC is pretty good about updating it's UI in it's Idle loop so I don't do anything here return S_OK; } // * CImpIDocHostUIHandler::EnableModeless // * // * Purpose: Called from MSHTML.DLL's IOleInPlaceActiveObject::EnableModeless // * HRESULT FAR EXPORT CCustomControlSite::XDocHostUIHandler::EnableModeless(BOOL /*fEnable*/) { METHOD_PROLOGUE(CCustomControlSite, DocHostUIHandler) return E_NOTIMPL; } // * CImpIDocHostUIHandler::OnDocWindowActivate // * // * Purpose: Called from MSHTML.DLL's IOleInPlaceActiveObject::OnDocWindowActivate // * HRESULT FAR EXPORT CCustomControlSite::XDocHostUIHandler::OnDocWindowActivate(BOOL /*fActivate*/) { METHOD_PROLOGUE(CCustomControlSite, DocHostUIHandler) return E_NOTIMPL; } // * CImpIDocHostUIHandler::OnFrameWindowActivate // * // * Purpose: Called from MSHTML.DLL's IOleInPlaceActiveObject::OnFrameWindowActivate // * HRESULT FAR EXPORT CCustomControlSite::XDocHostUIHandler::OnFrameWindowActivate(BOOL /*fActivate*/) { METHOD_PROLOGUE(CCustomControlSite, DocHostUIHandler) return E_NOTIMPL; } // * CImpIDocHostUIHandler::ResizeBorder // * // * Purpose: Called from MSHTML.DLL's IOleInPlaceActiveObject::ResizeBorder // * HRESULT FAR EXPORT CCustomControlSite::XDocHostUIHandler::ResizeBorder( LPCRECT /*prcBorder*/, IOleInPlaceUIWindow* /*pUIWindow*/, BOOL /*fRameWindow*/) { METHOD_PROLOGUE(CCustomControlSite, DocHostUIHandler) return E_NOTIMPL; } // * CImpIDocHostUIHandler::ShowContextMenu // * // * Purpose: Called when MSHTML.DLL would normally display its context menu // * HRESULT FAR EXPORT CCustomControlSite::XDocHostUIHandler::ShowContextMenu( DWORD /*dwID*/, POINT* pptPosition, IUnknown* /*pCommandTarget*/, IDispatch* /*pDispatchObjectHit*/) { METHOD_PROLOGUE(CCustomControlSite, DocHostUIHandler) return E_NOTIMPL; //CMenu menu; //menu.LoadMenu(IDR_CUSTOM_POPUP); //CMenu* pSubMenu = menu.GetSubMenu(0); ////Because we passed in theApp.m_pMainWnd all of our ////WM_COMMAND handlers for the menu items must be handled ////in CCustomBrowserApp. If you want this to be your dialog ////you will have to grab a pointer to your dialog class and ////pass the hWnd of it into the last parameter in this call //pSubMenu->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON, pptPosition->x, pptPosition->y, theApp.m_pMainWnd); return S_OK; // We've shown our own context menu. MSHTML.DLL will no longer try to show its own. } // * CImpIDocHostUIHandler::TranslateAccelerator // * // * Purpose: Called from MSHTML.DLL's TranslateAccelerator routines // * HRESULT FAR EXPORT CCustomControlSite::XDocHostUIHandler::TranslateAccelerator(LPMSG lpMsg, /* [in] */ const GUID __RPC_FAR *pguidCmdGroup, /* [in] */ DWORD nCmdID) { METHOD_PROLOGUE(CCustomControlSite, DocHostUIHandler) //disable F5 if(lpMsg->message == WM_KEYDOWN && GetAsyncKeyState(VK_F5) < 0) return S_OK; if(GetKeyState(VK_CONTROL) & 0x8000) { //disable ctrl + O if(lpMsg->message == WM_KEYDOWN && GetAsyncKeyState(0x4F) < 0) return S_OK; //disable ctrl + p if(lpMsg->message == WM_KEYDOWN && GetAsyncKeyState(0x50) < 0) return S_OK; //disable ctrl + N if(lpMsg->message == WM_KEYDOWN && GetAsyncKeyState(0x4E) < 0) return S_OK; } //disable back space if(lpMsg->wParam == VK_BACK) return S_OK; return S_FALSE; } // * CImpIDocHostUIHandler::GetOptionKeyPath // * // * Purpose: Called by MSHTML.DLL to find where the host wishes to store // * its options in the registry // * HRESULT FAR EXPORT CCustomControlSite::XDocHostUIHandler::GetOptionKeyPath(BSTR* pbstrKey, DWORD) { METHOD_PROLOGUE(CCustomControlSite, DocHostUIHandler) return E_NOTIMPL; } STDMETHODIMP CCustomControlSite::XDocHostUIHandler::GetDropTarget( /* [in] */ IDropTarget __RPC_FAR *pDropTarget, /* [out] */ IDropTarget __RPC_FAR *__RPC_FAR *ppDropTarget) { METHOD_PROLOGUE(CCustomControlSite, DocHostUIHandler) return E_NOTIMPL; } STDMETHODIMP CCustomControlSite::XDocHostUIHandler::GetExternal( /* [out] */ IDispatch __RPC_FAR *__RPC_FAR *ppDispatch) { // return the IDispatch we have for extending the object Model IDispatch* pDisp = (IDispatch*)theApp.m_pDispOM; //这里 pDisp->AddRef(); *ppDispatch = pDisp; return S_OK; } STDMETHODIMP CCustomControlSite::XDocHostUIHandler::TranslateUrl( /* [in] */ DWORD dwTranslate, /* [in] */ OLECHAR __RPC_FAR *pchURLIn, /* [out] */ OLECHAR __RPC_FAR *__RPC_FAR *ppchURLOut) { METHOD_PROLOGUE(CCustomControlSite, DocHostUIHandler) return E_NOTIMPL; } STDMETHODIMP CCustomControlSite::XDocHostUIHandler::FilterDataObject( /* [in] */ IDataObject __RPC_FAR *pDO, /* [out] */ IDataObject __RPC_FAR *__RPC_FAR *ppDORet) { METHOD_PROLOGUE(CCustomControlSite, DocHostUIHandler) return E_NOTIMPL; }
三》修改App
1.增加头文件 #include "Custsite.h"
2.在 InitInstance()函数中 增加2处,修改一处
新增的两处
CCustomOccManager *pMgr = new CCustomOccManager; m_pDispOM = new CImpIDispatch;
修改的一处
把AfxEnableControlContainer();改为 AfxEnableControlContainer(pMgr);
四》htm文件为:
<!DOCTYPE html> <html> <head> <meta charset=gb2312> <title></title> <script type="text/javascript"> function CallCpp(){ //JavaScriptCallCpp 是C++中函数, //与idispimp.cpp文件中javaScriptName进行对应并且与DISPID_CallCppFromJs进行绑定 window.external.JavaScriptCallCpp('This is a test for call C++ in JavaScript'); } </script> </head> <body> <button onclick="CallCpp()">JavaScript访问C++代码</button> </body> </html>
五: 整个完成了
来源:https://www.cnblogs.com/dengpeng1004/p/5236717.html