程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C# 程序員參考--不安全代碼教學文章

C# 程序員參考--不安全代碼教學文章

編輯:C#入門知識

該教程說明如何在 C# 中使用不安全代碼(使用指針的代碼)。

教程

在 C# 中很少需要使用指針,但仍有一些需要使用的情況。例如,在下列情況中使用允許采用指針的不安全上下文是正確的:

  • 處理磁盤上的現有結構
  • 涉及內部包含指針的結構的高級 COM 或平台調用方案
  • 性能關鍵代碼

不鼓勵在其他情況下使用不安全上下文。具體地說,不應該使用不安全上下文嘗試在 C# 中編寫 C 代碼。

警告   使用不安全上下文編寫的代碼無法被驗證為安全的,因此只有在代碼完全受信任時才會執行該代碼。換句話說,不可以在不受信任的環境中執行不安全代碼。例如,不能從 Internet 上直接運行不安全代碼。

該教程包括下列示例:

  • 示例 1   使用指針復制一個字節數組。
  • 示例 2   顯示如何調用 Windows ReadFile 函數。
  • 示例 3   顯示如何打印可執行文件的 Win32 版本。

示例 1

以下示例使用指針將一個字節數組從 src 復制到 dst。用 /unsafe 選項編譯此示例。

// fastcopy.cs



// compile with: /unsafe



using System;



 



class Test



{



    // The unsafe keyword allows pointers to be used within



    // the following method:



    static unsafe void Copy(byte[] src, int srcIndex,



        byte[] dst, int dstIndex, int count)



    {



        if (src == null || srcIndex < 0 ||



            dst == null || dstIndex < 0 || count < 0)



        {



            throw new ArgumentException();



        }



        int srcLen = src.Length;



        int dstLen = dst.Length;



        if (srcLen - srcIndex < count ||



            dstLen - dstIndex < count)



        {



            throw new ArgumentException();



        }



 



 



            // The following fixed statement pins the location of



            // the src and dst objects in memory so that they will



            // not be moved by garbage collection.          



            fixed (byte* pSrc = src, pDst = dst)



            {



                  byte* ps = pSrc;



                  byte* pd = pDst;







            // Loop over the count in blocks of 4 bytes, copying an



            // integer (4 bytes) at a time:



            for (int n =0 ; n < count/4 ; n++)



            {



                *((int*)pd) = *((int*)ps);



                pd += 4;



                ps += 4;



            }



 



            // Complete the copy by moving any bytes that weren't



            // moved in blocks of 4:



            for (int n =0; n < count%4; n++)



            {



                *pd = *ps;



                pd++;



                ps++;



            }



            }



    }



 



 



    static void Main(string[] args) 



    {



        byte[] a = new byte[100];



        byte[] b = new byte[100];



        for(int i=0; i<100; ++i) 



           a[i] = (byte)i;



        Copy(a, 0, b, 0, 100);



        Console.WriteLine("The first 10 elements are:");



        for(int i=0; i<10; ++i) 



           Console.Write(b[i] + " ");



        Console.WriteLine("\n");



    }



}

輸出示例

The first 10 elements are:



0 1 2 3 4 5 6 7 8 9

代碼討論

  • 請注意使用了 unsafe 關鍵字,這允許在 Copy 方法內使用指針。
  • fixed 語句用於聲明指向源和目標數組的指針。它鎖定 srcdst 對象在內存中的位置以便使其不會被垃圾回收移動。當 fixed 塊完成後,這些對象將被解除鎖定。
  • 通過略過數組界限檢查,不安全代碼可提高性能。

示例 2

[1] [2] [3] [4] 下一頁  

示例顯示如何從 Platform SDK 調用 Windows ReadFile 函數,這要求使用不安全上下文,因為讀緩沖區需要將指針作為參數。

// readfile.cs



// compile with: /unsafe



// arguments: readfile.cs



 



// Use the program to read and display a text file.



using System;



using System.Runtime.InteropServices;



using System.Text;



 



class FileReader



{



      const uint GENERIC_READ = 0x80000000;



      const uint OPEN_EXISTING = 3;



      IntPtr handle;



 



      [DllImport("kernel32", SetLastError=true)]



      static extern unsafe IntPtr CreateFile(



            string FileName,                    // file name



            uint DesiredAccess,                 // access mode



            uint ShareMode,                     // share mode



            uint SecurityAttributes,            // Security Attributes



            uint CreationDisposition,           // how to create



            uint FlagsAndAttributes,            // file attributes



            int hTemplateFile                   // handle to template file



            );



 



       [DllImport("kernel32", SetLastError=true)]



      static extern unsafe bool ReadFile(



            IntPtr hFile,                       // handle to file



            void* pBuffer,                      // data buffer



            int NumberOfBytesToRead,            // number of bytes to read



            int* pNumberOfBytesRead,            // number of bytes read



            int Overlapped                      // overlapped buffer



            );



 



      [DllImport("kernel32", SetLastError=true)]



      static extern unsafe bool CloseHandle(



            IntPtr hObject   // handle to object



            );



      



      public bool Open(string FileName)



      {



            // open the existing file for reading          



            handle = CreateFile(



                  FileName,



                  GENERIC_READ,



                  0, 



                  0, 



                  OPEN_EXISTING,



                  0,



                  0);



      



            if (handle != IntPtr.Zero)



                  return true;



            else



                  return false;



      }



 



