Заметка
Доступ к этой странице требует авторизации. Вы можете попробовать войти в систему или изменить каталог.
Доступ к этой странице требует авторизации. Вы можете попробовать сменить директорию.
Собственные функции, принимаюющие строки в стиле C, можно вызывать с помощью типа System::String строки CLR с помощью поддержки платформа .NET Framework Platform Invoke (P/Invoke). Мы рекомендуем использовать функции взаимодействия C++ вместо P/Invoke, когда это возможно. Поскольку P/Invoke предоставляет мало отчетов об ошибках во время компиляции, не является типобезопасным и может быть небезопасным для реализации. Если неуправляемый API упакован в виде библиотеки DLL, и исходный код недоступен, P/Invoke является единственным вариантом. В противном случае см. раздел "Использование взаимодействия C++ (неявное P/Invoke)".
Управляемые и неуправляемые строки размещаются по-разному в памяти, поэтому передача строк из управляемых в неуправляемые функции требует MarshalAsAttribute от атрибута указать компилятору вставлять необходимые механизмы преобразования для маршалинга строковых данных правильно и безопасно.
Как и функции, использующие только встроенные типы данных, DllImportAttribute используются для объявления управляемых точек входа в собственные функции. Функции, которые передают строки, могут использовать дескриптор для String типа вместо определения этих точек входа при использовании строк в стиле C. При использовании этого типа компилятор запрашивает вставку кода, выполняющего необходимое преобразование. Для каждого аргумента функции в неуправляемой функции, принимающей строку, используйте MarshalAsAttribute атрибут, чтобы указать, что String объект должен быть маршалирован в собственную функцию в виде строки в стиле C.
Маршалер упаковывает вызов неуправляемой функции в скрытую подпрограмму оболочки. Подпрограмма-оболочка закрепляет и копирует управляемую строку в локально выделенной строке в неуправляемом контексте. Затем локальная копия передается неуправляемой функции. Когда неуправляемая функция возвращается, оболочка удаляет ресурс. Или, если он был в стеке, он был восстановлен, когда оболочка выходит из области. Неуправляемая функция не отвечает за эту память. Неуправляемый код создает и удаляет память только в куче, настроенной собственной CRT, поэтому никогда не возникает проблемы с маршаллером с использованием другой версии CRT.
Если неуправляемая функция возвращает строку в виде возвращаемого значения или параметра out, маршалер копирует его в новую управляемую строку, а затем освобождает память. Дополнительные сведения см. в разделе "Поведение маршалинга по умолчанию" и "Маршалинг данных" с помощью вызова платформы.
Пример
Следующий код состоит из неуправляемого модуля и управляемого модуля. Неуправляемый модуль — это библиотека DLL, которая определяет функцию, называемую TakesAString.
TakesAStringпринимает узкую строку в стиле C в виде .char*
// TraditionalDll2.cpp
// compile with: /LD /EHsc
#include <windows.h>
#include <stdio.h>
#include <iostream>
using namespace std;
#define TRADITIONALDLL_EXPORTS
#ifdef TRADITIONALDLL_EXPORTS
#define TRADITIONALDLL_API __declspec(dllexport)
#else
#define TRADITIONALDLL_API __declspec(dllimport)
#endif
extern "C" {
TRADITIONALDLL_API void TakesAString(char*);
}
void TakesAString(char* p) {
printf_s("[unmanaged] %s\n", p);
}
Управляемый модуль — это приложение командной строки, которое импортирует TakesAString функцию, но определяет ее как управляемую System.String вместо .char* Атрибут MarshalAsAttribute используется для указания того, как следует маршалировать управляемую строку при TakesAString вызове.
// MarshalString.cpp
// compile with: /clr
using namespace System;
using namespace System::Runtime::InteropServices;
value struct TraditionalDLL
{
[DllImport("TraditionalDLL2.dll")]
static public void
TakesAString([MarshalAs(UnmanagedType::LPStr)]String^);
};
int main() {
String^ s = gcnew String("sample string");
Console::WriteLine("[managed] passing managed string to unmanaged function...");
TraditionalDLL::TakesAString(s);
Console::WriteLine("[managed] {0}", s);
}
Этот метод создает копию строки в неуправляемой куче, поэтому изменения, внесенные в строку собственной функцией, не будут отражены в управляемой копии строки.
Часть библиотеки DLL не предоставляется управляемому коду с помощью традиционной #include директивы. На самом деле библиотека DLL доступна только во время выполнения, поэтому проблемы в функциях, импортированных с помощью, DllImport не обнаруживаются во время компиляции.