Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.88/25: Рейтинг темы: голосов - 25, средняя оценка - 4.88
1 / 1 / 0
Регистрация: 26.07.2012
Сообщений: 133

Маршалинг string

11.09.2015, 15:42. Показов 4845. Ответов 15

Студворк — интернет-сервис помощи студентам
Возник затуп при обращении к dll на с++.

Как связан .net'овский string и CHAR,WCHAR,LPSTR,LPCSTR,LPWSTR,LPCWSTR? Как будет маршалинг происходить?

Я так понимаю, string - это всегда юникод, каждый символ - 2 байта. Т.е. входной параметр с++ функции должен быть объявлен как *WCHAR или LPWSTR? А если он объявлен, например, как CHAR*, что будет происходить? И важно ли при этом, включена или нет поддержка юникода в проекте c++ при компиляции?

Несколько сумбурно, но суть, надеюсь, ясна)
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
11.09.2015, 15:42
Ответы с готовыми решениями:

Маршалинг структур. Размер string
В общем начал разбираться с маршалингом структур. правда некоторые моменты непонятны. например Вот я делаю так public...

Маршалинг структуры C# --> C
В неуправляемом коде (bla.dll) есть структура: typedef struct { ULONG32 a; UINT8 b; UINT8 c; UINT16 d; ...

Маршалинг C++ wchar_t** в C#
Доброго времени суток! Столкнулся со следующей задачей. Есть библиотека, в библиотеке есть функция, которую необходимо вызвать в C#...

15
Каратель
Эксперт С++
6610 / 4029 / 401
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
11.09.2015, 17:19
Цитата Сообщение от navab Посмотреть сообщение
Как связан .net'овский string и CHAR,WCHAR,LPSTR,LPCSTR,LPWSTR,LPCWSTR? Как будет маршалинг происходить?
Я так понимаю, string - это всегда юникод, каждый символ - 2 байта. Т.е. входной параметр с++ функции должен быть объявлен как *WCHAR или LPWSTR? А если он объявлен, например, как CHAR*, что будет происходить?
какой CharSet укажешь в DllImport так и будет

Цитата Сообщение от navab Посмотреть сообщение
И важно ли при этом, включена или нет поддержка юникода в проекте c++ при компиляции?
И да и нет, зависит от того что в этом С++ коде.
0
Администратор
Эксперт .NET
 Аватар для OwenGlendower
18298 / 14222 / 5368
Регистрация: 17.03.2014
Сообщений: 28,898
Записей в блоге: 1
11.09.2015, 17:50
navab, передавать можно любые строки, но тебе необходимо точно знать что ожидает неуправляемый код. Точный тип строки указыватся с помощью атрибута MarshalAs.
0
1 / 1 / 0
Регистрация: 26.07.2012
Сообщений: 133
15.09.2015, 15:01  [ТС]
Если сигнатура функции на с++
C++
1
2
3
4
5
6
BYTE* CppF(char* A, BYTE* B, DWORD* C)
{
...
std::cout<<*A<<"||||||||"<<A<<"|||||||"; //смотрим, что пришло
...
}
вызов на С#
C#
1
2
3
[DllImport("Library.dll", CharSet=CharSet.Ansi)]
public static extern IntPtr CppF(string P1, IntPtr P2, [In,Out] ref ulong P3);
P1="Тест";
В консоли после вызова вижу "тест" в неправильной кодировке. Можно как-то явно ее указать?

Или второй вариант:
с++
C++
1
BYTE* CppF(wchar_t* A, BYTE* B, DWORD* C)
c#
C#
1
[DllImport("Library.dll", CharSet=CharSet.Unicode)]
Тогда по адресу *А вижу 1058, что соответствует символу "Т". Но полностью строку отладчик в А не показывает, только адрес указателя.
Как все-таки правильно выполнить такой вызов?
0
Master of Orion
Эксперт .NET
 Аватар для Psilon
6102 / 4958 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
15.09.2015, 15:29
navab, то сказал, что IntPtr это byte* ? Вам слова Int или Ptr о чем-то говорят?
почему ref стал ulong, когда ulong это 8 байт, а DWORD - 4, тоже непонятно.

Хотя это, конечно, не должно влиять на работоспособность передачи строки, которая идет первым аргументом. callcontention указали как cdecl или какой-либо еще?

Добавлено через 1 минуту
https://msdn.microsoft.com/en-... v=vs.71%29
0
1 / 1 / 0
Регистрация: 26.07.2012
Сообщений: 133
15.09.2015, 15:45  [ТС]
стал байт потому что:
C#
1
2
3
4
            byte[] bytes = new byte[Data.Length * sizeof(char)];
            System.Buffer.BlockCopy(Data.ToCharArray(), 0, bytes, 0, bytes.Length);
            IntPtr pData = Marshal.AllocHGlobal(bytes.Length);
            Marshal.Copy(bytes, 0, pData, bytes.Length);
Просто не стал загромождать код.
ulong да, uint должен быть.

Добавлено через 4 минуты
по умолчанию. STDCALL я полагаю.
0
Master of Orion
Эксперт .NET
 Аватар для Psilon
6102 / 4958 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
15.09.2015, 17:00
navab, только что проверил для интереса - всё работает
Вложения
Тип файла: zip ConsoleApplication73.zip (2.52 Мб, 11 просмотров)
0
1 / 1 / 0
Регистрация: 26.07.2012
Сообщений: 133
16.09.2015, 12:34  [ТС]
Хорошо, с передачей строк в dll разобрался. Теперь возвращаю.
C++
1
2
3
4
5
6
BYTE* CppF(char* A, BYTE* B, DWORD* C, wchar_t* D)
{
   LPTSTR d = ...
   ...
   *D=*d;
}
Вызов.
C#
1
2
3
4
5
[DllImport("D:\\Proj\\CryptoLibrary\\Debug\\CryptoLibrary.dll", CharSet=CharSet.Unicode)]
public static extern IntPtr CppF(string P1, IntPtr P2,int P3, [In,Out] ref uint P4, [In,Out] ref string OutString);
...
string resultString="";
IntPtr result= CppF(P1, P2,P4, ref p5, ref resultString);
Я рассчитываю, что в resultString окажется первая буква строки, на которую указывает d, чего не наблюдается.

ps/Пардоньте за тупые вопросы, но этот момент до конца хотел бы прояснить.
0
Master of Orion
Эксперт .NET
 Аватар для Psilon
6102 / 4958 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
16.09.2015, 14:17
navab, а обязательно в одной функции по 5 параметров со ссылками передавать? Попахивает каким-то винапи. Вы сначала с 1-2 аргументами функции разберитесь, потом в одну соедините. Упростите пример, хотя бы. До минимально нерабочего.
0
1 / 1 / 0
Регистрация: 26.07.2012
Сообщений: 133
16.09.2015, 15:01  [ТС]
Это параметры для отладки, в боевой сигнатуре этих их не будет.
Пример рабочий, результат работы токмо не такой, как ожидалось)
0
Master of Orion
Эксперт .NET
 Аватар для Psilon
