Question

I'm using Invoke for late binding on a legacy COM objects that supports IDispatch. This seems necessary as .NET's Type.GetMethod Type.InvokeMember do not seem to work on these objects.

The following code works fine for getting a property from an object, the caller passes in the property name as a string for getting the property value with late binding. The class takes an object in its constructor and sets up this.idisp (and this.lcid) as an interface pointer to the object (Critiques welcome!)

public object InvokeGet(string propertyName)
{
    int id = GetDispID(propertyName);
    IntPtr[] pArgErr = default(IntPtr[]);
    object pVarResult;
    System.Runtime.InteropServices.ComTypes.DISPPARAMS pDispParams = default(System.Runtime.InteropServices.ComTypes.DISPPARAMS);
    System.Runtime.InteropServices.ComTypes.EXCEPINFO pExcepInfo = default(System.Runtime.InteropServices.ComTypes.EXCEPINFO);

    Guid guid = new Guid();
    int result = this.idisp.Invoke(id, ref guid, (uint)this.lcid,
                 (ushort)System.Runtime.InteropServices.ComTypes.INVOKEKIND.INVOKE_PROPERTYGET,
                 ref pDispParams, out pVarResult, ref pExcepInfo, pArgErr);

    if (result != 0)
    {
        throw new ArgumentException(string.Format("Error invoking property: {0}.  COM error code is {1}", propertyName, result));
    }

    return pVarResult;
}

I'm now trying to write the setter equivalent, i.e.

public void InvokeSet(string propertyName, object newValue)

however I am not sure how to package up the Dispatch paramaters with C#.

i.e. how to I set up the structure:

System.Runtime.InteropServices.ComTypes.DISPPARAMS 

I understand I need to create an unmanaged variant from the managed object to marshal. Any suggestions how to do this?

Was it helpful?

Solution

Very late to the party, I know, but I found an answer for you.

// Create the DISPPARAMS struct
var pDispParams= default(System.Runtime.InteropServices.ComTypes.DISPPARAMS);
// Set the number of unnamed parameters
pDispParams.cArgs = 1;

// Marshal a value to a variant
int value = 10;
IntPtr pVariant = Marshal.AllocCoTaskMem(16); // Default VARIANT size
Marshal.GetNativeVariantForObject(value, pVariant);

// Set the unnamed parameter arguments
pDispParams.rgvarg = pVariant;

// Call the IDispatch.Invoke
int result = this.idisp.Invoke(id, ref guid, (uint)this.lcid, 
    (ushort)System.Runtime.InteropServices.ComTypes.INVOKEKIND.INVOKE_PROPERTYGET,
    ref pDispParams, out pVarResult, ref pExcepInfo, pArgErr);

I had trouble figuring out how to marshal the variant in C#. I found this article which essentially answered all of my outstanding questions, and yours, too.

Hopefully this still helps someone.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top