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); } };
上面这些其实也都是调用了Invoke函数,当然你如果不想用它帮你封装过的这些函数的话,你可以自行调用比上面这些更原始的Invoke,或者重新封装一下它。
总而言之,当你做这就事的时候一定要不停的查阅MSDN,没了它你就是在蒙着眼睛摸象加自欺欺人。