Форум программистов, компьютерный форум, киберфорум
Наши страницы
C++/CLI
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.76/50: Рейтинг темы: голосов - 50, средняя оценка - 4.76
tezaurismosis
Администратор
Эксперт .NET
8629 / 3916 / 730
Регистрация: 17.04.2012
Сообщений: 8,694
Записей в блоге: 14
1

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

12.03.2016, 21:03. Просмотров 9225. Ответов 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 нет необходимости.
8
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
12.03.2016, 21:03
Ответы с готовыми решениями:

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

Преобразование из System::String в wchar_t*
Пишу так?pin_ptr&lt;const wchar_t&gt; ip = ::PtrToStringChars(dir); В переменной dir...

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

Преобразование char в System::String ^
Как перевести arr в System::String ^(массив arr типа char )for (int j(0);...

Преобразование Char в System::String
Здравствуйте. Пытаюсь вывести map в textBox (visual studo C++). ] map...

1
tezaurismosis
Администратор
Эксперт .NET
8629 / 3916 / 730
Регистрация: 17.04.2012
Сообщений: 8,694
Записей в блоге: 14
12.03.2016, 21:03  [ТС] 2
Преобразование 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::DllImport.
4
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
12.03.2016, 21:03

Преобразование System::String^ в const char *
Добрый день. Обыскал весь инет. Но так и не нашел нормально решения ...

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

Конфузы с русскими буквами при переводе из System::String^ в std::string
Использую такую конструкцию: string stdstr; for(int...


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

Или воспользуйтесь поиском по форуму:
2
Закрытая тема Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Рейтинг@Mail.ru