PreviewHandler用法(二)

来源:互联网 发布:淘宝网短裤套装 编辑:程序博客网 时间:2024/06/05 14:10

. 如何得到Preview HandlerGUID

首先说明一下,IPreviewHandler接口的GUID8895b1c6-b41f-4c1c-a562-0d564250836f,要找支持的Preview HandlerGUID就要用到它。如何去找呢,在注册表中有四个地方,我这个程序里是四个,不知道还没有别的方式。

第一种方式.docx后缀为例,注册表路径是:
    HKEY_CLASSES_ROOT\.docx\ShellEx\{8895b1c6-b41f-4c1c-a562-0d564250836f}
,如下图:



其中{8895b1c6-b41f-4c1c-a562-0d564250836f}IPreviewHandler接口的GUID(下同)。

第二种方式.html后缀为例,注册表路径是:先从HKEY_CLASSES_ROOT\.html得到其默认值htmlfile.再到HKEY_CLASSES_ROOT\htmlfile\ShellEx\{8895b1c6-b41f-4c1c-a562-0d564250836f}

第三种方式还是以.html后缀为例,注册表路径是HKEY_CLASSES_ROOT\SystemFileAssociations\.html\ShellEx\{8895b1c6-b41f-4c1c-a562-0d564250836f}。

第四种方式.txt后缀为例:先从HKEY_CLASSES_ROOT\.txt 得到PerceivedType名字的值text,再到这个路径得到GUIDHKEY_CLASSES_ROOT\SystemFileAssociations\text\ShellEx\{8895b1c6-b41f-4c1c-a562-0d564250836f}


以下代码都在PreviewsManager.cs里面

C#实现读注册表

    // The GUID of IPreviewHandler    string CLSID = "8895b1c6-b41f-4c1c-a562-0d564250836f";    Guid g = new Guid(CLSID);     // This method returns the GUID of supported preview handler associated strExtension    public string GetCLSIDFromExtensionShellEx(Guid previewHandlerGuid, string strExtension)    {         String strCLSID = String.Empty;         using (RegistryKey hkPreviewHandler = Registry.ClassesRoot.OpenSubKey(                String.Format(@"{0} \ShellEx\{0:B}", strExtension, previewHandlerGuid)))         {             if (hkPreviewHandler != null)             {                 strCLSID = hkPreviewHandler.GetValue(String.Empty).ToString();              }          }          return strCLSID;        }    }

 用法如下:

    String strGUID =  GetCLSIDFromExtensionShellEx(g, ".docx");

    注意:返回的字符串可能是null或String.Empty,所以要对其进行判断
    if(String.IsNullOrEmpty(strGUID))
    {
         // Try find GUID using the second mode, if the return value is still String.Empty, 

         // use the third mode and try again, if no guid is found, try the forth mode...
    }


根据GUID创建COM实例

    

    如果找到了GUID,那么就要用这个GUID来创建一个COM实例,相当于C++中的CoCreateInstance函数,如何实现呢?
    在C#中有一个类Activator,Activator类包含特定的方法,用以在本地或从远程创建对象类型,或获取对现有远程对象的引用。这个类提供了创建COM对象的方法。创建COM接口部分代码如下:

    // Create a COM instance, it is like CoCreateInstance in C++    Guid newCLSID = new Guid(strCLSID);    Get the type of the COM interface specified by CLSID(Guid)    Type typeofPreveiwHandler = Type.GetTypeFromCLSID(newCLSID, true);    Object obj = Activator.CreateInstance(typeofPreveiwHandler);

    COM实例我也创建好了,我应该怎么用这个实例来实现文件预览功能,不要着急,让我们分析一下。前面说过,IPreviewHandler是MS提供的一个接口,这个接口里面提供了一些方法,能实现文件预览,那么这些COM实例肯定是实现了IPreviewHandler接口,所以,就应该把刚才创建的COM实例转换成IPreviewHandler对象,用IPreviewHandler对象去调用它的函数,从而实现文件预览功能。

没错,就是这样的,但有一个问题,这些COM实例并没有打开过文件,它是怎么知道文件内容是什么? 问得好,在把COM实例转换成IPreviewHandler接口之前,要对Preview Handler进行初始化,这里就要用到两另外的两个接口IInitializeWithFile和IInitializeWithStream,这两个接口的相关信息请参见MSDN,这里不介绍。其实绝大部分Preview Handler都用IInitializeWithFile这个接口进行初始化。部分代码如下:

     // Convert COM instance to IInitializeWithFile or IInitializeWithStream to initialize.     IInitializeWithFile fileInit = obj as IInitializeWithFile;     IInitializeWithStream streamInit = obj as IInitializeWithStream;      bool bSuccess = false;     bool isInitalized = false;     if (fileInit != null)     {          fileInit.Initialize(fileName, 0);          isInitalized = true;     }     else if(streamInit != null)     {          // Open file and read data to stream          FileStream stream = new FileStream(fileName, FileMode.Open,                  FileAccess.Read, FileShare.ReadWrite);          COMStream stream = new COMStream(stream);          streamInit.Initialize(stream, 0);          isInitalized = true;     }      if(isInitalized)     {          // Convert obj to IPreviewHandler object          IPreviewHandler pHandler = obj as IPreviewHandler;          if(pHandler != null)          {               // TODO: Begin to get preview               RECT rect = new RECT(viewRect);               pHandler.SetWindow(handler, ref rect);               pHandler.SetRect(ref rect);               pHandler.DoPreview();               pHandler.Unload();               Marshal.ReleaseComObject(pHandler);          }     }
    以上就是得到Preview的部分代码,需要进行说明的,我已经将其标记为红色。下面对其进行一些解释(顺序从上到下):

    1,obj:这个对象就是COM实例,它会在后面用到。

    2,COMStream:这是一个自己写的类,它继承了IStream,IDispose接口,它实现了IStream,IDispose接口的方法。具体的我会在后面文章中说明。

    3,RECT rect = new RECT(viewRect); pHandler.SetRect(ref rect);这两句话就告诉IPreviewHander,你想把取得的Preview放在多大的位置上面。

    4,pHandler.SetWindow(handler, ref rect); 这句话就告诉IPreviewHander,你想把取得的Preview放在哪个窗体上面,窗体由handler指定,在C#中是IntPtr类型,C++中是HANDLE。这句话一定要有,不然Preview就是取到了,也显示不出来。

    5,pHandler.DoPreview(); 只要程序调用这一句,那么它就开始取Preivew了。

    6,pHandler.Unload():取完Preview后,不要忘记释放IPreviewHandler对象,不然会有内存泄漏。直接调用IPreviewHandler接口的Unload()函数。

    7,Marshal.ReleaseComObject(pHandler); 释放COM对象

 

    小结:
    1,根据文件后缀名从注册表中得到支持的Preview的GUID。
    2,根据得到的GUID,创建COM实例。
    3,得到COM实例后,将其转换为IInitializeWithFile或IInitializeWithStream,调用Initialize对这个COM实例进行初始化。
    4,如果初始化成功,将这个COM实例转换为IPreviewHandler接口对象。
    5,调用IPreviewHandler接口的函数,先指定要用于显示Preview的窗体和Rect,把窗体的Handler和Rect作为SetWindow的参数传入。SetWindow会计算出合适的Rect,再调用SetRect设置显示范围,再调用DoPreview函数来得到Preview,最后调用Unload释放对象。

    IPreviewHandler接口里面的函数定义的相当合理,你一定要查MSDN,好好看看,把它具体是干什么的搞明白。下文我将会说明COM与C#是如何交互的。

 

    未完待续,敬看下文





原创粉丝点击