Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
In questo argomento viene descritto come accedere a funzioni non gestite e vengono introdotti diversi campi di attributo che annotano la definizione del metodo nel codice gestito. Per esempi che illustrano come costruire dichiarazioni basate su .NET da usare con platform invoke, vedere Marshalling dei dati con Platform Invoke.
Prima di poter accedere a una funzione DLL non gestita dal codice gestito, è necessario conoscere il nome della funzione e il nome della DLL che la esporta. Con queste informazioni, è possibile iniziare a scrivere la definizione gestita per una funzione non gestita implementata in una DLL. Inoltre, è possibile modificare il modo in cui platform invoke crea la funzione e effettua il marshalling dei dati da e verso la funzione.
Annotazioni
Le funzioni API di Windows che allocano una stringa consentono di liberare la stringa usando un metodo come LocalFree
. Platform invoke gestisce tali parametri in modo diverso. Per le chiamate platform invoke, usare il tipo IntPtr
invece del tipo String
. Usare i metodi forniti dalla System.Runtime.InteropServices.Marshal classe per convertire manualmente il tipo in una stringa e liberarlo manualmente.
Nozioni di base sulla dichiarazione
Le definizioni gestite per le funzioni non gestite dipendono dal linguaggio, come illustrato negli esempi seguenti. Per esempi di codice più completi, vedere Esempi di platform invoke.
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
Per applicare i campi DllImportAttribute.BestFitMapping, DllImportAttribute.CallingConvention, DllImportAttribute.ExactSpelling, DllImportAttribute.PreserveSig, DllImportAttribute.SetLastError o DllImportAttribute.ThrowOnUnmappableChar a una dichiarazione di Visual Basic, è necessario utilizzare l'attributo DllImportAttribute invece dell'istruzione 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);
Modifica della definizione
Indipendentemente dal fatto che vengano impostati in modo esplicito o meno, i campi degli attributi sono in fase di lavoro definendo il comportamento del codice gestito. Platform invoke opera in base ai valori predefiniti impostati su vari campi esistenti come metadati in un assembly. È possibile modificare questo comportamento predefinito modificando i valori di uno o più campi. In molti casi, si usa DllImportAttribute per impostare un valore.
La tabella seguente elenca il set completo di campi di attributo relativi a platform invoke. Per ogni campo, la tabella include il valore predefinito e un collegamento alle informazioni su come usare questi campi per definire funzioni DLL non gestite.
Campo | Descrizione |
---|---|
BestFitMapping | Abilita o disabilita il mapping più adatto. |
CallingConvention | Specifica la convenzione di chiamata da utilizzare per passare gli argomenti del metodo. Il valore predefinito è WinAPI , che corrisponde a __stdcall per le piattaforme Intel basate su 32 bit. |
CharSet | Controlla il mangling dei nomi e il modo in cui gli argomenti di tipo stringa devono essere sottoposti a marshalling alla funzione. Il valore predefinito è CharSet.Ansi . |
EntryPoint | Specifica il punto di ingresso della DLL da chiamare. |
ExactSpelling | Controlla se un punto di ingresso deve essere modificato in modo che corrisponda al set di caratteri. Il valore predefinito varia in base al linguaggio di programmazione. |
PreserveSig | Controlla se la firma del metodo gestito deve essere trasformata in una firma non gestita che restituisce un HRESULT e ha un argomento [out, retval] aggiuntivo per il valore restituito. Il valore predefinito è true (la firma non deve essere trasformata). |
SetLastError | Consente al chiamante di usare la Marshal.GetLastWin32Error funzione API per determinare se si è verificato un errore durante l'esecuzione del metodo. In Visual Basic il valore predefinito è true ; in C# e C++, il valore predefinito è false . |
ThrowOnUnmappableChar | Controlla il lancio di un'eccezione su un carattere Unicode non mappabile convertito in un carattere ANSI "?". |
Per informazioni di riferimento dettagliate, vedere DllImportAttribute.
Considerazioni sulla sicurezza di Platform Invoke
I membri Assert
, Deny
e PermitOnly
dell'enumerazione SecurityAction vengono definiti modificatori del cammino dello stack. Questi membri vengono ignorati se vengono usati come attributi dichiarativi nelle dichiarazioni platform invoke e nelle istruzioni IDL (COM Interface Definition Language).
Esempi di Platform Invoke
Gli esempi di platform invoke in questa sezione illustrano l'uso dell'attributo RegistryPermission
con i modificatori della scansione dello stack.
Nell'esempio seguente i SecurityActionAssert
modificatori , Deny
e PermitOnly
vengono ignorati.
[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();
Tuttavia, il Demand
modificatore nell'esempio seguente viene accettato.
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]
[RegistryPermission(SecurityAction.Demand, Unrestricted = true)]
private static extern bool CallRegistryPermissionDeny();
SecurityAction I modificatori funzionano correttamente se vengono posizionati in una classe che racchiude la chiamata a platform invoke.
[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 I modificatori funzionano correttamente anche in uno scenario annidato in cui vengono posizionati sul chiamante della chiamata platform invoke:
{
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();
}
}
Esempi di interoperabilità COM
Gli esempi di interoperabilità COM in questa sezione illustrano l'uso dell'attributo RegistryPermission
con i modificatori dell'analisi dello stack.
Le dichiarazioni di interfaccia di interoperabilità COM seguenti ignorano i Assert
modificatori , Deny
e PermitOnly
, in modo analogo agli esempi di platform invoke nella sezione precedente.
[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();
}
Inoltre, il Demand
modificatore non viene accettato negli scenari di dichiarazione dell'interfaccia di interoperabilità COM, come illustrato nell'esempio seguente.
[ComImport, Guid("12345678-43E6-43c9-9A13-47F40B338DE0")]
interface IDemandStubsItf
{
[RegistryPermission(SecurityAction.Demand, Unrestricted = true)]
bool CallRegistryPermission();
[FileIOPermission(SecurityAction.Demand, Unrestricted = true)]
bool CallFileIoPermission();
}