1. Extension Methods 的應用: Save DataSet as Excel file...

    好久沒寫東西了,趁著還記得 C# 怎麼寫的時後多補幾篇 =_=

    要靠程式輸出Excel已經是個FAQ級的問題了,看過我之前文章的大概都知到,我很懶的寫那種FAQ級的東西,不是說寫了沒用,而是太多人寫,一定有寫的比我好的… 到最後連我自己忘了都會去查別人寫的,那我寫了還有啥用?

    所以當然是有些特別的東西,才會想寫這篇… 我碰到的問題是,程式要處理的都是 DataSet 物件,不過 DataSet 物件是從 Excel 來的,處理完也要能回存回 Excel …, 只不過為了先把 POC 作完,現在是以 DataSet 原生的 XML 格式代替。

    其實以儲存的角度來看,XML很好用。不過要教會客戶編輯XML可是個大挑戰啊… 像 Excel 這樣有個表格還是比較容易上手一點。原本的程式長的像這樣:

    原本的程式 (處理 dataset xml)

    DataSet ds = new DataSet();
    ds.ReadXml("data.xml");
    // do something
    ds.WriteXml("data.xml");
    

    我對程式碼的要求其實還蠻龜毛的,常常光為了一個變數名字取的好不好,就要想半天… 對於程式的結構寫起來漂不漂亮也是。上面的程式,要把 XML 換成 EXCEL 其實很簡單,把 ReadXml( ) 換成對等的載入 Excel 的程式碼,WriteXml( ) 也換成對等的輸出 Excel 就可以收工了。不過看起來就是不順眼,因為被太多細節干擾了,未來回過頭來看自己寫的 code, 如果一眼望去不能馬上看出這段 code 在做什麼,那就是不及格的作品了… 所以,我想要的 code 最好能像這樣:

    期望的程式 (處理 excel 檔)

    DataSet ds = new DataSet();
    ds.ReadExcel("data.xls");
    // do something
    ds.WriteExcel("data.xls");
    

    看起來酷多了,這段程式很清楚的說明他在幹嘛… load excel, processing… and save excel…

    繼承的作法,想都不用想就不考慮了。因為我的程式要嘛就直接用 System.Data.DataSet, 不然就是配合 XSD 讓 visual studio 替我 generate typed dataset 的類別… 這些情況下要用到我自訂的衍生類別都不方便… 於是我就把念頭動到 C# 的 extension …

    要怎麼把 DataSet 存成 Excel, 這就是典型的 FAQ 級的問題了,請各位 GOOGLE 一下就有了,不然文後我也附了幾個參考連結…。這裡的重點是 C# extension, 它很神奇的能讓你不需要重新編譯,也不需要拿到原始碼,就能 “擴充” 原本類別的能力。靠這樣的機制,我就能夠改造 .NET Framework 內建的 DataSet, 把它改造成我想要的樣子,如上面的範例用的 ReadExcel( ) / WriteExcel( )。

    C# Extension 是我慣用的說法,其實它正統的名字是 Extension Methods, 是 .NET 3.0 之後提供的功能,不只 C#,VB.NET 也支援。它能讓你在現有的 class 上 “附加” 新的 method … 是的,沒錯,它的能力有限,只能增加 “method”, 而且只能是 instance method, 不能是 class ( static ) method, 也不能是 property 或 field …

    不過這樣也足夠了,先來看看這種 code 要怎麼寫:

    ExtensionMethods 示範

    public static class NPOIExtension
    {
        public static void ReadExcel(this DataSet ds, string inputFile)
        {
            //do something
        }
    
        public static void WriteExcel(this DataSet ds, string outputFile)
        {
            //do something
        }
    }
    

    其實這又是另一種 Microsoft 提供的 Syntex Sugar 而已.. 注意到關鍵在那邊了嗎? 其實 “extension methods” 只不過是普通的 static method 而已,關鍵就在它的第一個參數,型別就是要附加的 class, 而宣告時要再額外加個 “this” modifier 來標示它,意思就是在裡面的 code, 這個參數就把它當作 “this” 來用 …

    換個角度看,其實這只是編譯器幫我們動一點手腳而已,好讓我們的 code 看起來會漂亮一點。用 extension methods 寫的 code, 其實跟這樣的寫法是完全同等的:

    不用 extension methods 的寫法

    DataSet ds = new DataSet();
    NPOIExtension.ReadXml(ds, "data.xml");
    // do something
    NPOIExtension.WriteXml(ds, "data.xml");
    
    public static class NPOIExtension
    {
       public static void ReadExcel(DataSet context, string inputFile)
        {
            // do something
        }
       public static void WriteExcel(DataSet context, string outputFile)
        {
            // do something
        }
    }
    

    少了 this 的用法,看起來就沒這麼神奇了。就是一般的 static method 而已。我喜歡 C# 就是喜歡它有很多這類的 syntax sugar, 可以滿足我寫程式想把程式碼弄的漂漂亮亮的慾望… extension methids 就是一例,還有像 yield return, attribute 等等也是個經典…

    這樣的改變讓我想起,以前公司新進工程師我都會教一堂課,就是講物件是怎麼一回事? 最早是 C / C++ 版,後來改用 javascript 來講這門課。講的就是一步一步示範如何由 procedure oriented language 轉變到 object oriented language 的過程。C++ 是個最清楚的例子,它靠 C 的 function pointer + struct, 用指標指向 function, 把 data 及 function 包裝在 struct 裡,就變成一個 object. (所以 C++ 的 struct 才會跟 class 這麼像啊)。而繼承的問題,則是在 struct 裡動一點手腳,用 virtual table 的方式,讓你寫起 code 來 “好像” 真的有物件導向這麼回事。其實 C++ 的 method, 也只是個普通的 function, 只不過它第一個參數一定叫作 “this” 而已…

    扯遠了,整篇的目的只是要講,用 Extension Method 可以把 code 包的很漂亮,而且也真的可以動而已… 哈哈,最後貼一下完整的 source code, 證明我沒有唬爛…

    程式我調一下,我只實作了 WriteExcel( ) 的部份,從 DataSet XML 讀進來,存成 Excel, 單純的一個轉檔程式。而轉換的過程中是這樣對應的: 一個 DataSet 就代表一個 EXCEL workbook,而一個 DataTable, 則對應到 EXCEL sheet。DataTable 的 Row / Column, 當然就是對應到 EXCEL Row 跟 Cell 了:

    完整的 source code

    public class Program
    {
        static void Main(string[] args)
        {
            DataSet ds = new DataSet();
            ds.ReadXml("data.xml");
            // do something
            ds.WriteExcel("data.xls");
        }
    }
    
    public static class NPOIExtension
    {
        public static void WriteExcel(this DataSet context, string outputFile)
        {
            HSSFWorkbook workbook = new HSSFWorkbook();
    
            foreach (DataTable table in context.Tables)
            {
                Sheet sheet = workbook.CreateSheet(table.TableName);
    
                Row headerRow = sheet.CreateRow(0);
                for(int cpos = 0; cpos < table.Columns.Count; cpos++)
                {
                    Cell cell = headerRow.CreateCell(cpos);
                    cell.SetCellType(CellType.STRING);
                    cell.SetCellValue(table.Columns[cpos].ColumnName);
                }
    
                int rpos = 0;
                foreach (DataRow row in table.Rows)
                {
                    rpos++;
                    Row sheetRow = sheet.CreateRow(rpos);
                    for (int cpos = 0; cpos < table.Columns.Count; cpos++)
                    {
                        object value = row[cpos];
                        Cell cell = sheetRow.CreateCell(cpos);
                        cell.SetCellValue((value == null) ? (null) : (value.ToString()));
                    }
                }
            }
    
            if (File.Exists(outputFile)) File.Delete(outputFile);
            FileStream fs = File.OpenWrite(outputFile);
            workbook.Write(fs);
            fs.Close();
        }
    }
    

    對啦,這真的是全部的 code … 開個 console project 就可以跑了。我就說我很少貼超過百行的 code … 哈哈

    順帶一提,NPOI 這個 open source project 做的真不錯,可以在 pure .net 環境下就能處理 excel … 這個範例就是用 NPOI 寫的,有興趣的朋友可以參考看看!


    Reference:

    1. MSDN: Extension Methods (C# Programming Guide) http://msdn.microsoft.com/en-us/library/bb383977.aspx

    2. NPOI (in CodePlex.com) http://npoi.codeplex.com/

    3. MSDN 學習園地的 NPOI 介紹文章 (中譯版) 在 Server 端存取 Excel 檔案的利器:NPOI Library http://msdn.microsoft.com/zh-tw/ee818993.aspx

    4. 另一套類似NPOI 的函式庫: Koogra Koogra Excel BIFF/XLSX Reader Library http://koogra.sourceforge.net/

    5. 直接用 OpenXML format 的範例 http://www.dotblogs.com.tw/mis2000lab/archive/2008/04/24/3454.aspx

    6. Microsoft Open XML SDK 1.0 / 2.0 for Microsoft Office 1.0 (http://www.microsoft.com/downloads/en/details.aspx?FamilyId=AD0B72FB-4A1D-4C52-BDB5-7DD7E816D046&displaylang=en) 2.0 (http://www.microsoft.com/downloads/en/details.aspx?FamilyID=c6e744e5-36e9-45f5-8d8c-331df206e0d0&DisplayLang=en)

    後記: 本來有寫一段,是整理到底有幾種方法,可以在 .NET 環境下輸出 EXCEL 的… 不過後來決定沒放在本文,就挪到 reference … 簡單的比較,需要的可以看看

    1. 直接用 Excel 提供的物件

      這種方式就是透過程式去操作 Excel 。優點是只要 Excel 有提供的功能,大概都做的到。不過也因為功能太多,用起來很複雜。這方法致命的缺點就是效能。它相當於你真的開啟 Excel 然後命令它做事,想像一下,要能很順暢的執行 Excel 的機器,都不會太差。單機的 windows form 程式還好,如果碰到 server side 的程式,如 ASP.NET 這種,只要同時有五個人點這個功能,你的 server 大概就跑不動了…。

    2. 透過 Jet odbc / oledb driver

      這種方式沒有第一種的缺點,不過也沒有它的優點。既然是透過 odbc 這類存取資料庫的 driver 來存取,那麼你也只能把 Excel 檔當成某種資料庫來看待。處理資料還不成問題,要套用公式或是輸出畫面就辦不到了。這方法還有個大缺點,Jet driver 沒有 x64 的版本 …. windows 2008 r2 之後就沒有 x86 版了,這方法不是長久之計…

    3. 輸出 HTML, 用 Excel 開啟

      這方法很簡單,只要輸出 HTML table, 再調整 content type, 讓 browser 叫 excel 出來幫你開啟就好了。老實說我一直覺的這招有點投機 XD,好處是很簡單,缺點是對 EXCEL 的掌控程度很低,大概就是幫你把資料貼進去的程度而已,不能用公式,也不能輸出多個 sheet 。

    4. Open XML Format 直接輸出

      Office 2007 開始,就放棄用了十幾年的 Ole structed storage compound file 二進位檔的格式,改以 XML 為主 (當然還是支援舊版的格式啦)。只要你知道它的 schema, 不需要太複雜的步驟就可以直接輸出 .xlsx 了。

      熟 XML 的話,甚至是寫寫 XSLT 就可以生的出來。不過這還蠻考驗你對 XML / Open XML 的掌握程度… 算是小有門崁的作法。

    5. 透過 NPOI / Koogra 這類 3rd party 含式庫

      這些含式庫都可以不需要安裝龐大的 Excel, 就有處理 excel 檔的能力。跟 Open XML 不同的是,這些 library 能夠處理到比較頭痛的 2003 及之前版本的 binary file, 相容性比 XML 來的好。

    2010/11/06 .NET C# MSDN Tips 有的沒的 技術隨筆

  2. [RUN! PC] 2010 七月號 - 結合檔案及資料庫的交易處理

    IMG_3972

    再次感謝編輯大人 :D,Transactional NTFS #2 也刊出來了!

    這篇是延續上一篇,進一步的介紹 TxF 如何與 TransactionScope 互動,讓你可以結合檔案系統及資料庫的異動,變成單一交易的技巧。

    由於TxF還沒有正式在.NET Framework裡支援,所以這篇最後也介紹了 AlphaFS,可以簡化應用時的障礙。AlphaFS 是一套想要取代 System.IO.* 的類別庫,它支援了許多 NTFS 的進階功能 (像是 VSS、HardLink 等) 的功能,而 TxF 也在範圍內,透過它就不用再像 上一篇 一樣,辛苦的用 P/Invoke 了。

    這篇提到的範例程式可以在這裡下載。有任何意見也歡迎在這裡留話給我 :D

    2010/07/09 RUN! PC 專欄文章 .NET RUN! PC Transactional NTFS 作品集 作業系統 技術隨筆 物件導向

  3. [RUN! PC] 2010 五月號 - TxF讓檔案系統也能達到交易控制

    image

    五月號就刊出來,還真有點意外 :D,這次稿件趕不及,晚了幾天才交出去,編輯大人還是讓我上五月號啦,真是感謝 :D

    之前執行緒的系列,是打算把各種應用執行緒的演算法都介紹一下,寫了五篇就沒靈感了。實際寫CODE的技巧倒是很多可以介紹,不過 .NET FX 4.0 出來之後,這些鎖碎的 coding 技巧又大幅簡化了,除非有特別的演算法需要 (如同之前那五篇 :D),否則還自己拿 Thread 物件硬幹已經沒什麼意義了,所以就換另一個我有興趣的主題 - Transactional NTFS 來寫。

    這系列第一篇出爐了,主要就是先介紹它的觀念及如何入門,國內這類資訊還不多,我就野人獻曝寫了一篇,試著寫看看了。較鎖碎的實作技巧 (如 P/Invoke) 我會直接貼 BLOG,而較完整的概念及實作探討等等就會整理成文章拿來投稿了。

    再次感謝各位支持啦,底下有範例程式跟一些參考資源的 LINK,需要的歡迎取用 :D

    範例程式:

    1. Visual Studio 2008 Project (C#) File: TransactionDemo.zip

    參考資訊:

    1. AlphaFS: Brining Advanced Windows FileSystem Support to .NET http://alphafs.codeplex.com/

    2. MSDN magazine (July 2007): Enhance Your Apps With File System Transactions http://msdn.microsoft.com/en-us/magazine/cc163388.aspx

    3. B# .NET BLOG: Windows Vista - Introducing TxF In C# Part 1: Transacted File Delete Part 2: Using System.Transactions and the DTC Part 3: CreateFileTransacted Demo

    4. Code Project: Windows Vista TxF / TxR http://www.codeproject.com/KB/vista/KTM.aspx

    5. BLOG: Because we can http://blogs.msdn.com/because_we_can/archive/2005/05/18/419809.aspx Discussion and explanation relating to the Transactional NTFS feature coming in Longhorn, plus any other interesting anecdotes…

    6. Performance Consoderations for Transactional NTFS http://msdn.microsoft.com/en-us/library/ee240893(VS.85).aspx

    7. When to Use Transactional NTFS http://msdn.microsoft.com/en-us/library/aa365738(VS.85).aspx

    2010/05/05 RUN! PC 專欄文章 .NET RUN! PC Transactional NTFS 作品集 作業系統 技術隨筆 物件導向

  4. [RUN! PC] 2010 四月號 - 生產者vs消費者– 執行緒的供需問題

    image

    隔了足足一年,趁著過年,生出第五篇了 :D,再次感謝編輯賞光啦,願意刊登我寫的題材…

    這篇 [生產者/消費者] 其實是延續上一篇 [生產線模式] 而來的,生產線模式,是利用 PIPE 的方式,把工作切成各個階段同時進行。而生產者消費者,則是去探討兩個階段之間如何做好進度的協調。這篇除了講講處理的原則之外,也實作了BlockQueue來簡化這個問題。

    其實更漂亮的用法,是我在 MSDN Magazine 上看到的 BlockingStream, 直接把它作成 System.IO.Stream 的衍生類別。像那些包裝成 Stream 的資料處理 (像是壓縮、加密、或是 Socket 這類),都很適合。不過一般情況下不是所有應用都能套上 Stream 的模式,因此就有了把它包裝成 Queue 的念頭,也就是這篇寫的 BlockQueue 的應用。

    相關的東西其實過去也寫了幾篇,只不過 BLOG 寫的都比較瑣碎,都是針對特定主題較深入的討論,而投稿的文章就會比較完整的介紹原理及作法等等,細節就沒辦法兼顧了。有興趣的讀者可以參考一下我部落格的相關文章 :D 這期的範例程式可以在底下下載,相關的 LINK 也列在底下。

    再次謝謝各位支持啦 :D

    MSDN Magazine 閱讀心得: Stream Pipeline RUN!PC 精選文章 - 生產線模式的多執行緒應用 [RUN! PC] 2008 十一月號 生產線模式的多執行緒應用 生產者 vs 消費者 - BlockQueue 實作

    2010/04/05 RUN! PC 專欄文章 .NET RUN! PC 作品集 多執行緒 技術隨筆 物件導向

  5. [TxF] #2. 先作功課 - 熟悉 P/Invoke 及 Win32 檔案處理...

    其實這篇是多寫的,因為前一篇提到的 Transactional NTFS 官方只提供 Win32 API 而已,不提供包裝好的 managed code 用的 library… 因此現階段想始用它,P/Invoke 是逃不掉的… 這篇就先來複習一下,想要在 C# 裡呼叫 unmanaged code 該怎麼用吧。這邊的例子為了配合後面幾篇,就同樣的以檔案處理為例。

    這篇我不想去長篇大論的討論 P/Invoke 那堆規則及語法,也不想去討論那堆 Marshal 的觀念等等… 想學好 P/Invoke 就別看我這篇了,應該去 MSDN 看… 這篇我只想交待一下該如何配合 windows api 來作檔案處理而已。因為這些是往後要用到 Transactional NTFS 必要的技巧,TxF 新的 API 都是跟 win32 標準檔案處理的 API 一一對應的,弄懂了如何用 win32 api 操作檔案,你大概就學會八成的 TxF 了… 想用 TxF … 熟悉點 P/Invoke 是應該的…

    先從最單純的 MoveFile 開始吧,它沒有扯到啥 pointer 或是 handle … 算是最單純的例子.. 先來看看這 API 原生的樣子:

    BOOL WINAPI MoveFile( __in LPCTSTR lpExistingFileName, __in LPCTSTR lpNewFileName );

    這 API 做啥事就不用多說了,把 lpExistingFileName 這檔案搬到 lpNewFileName 去… 搬成功還是失敗,就用 BOOL 值把結果傳回來。這時就要透過 P/Invoke 的用法,想辦法產生一個可以對應到 unmanaged code 的 C# function … 我先把宣告方式貼出來,再來解試 code …

    P/Invoke: MoveFile

    [DllImport("kernel32.dll")]
    static extern bool MoveFile(string lpExistingFileName, string lpNewFileName);
    

    寫過 C / C++ 的人,大概對 extern 這個 keyword 不陌生吧? extern 這修飾字代表這個 function 是外來的,C# 正好拿來用在這裡。外來的 DLL 都是 function 型態,所以一定是 static, 沒有綁著任何一個物件… 而標在上面的 Attribute: DllImport, 則是標上這個 function 是來自那個 DLL。

    在這個例子裡,這樣就足夠了,直接在程式裡試著寫一段 C# (managed code) 來試看看結果吧:

    P/Invoke Sample #1. MoveFile

    public class PInvokeTest
    {
        [DllImport("kernel32.dll")]
        static extern bool MoveFile(string lpExistingFileName, string lpNewFileName);
    
        public static void Main(string[] args)
        {
            string srcFileName = @"C:\file1.txt";
            string dstFileName = @"C:\file2.txt";
    
            Console.Write("move file: from [{0}] to [{1}] ... ", srcFileName, dstFileName);
    
            if (MoveFile(srcFileName, dstFileName) == true)
            {
                Console.WriteLine("OK!");
            }
            else
            {
                Console.WriteLine("FAIL!");
            }
        }
    }
    

    程式執行前,看一下 C:\ 的 DIR *.TXT 指令執行結果:

    image

    沒錯,有 c:\file1.txt 這檔案… 接著來執行範例程式:

    image

    執行成功。再重新看一下 C:\ 的 DIR *.TXT 指令執行結果:

    image

    看來程式很順利的呼叫了 win32 api 裡定義的 MoveFile( … ) … 這種範例有點不入流,要處理檔案總不可能只有這樣吧? 接著我們再來看看需要 Open File 加上讀寫檔案內容的應用。

    Windows 是個以 HANDLE 為主的作業系統,一般在寫 C / C++ 程式,都是以指標(POINTER)的方式在處理資料,但是在 windows 裡,作業系統提供的資料用的指標,則特別以 “HANDLE” 來稱呼,它比一般的 POINTER 來說多了一些管理的動作。因此你開啟的檔案,或是建立的視窗,通通都以 HANDLE 來稱呼,而不是單純的用 POINTER (雖然它也是個 POINTER 啦)。接下來的例子就來看看 HANDLE 的應用。

    public class PInvokeTest2
    {
        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern IntPtr CreateFile(
               string lpFileName,
               uint dwDesiredAccess,
               uint dwShareMode,
               IntPtr SecurityAttributes,
               uint dwCreationDisposition,
               uint dwFlagsAndAttributes,
               IntPtr hTemplateFile
               );
    
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool CloseHandle(IntPtr hObject);
    
        public static void Main(string[] args)
        {
            IntPtr pFile = CreateFile(
                @"c:\file1.txt",
                0x80000000,
                0x00000001,
                IntPtr.Zero,
                3,
                0,
                IntPtr.Zero);
    
            Stream fs = new FileStream(pFile, FileAccess.Read);
            TextReader tr = new StreamReader(fs);
    
            Console.WriteLine(tr.ReadToEnd());
    
            tr.Close();
            fs.Close();
            CloseHandle(pFile);
        }
    }
    

    這個例子裡,很 “神奇” 的把 unmanaged code 拿到的指標 (IntPtr), 丟給 System.IO.* 底下的 FileStream 來用,竟然還能成功的開啟檔案並且把資料讀出來… 沒錯,MS寫的東西本來就都是同一家人,System.IO 那堆東西就是這樣包出來的。 這段範例程式除了看起來複雜一點之外,跟那堆要查文件才知道是啥意思的 flags 之外,其它都很簡單,不過就 Open File, 然後讀出內容,接著 Close …

    較特別的是,在 P/Invoke 的世界裡,都用 struct System.IntPtr 這個型別,來代表 unmanaged 世界裡常用到的 POINTER.. 藉著這個型別,我們就可以把兩個世界的橋樑給搭起來。不過當你執行這個範例時,編譯器會給你一個很礙眼的警告:

    ‘System.IO.FileStream.FileStream(System.IntPtr, System.IO.FileAccess)’ is obsolete: ‘This constructor has been deprecated. Please use new FileStream(SafeFileHandle handle, FileAccess access) instead. http://go.microsoft.com/fwlink/?linkid=14202’

    沒錯,這是老用法了,一如用指標有數不盡的缺點,新的語言都想盡辦法扔掉它 (POINTER: 我是無辜的…),連包裝過的 IntPtr 也不例外。在 .NET Framework 2.0 裡就不再建議你用這個建構式了,請改用 SafeFileHandle …. 既然在 windows 的世界裡,一切系統的資源都是以 HANDLE 來處理,自然的在 managed code 裡也有對應的型別,它就是 System.Runtime.InteropServices.SafeHandle 。接著再來看看改用 SafeHandle 的版本:

    public class PInvokeTest3
    {
        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern SafeFileHandle CreateFile(
            string fileName,
            uint fileAccess,
            uint fileShare,
            IntPtr securityAttributes,
            uint creationDisposition,
            uint flags,
            IntPtr template);
    
        public static void Main(string[] args)
        {
            SafeFileHandle pFile = CreateFile(
                @"c:\file1.txt",
                0x80000000,
                0x00000001,
                IntPtr.Zero,
                3,
                0,
                IntPtr.Zero);
    
            Stream fs = new FileStream(pFile, FileAccess.Read);
            TextReader tr = new StreamReader(fs);
    
            Console.WriteLine(tr.ReadToEnd());
    
            tr.Close();
            fs.Close();
    
            pFile.Close();
        }
    }
    

    執行的結果,當然也是順利的把文字檔內容印到 CONSOLE 裡了,我就不再多貼,直接看程式碼。

    其實這裡有點偷吃步,用的是 SafeFileHandle, 而不是 SafeHandle。雖然兩者有繼承關係啦。不過後面我就都把它當成 SafeHandle 看待。這個版本的程式,除了把 IntPtr 換成 SafeFileHandle 之外,及最後的 CloseHandle( pFile ) 改成直接呼叫 SafeHandle.Close( ) 之外,沒有太大的不同了。有啦,把 IntPtr 跟 CloseHandle 兩者包裝在同一個 SafeHandler 裡是安全的多,至少 SafeHandle 實作了 IDispose 的介面,在適當的情況下,它至少會自動的被呼叫 Dispose( ) 回收資源…

    看到這裡,以前老搞不清楚的 FileStream 為什麼有幾個怪怪的 constructor, 自從研究了 TxF 之後,意外的晃然大悟… 算是額外的收穫吧! 原來就是要配合 P/Invoke 使用…

    其實說穿了,呼叫 win32 api 大概就這幾招了,幾種 unmanaged code 裡用到的型別,指標都可以對應之後,程式寫起來就簡單了。這篇我特意漏掉一部份,就是各種用 uint 來當作 flags 的型別,沒有轉到對應的 enum 列舉型別,我是覺的這是 option 啦,畢竟查查文件就有,多列上來我得多打好多字… 篇幅有限 XD

    這幾個例子如果都看懂後,那麼 TxF 就沒有障礙了! 接下來就看下回分解了 :D 下回會看到第一個 “交易式” 的檔案處理範例! 沒灌 windows vista / 2008 / 7 / 2008 R2 的讀者門,快去準備吧!

    參考資訊:

    1. 有用的網站: PINVOKE.NET http://www.pinvoke.net/index.aspx

      這網站幫你整理好了各種 win32 api 該如何宣告它的 C# signature, 以供 p/Invoke 使用。如果你不熟它的語法,這網站可以幫你不少忙。另外它也提供了一些方便的工具,像是 winform 的查詢工具,或是 visual studio 用的 add-ins

    2. MSDN 的 API 說明: MoveFile http://msdn.microsoft.com/en-us/library/aa365239(VS.85).aspx

    3. 什麼是 P/Invoke ? Wiki 的說明: http://en.wikipedia.org/wiki/Pinvoke

    4. Safe Handle & Critical Finalization (實在是看不懂的中譯… “安全控制代碼和關鍵結束” ???) http://msdn.microsoft.com/zh-tw/library/fh21e17c(v=VS.90).aspx

    2010/03/23 系列文章: 交易式 (Transactional) NTFS .NET C# MSDN Transactional NTFS