Frage

Ich habe eine Visual Studio 2008 C# .NET 3.5 -Anwendung, die eine native Methode aufruft, die ein Dateihandle als Parameter akzeptiert. Ursprünglich habe ich gerade fileStream.Safefilehandle.dangerousgetHandle () verwendet, um den Dateihandle zu erhalten. Aber nachdem ich FX Cop eingeschaltet hatte, bekam ich eine CA2001 Warnung darüber. Nach ein wenig Nachforschungen entdeckte ich "eingeschränkte Ausführungsregionen". Das ist neu für mich und ich habe nicht viele Informationen darüber gesehen. Ich hatte gehofft, dass jemand, der mehr erfahren hat, einen Blick darauf werfen und sicherstellen konnte, dass ich dies richtig gemacht habe.

class MyClass
{
    public static bool Write(string filename)
    {
        using (var fs = new System.IO.FileStream(filename, 
            System.IO.FileMode.Create, 
            System.IO.FileAccess.Write, 
            System.IO.FileShare.None))
        {
            bool got_handle;
            bool result;

            System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions();
            try { }
            finally
            {
                fs.SafeFileHandle.DangerousAddRef(ref got_handle);
                result = NativeMethods.Foo(fs.SafeFileHandle.DangerousGetHandle());
                if (got_handle)
                    fs.SafeFileHandle.DangerousRelease();   
            }

            return result;
        }
    }
}

internal sealed class NativeMethods
{
    [DllImport("mylib.dll",
        EntryPoint = "Foo",
        CallingConvention = CallingConvention.StdCall,
        CharSet = CharSet.Unicode,
        ExactSpelling = true, 
        SetLastError = true)]
    public static extern bool Foo(IntPtr hFile);
}

Danke, Paulh

War es hilfreich?

Lösung

Sie tun hier mehrere Dinge.

  1. Führen Sie den Code im endgültigen Block aus, um Threadabortexzepte zu verhindern, während Ihr sicherer Code ausgeführt wird.

  2. Bevor der Versuch/schließlich den Sie als PrepareconstraedRegions bezeichnen, was im Grunde genommen nichts bewirkt, außer um zu überprüfen, ob genügend Thread -Stack -Speicherplatz vorhanden ist, um sicherzustellen, dass zumindest einige Methodenaufrufe getätigt werden können, sodass Ihr sicherer Code von einer StackoverFlowexception nicht unvorbereitet ist.

Ja, Sie Code sehen also so sicher wie möglich aus. Im Beamten Doku Über CERS wird angegeben, dass die CLR diese Try/schließlich auch blockiert und zusätzliche Maßnahmen ergreift. Nach dem, was ich gesehen habe, gibt es keinen großen Unterschied, außer dass sich auch nach dem Laufen Ihrer Cer -Code verzögert.

Um wirklich sicher zu sein, dass Ihr Code Ihren Erwartungen entspricht, sollten Sie Tests für diese Dinge erstellen.

  • Erschöpfung Stapel
  • Aus dem Gedächtnis
  • Thread.abort

Das Schreiben von zuverlässigem Code ist sehr schwierig und selbst die meisten BCL -Klassen sind nicht gehärtet Gegen solche Dinge, die Joe Duffy erklärt. Auch wenn Ihr Code nicht fehlschlägt, kann der BCL -Code. Sie erhalten keinen zusätzlichen Nutzen, wenn ein großer Teil des BCL -Code diese extremen Bedingungen genau definiert ist.

Mit freundlichen Grüßen Alois Kraus

Andere Tipps

Die wirklich sichere Möglichkeit, den SaferHandle anstelle der INTPTR -Referenz zu bestehen - die P/Invoke -Schicht ist sicherer Handle -Senkt und macht diese Arbeit automatisch. Die einzige Ausnahme dafür ist, wenn Sie die native API anrufen, um Ihren Griff zu schließen, da der SaferHandle während der Verwendung entsorgt wird.

Zum Beispiel:

[DllImport( "qwave.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true )]
internal static extern bool QOSCreateHandle( ref QosVersion version, out QosSafeHandle qosHandle );

[DllImport( "qwave.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true )]
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
internal static extern bool QOSCloseHandle( IntPtr qosHandle );

[DllImport( "qwave.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true )]
internal static extern bool QOSAddSocketToFlow(
    QosSafeHandle qosHandle,
    IntPtr socket,
    byte[] destAddr,
    QosTrafficType trafficType,
    QosFlowFlags flags,
    ref uint flowId
);


/// <summary>
/// Safely stores a handle to the QWave QoS win32 API and ensures the handle is properly 
/// closed when all references to the handle have been garbage collected.
/// </summary>
public class QosSafeHandle : SafeHandle
{
    /// <summary>
    /// Initializes a new instance of the QosSafeHandle class.
    /// </summary>
    public QosSafeHandle() :
        base( IntPtr.Zero, true )
    {
    }

    /// <summary>
    /// Whether or not the handle is invalid.
    /// </summary>
    public override bool IsInvalid
    {
        get { return this.handle == IntPtr.Zero; }
    }

    /// <summary>
    /// Releases the Qos API instance handle.
    /// </summary>
    /// <returns></returns>
    protected override bool ReleaseHandle()
    {
        QosNativeMethods.QOSCloseHandle( this.handle );
        return true;
    }
}

Dies ist jedoch möglicherweise nicht möglich, wenn die SaferHandle -Implementierung als Parameter in einer Struktur übergeben wird oder wenn der zugrunde liegende Griff mehr als ein INTPTR ist. Zum Beispiel verwendet die Win32 SSPI -API Handles, die zwei INTPTRs sind. Um mit dieser Situation umzugehen, muss man den CER manuell machen.

Ihre Cer -Verwendung ist falsch. DangerousAddRef kann immer noch scheitern. Das Folgende ist das von Microsoft in ihrer .NET -Quelle verwendete Muster:

public static bool Write( string filename )
{
    using( var fs = new System.IO.FileStream( filename,
        System.IO.FileMode.Create,
        System.IO.FileAccess.Write,
        System.IO.FileShare.None ) )
    {
        bool got_handle;
        bool result;

        // The CER is here to ensure that reference counting on fs.SafeFileHandle is never
        // corrupted. 
        RuntimeHelpers.PrepareConstrainedRegions();
        try
        {
            fs.SafeFileHandle.DangerousAddRef( ref got_handle );
        }
        catch( Exception e )
        {
            if( got_handle )
            {
                fs.SafeFileHandle.DangerousRelease();
            }

            got_handle = false;

            throw;
        }
        finally
        {
            if( got_handle )
            {
                result = NativeMethods.Foo( fs.SafeFileHandle.DangerousGetHandle() );

                fs.SafeFileHandle.DangerousRelease();
            }
        }

        return result;
    }
}

Sie können dieses Muster in der Microsoft-Referenzquelle erkennen. Siehe _SafenaThandle.cs, Zeile 2071.

Ich sehe nicht, wie Sie überhaupt Probleme haben könnten, es sei denn, Sie generieren Ausnahmen innerhalb der try Block.

  • Ist der Code in der finally Abschnitt Atomic?
  • Tut NativeMethods.Foo() Haben Sie eine Chance, Gedächtnis zu verlassen oder einen Thread abzubrechen?
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top