• c++与js脚本交互,C++调用JS函数JS调用C++函数


    一、javascript调用c++,方法有两种
     
    方案1:
     
    1.html编写
     
    <html>
    <head>
    </head>
    <body>
    <h1>
    TEST
    </h1>
    <input type='button'name="xx3" value=调用c++函数 onclick="window.navigate('app:command&arg1=1&arg2=2')">
    </body>
    <script language="javascript">
    function TestFunc()
    {
    alert("TestFunc");
    }
    </script>
    </html>
     
    2.C++的CHtmlView类重写OnBeforeNavigate2函数
     
    void CAddGoogleMap_CHtmlView::OnBeforeNavigate2(LPCTSTR lpszURL, DWORD nFlags, LPCTSTR lpszTargetFrameName, CByteArray& baPostedData, LPCTSTR lpszHeaders, BOOL* pbCancel)
    {
    // TODO: Add your specialized code here and/or call the base class
    CString strUrl = lpszURL;
    if(strUrl.Left(4) == _T("app:"))
    {
    // cancel the common url navigate and call your c++ code here
    *pbCancel = TRUE;
    MessageBox("调用了C++函数", "来自对话框消息");
    // call other c++ function here or parse the argument in the strUrl
     
    }
     
    CHtmlView::OnBeforeNavigate2(lpszURL, nFlags, lpszTargetFrameName, baPostedData, lpszHeaders, pbCancel);
    }
     
    方案2:
     
    1.编写html
     
    <html>
     
    <head>
     
    </head>
     
    <body>
     
    <script language="javascript">
    function CallCpp()
     
    {
     
    alert('start to call cpp here');
     
    window.external.JavaScriptCallCpp('This is a test for call C++ in JavaScript');
     
    }
     
    </script>
     
    <input type='button'name="xx3" value=调用c++函数 onclick="CallCpp()" />
     
    </body>
     
    <html>
     
    2.C++代码
     
    CString javaScriptName = _T("JavaScriptCallCpp");
     
    #define DISPID_CallCppFromJs 1
     
    // 实现IDispatch 接口
     
    // .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);
    };
    // .cpp
    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 = rgszNames[i];
    if (cszName == javaScriptName)
    {
    rgDispId[i] = DISPID_CallCppFromJs;
    }
    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)
    {
    CXXXDlg* pDlg = (CCppCallJsDlg*) AfxGetMainWnd();
     
    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= pDispParams->rgvarg[0].bstrVal;
    pDlg->CallByScript(cszArg1);
    }
    }
    return S_OK;
    }
     
    // 改写COleControlSit
    // .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;
    }
    };
    // .cpp
    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
    // .h
    class CImpIDispatch;
    class CXXXApp : public CWinApp
    {
     
    CImpIDispatch *m_pDispOM;
     
    }
    // .cpp
    BOOL CXXXApp::InitInstance()
    {
     
    CWinApp::InitInstance();
    CCustomOccManager *pMgr = new CCustomOccManager;
    // Create an IDispatch class for extending the Dynamic HTML Object Model
    m_pDispOM = new CImpIDispatch;
    // Set our control containment up but using our control container
    // management class instead of MFC's default
    AfxEnableControlContainer(pMgr);
     
    }
     
    二、C++调用javascript函数
     
    1.编写html,如javascript调用c++的方案1的html
     
    2.c++代码
     
    void CAddGoogleMap_CHtmlView::OnTestSwap()
    {
    // call js function
    CComPtr<IDispatch> spScript;
    CComPtr<IHTMLDocument2> spDoc;
    GetHtmlDocument()->QueryInterface(IID_IHTMLDocument2,(void**)&spDoc);//取得网页文档接口指针
    spDoc->get_Script(&spScript);//取得脚本com接口
     
    CComBSTR bstrMember("TestFunc");//javaScript函数名称
    DISPID dispid = NULL;
    HRESULT hr = spScript->GetIDsOfNames(IID_NULL,&bstrMember,1,
    LOCALE_SYSTEM_DEFAULT,&dispid);//取得函数名对应 DISPID
    DISPPARAMS dispparams;//根据实际函数情况填写函数参数,这里示例TestFunc函数没有参数据
    memset(&dispparams, 0, sizeof dispparams);
    dispparams.cArgs = 0;//参数个数
    dispparams.rgvarg = new VARIANT[dispparams.cArgs];
    dispparams.cNamedArgs = 0;
     
    EXCEPINFO excepInfo;
    memset(&excepInfo, 0, sizeof excepInfo);
    CComVariant vaResult;
    UINT nArgErr = (UINT)-1; // initialize to invalid arg
    //执行JavaScript函数
    hr = spScript->Invoke(dispid,IID_NULL,0,
    DISPATCH_METHOD,&dispparams,&vaResult,&excepInfo,&nArgErr);
     
    }
     
  • 相关阅读:
    查找表类算法//字母异位词分组
    查找表类算法//四数相加 II
    查找表类算法//四数相加 II
    第六章 类文件结构
    第六章 类文件结构
    查找表的算法//四数之和
    查找表的算法//四数之和
    第五章 调优案例分析与实战
    第五章 调优案例分析与实战
    C++_基础4-分支语句和逻辑运算符
  • 原文地址:https://www.cnblogs.com/blogpro/p/11426718.html
Copyright © 2020-2023  润新知