Форум программистов, компьютерный форум, киберфорум
C++/CLI
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.69/270: Рейтинг темы: голосов - 270, средняя оценка - 4.69
Администратор
Эксперт .NET
 Аватар для tezaurismosis
9670 / 4823 / 762
Регистрация: 17.04.2012
Сообщений: 9,661
Записей в блоге: 14

Преобразование между типами System::String, char*, wchar_t*, std::string и др.

12.03.2016, 21:03. Показов 53205. Ответов 1
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
При написании кода, взаимодействующего как с .NET и управляемым кодом, так и с неуправляемым кодом (такими как стандартные библиотеки C и C++ или WinAPI), зачастую возникает необходимость в преобразовании между разными строковыми типами или другими типами, часто использующимися в разработке.

Эта статья описывает простые способы превращения управляемых строковых типов в неуправляемые и наоборот, и этот же процесс для типов HANDLE и System::IntPtr.

Содержание: #
Общие положения #

С выходом Visual Studio 2008 процесс преобразования строковых типов значительно упростился и ограничивается использованием всего лишь двух методов: marshal_as() и marshal_context::marshal_as(). Эти методы поддерживают маршалинг между строковыми типами System::String^, char*, const char*, wchar_t*, const wchar_t*, BSTR, bstr_t, std::string, std::wstring, CStringT<char>, CStringT<wchar_t> и CComBSTR. Также поддерживается преобразование между типами, представляющими указатели: System::IntPtr и HANDLE.

Для использования методов marshal_as() и marshal_context::marshal_as() нужно подключить один или несколько заголовочных файлов из папки msclr: marshal.h, marshal_windows.h, marshal_cppstd.h или marshal_atl.h. Определить, какой метод использовать и какой заголовочный файл подключать, можно из таблицы:

Из типаВ типМетодЗаголовочный файл
Строки в языке C
System::String^const char*marshal_context::marshal_as()marshal.h
const char*System::String^marshal_as()marshal.h
char*System::String^marshal_as()marshal.h
System::String^const wchar_t*marshal_context::marshal_as()marshal.h
const wchar_t*System::String^marshal_as()marshal.h
wchar_t*System::String^marshal_as()marshal.h
WinAPI и COM
System::IntPtrHANDLEmarshal_as()marshal_windows.h
HANDLESystem::IntPtrmarshal_as()marshal_windows.h
System::String^BSTRmarshal_context::marshal_as()marshal_windows.h
BSTRSystem::String^marshal_as()marshal.h
System::String^bstr_tmarshal_as()marshal_windows.h
bstr_tSystem::String^marshal_as()marshal_windows.h
Стандартная библиотека C++
System::String^std::stringmarshal_as()marshal_cppstd.h
std::stringSystem::String^marshal_as()marshal_cppstd.h
System::String^std::wstringmarshal_as()marshal_cppstd.h
std::wstringSystem::String^marshal_as()marshal_cppstd.h
ATL
System::String^CStringT<char>marshal_as()marshal_atl.h
CStringT<char>System::String^marshal_as()marshal_atl.h
System::String^CStringT<wchar_t>marshal_as()marshal_atl.h
CStringT<wchar_t>System::String^marshal_as()marshal_atl.h
System::String^CComBSTRmarshal_as()marshal_atl.h
CComBSTRSystem::String^marshal_as()marshal_atl.h

Другие преобразования, кроме указанных в таблице, не поддерживаются.

Однако, метод и заголовочный файл можно определить и без таблицы, ответив на два вопроса:
  1. Есть ли деструктор у типа, экземпляром которого является результат преобразования? Если нет, используем метод marshal_context::marshal_as(), если же имеет – вызываем marshal_as(). Деструктора нет у типов const char*, const wchar_t*, BSTR и HANDLE, у остальных поддерживаемых типов деструктор присутствует.
  2. К какой технологии относится тип, из которого или в который происходит преобразование?
    • Строки в языке С (типы char*, const char*, wchar_t* и const wchar_t*) – подключаем заголовочный файл marshal.h
    • Стандартная библиотека C++ (типы std::string и std::wstring) – подключаем заголовочный файл marshal_cppstd.h
    • WinAPI и COM (типы BSTR, bstr_t и HANDLE) – подключаем заголовочный файл marshal_windows.h
    • ATL (типы CStringT<char>, CStringT<wchar_t> и CComBSTR) – подключаем заголовочный файл marshal_atl.h

