Share via


Esempio di HandleRef

In questo esempio viene dimostrato come evitare la procedura di Garbage Collection su un oggetto gestito prima del completamento della funzione non gestita. Viene inoltre illustrato come utilizzare l'overload di funzione per passare un riferimento null (Nothing in Visual Basic) anziché un riferimento a un tipo di valore.

Nell'esempio di HandleRef viene utilizzata la seguente funzione non gestita, illustrata con la dichiarazione di funzione originale:

  • ReadFile esportata da Kernel32.dll.

    BOOL ReadFile(
       HANDLE hFile, 
       LPVOID lpBuffer, 
       DWORD nNumberOfBytesToRead, 
       LPDWORD lpNumberOfBytesRead, 
       LPOVERLAPPED lpOverlapped);
    

La struttura originale passata alla funzione contiene i seguenti elementi:

typedef struct _OVERLAPPED { 
    ULONG_PTR  Internal; 
    ULONG_PTR  InternalHigh; 
    DWORD  Offset; 
    DWORD  OffsetHigh; 
    HANDLE hEvent; 
} OVERLAPPED; 

In questo esempio la struttura Overlapped e la classe Overlapped2 contengono i tipi IntPtr invece dei tipi di puntatore e del tipo HANDLE. L'attributo StructLayoutAttribute viene impostato in modo che i membri vengano disposti in sequenza nella memoria, nell'ordine in cui appaiono.

La classe LibWrap contiene i prototipi gestiti dei metodi ReadFile e ReadFile2. ReadFile passa la struttura Overlapped come uno dei parametri. Mediante l'overload del metodo ReadFile, se necessario è possibile passare nell'esempio un riferimento null (Nothing in Visual Basic) anziché un riferimento alla struttura. Né in C# né in Visual Basic 2005 è possibile passare direttamente un riferimento null (Nothing).

ReadFile2 passa la classe Overlapped2. Le classi, che sono tipi di riferimento, vengono passate come parametri in per impostazione predefinita. L'applicazione degli attributi InAttribute e OutAttribute alla dichiarazione provoca il marshalling di Overlapped2 come parametro in/out. L'esempio consente di passare direttamente un riferimento null (Nothing) anziché una classe, se necessario, poiché le classi costituiscono tipi di riferimento al posto dei quali è possibile passare un riferimento null (Nothing). Con la classe App viene creato un wrapper HandleRef per FileStream per evitare la procedura di Garbage Collection prima del completamento delle chiamate a ReadFile o ReadFile2.

Dichiarazione dei prototipi

' Declares a managed structure for the unmanaged structure.
<StructLayout(LayoutKind.Sequential)> _
Public Structure Overlapped
    ' ...
End Structure

' Declares a managed class for the unmanaged structure.
<StructLayout(LayoutKind.Sequential)> _
Public Class Overlapped2
    ' ...
End Class

Public Class LibWrap
    ' Declares a managed prototypes for unmanaged functions.
    ' Because Overlapped is a structure, you cannot pass Nothing as a
    ' parameter. Instead, declares an overloaded method.
    Overloads Declare Ansi Function ReadFile Lib "Kernel32.dll" ( _
        ByVal hndRef As HandleRef, _
        ByVal buffer As StringBuilder, _
        ByVal numberOfBytesToRead As Integer, _
        ByRef numberOfBytesRead As Integer, _
        ByRef flag As Overlapped) As Boolean

    ' Declares an int instead of a structure reference for 'flag'
    Overloads Declare Ansi Function ReadFile Lib "Kernel32.dll" ( _
        ByVal hndRef As HandleRef, _
        ByVal buffer As StringBuilder, _
        ByVal numberOfBytesToRead As Integer, _
        ByRef numberOfBytesRead As Integer, _
        ByVal flag As IntPtr) As Boolean

    ' Because Overlapped2 is a class, you can pass Nothing as a parameter.
    ' No overloading is needed.
    Declare Ansi Function ReadFile2 Lib "Kernel32.dll" Alias "ReadFile" ( _
        ByVal hndRef As HandleRef, _
        ByVal buffer As StringBuilder, _
        ByVal numberOfBytesToRead As Integer, _
        ByRef numberOfBytesRead As Integer, _
        <[In], Out> ByVal flag As Overlapped2) As Boolean
End Class
// Declares a managed structure for the unmanaged structure.
[StructLayout(LayoutKind.Sequential)]
public struct Overlapped
{
    // ...
}

// Declares a managed class for the unmanaged structure.
[StructLayout(LayoutKind.Sequential)]
public class Overlapped2
{
    // ...
}

public class LibWrap
{
   // Declares managed prototypes for unmanaged functions.
   // Because Overlapped is a structure, you cannot pass null as a
   // parameter. Instead, declares an overloaded method.
    [DllImport("Kernel32.dll")]
    public static extern bool ReadFile(
        HandleRef hndRef,
        StringBuilder buffer,
        int numberOfBytesToRead,
        out int numberOfBytesRead,
        ref Overlapped flag );

