javascript 调用C++函数

柔情痞子 提交于 2020-02-26 12:41:56

分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>

五: 整个完成了

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!