Question

I am using the ITypeInfo interface to obtain information about COM objects and their members (in order to build some kind of reflection API). Reading types and members (and their parameters) works fine, but I don´t know how to access a parameter´s default value. This is what I have...

...

PARAMDESC paramDesc = elemDesc.desc.paramdesc;

object defaultValue = null;
PARAMFLAG paramFlags = paramDesc.wParamFlags;
bool hasDefaultValue = (paramFlags & PARAMFLAG.PARAMFLAG_FHASDEFAULT) == PARAMFLAG.PARAMFLAG_FHASDEFAULT;
if (hasDefaultValue && paramDesc.lpVarValue != IntPtr.Zero)
{
    defaultValue = null; // TODO: get value from paramDesc.lpVarValue
}

...

I check the wParamFlags field; if the parameter has a default value and the lpVarValue field has a valid pointer, I would like to read that value. I assumed that lpVarValue is pointing to a native COM variant, so I tried to get an object representing the default value using Marshal.GetObjectForNativeVariant, but this fails with a fatal error...

Was it helpful?

Solution

They took a shortcut on the PARAMDESC.lpVarValue because the pointer type is hard to declare in managed code. It is actually a pointer to PARAMDESCEX, declared like this in oaidl.idl:

typedef struct tagPARAMDESCEX {
    ULONG cBytes;               /* size of this structure */
    VARIANTARG varDefaultValue; /* default value of this parameter */
} PARAMDESCEX, * LPPARAMDESCEX;

So, yes, using Marshal.GetObjectForNativeVariant() is a good way to get the varDefaultValue field. You however have to add to skip the cBytes field. That takes adding 4 to skip the ULONG and an extra 4 to skip the padding between the fields. So use something like:

PARAMDESC pd = ...;
object defValue = null;
if ((pd.wParamFlags & 0x20) != 0) {
    IntPtr defptr = new IntPtr((long)pd.lpVarValue + 8);
    defValue = Marshal.GetObjectForNativeVariant(defptr);
}

OTHER TIPS

The documentation for PARAMFLAG_FHASDEFAULT says:

Parameter has default behaviors defined. The pPARAMDescEx field contains a pointer to a VARIANT that describes the default value for this parameter, if the PARAMFLAG_FOPT and PARAMFLAG_FHASDEFAULT bit of wParamFlags is set.

So, so long as both PARAMFLAG_FOPT and PARAMFLAG_FHASDEFAULT are set, you can read the information out of paramDesc.pPARAMDescEx.


But according to the answer from @Hans, this is actually PARAMDESCEX rather than PARAMDESC and hence my confusion.

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