简体   繁体   中英

Sending an Array of strings from c# to c++ via COM

I tried to send an array from c# to c++ via com interop.

Here is the c# Code

public void SendArraytoCPlusPlus()
{
    GGXForVBA.GeoAtlas GA = new GGXForVBA.GeoAtlas();
    string[] arr = new string[3];
    arr[0] = "One";
    arr[1] = "Two";
    arr[2] = "Five";
    GA.GetArrayVar(arr);
}

Here is the c++ code

void GeoAtlas::GetArrayVar(VARIANT& arr)
{ 
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    SAFEARRAY* pSafeArray = arr.parray;
    long lStartBound = 0;
    long lEndBound = 0;
    SafeArrayGetLBound(pSafeArray,1,&lStartBound);
    SafeArrayGetUBound(pSafeArray,1,&lEndBound);
    LPCSTR * arrayAccess = NULL;

    SafeArrayAccessData( pSafeArray , (void**)&arrayAccess);
    for(int iIndex = lStartBound; iIndex <= lEndBound; iIndex ++)
    {   
        LPCTSTR myString = (LPCTSTR)arrayAccess[iIndex];
        AfxMessageBox(myString);        
    }  
}

This is the idl

[id(23)] void GetArrayVar(VARIANT arr);

The problem is, The message box only shows the FIRST letters of the strings, ie ''O'. 'T', 'F' . I want to read the whole string. Any suggestions ?

This is based on the fact that you're sending an Unicode/UTF8 string but the message box expects an ANSI C string. Try to convert the strings to ASCII before sending them. Look at the Encoding class here http://msdn.microsoft.com/en-us/library/system.text.encoding.aspx

You may want to try to send them as byte array.

var bytes = Encoding.ASCII.GetBytes("one");

You should pass a SAFEARRAY instead of a VARIANT:

[id(23)] void GetArrayVar([in] SAFEARRAY(BSTR) arr);

And in the implementation, access it like this:

void GeoAtlas::GetArrayVar(SAFEARRAY* arr)
{
    CComSafeArray<BSTR> sa;
    sa.Attach(arr);

    for (int i = sa.GetLowerBound(); i <= sa.GetUpperBound(); ++i)
    {
        AfxMessageBox(sa[i]);
    }

    sa.Detach();
}

Sending side looks fine. On receiving side try this.

[id(1), helpstring("method SetArrayVar")] HRESULT SetArrayVar([in] VARIANT varMachineList);

STDMETHODIMP GeoAtlas::SetArrayVar(VARIANT arr)
{
    long lower, upper;
    SafeArrayGetLBound(pSafeArray, 1, &lower);
    SafeArrayGetUBound(pSafeArray, 1, &upper);
    DWORD dwItems = upper - lower + 1;
    resize(dwItems);

    SAFEARRAY* pSafeArray = arr.parray;
    BSTR* pBstr;
    if ( SUCCEEDED(SafeArrayAccessData(pSafeArray, (LPVOID*) &pBstr)) )
    {
        iterator it = begin();
        for ( long i=lower; i<=upper; i++, pBstr++, it++ )
        {
            USES_CONVERSION;
            *it = OLE2CT(*pBstr);
            // Here you gets array elements and use it
        }
    }

    // release the data block
    SafeArrayUnaccessData(pSafeArray);
}

Not sure, but looks like you have Unicode/MBCS mismatch.

The managed part creates an array of UTF-16 encoded strings, while it seems that the unmanaged part is compiled with multibyte charset. Therefore, upon seeing first null character (which is actually just the second byte of UTF-16 character) your MBCS code thinks it has reached the end of the string.

One solution is to change the character set setting in your C++ project to Unicode and rebuild.

Another one is to change the code:

...
LPCWSTR * arrayAccess = NULL; // change LPCSTR -> LPCWSTR
...

for(int iIndex = lStartBound; iIndex <= lEndBound; iIndex ++)
{   
    bstr_t myString = arrayAccess[iIndex];
    AfxMessageBox(myString);        
} 

bstr_t will be correctly initialized with BSTR, but it also provides conversion to const char* so call to AfxMessageBox will be OK.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM