Argument-Constructor Functions

The argument-constructor functions in dispargs.c are used to set up an argument list before you use the Invoke function. Each argument-constructor function adds a single argument of a specific type to the list of arguments (the global argument arrays). If appropriate, memory may be allocated to represent the argument. This memory will be automatically freed when the ClearAllArgs function is called unless you specify the NOFREEVARIANT flag for the argument. If you specify this flag, it is your responsibility to free the memory allocated for or contained within the argument.

For example, if a method has one Boolean argument and two integer arguments, you would call AddArgumentBool, AddArgumentInt2, AddArgumentInt2. Each AddArgumentType function accepts the name of the argument, a flag that tells the function whether the argument should be freed after use, and the value of the argument. Functions are provided for the following data types: integers, Booleans, doubles, objects, strings, and arrays of strings. IDispatch is capable of supporting other data types; you can add an argument handler for a data type by writing the appropriate AddArgumentType function and adding argument-release code to the ReleaseVariant function.

Arguments may be named. The name string must be a C-style (null-terminated) string, and it is owned by the caller. If the string is dynamically allocated, the caller is responsible for freeing the string.

All named arguments must be set before any positional arguments. The following example shows a Visual Basic call and its equivalent call using the AddArgumentInt2 function (the flags argument is omitted for clarity). Notice that the arguments are added in reverse order (the last argument is added first).

Visual Basic

SomeMethod 5, 2, named1 := 3, named2 := 4

Dispargs

AddArgumentInt2("named2", 4);
AddArgumentInt2("named1", 3);
AddArgumentInt2(NULL, 2);
AddArgumentInt2(NULL, 5);

If you are using PropertyPut, use a NULL name and add the value to be set as the argument.

All argument-constructor functions use the AddArgumentCommon function to set the name and value of the argument and increment the argument count.

void AddArgumentCommon(LPOLESTR lpszArgName, WORD wFlags, VARTYPE vt)
{
    ClearVariant(&g_aVargs[g_iArgCount]);

    g_aVargs[g_iArgCount].vt = vt;
    g_awFlags[g_iArgCount] = wFlags;

    if (lpszArgName != NULL) 
    {
        g_alpszArgNames[g_iNamedArgCount + 1] = lpszArgName;
        g_iNamedArgCount++;
    }
}    

Object Arguments

BOOL AddArgumentDispatch(LPOLESTR lpszArgName, WORD wFlags, 
    IDispatch * pdisp)
{
    AddArgumentCommon(lpszArgName, wFlags, VT_DISPATCH);
    g_aVargs[g_iArgCount++].pdispVal = pdisp;
    return TRUE;
}

Integer Arguments

BOOL AddArgumentInt2(LPOLESTR lpszArgName, WORD wFlags, int i)
{
    AddArgumentCommon(lpszArgName, wFlags, VT_I2);
    g_aVargs[g_iArgCount++].iVal = i;
    return TRUE;
}

Boolean Arguments

BOOL AddArgumentBool(LPOLESTR lpszArgName, WORD wFlags, BOOL b)
{
    AddArgumentCommon(lpszArgName, wFlags, VT_BOOL);
    // Note the variant representation of True as -1
    g_aVargs[g_iArgCount++].boolVal = b ? -1 : 0;
    return TRUE;
}

Double Arguments

BOOL AddArgumentDouble(LPOLESTR lpszArgName, WORD wFlags, double d)
{
    AddArgumentCommon(lpszArgName, wFlags, VT_R8);
    g_aVargs[g_iArgCount++].dblVal = d;
    return TRUE;
}

String Arguments

OLE and IDispatch use a BSTR for strings (for more information about BSTR values, see Chapter 6 in Volume 2 of the OLE 2 Programmer's Reference). The AddArgumentCString function copies the passed-in C-style string into a BSTR. You must not set the NOFREEVARIANT flag for C-string arguments; the allocated BSTR should be freed by the ReleaseVariant function.

BOOL AddArgumentCString(LPOLESTR lpszArgName, WORD wFlags, 
    LPOLESTR lpsz)
{
    BSTR b;

    b = SysAllocString(lpsz);
    if (!b)
        return FALSE;
    AddArgumentCommon(lpszArgName, wFlags, VT_BSTR);
    g_aVargs[g_iArgCount++].bstrVal = b;
    return TRUE;
}

If you already have a BSTR argument, you should use the AddArgumentBSTR function to avoid making an extra copy of the BSTR. With BSTR arguments, you should set the NOFREEVARIANT flag unless you want the ReleaseVariant function to free the passed-in BSTR. (If you plan to use the BSTR after the Invoke function call, you should set this flag.) Be aware that the BSTR must contain a UNICODE string as opposed to the ANSI string required in Win16.

BOOL AddArgumentBSTR(LPOLESTR lpszArgName, WORD wFlags, BSTR bstr)
{
    AddArgumentCommon(lpszArgName, wFlags, VT_BSTR);
    g_aVargs[g_iArgCount++].bstrVal = bstr;
    return TRUE;
}

String-Array Arguments

The following function copies an array of C-style strings into a one-dimensional array of string variants. You should allow the ReleaseVariant function to free the allocated strings; do not set the NOFREEVARIANT flag.

BOOL AddArgumentCStringArray(LPOLESTR lpszArgName, WORD wFlags, 
    LPOLESTR *paszStrings, int iCount)
{
    SAFEARRAY *psa;
    SAFEARRAYBOUND saBound;
    VARIANTARG *pvargBase;
    VARIANTARG *pvarg;
    int i, j;

    saBound.lLbound = 0;
    saBound.cElements = iCount;
    
    psa = SafeArrayCreate(VT_VARIANT, 1, &saBound);
    if (psa == NULL)
        return FALSE;

    SafeArrayAccessData(psa, & (VARIANTARG _huge *) pvargBase);

    pvarg = pvargBase;
    for (i = 0; i < iCount; i++) 
    {
        // copy each string in the list of strings
        ClearVariant(pvarg);
        pvarg->vt = VT_BSTR;
        if ((pvarg->bstrVal = SysAllocString(*paszStrings++)) == NULL) 
        {
            // memory failure:  back out and free strings alloc'ed up to
            // now, and then the array itself.
            pvarg = pvargBase;
            for (j = 0; j < i; j++) 
            {
                SysFreeString(pvarg->bstrVal);
                pvarg++;
            }
            SafeArrayDestroy(psa);
            return FALSE;
        }
        pvarg++;
    }

    SafeArrayUnaccessData(psa);

    // With all memory allocated, set up this argument
    AddArgumentCommon(lpszArgName, wFlags, VT_VARIANT | VT_ARRAY);
    g_aVargs[g_iArgCount++].parray = psa;
    return TRUE;
}