6102 / 4958 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
16.09.2015, 17:24
navab, подредактировал пример
Вложения
Тип файла: zip ConsoleApplication732.zip (2.93 Мб, 12 просмотров)
1
1 / 1 / 0
Регистрация: 26.07.2012
Сообщений: 133
17.09.2015, 11:39  [ТС]
Psilon, то что нужно.
Я такой вариант сделал:
C++
1
2
3
4
5
BYTE* CppF(wchar_t** P)
{
   LPTSTR p = ...
   *P=p;
}
Вызов
C#
1
2
[DllImport("Library.dll", CharSet=CharSet.Unicode)]
public static extern IntPtr CppF([In,Out] ref  string P);
Допустим такой вариант? Строку возвращает правильно, токмо как именно приводится ** к string мне не вполне понятно.
0
Эксперт .NET
6691 / 4102 / 1607
Регистрация: 09.05.2015
Сообщений: 9,574
17.09.2015, 12:16
Зачем вам тут атрибуты In/Out не понятно. Просто ref или out в 99% случаев достаточно.
0
Master of Orion
Эксперт .NET
 Аватар для Psilon
6102 / 4958 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
17.09.2015, 12:50
navab, недопустим. Нельзя менять ссылку, которая из шарпового кода приходит. Поэтому там wcscpy. Его вполне достаточно для работы. Ну и StringBuilder там не просто так. Если не хочется возни с IntPtr, то это лучший вариант, потому что маршаллер по-особому с ним обращается. В примере всё есть, разбирайтесь. И пробуйте. Могли бы просто скомпилировать такой вариант и увидеть, что всё падает.
0
1 / 1 / 0
Регистрация: 26.07.2012
Сообщений: 133
17.09.2015, 14:04  [ТС]
Ничего не падает. Сначала думал из-за того, что строка объявлена в ансейф блоке, проверил, убрав ансейф - тоже все работает.

