示例#1
0
HRESULT
ComObject::invoke (const Method &method,
                   bool isProperty,
                   REFIID /*riid*/,
                   LCID /*lcid*/,
                   WORD wFlags,
                   DISPPARAMS *pDispParams,
                   VARIANT *pReturnValue,
                   EXCEPINFO *pExcepInfo,
                   UINT *pArgErr)
{

    HRESULT hresult;

    try {
        // Construct Tcl script to invoke operation on the servant.
        TclObject script(m_servant);

        // Get the method or property to invoke on the servant.
        std::string operation;
        if ((wFlags & DISPATCH_PROPERTYGET) != 0 && isProperty) {
            operation = getPrefix + method.name();

        } else if (wFlags & (DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF)) {
            operation = setPrefix + method.name();

        } else if (wFlags & DISPATCH_METHOD) {
            operation = method.name();

        } else {
            return DISP_E_MEMBERNOTFOUND;
        }

        script.lappend(
            Tcl_NewStringObj(const_cast<char *>(operation.c_str()), -1));

        // Set the argument error pointer in case we need to use it.
        UINT argErr;
        if (pArgErr == 0) {
            pArgErr = &argErr;
        }

        // Convert arguments to Tcl values.
        // TODO: Should handle named arguments differently than positional
        // arguments.
        const Method::Parameters &parameters = method.parameters();

        int argIndex = pDispParams->cArgs - 1;
        Method::Parameters::const_iterator pParam;
        for (pParam = parameters.begin(); pParam != parameters.end();
         ++pParam, --argIndex) {
            // Append argument value.
            VARIANT *pArg = &(pDispParams->rgvarg[argIndex]);
            try {
                script.lappend(getArgument(pArg, *pParam));
            }
            catch (_com_error &) {
                *pArgErr = argIndex;
                throw;
            }
        }
        
        if (wFlags & (DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF)) {
            VARIANT *pArg = &(pDispParams->rgvarg[argIndex]);
            try {
                TclObject value(pArg, method.type(), m_interp);
                script.lappend(value);
            }
            catch (_com_error &) {
                *pArgErr = argIndex;
                throw;
            }
        }

        // Execute the Tcl script.
        TclObject result;
        int completionCode = eval(script, &result);
        if (completionCode == TCL_OK) {
            hresult = S_OK;
        } else {
            if (m_isSink) {
                Tcl_BackgroundError(m_interp);
            }

            hresult = hresultFromErrorCode();
            if (FAILED(hresult)) {
                fillExcepInfo(
                    pExcepInfo,
                    hresult,
                    m_servant.c_str(),
                    result.c_str());
                hresult = DISP_E_EXCEPTION;
            }
        }

        // Copy values to out arguments.
        argIndex = pDispParams->cArgs - 1;
        for (pParam = parameters.begin(); pParam != parameters.end();
         ++pParam, --argIndex) {
            VARIANT *pArg = &(pDispParams->rgvarg[argIndex]);
            if ((pParam->flags() & PARAMFLAG_FOUT) && (V_VT(pArg) & VT_BYREF)) {
                // Get name of Tcl variable that holds out value.
                TclObject varName = getOutVariableName(*pParam);

                // Copy variable value to out argument.
                TclObject value;
                if (getVariable(varName, value) == TCL_OK) {
                    putOutVariant(m_interp, pArg, value, pParam->type());
                }
            }
        }

        // Convert return value.
        if (pReturnValue != 0 && method.type().vartype() != VT_VOID) {
            // Must increment reference count of interface pointers returned
            // from methods.
            result.toVariant(pReturnValue, method.type(), m_interp, true);
        }
    }
    catch (_com_error &e) {
        fillExcepInfo(pExcepInfo, e.Error(), m_servant.c_str(), 0);
        hresult = DISP_E_EXCEPTION;
    }
    return hresult;
}
示例#2
0
static void
putOutVariant (Tcl_Interp *interp,
               VARIANT *pDest,
               TclObject &tclObject,
               const Type &type)
{
    switch (type.vartype()) {
    case VT_BOOL:
        *V_BOOLREF(pDest) = tclObject.getBool() ? VARIANT_TRUE : VARIANT_FALSE;
        break;

    case VT_R4:
        *V_R4REF(pDest) = static_cast<float>(tclObject.getDouble());
        break;

    case VT_R8:
        *V_R8REF(pDest) = tclObject.getDouble();
        break;

    case VT_DISPATCH:
    case VT_UNKNOWN:
    case VT_USERDEFINED:
        {
            IUnknown *pUnknown;

            Tcl_Obj *pObj = tclObject;
            if (pObj->typePtr == &Extension::unknownPointerType) {
                pUnknown =
                    static_cast<IUnknown *>(pObj->internalRep.otherValuePtr);
            } else {
                Reference *pRef = Extension::referenceHandles.find(
                    interp, tclObject);
                pUnknown = (pRef == 0) ? 0 : pRef->unknown();
            }

            *V_UNKNOWNREF(pDest) = pUnknown;

            // The COM rules say we must increment the reference count of
            // interface pointers returned from methods.
            if (pUnknown != 0) {
                pUnknown->AddRef();
            }
        }
        break;

    case VT_BSTR:
        *V_BSTRREF(pDest) = tclObject.getBSTR();
        break;

    case VT_VARIANT:
        {
            // Must increment reference count of interface pointers returned
            // from methods.
            tclObject.toVariant(
                V_VARIANTREF(pDest), Type::variant(), interp, true);
        }
        break;

    case VT_SAFEARRAY:
        if (*V_ARRAYREF(pDest) != 0) {
            SafeArrayDestroy(*V_ARRAYREF(pDest));
        }
        *V_ARRAYREF(pDest) =
            tclObject.getSafeArray(type.elementType(), interp);
        break;

    default:
        *V_I4REF(pDest) = tclObject.getLong();
    }
}