Skapa prototyper i hanterad kod
Det här avsnittet beskriver hur du får åtkomst till ohanterade funktioner och introducerar flera attributfält som kommenterar metoddefinition i hanterad kod. Exempel som visar hur du konstruerar . NET-baserade deklarationer som ska användas med plattformsanrop finns i Marshalling Data with Platform Invoke (Marshalling Data with Platform Invoke).
Innan du kan komma åt en ohanterad DLL-funktion från hanterad kod måste du känna till namnet på funktionen och namnet på den DLL som exporterar den. Med den här informationen kan du börja skriva den hanterade definitionen för en ohanterad funktion som implementeras i en DLL. Dessutom kan du justera hur plattformsanrop skapar funktionen och konverterar data till och från funktionen.
Kommentar
Med Windows API-funktioner som allokerar en sträng kan du frigöra strängen med hjälp av en metod som LocalFree
. Plattformsanrop hanterar sådana parametrar på olika sätt. För anrop av plattformsanrop gör du parametern till en IntPtr
typ i stället för en String
typ. Använd metoder som tillhandahålls av System.Runtime.InteropServices.Marshal klassen för att konvertera typen till en sträng manuellt och frigöra den manuellt.
Grundläggande deklaration
Hanterade definitioner för ohanterade funktioner är språkberoende, som du kan se i följande exempel. Mer fullständiga kodexempel finns i Exempel på plattformsanrop.
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
Om du vill tillämpa fälten DllImportAttribute.BestFitMapping, DllImportAttribute.CallingConvention, DllImportAttribute.ExactSpellingDllImportAttribute.PreserveSig, DllImportAttribute.SetLastErroreller DllImportAttribute.ThrowOnUnmappableChar på en Visual Basic-deklaration måste du använda DllImportAttribute attributet i stället för -instruktionenDeclare
.
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);
Justera definitionen
Oavsett om du anger dem explicit eller inte, fungerar attributfält som definierar beteendet för hanterad kod. Plattformsanrop fungerar enligt de standardvärden som anges för olika fält som finns som metadata i en sammansättning. Du kan ändra det här standardbeteendet genom att justera värdena för ett eller flera fält. I många fall använder DllImportAttribute du för att ange ett värde.
I följande tabell visas den fullständiga uppsättningen attributfält som gäller plattformsanrop. För varje fält innehåller tabellen standardvärdet och en länk till information om hur du använder dessa fält för att definiera ohanterade DLL-funktioner.
Fält | beskrivning |
---|---|
BestFitMapping | Aktiverar eller inaktiverar mappning med bästa passform. |
CallingConvention | Anger den anropskonvention som ska användas för att skicka metodargument. Standardvärdet är WinAPI , vilket motsvarar för de 32-bitars __stdcall Intel-baserade plattformarna. |
CharSet | Styr namn-mangling och hur strängargumenten ska kopplas till funktionen. Standardvärdet är CharSet.Ansi . |
EntryPoint | Anger den DLL-startpunkt som ska anropas. |
ExactSpelling | Styr om en startpunkt ska ändras så att den motsvarar teckenuppsättningen. Standardvärdet varierar beroende på programmeringsspråk. |
PreserveSig | Styr om signaturen för den hanterade metoden ska omvandlas till en ohanterad signatur som returnerar en HRESULT och har ytterligare ett [out, retval]-argument för returvärdet. Standardvärdet är true (signaturen ska inte transformeras). |
SetLastError | Gör att anroparen kan använda Marshal.GetLastWin32Error API-funktionen för att avgöra om ett fel uppstod när metoden kördes. I Visual Basic är true standardvärdet ; i C# och C++, är false standardvärdet . |
ThrowOnUnmappableChar | Styr utkastning av ett undantag på ett unicode-tecken som inte kan mappas och som konverteras till ett ANSI-tecken "?". |
Detaljerad referensinformation finns i DllImportAttribute.
Plattform som anropar säkerhetsöverväganden
Uppräkningsmedlemmarna , och PermitOnly
kallas för stack walk-modifierare. Deny
Assert
SecurityAction Dessa medlemmar ignoreras om de används som deklarativa attribut på plattformsanropsdeklarationer och IDL-instruktioner (COM Interface Definition Language).
Exempel på plattformsanrop
Plattformen anropar exempel i det här avsnittet illustrerar användningen av RegistryPermission
attributet med stack walk-modifierare.
I följande exempel SecurityActionAssert
ignoreras modifierarna , Deny
och PermitOnly
.
[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();
Modifieraren Demand
i följande exempel accepteras dock.
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]
[RegistryPermission(SecurityAction.Demand, Unrestricted = true)]
private static extern bool CallRegistryPermissionDeny();
SecurityAction modifierare fungerar korrekt om de placeras på en klass som innehåller (omsluter) plattformen anropar anropet.
[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 modifierare fungerar också korrekt i ett kapslat scenario där de placeras på anroparen för plattformsanropet:
{
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();
}
}
COM Interop-exempel
COM-interopexemplen i det här avsnittet illustrerar användningen av RegistryPermission
attributet med stack walk-modifierare.
Följande COM-interop-gränssnittsdeklarationer ignorerar Assert
modifierarna , Deny
och PermitOnly
, på samma sätt som plattformen anropar exempel i föregående avsnitt.
[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();
}
Dessutom Demand
accepteras inte modifieraren i deklarationsscenarier för COM-interop-gränssnittet, som du ser i följande exempel.
[ComImport, Guid("12345678-43E6-43c9-9A13-47F40B338DE0")]
interface IDemandStubsItf
{
[RegistryPermission(SecurityAction.Demand, Unrestricted = true)]
bool CallRegistryPermission();
[FileIOPermission(SecurityAction.Demand, Unrestricted = true)]
bool CallFileIoPermission();
}