Добавлено через 37 секунд
я ж напислал, что строку возвращает правильно, наверно скомпилировал?

Добавлено через 1 минуту
Но wcscpy, конечно, нагляднее.
0
Master of Orion
Эксперт .NET
 Аватар для Psilon
6102 / 4958 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
19.09.2015, 00:00
navab, недопустим хотя бы потому, что мы не можем контролировать размер буфера, который таскаем туда-сюда. Если нужно менять размер строки, то тогда нужно юзать IntPtr в качестве значения (Это местный (void*) и уже его вручную маршаллить в строку с помощью класса Marshal собственно.

Добавлено через 4 минуты
Полная цитатка:
You cannot use StringBuilder, it has to be passed without ref and is intended to allow the callee to copy the string contents in the buffer. You need an extra argument, bufferLength, that ensures that the native code cannot destroy the GC heap. Pass the Capacity value. Use wcscpy_s() to copy the string content.

But you are returning a pointer. That doesn't make the pinvoke marshaller very happy, it is a troublesome memory management issue. It assumes that somebody has to clean up the string buffer. When you let the marshaller do it then it will call CoTaskMemFree(), that rarely comes to a good end.

You'll have to fool it and declare the argument as ref IntPtr instead. Then use Marshal.PtrToStringUni() in your C# code to retrieve the string. Otherwise a nasty failure mode if you don't return a pointer to a string literal but allocate on the heap or dangle a wchar[] pointer. Copying is the safe way.
Автор :D
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
19.09.2015, 00:00
Помогаю со студенческими работами здесь

Маршалинг и структура
Добрый день, товарищи. Есть библиотека С++, в которой имеется структура и метод с нею работающий: struct MyCPPStruct { char...

Маршалинг данных
Необходимо передавать массивы данных из управляемого кода в неуправляемый. Почитал про атрибуты , но я понял так, что независимо от...

Что такое маршалинг?
Можете по простому объяснить что это такое. И пример, где это используется и для чего он нужен.

Маршалинг Waveform Audio
Привет. Возникла необходимость сделать wrapper для c# библиотеки Windows Waveform Audio. Пока работаю пока только с одной структурой...

Маршалинг структур: динамическое управление размером
Решил изучить как с помощью средств c# передавать структуры. Нашел способы преобразования структур в массив байт с помощью Marashal. Вот...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
16
Ответ Создать тему
Новые блоги и статьи
Символические и жёсткие ссылки в Linux.
algri14 15.03.2026
Существует два типа ссылок — символические и жёсткие. Ссылка в Linux — это дополнительная запись в каталоге, которая может указывать либо на inode «файла-ИСТОЧНИКА», тогда это будет «жёсткая. . .
[Owen Logic] Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора
ФедосеевПавел 14.03.2026
Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора ВВЕДЕНИЕ Выполняя задание на управление насосной группой заполнения резервуара,. . .
делаю науч статью по влиянию грибов на сукцессию
anaschu 13.03.2026
прикрепляю статью
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru