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, Denyi wyliczenia PermitOnlySecurityAction 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 SecurityActionAssertmodyfikatory , Denyi 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ą Assertmodyfikatory , Denyi 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();  
}  

Zobacz też