IE的Trident引擎下實現C++和Javascript相互調用

咱們知道實現C++和Javascript通信有下表5種接口:ide

引擎 編寫語言 API接口 C、C++與JavaScript交互(變量、函數、類) vc2005編譯靜態庫的大小 示例EXE的大小 執行、解析JavaScript的速度
Google V8 C++ C++ 能夠 23.1M 1.1M 最快
Firefox3.5之前 SpiderMonkey C C 能夠 1.3M 500K
Firefox高版本SpiderMonkey C++ C 能夠 15.3M 1.7M 通常
Webkit  JavaScriptCore C++ C 能夠 26.2M 1.4M 通常
IE 未知 COM 能夠 未知 100K(沒有連接庫) 通常

IE的Trident引擎是非開源的,微軟JavaScript引擎也是非開源的。微軟對外提供了一組COM接口。使用這組COM接口,可以將微軟的JavaScript、VBScript嵌入到C、C++、VB、C#等宿主語言中。函數

 說到底其實也沒什麼好說的,先定義一個 CComPtr<IDispatch> 對象,而後調用其對象的Invoke函數,只要弄清楚他的參數正確的傳遞就行了。this

除此以外該接口還提供有一種簡易的方法。spa

CComPtr<IDispatch> Obj;
CComVariant var(true);
if( FAILED(Obj.Invoke1(L"ReflowDocument", &var)) )
   MessageBox(_T("Invoke ReflowDocument failed."));

另外還有Invoke0、Invoke二、InvokeN、GetProperty、PutProperty、GetIDOfName、GetPropertyByName。這些函數的實現都在\VC\atlmfc\include\atlcomcli.h頭文件中有聲明和實現。code

