Tworzenie prototypów w kodzie zarządzanym
W tym temacie opisano sposób uzyskiwania dostępu do funkcji niezarządzanych i wprowadzono kilka pól atrybutów, które dodają adnotację do definicji metody w kodzie zarządzanym. Przykłady demonstrujące sposób konstruowania elementu . Deklaracje oparte na platformie net, które mają być używane z wywołaniem platformy, zobacz Marshalling Data with Platform Invoke (Marshalling Data with Platform Invoke).
Aby uzyskać dostęp do niezarządzanej funkcji DLL z kodu zarządzanego, musisz znać nazwę funkcji i nazwę biblioteki DLL, która ją eksportuje. Dzięki tym informacjom można rozpocząć pisanie definicji zarządzanej dla niezarządzanej funkcji implementowanej w bibliotece DLL. Ponadto można dostosować sposób wywoływania przez platformę, tworząc funkcję i marshals danych do i z funkcji.
Uwaga
Funkcje interfejsu API systemu Windows, które przydzielają ciąg, umożliwiają zwolnienie ciągu przy użyciu metody takiej jak LocalFree
. Wywołanie platformy obsługuje takie parametry inaczej. W przypadku wywołań wywołań wywołań platformy należy ustawić parametr jako IntPtr
typ zamiast String
typu. Użyj metod dostarczanych przez klasę System.Runtime.InteropServices.Marshal , aby przekonwertować typ na ciąg ręcznie i zwolnić go ręcznie.
Podstawy deklaracji
Definicje zarządzane do funkcji niezarządzanych są zależne od języka, jak widać w poniższych przykładach. Aby uzyskać więcej kompletnych przykładów kodu, zobacz Przykłady wywołań platformy.
Friend Class NativeMethods
Friend Declare Auto Function MessageBox Lib "user32.dll" (
ByVal hWnd As IntPtr,
ByVal lpText As String,
ByVal lpCaption As String,
ByVal uType As UInteger) As Integer
End Class
Aby zastosować DllImportAttribute.BestFitMappingpola , , DllImportAttribute.CallingConvention, DllImportAttribute.ExactSpellingDllImportAttribute.PreserveSig, DllImportAttribute.SetLastErrorlub DllImportAttribute.ThrowOnUnmappableChar do deklaracji języka Visual Basic, należy użyć atrybutu DllImportAttribute zamiast instrukcji Declare
.
Imports System.Runtime.InteropServices
Friend Class NativeMethods
<DllImport("user32.dll", CharSet:=CharSet.Auto)>
Friend Shared Function MessageBox(
ByVal hWnd As IntPtr,
ByVal lpText As String,
ByVal lpCaption As String,
ByVal uType As UInteger) As Integer
End Function
End Class
using System;
using System.Runtime.InteropServices;
internal static class NativeMethods
{
[DllImport("user32.dll")]
internal static extern int MessageBox(
IntPtr hWnd, string lpText, string lpCaption, uint uType);
}
using namespace System;
using namespace System::Runtime::InteropServices;
[DllImport("user32.dll")]
extern "C" int MessageBox(
IntPtr hWnd, String* lpText, String* lpCaption, unsigned int uType);
Dostosowywanie definicji
Niezależnie od tego, czy ustawiasz je jawnie, czy nie, pola atrybutów są w pracy definiujące zachowanie kodu zarządzanego. Wywołanie platformy działa zgodnie z wartościami domyślnymi ustawionymi na różnych polach, które istnieją jako metadane w zestawie. To zachowanie domyślne można zmienić, dostosowując wartości jednego lub większej liczby pól. W wielu przypadkach należy użyć elementu , DllImportAttribute aby ustawić wartość.
W poniższej tabeli wymieniono pełny zestaw pól atrybutów odnoszących się do wywołania platformy. Dla każdego pola tabela zawiera wartość domyślną i link do informacji na temat sposobu używania tych pól do definiowania niezarządzanych funkcji bibliotek DLL.
Pole | opis |
---|---|
BestFitMapping | Włącza lub wyłącza mapowanie najlepiej dopasowane. |
CallingConvention | Określa konwencję wywoływania, która ma być używana w przekazywaniu argumentów metody. Wartość domyślna to WinAPI , która odpowiada __stdcall 32-bitowym platformom opartym na technologii Intel. |
CharSet | Kontroluje mangling nazw i sposób, w jaki argumenty ciągów powinny być przesłane do funkcji. Wartość domyślna to CharSet.Ansi . |
EntryPoint | Określa punkt wejścia biblioteki DLL, który ma być wywoływany. |
ExactSpelling | Określa, czy punkt wejścia powinien zostać zmodyfikowany tak, aby odpowiadał zestawowi znaków. Wartość domyślna zależy od języka programowania. |
PreserveSig | Określa, czy sygnatura metody zarządzanej powinna zostać przekształcona w niezarządzany podpis, który zwraca wartość HRESULT i ma dodatkowy argument [out, retval] dla wartości zwracanej. Wartość domyślna to true (podpis nie powinien być przekształcany). |
SetLastError | Umożliwia obiektowi wywołującemu używanie funkcji interfejsu Marshal.GetLastWin32Error API w celu określenia, czy wystąpił błąd podczas wykonywania metody. W języku Visual Basic wartość domyślna to true ; w języku C# i C++wartość domyślna to false . |
ThrowOnUnmappableChar | Kontrolki zgłaszające wyjątek dla niezastosowanego znaku Unicode konwertowanego na znak ANSI "?". |
Aby uzyskać szczegółowe informacje referencyjne, zobacz DllImportAttribute.
Zagadnienia dotyczące zabezpieczeń wywoływania platformy
Elementy Assert
, Deny
i wyliczenia PermitOnly
SecurityAction są określane jako modyfikatory stosu. Te elementy członkowskie są ignorowane, jeśli są one używane jako atrybuty deklaratywne na platformie wywołują deklaracje i instrukcje języka IDL (COM Interface Definition Language).
Przykłady wywołań platformy
Platforma wywołuje przykłady w tej sekcji ilustruje użycie atrybutu RegistryPermission
z modyfikatorami stosu.
W poniższym przykładzie SecurityActionAssert
modyfikatory , Deny
i PermitOnly
są ignorowane.
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]
[RegistryPermission(SecurityAction.Assert, Unrestricted = true)]
private static extern bool CallRegistryPermissionAssert();
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]
[RegistryPermission(SecurityAction.Deny, Unrestricted = true)]
private static extern bool CallRegistryPermissionDeny();
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]
[RegistryPermission(SecurityAction.PermitOnly, Unrestricted = true)]
private static extern bool CallRegistryPermissionDeny();
Demand
Jednak modyfikator w poniższym przykładzie jest akceptowany.
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]
[RegistryPermission(SecurityAction.Demand, Unrestricted = true)]
private static extern bool CallRegistryPermissionDeny();
SecurityAction Modyfikatory działają poprawnie, jeśli są one umieszczane w klasie zawierającej (zawijania) wywołanie wywołania platformy.
[RegistryPermission(SecurityAction.Demand, Unrestricted = true)]
public ref class PInvokeWrapper
{
public:
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]
private static extern bool CallRegistryPermissionDeny();
};
[RegistryPermission(SecurityAction.Demand, Unrestricted = true)]
class PInvokeWrapper
{
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]
private static extern bool CallRegistryPermissionDeny();
}
SecurityAction Modyfikatory działają również poprawnie w zagnieżdżonym scenariuszu, w którym są one umieszczane w wywołującym wywołaniu wywołania platformy:
{
public ref class PInvokeWrapper
public:
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]
private static extern bool CallRegistryPermissionDeny();
[RegistryPermission(SecurityAction.Demand, Unrestricted = true)]
public static bool CallRegistryPermission()
{
return CallRegistryPermissionInternal();
}
};
class PInvokeScenario
{
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]
private static extern bool CallRegistryPermissionInternal();
[RegistryPermission(SecurityAction.Assert, Unrestricted = true)]
public static bool CallRegistryPermission()
{
return CallRegistryPermissionInternal();
}
}
Przykłady międzyoperańcowe modelu COM
Przykłady międzyoperacyjności MODELU COM w tej sekcji ilustrują użycie atrybutu RegistryPermission
z modyfikatorami stosu.
Następujące deklaracje interfejsu międzyoperacyjności MODELU COM ignorują Assert
modyfikatory , Deny
i PermitOnly
podobnie jak w przypadku platformy wywołują przykłady w poprzedniej sekcji.
[ComImport, Guid("12345678-43E6-43c9-9A13-47F40B338DE0")]
interface IAssertStubsItf
{
[RegistryPermission(SecurityAction.Assert, Unrestricted = true)]
bool CallRegistryPermission();
[FileIOPermission(SecurityAction.Assert, Unrestricted = true)]
bool CallFileIoPermission();
}
[ComImport, Guid("12345678-43E6-43c9-9A13-47F40B338DE0")]
interface IDenyStubsItf
{
[RegistryPermission(SecurityAction.Deny, Unrestricted = true)]
bool CallRegistryPermission();
[FileIOPermission(SecurityAction.Deny, Unrestricted = true)]
bool CallFileIoPermission();
}
[ComImport, Guid("12345678-43E6-43c9-9A13-47F40B338DE0")]
interface IAssertStubsItf
{
[RegistryPermission(SecurityAction.PermitOnly, Unrestricted = true)]
bool CallRegistryPermission();
[FileIOPermission(SecurityAction.PermitOnly, Unrestricted = true)]
bool CallFileIoPermission();
}
Demand
Ponadto modyfikator nie jest akceptowany w scenariuszach deklaracji interfejsu międzyoperacyjności MODELU COM, jak pokazano w poniższym przykładzie.
[ComImport, Guid("12345678-43E6-43c9-9A13-47F40B338DE0")]
interface IDemandStubsItf
{
[RegistryPermission(SecurityAction.Demand, Unrestricted = true)]
bool CallRegistryPermission();
[FileIOPermission(SecurityAction.Demand, Unrestricted = true)]
bool CallFileIoPermission();
}