      public unsafe int Read(byte[] buffer, int index, int count) 



      {



            int n = 0;



            fixed (byte* p = buffer) 



            {



                  if (!ReadFile(handle, p + index, count, &n, 0))



                        return 0;



            }



            return n;



      }



 



      public bool Close()



      {



            // close file handle



            return CloseHandle(handle);



      }



}



 



class Test



{



      public static int Main(string[] args)



      {



            if (args.Length != 1)



            {



                  Console.WriteLine("Usage : ReadFile <FileName>");



                  return 1;



            }



            



            if (! System.IO.File.Exists(args[0]))



            {



                  Console.WriteLine("File " + args[0] + " not found."); 



                  return 1;



            }



 



            byte[] buffer = new byte[128];



            FileReader fr = new FileReader();



            



            if (fr.Open(args[0]))



            {



                  



                  // Assume that an ASCII file is being read



                  ASCIIEncoding Encoding = new ASCIIEncoding();



                  



                  int bytesRead;



                  do 



                  {



                        bytesRead = fr.Read(buffer, 0, buffer.Length);



                        string content = Encoding.GetString(buffer,0,bytesRead);



                        Console.Write("{0}", content);



                  }



                  while ( bytes

上一頁  [1] [2] [3] [4] 下一頁  

Read > 0); fr.Close(); return 0; } else { Console.WriteLine("Failed to open requested file"); return 1; } } }

輸入示例

在編譯和運行此示例時,下列來自 readfile.txt 的輸入將產生在“輸出示例”中顯示的輸出。

line 1



line 2

輸出示例

line 1



line 2

代碼討論

傳遞到 Read 函數的字節數組是托管類型。這意味著公共語言運行庫垃圾回收器可能會隨意地對數組使用的內存進行重新定位。fixed 語句允許您獲取指向字節數組使用的內存的指針,並且標記實例,以便垃圾回收器不會移動它。

fixed 塊的末尾,將標記該實例以便可以移動它。此功能稱為聲明式鎖定。鎖定的好處是系統開銷非常小,除非在 fixed 塊中發生垃圾回收(但此情況不太可能發生)。

示例 3

本示例讀取並顯示可執行文件的 Win32 版本號,在本示例中此版本號與程序集版本號相同。本例中使用的可執行文件為 printversion.exe。本示例使用 Platform SDK 函數 VerQueryValue、GetFileVersionInfoSize 和 GetFileVersionInfo 從指定的版本信息資源中檢索指定的版本信息。

本示例使用了指針,因為它可以簡化在其簽名中使用指向指針的指針(這在 Win32 API 中很常見)的方法的使用。

// printversion.cs



// compile with: /unsafe



using System;



using System.Reflection;



using System.Runtime.InteropServices;



 



// Give this assembly a version number:



[assembly:AssemblyVersion("4.3.2.1")]



 



public class Win32Imports 



{



      [DllImport("version.dll")]



      public static extern bool GetFileVersionInfo (string sFileName,



            int handle, int size, byte[] infoBuffer);



      [DllImport("version.dll")]



      public static extern int GetFileVersionInfoSize (string sFileName,



            out int handle);



   



      // The third parameter - "out string pValue" - is automatically



      // marshaled from ANSI to Unicode:



      [DllImport("version.dll")]



      unsafe public static extern bool VerQueryValue (byte[] pBlock,



            string pSubBlock, out string pValue, out uint len);



      // This VerQueryValue overload is marked with 'unsafe' because 



      // it uses a short*:



      [DllImport("version.dll")]



      unsafe public static extern bool VerQueryValue (byte[] pBlock,



            string pSubBlock, out short *pValue, out uint len);



}



 



public class C 



{



      // Main is marked with 'unsafe' because it uses pointers:



      unsafe public static int Main () 



      {



            try 



            {



                  int handle = 0;



                  // Figure out how much version info there is:



                  int size =



                        Win32Imports.GetFileVersionInfoSize("printversion.exe",



                        out handle);



 



                  if (size == 0) return -1;



 



                  byte[] buffer = new byte[size];



 



                  if (!Win32Imports.GetFileVersionInfo("printversion.exe", handle, size, buffer))



                  {



                        Console.WriteLine("Failed to query file version information.");



                        return 1;



                  }



 



                  short *subBlock = null;



                  uint len = 0;



                  // Get the locale info from the version info:



                  if (!Win32Imports.VerQueryValue (buffer, @"\VarFileInfo\Translation", out subBlock, out len))



                  {



                        Console.WriteLine("Failed to query version information.");



                        return 1;



                  }



 



                  string spv = @"\StringFileInfo\" + subBlock[0].ToString("X4") + subBlock[1].ToString("X4") + @"\ProductVersion";



 



                  byte *pVersion = null;



                  // Get the ProductVersion value for this program:



                  string ver

上一頁  [1] [2] [3] [4] 下一頁  

sionInfo; if (!Win32Imports.VerQueryValue (buffer, spv, out versionInfo, out len)) { Console.WriteLine("Failed to query version information."); return 1; } Console.WriteLine ("ProductVersion == {0}", versionInfo); } catch (Exception e) { Console.WriteLine ("Caught unexpected exception " + e.Message); } return 0; } }

輸出示例

ProductVersion == 4.3.2.1

 

上一頁  [1] [2] [3] [4] 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved