Allocating BSTR Values

You should always use OLE functions to operate on BSTR values. If you need to change a BSTR value, first test the BSTR to see if it is already assigned. If it isn't, you may use the SysAllocStringByteLen function to assign a value to the BSTR. If the BSTR is already assigned, you must free the current assignment (with the SysFreeString function) before you can use SysAllocStringByteLen. You cannot use the SysReAllocString or SysReAllocStringLen function to reallocate the string (these functions automatically free the initial assignment) because they do not have a byte version for dealing with the ANSI strings that Microsoft Excel is passing into the code.

For example, the following C-language code copies some number of characters from one BSTR into another. Notice that this example tests the second BSTR to see if it is already assigned. If it is, the example uses the SysReAllocStringLen function to free the existing string before replacing it.

short WINAPI StringArgs(BSTR *pbstrArg1, 
    BSTR *pbstrArg2, short cch)
{
    BSTR *pbstrTemp;

    // Return error code if requested characters 
    // less than zero, or input string is unassigned 
    // or has too few characters.
    // Use ByteLen since string is not unicode
    if (cch < 0 || *pbstrArg1 == NULL || 
        (short)SysStringByteLen(*pbstrArg1) < cch)
        return -1;        

    if (*pbstrArg2 == NULL) 
    {     // String is unassigned; 
        // we can allocate a new one.
        // Use ByteLen since string is not unicode
        *pbstrArg2 = SysAllocStringByteLen((LPSTR)*pbstrArg1, cch);
        if (*pbstrArg2 == NULL)
            return -2;
    }
    else 
    {     // Argument string is already assigned; 
        // we must reallocate.
        *pbstrTemp = SysAllocStringByteLen((LPSTR)*pbstrArg1, cch);
        // Did it fail?
        if (pbstrTemp == NULL)
            return -3;

        SysFreeString(*pbstrArg2);
        *pbstrArg2 = *pbstrTemp;
    }
        
    return 0;
}

The calls to the SysAllocStringByteLen function use the dereferenced BSTR pointer *pbstrArg1 to access the characters in the first argument. This is permitted when you are reading the characters, but you should not write to the dereferenced pointer.

This Visual Basic code declares and calls the StringArgs function:

Declare Function StringArgs Lib "debug\ADVDLL.DLL" _
    (inpStr As String, outStr As String, ByVal n As Integer) As Integer

Sub StringArgsTest()
    Dim newStr As String
    Dim x As Boolean

    ''' First code path
    x = StringArgs("abracadabra", newStr, 5)
    MsgBox x & ":" & newStr

    ''' Second code path
    x = StringArgs("abracadabra", newStr, 4)
    MsgBox x & ":" & newStr
End Sub