1. 程式人生 > >C#實現Windows資源管理器檔案預覽

C#實現Windows資源管理器檔案預覽

上一篇文章大致介紹了一下C++實現Windows檔案預覽的方法,這裡介紹一下通過.NET方式實現檔案預覽。

其實原理還是一樣,需要通過實現系統定義的COM介面,包括

IInitializeWithFile,IObjectWithSite, IOleWindow,IPreviewHandler
```等
而C#並沒有定義這些介面,因此我們需要把這些介面通過System.Runtime.InteropServices先從COM中引進到專案中




<div class="se-preview-section-delimiter"></div>

[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid(“8895b1c6-b41f-4c1c-a562-0d564250836f”)]
public interface IPreviewHandler
{
///
/// Sets the parent window of the previewer window, as well as the area within the parent to be used for the previewer window.
///
/// A handle to the parent window.
/// A pointer to a RECT defining the area for the previewer.
/// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.
[PreserveSig]
int SetWindow(IntPtr hwnd, ref RECT prc);

    /// <summary>
    /// Directs the preview handler to change the area within the parent hwnd that it draws into.
    /// </summary>
    /// <param name="prc">A pointer to a RECT to be used for the preview.</param>
    /// <returns>If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.</returns>
    [PreserveSig] 
    int SetRect(RECT prc);

    /// <summary>
    /// Directs the preview handler to load data from the source specified in an earlier Initialize method call, and to begin rendering to the previewer window.
    /// </summary>
    /// <returns>This method can return one of these values.</returns>
    [PreserveSig] 
    int DoPreview();

    /// <summary>
    /// Directs the preview handler to cease rendering a preview and to release all resources that have been allocated based on the item passed in during the initialization.
    /// </summary>
    /// <returns>If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.</returns>
    [PreserveSig] 
    int Unload();

    /// <summary>
    /// Directs the preview handler to set focus to itself.
    /// </summary>
    /// <returns>If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.</returns>
    [PreserveSig] 
    int SetFocus();

    /// <summary>
    /// Directs the preview handler to return the HWND from calling the GetFocus Function.
    /// </summary>
    /// <param name="phwnd">When this method returns, contains a pointer to the HWND returned from calling the GetFocus Function from the preview handler's foreground thread.</param>
    /// <returns>If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.</returns>
    [PreserveSig] 
    int QueryFocus(out IntPtr phwnd);

    /// <summary>
    /// Directs the preview handler to handle a keystroke passed up from the message pump of the process in which the preview handler is running.
    /// </summary>
    /// <param name="pmsg">A pointer to a window message.</param>
    /// <returns>If the keystroke message can be processed by the preview handler, the handler will process it and return S_OK. If the preview handler cannot process the keystroke message, it will offer it to the host using TranslateAccelerator. If the host processes the message, this method will return S_OK. If the host does not process the message, this method will return S_FALSE.</returns>
    [PreserveSig] 
    int TranslateAccelerator(MSG pmsg);
};

“`

注:程式碼來自SharpShell專案
接著,我們可以通過託管程式碼實現上述介面,並編譯成託管dll。
這裡需要注意的是,通過.NET框架編譯出來的DLL,即使實現了一些COM介面,但它本質上並不是COM元件,但是.NET的執行環境CLR本身卻是一個COM元件,名為mscoree.dll。因此,對託管DLL元件註冊時應該按照以下規則:
託管DLL註冊
可以看到,被註冊的COM元件其實是mscoree.dll,而我們的託管程式只是作為被該元件呼叫的一個外掛。
在註冊了該元件之後,照上一篇文章的方法,把檔案型別與應用CLSID進行繫結,我們就可以在資源管理器中對檔案進行預覽了。

另外,如果利用SharpShell庫提供的方法,我們不必自己對COM介面進行引入,SharpShell為我們提供了多種Windows Shell介面託管封裝,包括DropHandler, IconHandler, IconOverlayHandler,InfoTipHandler,PreviewHandler,PropertySheet以及ContexMenu的封裝。使用的方法也很簡單,在新建了.NET專案之後可以通過Nuget包對其進行引用,最新版本支援.NET 4.5
NUGET引用SharpShell

由於SharpShell提供了很好的託管封裝,在自定義Windows互動的時候非常推薦大家使用。