如何調用IDispatch接口的方法和屬性

我們知道在C/C++語言中有函數,與函數對應的有函數指針。我們可以把一個函數指針傳給一個過程,從而實現回調。

那麼在腳本語言(如JavaScript)中,可以用"function"來定義一個函數,但與之相對應的卻沒有函數指針的概念。那麼如何將這個函數傳給某個過程,來實現回調的功能呢?事實上,在JavaScript中,常常將函數直接傳遞給一個組件的方法,實現回調。那麼,反過來我們問一下,JavaScript將這個函數傳入組件,到底是一個什麼樣的參數類型呢?

傳入的參數類型即可以是IDispatch*,也可以是VARIANT(包裝的仍是一個IDispatch*值)。這個函數,本質上是一個實現了IDispatch接口的對象,通過訪問IDispatch接口的第一個方法,也就實現了對這個函數的回調調用。

下面的函數CCuteTools::AutoWrap以可變參數的形式,實現了對IDispatch接口中方法和屬性的調用。
在寫出源代碼之前,我們先舉一個調用它的例子。
CComPtr<IDispatch> pDispCallback; //需要回調的IDispatch接口 
CComVariant vParam1="test";    //準備接收的參數1
CComVariant vParam2=(long)1234;     //準備接收的參數2

CCuteTools::AutoWrap(DISPATCH_METHOD,NULL,pDispCallback,NULL,2,vParam2,vParam1);

//////////////////////////////////////////////////////////

//採用的是可變參數的形式
HRESULT CCuteTools::AutoWrap(int autoType, VARIANT *pvResult, IDispatch *pDisp,
    LPOLESTR ptName, int cArgs...)
{
 // Begin variable-argument list...
 va_list marker;
 va_start(marker, cArgs);

 HRESULT hr=AutoWrap(autoType,pvResult,pDisp,ptName,cArgs,marker);
 
 // End variable-argument section...
 va_end(marker);
 
 return hr;
}

//
HRESULT CCuteTools::AutoWrap(int autoType, VARIANT *pvResult, IDispatch *pDisp,
    LPOLESTR ptName, int cArgs,va_list& marker)
{
 //
 if(!pDisp) {
  return E_FAIL;
 }

 // Variables used...
 DISPPARAMS dp = { NULL, NULL, 0, 0 };
 DISPID dispidNamed = DISPID_PROPERTYPUT;
 DISPID dispID;
 HRESULT hr;

 if(ptName==NULL)
 {
  dispID=0;
 }
 else
 {
 
  // Get DISPID for name passed...
  hr = pDisp->GetIDsOfNames(IID_NULL, &ptName, 1, LOCALE_USER_DEFAULT,
         &dispID);
  if(FAILED(hr)) {
    return hr;
  }
 }

 // Allocate memory for arguments...
 VARIANT *pArgs = new VARIANT[cArgs+1];

 // Extract arguments...
 for(int i=0; i<cArgs; i++) {
   pArgs[i] = va_arg(marker, VARIANT);
 }
 
 // Build DISPPARAMS
 dp.cArgs = cArgs;
 dp.rgvarg = pArgs;
 
 // Handle special-case for property-puts!
 if(autoType & DISPATCH_PROPERTYPUT) {
   dp.cNamedArgs = 1;
   dp.rgdispidNamedArgs = &dispidNamed;
 }
 
 // Make the call!
 CComVariant vResult;
 hr = pDisp->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, autoType,
      &dp, &vResult, NULL, NULL);
 if(FAILED(hr)) {
  delete [] pArgs;
   return hr;
 }
 
 if(pvResult!=NULL)
 {
  vResult.Detach(pvResult);
 }
 
 delete [] pArgs;
 
 return hr;
}

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章