IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Použitie Windows API v C # .NET - 4. diel

Doteraz sme riešili implementáciu API do programu skôr intuíciou a v mnohých prípadoch zavádzame do programu chyby, ktoré sa veľmi ťažko hľadajú. Ak nahliadneme do implementácie API do .NET Frameworku, zistíme, že približne 20% API je riešené pomocou ukazovateľov (pointer) a tak zvaným nebezpečným kódom (unsafe). Dôvod je prostý, lepšia optimalizácia a rýchlosť programu. V ďalších tutoriáloch sa naučíme ako programovať tento unsafe kód. Pre lepšiu efektivitu našej práce doinštalujeme do Visual Studia balíček PInvoke.net, ktorý nám veľmi uľahčí prácu.

PInvoke.net

Inštalácia balíčka cez správcu rozšírení je veľmi jednoduchá a myslím si, že nie je nutný ďalší popis.

Inštalácia rozšírenia PInvoke.net do Visual Studia - C # - Pre pokročilých

Ak zadáme napríklad API ReadFile (), sú nám ponúknuté štyri varianty v C# a dva varianty pre VB.NET:

PInvoke_2 - C # - Pre pokročilých

Variant dve a štyri používa nové kľúčové slovo unsafe a to znamená, že funkcia bude používať nebezpečný kód a bude využívať ukazovatele. Tiež príklad s uvedenou API používa nebezpečný kód.

public class Class1
{
    //1
    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer,
    uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped);

    //2
    [DllImport("kernel32.dll", SetLastError = true)]
    static extern unsafe int ReadFile(IntPtr handle, IntPtr bytes, uint numBytesToRead,
    IntPtr numBytesRead, NativeOverlapped* overlapped);

    //3
    [DllImport("kernel32.dll", SetLastError=true)]
    static extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer, uint nNumberOfBytesToRead,
    out uint lpNumberOfBytesRead, [In] ref System.Threading.NativeOverlapped lpOverlapped);

    //4
    [DllImport(@"kernel32.dll", SetLastError = true)]
    static extern unsafe bool ReadFile(
    SafeFileHandle hFile,       // handle to file
    byte* pBuffer,              // data buffer, should be fixed
    int NumberOfBytesToRead,    // number of bytes to read
    IntPtr pNumberOfBytesRead,  // number of bytes read, provide IntPtr.Zero here
    NativeOverlapped *lpOverlapped // should be fixed, if not IntPtr.Zero
    );

    // This is taken from the USBSharp.cs class
    public unsafe byte[] CT_ReadFile(int InputReportByteLength)
    {
        int BytesRead = 0;
        byte[] BufBytes = new byte[InputReportByteLength];
        if (ReadFile(HidHandle, BufBytes, InputReportByteLength, ref BytesRead, null))
        {
            byte[] OutBytes = new byte[BytesRead];
            Array.Copy(BufBytes, OutBytes, BytesRead);
            return OutBytes;
        }
        else
        {
            return null;
        }
    }
}

Veľkou výhodou je automatické načítanie kódu do Visual Studia.

Nahliadnutie pod pokrievku .NET frameworku

Pozrime sa pod pokrievku .NET frameworku. Najprv vykonáme dekompiláciu napríklad System.Core:

// Type: System.IO.Pipes.AnonymousPipeServerStream
// Assembly: System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// MVID: BA37026F-1371-4849-854A-E2CCE7CAD02B
// Assembly location: C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Core.dll

using Microsoft.Win32.SafeHandles;
using System;
using System.IO;
using System.Runtime;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;

namespace System.IO.Pipes
{
    [HostProtection(SecurityAction.LinkDemand, MayLeakOnAbort = true)]
    public sealed class AnonymousPipeServerStream : PipeStream
    {
        private SafePipeHandle m_clientHandle;
        private bool m_clientHandleExposed;

    //nějaký kód


    [SecurityCritical]
        private void Create(PipeDirection direction, Microsoft.Win32.UnsafeNativeMethods.SECURITY_ATTRIBUTES
        secAttrs, int bufferSize)
        {
            SafePipeHandle hSourceHandle;
            if (!(direction != PipeDirection.In ? Microsoft.Win32.UnsafeNativeMethods.CreatePipe(out
        this.m_clientHandle, out hSourceHandle, secAttrs, bufferSize) :
           Microsoft.Win32.UnsafeNativeMethods.CreatePipe(out hSourceHandle, out this.m_clientHandle,
         secAttrs, bufferSize)))
                __Error.WinIOError(Marshal.GetLastWin32Error(), string.Empty);
            SafePipeHandle lpTargetHandle;
    if(!Microsoft.Win32.UnsafeNativeMethods.DuplicateHandle(
    Microsoft.Win32.UnsafeNativeMethods.GetCurrentProcess(), hSourceHandle,
    Microsoft.Win32.UnsafeNativeMethods.GetCurrentProcess(), out lpTargetHandle, 0U, false, 2U))
                __Error.WinIOError(Marshal.GetLastWin32Error(), string.Empty);
            hSourceHandle.Dispose();
            this.InitializeHandle(lpTargetHandle, false, false);
            this.State = PipeState.Connected;
        }
    }
}