Например, мы хотим преобразовать std::wstring в System::String^. Результат преобразования (System::String^) имеет деструктор (если быть более точным, удалением этого объекта занимается сборщик мусора, т.к. это управляемый тип), следовательно используем метод marshal_as(). Тип std::wstring относится к стандартной библиотеке C++, значит нужный нам заголовочный файл – marshal_cppstd.h.

Тем не менее, из этого правила есть два исключения, а именно:
  1. Для преобразования System::IntPtr в HANDLE используется marshal_as(), несмотря на то, что у HANDLE нет деструктора.
  2. Метод преобразования BSTR в System::String^ расположен в marshal.h.

Как использовать методы marshal_as() и marshal_context::marshal_as()? #

Подключаем нужный заголовочный файл и не забываем, что оба этих метода расположены в пространстве имён msclr::interop.

Метод marshal_as() достаточно вызвать, указав тип-назначение. Результат преобразования будет удалён автоматически сборщиком мусора.
C++
1
2
3
4
5
6
7
8
9
#include <msclr/marshal.h>
using namespace System;
 
int main() {
    const char* text = "I will be a String!";
    String^ managed = msclr::interop::marshal_as<String^>(text);
    Console::WriteLine(managed);
    return 0;
}
Использование marshal_context::marshal_as() предполагает самостоятельное удаление результата преобразования. Естественно, после удаления экземпляра типа marshal_context, результат преобразования станет недоступен.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <cstdio>
#include <msclr/marshal.h>
using namespace System;
using namespace msclr::interop;
 
int main() {
    String^ managed = "Transformed to const char*";
    marshal_context^ marshal = gcnew marshal_context();
    const char* native = marshal->marshal_as<const char*>(managed);
    puts(native);
    delete marshal;
    return 0;
}
Преобразование System::String^ в char*, wchar_t* и обратно #

Преобразование из char*, const char*, wchar_t* и const wchar_t* в System::String^ осуществляется методом marshal_as(), расположенном в заголовочном файле marshal.h. Рассмотрим это на примере получения имени локали с помощью функции setlocale()
C++
1
2
3
4
5
6
7
8
9
10
11
#include <clocale>
#include <msclr/marshal.h>
using namespace System;
using namespace msclr::interop;
 
int main() {
    char* loc = setlocale(LC_ALL, NULL);
    String^ text = marshal_as<String^>(loc);
    Console::WriteLine(text);
    return 0;
}
ПримечаниеБолее приемлемым путём работы с локалями (культурами), является использование типа System::Globalization::CultureInfo.


Есть другой способ преобразования строк из стандартной библиотеки C в System::String^ - это использование конструктора, который принимает как обычные, так и широкие (wchar_t) строки. Предыдущий пример можно переписать так:
C++
1
2
3
4
5
6
7
8
9
10
11
#include <clocale>
#include <msclr/marshal.h>
using namespace System;
using namespace msclr::interop;
 
int main() {
    char* loc = setlocale(LC_ALL, NULL);
    String^ text = gcnew String(loc);
    Console::WriteLine(text);
    return 0;
}
Преобразование System::String^ возможно только в указатели на константу, т.е. в const char* и в const wchar_t* и с использованием marshal_context::marshal_as().
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <msclr/marshal.h>
#include <windows.h>
using namespace System;
using namespace msclr::interop;
 
int main() {
    marshal_context^ ctx = gcnew marshal_context();
 
    String^ now = DateTime::Now.ToString();
    MessageBox(NULL,
        ctx->marshal_as<const wchar_t*>(now),
        L"Now",
        MB_OK);
 
    delete ctx;
    return 0;
}
ПримечаниеДля функции MessageBox() существует управляемая обёртка: System::Windows::Forms::MessageBox::Show (), позволяющая вызывать окно с сообщением без преобразования строк.

ПримечаниеСтроки типа System::String хранят символы в кодировке Unicode. Поэтому более предпочтительным является преобразование System::String^ в const wchar_t*.


Преобразование System::String^ в std::string, std::wstring и обратно #

Для маршалинга строки из стандартной библиотеки C++ в System::String^ требуется минимум усилий – вызов метода marshal_as(). В данном примере показан разворот строки на месте.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <algorithm>
#include <string>
#include <msclr/marshal_cppstd.h>
using namespace System;
using namespace msclr::interop;
 
int main() {
    std::wstring str = L"алукард";
    std::reverse(str.begin(), str.end());
    String^ text = marshal_as<String^>(str);
    Console::WriteLine(text);
    return 0;
}
Обратное преобразование осуществляется тем же путём. Использовать marshal_context нет необходимости.
10
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
12.03.2016, 21:03
Ответы с готовыми решениями:

Преобразование System::String^ в std::string
Здравствуйте. Как можно преоброзовать System String^ в std::string Дело в том что получение имени пользователя происходит в поле System...

Преобразование из System::String в wchar_t*
Пишу так?pin_ptr&lt;const wchar_t&gt; ip = ::PtrToStringChars(dir); В переменной dir строка такая: &quot;D:\Program Files\Fraps\Screenshots\ExeFile...

Преобразование System::String в char*
Как преобразовать System String^ в массив char* или System String в std string?

1
Администратор
Эксперт .NET
 Аватар для tezaurismosis
9670 / 4823 / 762
Регистрация: 17.04.2012
Сообщений: 9,661
Записей в блоге: 14
12.03.2016, 21:03  [ТС]
Преобразование System::IntPtr в HANDLE и обратно #

Методы для маршалинга также позволяют преобразовать управляемое представление указателя – System::IntPtr в неуправляемое – HANDLE и обратно. Особенностью является тот факт, что использовать контекст маршалинга для такого преобразования не нужно – вся работа выполняется через встроенные в System::IntPtr методы. Ниже приведён пример преобразования System::IntPtr в HANDLE для получения количества GDI-объектов, используемых проводником:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <msclr/marshal_windows.h>
#include <windows.h>
using namespace System;
using namespace System::Diagnostics;
using namespace msclr::interop;
 
int main() {
    IntPtr managedHandle = Process::GetProcessesByName("explorer")[0]->Handle;
    HANDLE nativeHandle = marshal_as<HANDLE>(managedHandle);
    int count = 0;
    if (!(count = GetGuiResources(nativeHandle, GR_GDIOBJECTS)))
        Console::WriteLine("Something goes wrong with code #{0}", GetLastError());
    else
        Console::WriteLine("GDI objects: {0}", count);
    return 0;
}
Обратное преобразование осуществляется таким же путём.

Использование P/Invoke для автоматического маршалинга #

Во многих приложениях строки используются очень часто и перевод каждой строки из одного типа в другой может быть утомительным занятием. Его можно автоматизировать, если использовать технологию P/Invoke.
Рассмотрим пример
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using namespace System;
using namespace System::Runtime::InteropServices;
 
namespace MarshalledFuncs
{
    [DllImport("user32.dll",
        CharSet = CharSet::Unicode,
        EntryPoint = "MessageBoxW",
        ExactSpelling = true)]
    Int32 MessageBox(IntPtr hWnd, String^ lpText, String^ lpCaption, UInt32 uType);
}
 
int main() {
    String^ text = L"Привет, Мир!";
    String^ title = L"Сообщение";
    MarshalledFuncs::MessageBox(IntPtr::Zero, text, title, 0);
    return 0;
}
Обратите внимание на сигнатуру метода MarshalledFuncs::MessageBox() – он использует только управляемые типы. Строки преобразовываются из System::String^ в const wchar_t* автоматически перед передачей аргументов в метод MessageBoxW из библиотеки user32.dll. Тоже самое касается и перехода System::IntPtr в HANDLE (в сигнатуре исходной функции – HWND). Это достигается путём создания компилятором специального IL-кода при использовании атрибута System::Runtime::InteropServices::DllImp ort.
7
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
12.03.2016, 21:03
Помогаю со студенческими работами здесь

Преобразование Char в System::String
Здравствуйте. Пытаюсь вывести map в textBox (visual studo C++). ] map &lt;char,vector&lt;bool&gt; &gt;::iterator p; for (p=table.begin();...

Преобразование char в System::String ^
Как перевести arr в System::String ^(массив arr типа char )for (int j(0); j&lt;kolvo; j++) {String^ qwe = gcnew String(arr); pass-&gt;Text +=...

Преобразование System::String^ в const char *
Добрый день. Обыскал весь инет. Но так и не нашел нормально решения http://2lx.ru/2010/07/perevod-systemstring-v-char/ ...

Преобразование System::String в Char* и наоборот
Функция преобразования: void sts(String ^orig, char *&amp;out) { int length = orig-&gt;Length; out = new char; for(int...

Конфузы с русскими буквами при переводе из System::String^ в std::string
Использую такую конструкцию: string stdstr; for(int i=0;i&lt;sysstr-&gt;Length;++i) stdstr+=sysstr; Для английского текста все...


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

Или воспользуйтесь поиском по форуму:
2
Закрытая тема Создать тему
Новые блоги и статьи
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост. Налог на собак: https:/ / **********/ gallery/ V06K53e Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf Пост отсюда. . .
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop? Ниже её машинный перевод. После долгих разбирательств я наконец-то вернула себе. . .
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru