IE的Trident引擎下实现C++和Javascript相互调用

我们知道实现C++和Javascript通讯有下表5种接口:

引擎 编写语言 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函数,只要弄清楚他的参数正确的传递就好了。

除此之外该接口还提供有一种简易的方法。

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

另外还有Invoke0、Invoke2、InvokeN、GetProperty、PutProperty、GetIDOfName、GetPropertyByName。这些函数的实现都在\VC\atlmfc\include\atlcomcli.h头文件中有声明和实现。

//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,没了它你就是在蒙着眼睛摸象加自欺欺人。

posted @ 2013-09-09 10:06 重庆Debug 阅读(...) 评论(...) 编辑 收藏