Udostępnij za pomocą


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, jak konstruować deklaracje oparte na .NET, które mają być używane z wywołaniem platformy, zobacz 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żesz dostosować sposób, w jaki platforma wywołuje funkcję oraz przetwarza dane do i z funkcji.

Uwaga / Notatka

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ń platformowych ustaw parametr jako typ IntPtr zamiast typu String. 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ć pola DllImportAttribute.BestFitMapping, DllImportAttribute.CallingConvention, DllImportAttribute.ExactSpelling, DllImportAttribute.PreserveSig, DllImportAttribute.SetLastError lub DllImportAttribute.ThrowOnUnmappableChar do deklaracji w 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 pracują nad definiowaniem zachowania 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.

(No changes needed) 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 zmiany nazw i sposób, w jaki argumenty tekstowe powinny być przekazywane 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 Kontroluje rzucanie wyjątku w przypadku nieodwzorowanego znaku Unicode, który jest konwertowany na znak ANSI „?”.

Aby uzyskać szczegółowe informacje referencyjne, zobacz DllImportAttribute.

Zagadnienia dotyczące zabezpieczeń wywoływania platformy

Assert, Deny oraz PermitOnly członkowie wyliczenia SecurityAction są określani jako modyfikatory stosu. Te członki są ignorowane, jeśli są używane jako atrybuty deklaratywne w deklaracjach wywołujących platformę i instrukcjach IDL (Interface Definition Language COM).

Przykłady wywołań platformy

Przykłady wywołań na platformie w tej sekcji przedstawiają 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ą umieszczane w klasie obejmującej wywołanie 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ą umieszczane na wywołującym platformowe wywołanie.

      {  
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 interoperacyjności COM

Przykłady interop COM w tej sekcji ilustrują użycie atrybutu RegistryPermission z modyfikatorami stosu.

Następujące deklaracje interfejsu międzyoperacyjności COM ignorują modyfikatory Assert, Deny, i PermitOnly, podobnie jak przykłady wywołania platformy 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();  
}  

Ponadto, modyfikator Demand nie jest akceptowany w scenariuszach deklaracji interfejsu międzyoperacyjności 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 także