Windows平台下檔案圖式的呈現、變更與清理,基本上都是由explorer.exe程序處理的。系統安裝完成後對於一般檔案有預設的檔案型態定義與預設圖式,雖然這些圖式可以透過管理介面變更,但其實都是在變更系統登錄資料庫中的icon值。至於新安裝的應用軟體和其所屬的檔案型態,在成式安裝時必須告訴explorer其對應的檔案副檔名與檔案圖式。微軟提供許多應用程式開發時的工具,透過不同的方式來該變檔案的圖式,其中較為普片的就是利用COM(Component)組件來完成這項工作。
由於系統的多功,複雜了系統的處理邏輯,微軟為了應付大量的系統功能變更與更新,將系統許多功能模組拆解成功能性的組件,這些組件都以shell interface的方式定義,裡面定義了相關屬性與方法,利用物件繼承的特性實作這些方法與改變物件屬性。Explorer.exe只需要針對用戶發出的event透過QueryInterface()查詢到相關的interface以處理用戶端的動作。
下面我利用變更檔案突式來解釋程式的運作流程:
微軟定義了非常多的shell interface(http://msdn.microsoft.com/en-us/library/bb774328(v=VS.85).aspx),其中IExtractIcon定義了如何由物件中取出icon及其位置的方法,利用這個interface來實作我所想要的動作,我以c#來處理,當然也可以用c++,不過目的都一樣。
(1) 編輯c#類別(ShellLib.cs)來定義要時做的shell interface
下面為IExtractIcon的原型,必須先定義。
[ComVisible(true), ComImport, Guid("000214eb-0000-0000-c000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IExtractIcon { [PreserveSig] int GetIconLocation([In] ExtractIconOptions uFlags, [In] IntPtr szIconFile, [In] uint cchMax, [Out] out int piIndex, [Out] out ExtractIconFlags pwFlags); [PreserveSig] int Extract([In, MarshalAs(UnmanagedType.LPWStr)] string pszFile, uint nIconIndex, [Out, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(IconMarshaler))] out Icon phiconLarge, [Out, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(IconMarshaler))] out Icon phiconSmall, [In] uint nIconSize); }
此外變更圖示要看是要在甚麼樣的動作下變更圖示,由msdn中可以查的一個叫IPersistFile的COM interface(http://msdn.microsoft.com/zh-tw/library/system.runtime.interopservices.comtypes.ipersistfile(v=vs.85).aspx),如此可以知道explorer正在讀寫甚麼檔案。
(2) 實作interface(MyIconView.cs)
實作的部分最主要是變更當shell讀取檔案圖式時,程式會判斷檔案內容起始值是否為”GWGDE”和文件是否有內容,來決定要呈現何種圖式。
int IExtractIcon.Extract(string pszFile, uint nIconIndex, out System.Drawing.Icon phiconLarge, out System.Drawing.Icon phiconSmall, uint nIconSize) { phiconLarge = null; phiconSmall = null; StreamReader sr = new StreamReader(szFileName, Encoding.GetEncoding("big5")); string text = sr.ReadToEnd(); sr.Close(); try { if (text.ToUpper().StartsWith("GWGDE")) { phiconLarge = Resource1.encrypted; phiconSmall = new Icon(Resource1.encrypted, new Size(16, 16)); } else if (lngFileSize > 0) { phiconLarge = Resource1.decrypted; phiconSmall = new Icon(Resource1.decrypted, new Size(16, 16)); } else { phiconLarge = Resource1.empty; phiconSmall = new Icon(Resource1.empty, new Size(16, 16)); } return S_OK; } catch { } return S_FALSE; }
(3) 註冊要處理的檔案型態(MyIconView.cs)
有了以上的處理動作,還必須告訴explorer要針對哪種檔案型態做動作,這個動作牽涉到註冊DLL檔案,必須利用RegAsm.exe註冊工具來註冊DELL,但DLL必須先實作RegisterServer和UnregisterServer來告訴RegAsm要註冊的動作,範例中我只使用.txt的檔案型態做動作
(4) 標示DLL為強式名稱(strong name)
要成功註冊DLL,必須先將DLL標示成強勢名稱,我們可以利用sn.exe工具來產生金鑰檔案(sn –k Key.snk)
再透過專案屬性中的簽署來設定簽署檔案,如此編譯出的DLL就符合標準
(5) 利用RegAsm.exe註冊與註銷DLL
因為註冊工具有分成32和64位元的作業系統版本,所以在使用時要有所區分,我將動作寫在batch檔案中分成reg32.bat和reg64.bat,如果要註銷時須使用unreg32.bat和unreg64.bat,安裝完後必須重新啟動explorer,使DLL載入;註銷完後也不會立即失效,因為此時只清除登錄資料庫中的資料,但DLL已載入到explorer中所以必須重新啟動explorer才能徹底移除該DLL。
此外因為動作牽涉到登錄資料庫,所以命令提示字元必須以管理員身分開啟,否則會註冊失敗。
(6) 測試
由下面可以看檔三個檔案都是文字檔(.txt),但會因為內容不同呈現出不同圖示
留言列表