Tu vidíme neznáme using Microsoft.Win32­.UnsafeNative­Methods. Ak túto triedu dekompiluje:

// Type: Microsoft.Win32.UnsafeNativeMethods
// Assembly: System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// MVID: BA37026F-1371-4849-854A-E2CCE7CAD02B
// Assembly location: C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Core.dll

using Microsoft.Win32.SafeHandles;
using System;
using System.Diagnostics.Eventing;
using System.Diagnostics.Eventing.Reader;
using System.IO;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using System.Threading;

namespace Microsoft.Win32
{
    internal static readonly IntPtr NULL = IntPtr.Zero;
    internal const string KERNEL32 = "kernel32.dll";
    internal const string ADVAPI32 = "advapi32.dll";
    internal const string WEVTAPI = "wevtapi.dll";
    internal const int CREDUI_MAX_USERNAME_LENGTH = 513;
    internal const int ERROR_SUCCESS = 0;
    internal const int ERROR_FILE_NOT_FOUND = 2;
    internal const int ERROR_PATH_NOT_FOUND = 3;
    internal const int ERROR_ACCESS_DENIED = 5;

    //pokračují další konstanty

    [SecurityCritical]
    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
    [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool FreeLibrary(IntPtr hModule);

    [SecurityCritical]
    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
    [DllImport("advapi32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool RevertToSelf();

    [SecurityCritical]
    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
    [DllImport("advapi32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool ImpersonateNamedPipeClient(SafePipeHandle hNamedPipe);

    //Další funkce API použité v System.Core

Dôležitý poznatok teda je, že vývojári .NET frameworku majú k dispozícii nešpecifikované triedy, ktoré obsahujú Pinvoke všetkých API funkcií.

Importované funkcie majú dodané atribúty, pokúsim sa ich v stručnosti popísať.

[HostProtection (SecurityActi­on.LinkDemand, MayLeakOnAbort = true)]

  • HostProtectio­nAttribute - Táto trieda umožňuje používať deklarované zabezpečenie akcie a určiť požiadavky na ochranu hostiteľa.
  • SecurityAction­.LinkDemand (podporované rozhraním XNA) - Nepoužívať v .NET Framework 4. Pridelí oprávnenia volajúcemu.
  • MayLeakOnAbort = true - Kód ukončenie môže spôsobiť únik pamäti, ak nie sú chránené bezpečným popisovačom alebo nie je iným spôsobom zabezpečiť uvoľnenie pamäte.

[SecurityCriti­cal]

  • Je ekvivalentná pre odkaz na úplný vzťah dôveryhodnosti.
  • Typ alebo člena označeného SecurityCriti­calAttribute možno volať len prostredníctvom plne dôveryhodného kódu. Nemôže byť volaný z čiastočne dôveryhodného kódu.

[PermissionSet (SecurityActi­on.Demand, Name = "FullTrust")]

  • Kód môže volať držiteľ špeciálneho oprávnenia.

SecuritySafeCri­tical

  • Typy alebo členmi označené SecuritySafeCri­ticalAttribute - Atribút pre prístup k čiastočne dôveryhodnému typu a členovi.

Pre milovníkov dobrého kódu je zaujímavé uvoľňovanie alokovanej pamäte v triede System.IO.Pipes

Ukážka prekladu:

preklad - C # - Pre pokročilých

Záver

Na záver som do zdrojových kódov pridal celú triedu class UnsafeNativeMet­hods a niekoľko tried, ktoré ju volajú. Pre milovníkov kódu je to veľmi poučná pasáž, ukážka rieši ako programujú profesionáli. Tým ale nemyslím seba. V ďalších častiach popíšem nebezpečný kód založený na použití pointer a uvediem niekoľko príkladov. Príjemné čítanie.


 

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 72x (17.08 kB)
Aplikácia je vrátane zdrojových kódov v jazyku C#

 

Všetky články v sekcii
C # - Pre pokročilých
Článok pre vás napísal zpavlu
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
C# , C++ a assembler
Aktivity