//specialization for IDispatch
template <>
class CComPtr<IDispatch> : 
    public CComPtrBase<IDispatch>
{
public:
    CComPtr() throw()
    {
    }
    CComPtr(_Inout_opt_ IDispatch* lp) throw() :
        CComPtrBase<IDispatch>(lp)
    {
    }
    CComPtr(_Inout_ const CComPtr<IDispatch>& lp) throw() :
        CComPtrBase<IDispatch>(lp.p)
    {
    }        
    IDispatch* operator=(_Inout_opt_ IDispatch* lp) throw()
    {
        if(*this!=lp)
        {
            return static_cast<IDispatch*>(AtlComPtrAssign((IUnknown**)&p, lp));
        }
        return *this;
    }
    IDispatch* operator=(_Inout_ const CComPtr<IDispatch>& lp) throw()
    {
        if(*this!=lp)
        {
            return static_cast<IDispatch*>(AtlComPtrAssign((IUnknown**)&p, lp.p));
        }
        return *this;
    }    
    CComPtr(_Inout_ CComPtr<IDispatch>&& lp) throw() :    
        CComPtrBase<IDispatch>()
    {        
        p = lp.p;        
        lp.p = NULL;
    }
    IDispatch* operator=(_Inout_ CComPtr<IDispatch>&& lp) throw()
    {        
        if (*this != lp)
        {
            if (p != NULL)            
                p->Release();
            
            p = lp.p;
            lp.p = NULL;
        }        
        return *this;
    }    
// IDispatch specific stuff
    _Check_return_ HRESULT GetPropertyByName(
        _In_z_ LPCOLESTR lpsz, 
        _Out_ VARIANT* pVar) throw()
    {
        ATLASSERT(p);
        ATLASSERT(pVar);
        DISPID dwDispID;
        HRESULT hr = GetIDOfName(lpsz, &dwDispID);
        if (SUCCEEDED(hr))
            hr = GetProperty(dwDispID, pVar);
        return hr;
    }
    _Check_return_ HRESULT GetProperty(
        _In_ DISPID dwDispID, 
        _Out_ VARIANT* pVar) throw()
    {
        return GetProperty(p, dwDispID, pVar);
    }
    _Check_return_ HRESULT PutPropertyByName(
        _In_z_ LPCOLESTR lpsz, 
        _In_ VARIANT* pVar) throw()
    {
        ATLASSERT(p);
        ATLASSERT(pVar);
        DISPID dwDispID;
        HRESULT hr = GetIDOfName(lpsz, &dwDispID);
        if (SUCCEEDED(hr))
            hr = PutProperty(dwDispID, pVar);
        return hr;
    }
    _Check_return_ HRESULT PutProperty(
        _In_ DISPID dwDispID, 
        _In_ VARIANT* pVar) throw()
    {
        return PutProperty(p, dwDispID, pVar);
    }
    _Check_return_ HRESULT GetIDOfName(
        _In_z_ LPCOLESTR lpsz, 
        _Out_ DISPID* pdispid) throw()
    {
        return p->GetIDsOfNames(IID_NULL, const_cast<LPOLESTR*>(&lpsz), 1, LOCALE_USER_DEFAULT, pdispid);
    }
    // Invoke a method by DISPID with no parameters
    _Check_return_ HRESULT Invoke0(
        _In_ DISPID dispid, 
        _Out_opt_ VARIANT* pvarRet = NULL) throw()
    {
        DISPPARAMS dispparams = { NULL, NULL, 0, 0};
        return p->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, pvarRet, NULL, NULL);
    }
    // Invoke a method by name with no parameters
    _Check_return_ HRESULT Invoke0(
        _In_z_ LPCOLESTR lpszName, 
        _Out_opt_ VARIANT* pvarRet = NULL) throw()
    {
        HRESULT hr;
        DISPID dispid;
        hr = GetIDOfName(lpszName, &dispid);
        if (SUCCEEDED(hr))
            hr = Invoke0(dispid, pvarRet);
        return hr;
    }
    // Invoke a method by DISPID with a single parameter
    _Check_return_ HRESULT Invoke1(
        _In_ DISPID dispid, 
        _In_ VARIANT* pvarParam1, 
        _Out_opt_ VARIANT* pvarRet = NULL) throw()
    {
        DISPPARAMS dispparams = { pvarParam1, NULL, 1, 0};
        return p->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, pvarRet, NULL, NULL);
    }
    // Invoke a method by name with a single parameter
    _Check_return_ HRESULT Invoke1(
        _In_z_ LPCOLESTR lpszName, 
        _In_ VARIANT* pvarParam1, 
        _Out_opt_ VARIANT* pvarRet = NULL) throw()
    {         
        DISPID dispid;
        HRESULT hr = GetIDOfName(lpszName, &dispid);
        if (SUCCEEDED(hr))
            hr = Invoke1(dispid, pvarParam1, pvarRet);
        return hr;
    }
    // Invoke a method by DISPID with two parameters
    _Check_return_ HRESULT Invoke2(
        _In_ DISPID dispid, 
        _In_ VARIANT* pvarParam1, 
        _In_ VARIANT* pvarParam2, 
        _Out_opt_ VARIANT* pvarRet = NULL) throw();
    // Invoke a method by name with two parameters
    _Check_return_ HRESULT Invoke2(
        _In_z_ LPCOLESTR lpszName, 
        _In_ VARIANT* pvarParam1, 
        _In_ VARIANT* pvarParam2, 
        _Out_opt_ VARIANT* pvarRet = NULL) throw()
    {
        DISPID dispid;
        HRESULT hr = GetIDOfName(lpszName, &dispid);
        if (SUCCEEDED(hr))
            hr = Invoke2(dispid, pvarParam1, pvarParam2, pvarRet);
        return hr;
    }
    // Invoke a method by DISPID with N parameters
    _Check_return_ HRESULT InvokeN(
        _In_ DISPID dispid, 
        _In_ VARIANT* pvarParams, 
        _In_ int nParams, 
        _Out_opt_ VARIANT* pvarRet = NULL) throw()
    {
        DISPPARAMS dispparams = { pvarParams, NULL, nParams, 0};
        return p->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, pvarRet, NULL, NULL);
    }
    // Invoke a method by name with Nparameters
    _Check_return_ HRESULT InvokeN(
        _In_z_ LPCOLESTR lpszName, 
        _In_ VARIANT* pvarParams, 
        _In_ int nParams, 
        _Out_opt_ VARIANT* pvarRet = NULL) throw()
    {
        HRESULT hr;
        DISPID dispid;
        hr = GetIDOfName(lpszName, &dispid);
        if (SUCCEEDED(hr))
            hr = InvokeN(dispid, pvarParams, nParams, pvarRet);
        return hr;
    }
    _Check_return_ static HRESULT PutProperty(
        _In_ IDispatch* p, 
        _In_ DISPID dwDispID, 
        _In_ VARIANT* pVar) throw()
    {
        ATLASSERT(p);
        ATLASSERT(pVar != NULL);
        if (pVar == NULL)
            return E_POINTER;
        
        if(p == NULL)
            return E_INVALIDARG;
        
        ATLTRACE(atlTraceCOM, 2, _T("CPropertyHelper::PutProperty\n"));
        DISPPARAMS dispparams = {NULL, NULL, 1, 1};
        dispparams.rgvarg = pVar;
        DISPID dispidPut = DISPID_PROPERTYPUT;
        dispparams.rgdispidNamedArgs = &dispidPut;

        if (pVar->vt == VT_UNKNOWN || pVar->vt == VT_DISPATCH || 
            (pVar->vt & VT_ARRAY) || (pVar->vt & VT_BYREF))
        {
            HRESULT hr = p->Invoke(dwDispID, IID_NULL,
                LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUTREF,
                &dispparams, NULL, NULL, NULL);
            if (SUCCEEDED(hr))
                return hr;
        }
        return p->Invoke(dwDispID, IID_NULL,
                LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT,
                &dispparams, NULL, NULL, NULL);
    }
    _Check_return_ static HRESULT GetProperty(
        _In_ IDispatch* p, 
        _In_ DISPID dwDispID, 
        _Out_ VARIANT* pVar) throw()
    {
        ATLASSERT(p);
        ATLASSERT(pVar != NULL);
        if (pVar == NULL)
            return E_POINTER;
        
        if(p == NULL)
            return E_INVALIDARG;
            
        ATLTRACE(atlTraceCOM, 2, _T("CPropertyHelper::GetProperty\n"));
        DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
        return p->Invoke(dwDispID, IID_NULL,
                LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
                &dispparamsNoArgs, pVar, NULL, NULL);
    }
};
atlcomcli.h部分代碼

上面這些其實也都是調用了Invoke函數,固然你若是不想用它幫你封裝過的這些函數的話,你能夠自行調用比上面這些更原始的Invoke,或者從新封裝一下它。對象

總而言之,當你作這就事的時候必定要不停的查閱MSDN,沒了它你就是在蒙着眼睛摸象加自欺欺人。blog

相關文章
相關標籤/搜索