close

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就符合標準

clip_image002

(5) 利用RegAsm.exe註冊與註銷DLL

因為註冊工具有分成32和64位元的作業系統版本,所以在使用時要有所區分,我將動作寫在batch檔案中分成reg32.bat和reg64.bat,如果要註銷時須使用unreg32.bat和unreg64.bat,安裝完後必須重新啟動explorer,使DLL載入;註銷完後也不會立即失效,因為此時只清除登錄資料庫中的資料,但DLL已載入到explorer中所以必須重新啟動explorer才能徹底移除該DLL。

此外因為動作牽涉到登錄資料庫,所以命令提示字元必須以管理員身分開啟,否則會註冊失敗。

(6) 測試

由下面可以看檔三個檔案都是文字檔(.txt),但會因為內容不同呈現出不同圖示

2011-06-12_225800

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 周 家良 的頭像
    周 家良

    痞子部落

    周 家良 發表在 痞客邦 留言(0) 人氣()