theAnonymous
theAnonymous

Reputation: 1804

C++ to C# char[]

C# code:

class Hello{
    public void helloWorld(char[] chars){
        //do something
    }
}

C++ code to call C#:

MyCSDLL::Hello* hello;
//init hello, some calls are ok.

char* myCharPtr;
//init with message
 HRESULT result = hello->helloWorld(safeArray, (MyCSDLL::_MyRetVal) _retValPtr);

Adapting from How to create and initialize SAFEARRAY of doubles in C++ to pass to C#

void createSafeArray(SAFEARRAY** saData, char* charPtr)
{
    char* iterator = charPtr;
    SAFEARRAYBOUND  Bound;
    Bound.lLbound = 0;
    Bound.cElements = 10;

    *saData = SafeArrayCreate(VT_R8, 1, &Bound);

    char HUGEP *pdFreq;
    HRESULT hr = SafeArrayAccessData(*saData, (void HUGEP* FAR*)&pdFreq);
    if (SUCCEEDED(hr))
    {
        do {
            *pdFreq++ = *iterator;
        } while (*iterator++);

    }

}

How to call hello->helloWorld()? it is expecting SAFEARRAY*. The current code gives 80131538 error. How to fix it?

C++ Project is not CLR.

Upvotes: 0

Views: 661

Answers (1)

Simon Mourier
Simon Mourier

Reputation: 139276

Let's suppose the C# code is this:

namespace ClassLibrary1
{
    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.AutoDual)]
    public class Hello
    {
        public void helloWorld(char[] chars)
        {
           ...
        }
    }
}

Then, you can call it with this C/C++ code, for example:

#import "C:\mycode\ClassLibrary1\bin\Debug\classlibrary1.tlb" raw_interfaces_only

using namespace ClassLibrary1;

HRESULT CallHello(wchar_t* charPtr, int count)
{
  CComPtr<_Hello> p;
  HRESULT hr = p.CoCreateInstance(__uuidof(Hello));
  if (FAILED(hr))
    return hr;

  SAFEARRAY* psa = SafeArrayCreateVector(VT_UI2, 0, count);
  if (!psa)
    return E_OUTOFMEMORY;

  LPVOID pdata;
  hr = SafeArrayAccessData(psa, &pdata);
  if (SUCCEEDED(hr))
  {
    CopyMemory(pdata, charPtr, count * 2); // count is the number of chars
    SafeArrayUnaccessData(psa);
    hr = p->helloWorld(psa);
  }
  SafeArrayDestroy(psa);
  return hr;
}

.NET's char type is unicode, so the binary size is two bytes, the C equivalent is wchar_t (or unsigned short, etc...). So the safearray element type must match that, that's why I used VT_UI2 (VT_R8 that you used is Real of size 8 bytes, so it's equivalent to .NET's double type).

If you really want to use C's char, then you must do some kind of conversion to a 2-byte character.

Also, you can use the SafeArrayCreateVector function which directly allocates a 1-dimension safe array. Don't forget to call cleanup methods.

Upvotes: 1

Related Questions