Porady: kierowanie ciągów za pomocą funkcji PInvoke
W tym temacie wyjaśniono sposób macierzysty funkcji, które akceptują ciągi stylu C może być wywoływana przy użyciu ciągu CLR wpisz System::String korzystanie z obsługi wywołanie platformy.NET Framework.Programiści Visual C++ są zachęcani do zamiast korzystać z funkcji C++ Interop (jeśli możliwe), ponieważ P i Invoke zawiera niewiele kompilacji raportowanie błędów, nie jest typu palety i może być uciążliwe do wdrożenia.Jeśli API niezarządzanego, jest dostarczana w bibliotekę DLL, a kod źródłowy nie jest dostępny, a następnie P i Invoke jest jedyną opcją, ale w przeciwnym razie zobacz Korzystanie z międzyoperacyjności języka C++ (niejawna funkcja PInvoke).
Zarządzany i niezarządzany ciągi są określone inaczej w pamięci, więc przechodzącą ciągi z zarządzanych do niezarządzanych funkcji wymaga MarshalAsAttribute atrybutu, aby nakazać kompilatorowi Wstaw mechanizmów konwersję wymagane dla przekazywania międzyprocesowego danych string poprawnie i bezpiecznie.
Funkcje używające tylko typy wewnętrzne dane, DllImportAttribute jest używany do zadeklarować punkty wejścia zarządzanych do macierzystych funkcji, ale--ciągi--bez określenia te punkty wejścia jak przy ciągi stylu C, dojścia do procesu przesyłania String można użyć zamiast tego typu.Powoduje to wyświetlenie kompilatora, aby wstawić kod, który wykonuje konwersję wymagane.Dla każdego argumentu funkcji w niezarządzanych funkcji, która pobiera ciąg MarshalAsAttribute atrybut powinien być używany, aby wskazać, że obiekt String należy zorganizować macierzystych funkcji jako ciąg stylu C.
Przykład
Poniższy kod składa się z modułu zarządzane i niezarządzane.Moduł niezarządzanych to biblioteki DLL, która zawiera definicję funkcji o nazwie TakesAString, która akceptuje ciąg ANSI C stylu w formie char *.Moduł zarządzany jest aplikacją wiersza polecenia, która importuje funkcji TakesAString, ale definiuje go jako biorąc zarządzanych System.String zamiast char *.MarshalAsAttribute Atrybut jest używany do wskazania, jak należy zorganizować zarządzanych ciąg po nazywa się TakesAString.
Moduł zarządzany jest skompilowany z/CLR, ale/CLR: pure działa jak również.
// 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);
}
// 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);
}
Ta technika sprawia, że kopię ciągu skonstruowano na stercie niezarządzanych, więc zmiany wprowadzone do ciągu przy użyciu funkcji macierzystego nie znajdziesz w zarządzanych kopię ciąg.
Należy zauważyć, że żadna część biblioteki DLL jest narażony na kod zarządzany za pośrednictwem tradycyjnych # dyrektywy include.W rzeczywistości, biblioteka DLL jest dostępny w czasie wykonywania, więc problemów z funkcjami importowane z DllImport nie zostaną wykryte w czasie kompilacji.
Zobacz też
Inne zasoby
Używanie jawnej funkcji PInvoke w języku C++ (atrybut DllImport)