views:

799

answers:

1

Setup:
I have a COM DLL that calls a method inside a managed C# DLL. This function returns a C# string[] array, which is marshaled to a SAFEARRAY.

Problem:
When I try to access the strings within the safearray I only get the first char of the string. What am I doing wrong?

The code:

    // Pointer to the managed interface
    DatabasePtr pODB(__uuidof(DBClass));

    // Get the string[] array from the managed method
    SAFEARRAY* safearray = pODB->GetStringArray();

    HRESULT hresult;

    long ubound;
    long lbound;

    hresult = SafeArrayGetUBound(safearray, 1, &ubound);
    hresult = SafeArrayGetLBound(safearray, 1, &lbound);

    long index;
    BSTR fromarray;

    for (; lbound <= ubound; lbound++)
    {
        index = lbound;

        hresult = SafeArrayGetElement(safearray, &index, (void*)&fromarray);

        char buffer[512];
        sprintf_s(buffer,"%s",fromarray);

        MessageBox(0, (LPCSTR)buffer, "...", 0);
    }

Thanks for your help,
-Sean!

+2  A: 

The BSTR is an unicode string, so you must use an wchar_t buffer and the wsprintf_s. Right now u print the ANSI part of the first unicode character then stop on the \0. And please, please, don't stack overflow like that (sic!). Use the safe _vsnwprintf_s_l and its family, your code is a hacker's delight as it is right now and u'll be pwned. See http://msdn.microsoft.com/en-us/library/d3xd30zz(VS.80).aspx

Remus Rusanu
Thanks for the help. What do you mean by, "don't stack overflow like that?"
Sean
sprintf will overflow buffer if fromarray is bigger that 512
Remus Rusanu
Alright. It won't be bigger than 512, but I'll go w/ the safe route anyways. Thanks again.
Sean
Also, you didn't mention that I should've been using MessageBoxW, instead of MessageBox...
Sean
right, and your database routines access also. You may want to use the generic TCHAR type and change the project settings to Unicode. Or, if you must stick to ANSI, convert the received fromarray to ANSI first via something like MultiByteToWideChar (http://msdn.microsoft.com/en-us/library/dd319072(VS.85).aspx). Also you should look into the BSTR wrapper helpers, _bstr_t and CComBSTR. I prefer _bstr_t see http://msdn.microsoft.com/en-us/library/zthfhkd6(VS.80).aspx
Remus Rusanu
btw about the 512 comment: it may not be bigger that 512 *in your call stack*, but once you exposed urself to COM an arbitrary process may load your DLL. Hacker knows the exploit in ur DLL, causes a process to load it (activex script in browser, config setting for some service, modify a registry CLSIID etc), passes in long string and bam! it hijacked that process.
Remus Rusanu
I think I'm going to stick with Unicode, I read somewhere that's its preferred over ANSI anyways.Ah ok, thanks for that useful bit of info in your last post (the first was helpful too ;). I'm new to COM programming and such and I wasn't even thinking about someone doing that, but I'll remember to guard against it in future projects (and this one).
Sean