    [DllImport("Kernel32.dll")]
    public static extern bool ReadFile(
        HandleRef hndRef,
        StringBuilder buffer,
        int numberOfBytesToRead,
        out int numberOfBytesRead,
        IntPtr flag ); // Declares an int instead of a structure reference.

    // Because Overlapped2 is a class, you can pass null as parameter.
    // No overloading is needed.
    [DllImport("Kernel32.dll", EntryPoint="ReadFile")]
    public static extern bool ReadFile2(
        HandleRef hndRef,
        StringBuilder buffer,
        int numberOfBytesToRead,
        out int numberOfBytesRead,
        Overlapped2 flag);
}
// Declares a managed structure for the unmanaged structure.
[StructLayout(LayoutKind::Sequential)]
public value struct Overlapped
{
    // ...
};

// Declares a managed class for the unmanaged structure.
[StructLayout(LayoutKind::Sequential)]
public ref class Overlapped2
{
    // ...
};

public ref class LibWrap
{
public:
    // Declares managed prototypes for unmanaged functions.
    // Because Overlapped is a structure, you cannot pass null as a
    // parameter. Instead, declares an overloaded method.
    [DllImport("Kernel32.dll")]
    static bool ReadFile(
        HandleRef hndRef,
        StringBuilder^ buffer,
        int numberOfBytesToRead,
        int numberOfBytesRead,
        Overlapped% flag );

    [DllImport("Kernel32.dll")]
    static bool ReadFile(
        HandleRef hndRef,
        StringBuilder^ buffer,
        int numberOfBytesToRead,
        int% numberOfBytesRead,
        IntPtr flag ); // Declares an int instead of a structure reference.

    // Because Overlapped2 is a class, you can pass null as parameter.
    // No overloading is needed.
    [DllImport("Kernel32.dll", EntryPoint="ReadFile")]
    static bool ReadFile2(
        HandleRef hndRef,
        StringBuilder^ buffer,
        int numberOfBytesToRead,
        int% numberOfBytesRead,
        Overlapped2^ flag);
};

Chiamata delle funzioni

Public Class App
    Public Shared Sub Main()
        Dim fs As New FileStream("HandleRef.txt", FileMode.Open)
        ' Wraps the FileStream handle in HandleRef to prevent it
        ' from being garbage collected before the call ends.
        Dim hr As New HandleRef(fs, fs.SafeFileHandle.DangerousGetHandle())
        Dim buffer As New StringBuilder(5)
        Dim read As Integer = 0
        ' Platform invoke holds the reference to HandleRef until the
        ' call ends.
        LibWrap.ReadFile(hr, buffer, 5, read, IntPtr.Zero)
        Console.WriteLine("Read {0} bytes with struct parameter: {1}", read, buffer)
        LibWrap.ReadFile2(hr, buffer, 5, read, Nothing)
        Console.WriteLine("Read {0} bytes with class parameter: {1}", read, buffer)
    End Sub
End Class
public class App
{
    public static void Main()
    {
        FileStream fs = new FileStream("HandleRef.txt", FileMode.Open);
        // Wraps the FileStream handle in HandleRef to prevent it
        // from being garbage collected before the call ends.
        HandleRef hr = new HandleRef(fs, fs.SafeFileHandle.DangerousGetHandle());
        StringBuilder buffer = new StringBuilder(5);
        int read = 0;
        // Platform invoke holds a reference to HandleRef until the call
        // ends.
        LibWrap.ReadFile(hr, buffer, 5, out read, IntPtr.Zero);
        Console.WriteLine("Read {0} bytes with struct parameter: {1}", read, buffer);
        LibWrap.ReadFile2(hr, buffer, 5, out read, null);
        Console.WriteLine("Read {0} bytes with class parameter: {1}", read, buffer);
    }
}
public ref class App
{
public:
    static void Main()
    {
        FileStream^ fs = gcnew FileStream("HandleRef.txt", FileMode::Open);
        // Wraps the FileStream handle in HandleRef to prevent it
        // from being garbage collected before the call ends.
        HandleRef hr = HandleRef(fs, fs->SafeFileHandle->DangerousGetHandle());
        StringBuilder^ buffer = gcnew StringBuilder(5);
        int read = 0;
        // Platform invoke holds a reference to HandleRef until the call
        // ends.
        LibWrap::ReadFile(hr, buffer, 5, read, IntPtr::Zero);
        Console::WriteLine("Read {0} bytes with struct parameter: {1}", read, buffer);
        LibWrap::ReadFile2(hr, buffer, 5, read, nullptr);
        Console::WriteLine("Read {0} bytes with class parameter: {1}", read, buffer);
    }
};

Vedere anche

Concetti

Esempi vari di marshalling

Tipi di dati di platform invoke

Creazione di prototipi nel codice gestito