Маршалинг строк из C++ в C# (interop)

Здравствуйте. Подскажите в чем проблема??
Вроде все правильно но вылетает ошибка.

Есть такая функция С++;
Надо обменятся с ней данными о домене.

extern "C" __declspec(dllexport) unsigned char ExchangeInfoDevice(int devIndex, int RW, string *domain, string *username, string *password, byte* containerpass, DWORD containerpasslen)
{
	*domain = "123123123";
	//*username = "adfasdfasdfasfasfsadfasdfw5e23452356236545623456";
	//*password = "aasdfasfafasdfasdfasdfasdfasf";
	containerpass[2] = containerpass[4] = 46;
	return 123;

В шарпе извращаюсь как только можно.

static extern byte ExchangeInfoDevice(int devIndex, int RW, [MarshalAs(UnmanagedType.LPWStr)] ref string domain, [MarshalAs(UnmanagedType.LPWStr)] ref string username, [MarshalAs(UnmanagedType.LPWStr)] ref string password, byte[] containerpass, uint containerpasslen);
 

И реф передавал и указатель на неуправляемую память. Все равно либо ошибка AccessViolation либо еще куча всяких. А если ошибки не возникает то все равно передаваемые параметры своих значений не меняют.

Что я не так делаю то??

Возвращаемое значение буфера байтов меняется. И результат тоже правильный. Проблема только со строками.

Это std::string или что?

Если да, то скорее всего всё сложно. :kolobokcrossing: Это ж класс, да еще и шаблон.
Если нельзя изменить функцию, чтоб она принимала char*/wchar_t*, то может быть как-то с помощью C++/CLI.

Ну да… он самый.

Ну можно наверное если подскажете как из этого стринга в чары сконверптить и обратно.

Если для возврата в C#, то .c_str() + strncpy. В С принимать char* и размер, из C# StringBuilder.

            var sb = new StringBuilder(2048);
            MyCFunc(sb, sb.Capacity);

Если надо юникод, то в DllImportAttribute CharSet = CharSet.Unicode и в С wchar_t, std::wstring, wcsncpy.

конструктор. И из C# можно передавать просто string.

Ну видимо придется через прослойку делать. Для методов провайдера нужен именно такой тип. Не хочется переписывать рабочие версии сильно. Там итак дичь еще та. ))

Ну вообще если библиотека предназначена не только для С++, то API для её пользователей надо ограничивать до С (внутри ессно может использоваться С++), иначе никто не сможет её использовать )
Так что для этого бывает поверх С++ классов создают С API, где внутри их вызывают.

Либо для .NET еще есть вариант с C++/CLI — единственное норм применение этого языка )
https://www.google.com/search?q=c%2B%2B%2Fcli+c%2B%2B+wrapper

Сделал вот так:

extern "C" __declspec(dllexport) unsigned char ExchangeInfoDevice(int devIndex, int RW, char *domain, char *username, char *password, byte* containerpass, DWORD containerpasslen)
{
	string domain_s(domain);
	string username_s(username);
	string password_s(password);

	unsigned char  result = ExchangeInfoDevice(devIndex, RW, &domain_s, &username_s, &password_s, containerpass, containerpasslen);

	strcpy(domain, domain_s.c_str());
	strcpy(username, username_s.c_str());
	strcpy(password, password_s.c_str());

	return result;
}

А в шарпе:

      [DllImport("HIDComLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern byte ExchangeInfoDevice(int devIndex, int RW, [MarshalAs(UnmanagedType.LPStr)] StringBuilder domain, [MarshalAs(UnmanagedType.LPStr)] StringBuilder username, [MarshalAs(UnmanagedType.LPStr)] StringBuilder password, byte[] containerpass, uint containerpasslen);

            StringBuilder strb = new StringBuilder("trololo", 1024);
            StringBuilder strb2 = new StringBuilder("trololo", 1024);
            StringBuilder strb3 = new StringBuilder("trololo", 1024);
            var gh = ExchangeInfoDevice(0, 0, strb, strb2, strb3, cont, 24);

Все работает. И с латиницей и с кирилицей тоже.

В идеале надо принимать размер буфера параметром и использовать strcpy_s, современные компиляторы обычно ругаются на не _s функции.

Это не нужно вроде, у меня без этого работает.

Да лениво как то уже … )) а ругань всегда можно заткнуть каким нибудь #define _CRT_SECURE_NO_WARNINGS