The Invoke Function

Once you have set up the argument arrays with the argument-constructor functions, you can use the Invoke function to call a method or to set or get a property.

This function accepts a pointer to the object; the name of the method or property; a pointer to a location for the return value; a flag indicating whether you are calling a method, setting a property, or getting the value of a property; and a flag indicating whether the Invoke function should clear the arguments when it returns.

The Invoke function returns True if the call succeeded and False if an error occurred. A message box will be displayed explaining the error unless the DISP_NOSHOWEXCEPTIONS flag is specified. Errors result from unrecognized method or property names, bad argument names, invalid data types, or run-time exceptions defined by the recipient of the IDispatch call.

After the IDispatch call, the Invoke function calls the ClearAllArgs function to reset the argument list if the DISP_FREEARGS flag is specified. If this flag is not specified, it is up to the caller to call ClearAllArgs.

The return value is placed in the pvargReturn variable, which is allocated by the caller. If no return value is required, this argument should be NULL. It is up to the caller to free the return value (use the ReleaseVariant function).

This function calls IDispatch::GetIDsOfNames every time it is called. This is not very efficient if the same method or property is invoked multiple times, because the DISPID value for a particular method or property will remain the same during the lifetime of an IDispatch object. Modifications could be made to this code to cache DISPID values. If the target application is always the same, you could store the DISPID values at compile time (an application will return the same DISPID values in different sessions). Eliminating the extra cross-process GetIDsOfNames calls can result in a significant time savings.

BOOL Invoke(IDispatch *pdisp, LPOLESTR szMember, 
            VARIANTARG * pvargReturn,
            WORD wInvokeAction, WORD wFlags)
{

    HRESULT hr;
    DISPPARAMS dispparams;
    unsigned int uiArgErr;
    EXCEPINFO excep;
    
    // Get the IDs for the member and its arguments.  
    // GetIDsOfNames expects the member name as the
    // first name, followed by argument names (if any).
    g_alpszArgNames[0] = szMember;
    hr = (*(pdisp->lpVtbl->GetIDsOfNames))(pdisp, &IID_NULL, 
        g_alpszArgNames,    1 + g_iNamedArgCount, LOCALE_SYSTEM_DEFAULT, 
        g_aDispIds);
    if (FAILED(hr)) 
    {
        if (!(wFlags & DISP_NOSHOWEXCEPTIONS))
            ShowException(szMember, hr, NULL, 0);
        return FALSE;
    }

    if (pvargReturn != NULL)
        ClearVariant(pvargReturn);

    // if doing a property put(ref), 
    // we need to adjust the first argument to have a
    // named arg of DISPID_PROPERTYPUT.
    if (wInvokeAction & (DISPATCH_PROPERTYPUT | 
        DISPATCH_PROPERTYPUTREF)) 
    {
        g_iNamedArgCount = 1;
        g_aDispIds[1] = DISPID_PROPERTYPUT;
        pvargReturn = NULL;
    }

    dispparams.rgdispidNamedArgs = g_aDispIds + 1;
    dispparams.rgvarg = g_aVargs;
    dispparams.cArgs = g_iArgCount;
    dispparams.cNamedArgs = g_iNamedArgCount;

    excep.pfnDeferredFillIn = NULL;

    hr = (*(pdisp->lpVtbl->Invoke))(pdisp, g_aDispIds[0], &IID_NULL, 
        LOCALE_SYSTEM_DEFAULT, wInvokeAction, &dispparams, pvargReturn, 
        &excep, &uiArgErr);

    if (wFlags & DISP_FREEARGS)
        ClearAllArgs();

    if (FAILED(hr)) 

    {
        // display the exception information if appropriate:
        if (!(wFlags & DISP_NOSHOWEXCEPTIONS))
            ShowException(szMember, hr, &excep, uiArgErr);

        // free exception structure information
        SysFreeString(excep.bstrSource);
        SysFreeString(excep.bstrDescription);
        SysFreeString(excep.bstrHelpFile);
    
        return FALSE;
    }
        
    return TRUE;
}