Практическое руководство. Маршалирование массивов с помощью P/Invoke
Вы можете вызывать собственные функции, принимаюющие строки в стиле C, с помощью типа String строки CLR при использовании поддержки платформа .NET Framework Platform Invoke (P/Invoke). Мы рекомендуем использовать функции взаимодействия C++ вместо P/Invoke, когда это возможно. P/Invoke предоставляет мало отчетов об ошибках во время компиляции, не является типобезопасным и может быть небезопасным для реализации. Если неуправляемый API упакован в виде библиотеки DLL и исходный код недоступен, P/Invoke является единственным вариантом. В противном случае см. раздел "Использование взаимодействия C++ (неявное P/Invoke)".
Пример
Так как собственные и управляемые массивы размещаются по-разному в памяти, их успешно передается через управляемую или неуправляемую границу, требуется преобразование или маршалинг. В этой статье показано, как можно передать массив простых (доступных) элементов в собственные функции из управляемого кода.
Как и в случае с маршалингом управляемых или неуправляемых данных, DllImportAttribute атрибут используется для создания управляемой точки входа для каждой используемой собственной функции. В функциях, которые принимают массивы в качестве аргументов, MarshalAsAttribute атрибут должен использоваться для указания способа маршалирования данных. В следующем примере UnmanagedType перечисление используется для указания, что управляемый массив маршалируется как массив стилей C.
Следующий код состоит из неуправляемого и управляемого модуля. Неуправляемый модуль — это библиотека DLL, которая определяет функцию, которая принимает массив целых чисел. Второй модуль — это управляемое приложение командной строки, которое импортирует эту функцию, но определяет его с точки зрения управляемого массива. Он использует MarshalAsAttribute атрибут, чтобы указать, что массив должен быть преобразован в собственный массив при вызове.
// TraditionalDll4.cpp
// compile with: /LD /EHsc
#include <iostream>
#define TRADITIONALDLL_EXPORTS
#ifdef TRADITIONALDLL_EXPORTS
#define TRADITIONALDLL_API __declspec(dllexport)
#else
#define TRADITIONALDLL_API __declspec(dllimport)
#endif
extern "C" {
TRADITIONALDLL_API void TakesAnArray(int len, int[]);
}
void TakesAnArray(int len, int a[]) {
printf_s("[unmanaged]\n");
for (int i=0; i<len; i++)
printf("%d = %d\n", i, a[i]);
}
Управляемый модуль компилируется с помощью /clr
.
// MarshalBlitArray.cpp
// compile with: /clr
using namespace System;
using namespace System::Runtime::InteropServices;
value struct TraditionalDLL {
[DllImport("TraditionalDLL4.dll")]
static public void TakesAnArray(
int len,[MarshalAs(UnmanagedType::LPArray)]array<int>^);
};
int main() {
array<int>^ b = gcnew array<int>(3);
b[0] = 11;
b[1] = 33;
b[2] = 55;
TraditionalDLL::TakesAnArray(3, b);
Console::WriteLine("[managed]");
for (int i=0; i<3; i++)
Console::WriteLine("{0} = {1}", i, b[i]);
}
Часть библиотеки DLL не предоставляется управляемому коду с помощью традиционной #include
директивы. На самом деле, поскольку библиотека DLL доступна только во время выполнения, проблемы в функциях, импортированных с помощью, DllImportAttribute не могут быть обнаружены во время компиляции.
См. также
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по