0

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.

theAnonymous
  • 1,701
  • 2
  • 28
  • 62
  • Yes. Consider to [create a safe array](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/api/oleauto/nf-oleauto-safearraycreate). Maybe char[] was not a very good choice, it rarely is, hard to tell. – Hans Passant Aug 07 '18 at 11:00
  • Please check the code for `createSafeArray()`. The method call is failing now. – theAnonymous Aug 07 '18 at 11:13
  • 1
    It should fail, you created a double[] with VT_R8. This should not be a char[] at all, it should be byte[]. Use VT_U1. – Hans Passant Aug 12 '18 at 09:02

1 Answers1

1

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.

Simon Mourier
  • 132,049
  • 21
  • 248
  • 298