Automatically fix Office preview handler registry

This function requires QuickLook to run with administrator privileges and preview the corresponding Office file once
This commit is contained in:
ema
2025-06-12 15:25:18 +08:00
parent 9a3591e6f6
commit e2e5885fd5
4 changed files with 103 additions and 35 deletions

View File

@@ -23,8 +23,10 @@ namespace QuickLook.Plugin.OfficeViewer;
internal static class CLSIDRegister
{
public const string Office = "{84F66100-FF7C-4fb4-B0C0-02CD7FB668FE}";
public const string Visio = "{279D6C9A-652E-4833-BEFC-312CA8887857}";
public const string MicrosoftWord = "{84F66100-FF7C-4fb4-B0C0-02CD7FB668FE}";
public const string MicrosoftExcel = "{00020827-0000-0000-C000-000000000046}";
public const string MicrosoftPowerPoint = "{65235197-874B-4A07-BDC5-E65EA825B718}";
public const string MicrosoftVisio = "{21E17C2F-AD3A-4b89-841F-09CFE02D16B7}";
public static string GetName(string clsid)
{

View File

@@ -31,8 +31,8 @@ public class Plugin : IViewer
[
".doc", ".docx", ".docm",
".xls", ".xlsx", ".xlsm", ".xlsb",
".vsd", ".vsdx",
".ppt", ".pptx",
".vsd", ".vsdx",
".odt", ".ods", ".odp"
];
@@ -52,12 +52,41 @@ public class Plugin : IViewer
if (!Extensions.Any(path.ToLower().EndsWith))
return false;
var previewHandler = PreviewHandlerHost.GetPreviewHandlerGUID(path);
var previewHandler = ShellExRegister.GetPreviewHandlerGUID(Path.GetExtension(path));
if (previewHandler == Guid.Empty)
return false;
if (!string.IsNullOrWhiteSpace(CLSIDRegister.GetName($"{{{previewHandler}}}")))
if (!string.IsNullOrWhiteSpace(CLSIDRegister.GetName(previewHandler.ToString("B"))))
{
return true;
}
else
{
// To restore the preview handler CLSID to MS Office
// if running with administrative privileges
if (ShellExRegister.IsRunAsAdmin())
{
var fileExtension = Path.GetExtension(path);
var fallbackHandler = fileExtension switch
{
".doc" or ".docx" or ".docm" or ".odt" => CLSIDRegister.MicrosoftWord,
".xls" or ".xlsx" or ".xlsm" or ".xlsb" or ".ods" => CLSIDRegister.MicrosoftExcel,
".ppt" or ".pptx" or ".odp" => CLSIDRegister.MicrosoftPowerPoint,
".vsd" or ".vsdx" => CLSIDRegister.MicrosoftVisio,
_ => null,
};
if (fallbackHandler == null)
return false;
if (!string.IsNullOrWhiteSpace(CLSIDRegister.GetName(fallbackHandler)))
{
// Admin requested
ShellExRegister.SetPreviewHandlerGUID(fileExtension, new Guid(fallbackHandler));
return true;
}
}
}
return false;
}

View File

@@ -21,7 +21,6 @@ using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Microsoft.Win32;
namespace QuickLook.Plugin.OfficeViewer;
@@ -70,34 +69,6 @@ public class PreviewHandlerHost : Control
base.Dispose(disposing);
}
/// <summary>
/// Returns the GUID of the preview handler associated with the specified file.
/// </summary>
/// <param name="filename"></param>
/// <returns></returns>
public static Guid GetPreviewHandlerGUID(string filename)
{
// open the registry key corresponding to the file extension
var ext = Registry.ClassesRoot.OpenSubKey(Path.GetExtension(filename));
if (ext != null)
{
// open the key that indicates the GUID of the preview handler type
var test = ext.OpenSubKey(@"shellex\{8895b1c6-b41f-4c1c-a562-0d564250836f}");
if (test != null) return new Guid(Convert.ToString(test.GetValue(null)));
// sometimes preview handlers are declared on key for the class
var className = Convert.ToString(ext.GetValue(null));
if (className != null)
{
test = Registry.ClassesRoot.OpenSubKey(
className + @"\shellex\{8895b1c6-b41f-4c1c-a562-0d564250836f}");
if (test != null) return new Guid(Convert.ToString(test.GetValue(null)));
}
}
return Guid.Empty;
}
/// <summary>
/// Resizes the hosted preview handler when this PreviewHandlerHost is resized.
/// </summary>
@@ -123,7 +94,7 @@ public class PreviewHandlerHost : Control
return false;
// try to get GUID for the preview handler
var guid = GetPreviewHandlerGUID(path);
var guid = ShellExRegister.GetPreviewHandlerGUID(Path.GetExtension(path));
if (guid == Guid.Empty)
return false;

View File

@@ -0,0 +1,66 @@
using Microsoft.Win32;
using System;
using System.IO;
using System.Security.Principal;
namespace QuickLook.Plugin.OfficeViewer;
internal static class ShellExRegister
{
/// <summary>
/// Returns the GUID of the preview handler associated with the specified file extension.
/// </summary>
/// <param name="filename"></param>
/// <returns></returns>
public static Guid GetPreviewHandlerGUID(string fileExtension)
{
// open the registry key corresponding to the file extension
var ext = Registry.ClassesRoot.OpenSubKey(fileExtension);
if (ext != null)
{
// open the key that indicates the GUID of the preview handler type
// Such as `Computer\HKEY_CLASSES_ROOT\.docx\shellex\{8895b1c6-b41f-4c1c-a562-0d564250836f}`
// Such as `Computer\HKEY_CLASSES_ROOT\.xlsx\shellex\{8895b1c6-b41f-4c1c-a562-0d564250836f}`
var test = ext.OpenSubKey(@"shellex\{8895b1c6-b41f-4c1c-a562-0d564250836f}");
if (test != null) return new Guid(Convert.ToString(test.GetValue(null)));
// sometimes preview handlers are declared on key for the class
var className = Convert.ToString(ext.GetValue(null));
if (className != null)
{
// Such as `Computer\HKEY_CLASSES_ROOT\{CLASS_NAME}\shellex\{8895b1c6-b41f-4c1c-a562-0d564250836f}`
test = Registry.ClassesRoot.OpenSubKey(
className + @"\shellex\{8895b1c6-b41f-4c1c-a562-0d564250836f}");
if (test != null) return new Guid(Convert.ToString(test.GetValue(null)));
}
}
return Guid.Empty;
}
/// <summary>
/// Set the GUID of the preview handler associated with the specified file extension.
/// </summary>
/// <param name="fileExtension"></param>
/// <param name="guid"></param>
public static void SetPreviewHandlerGUID(string fileExtension, Guid guid)
{
// open the registry key corresponding to the file extension
var ext = Registry.ClassesRoot.OpenSubKey(fileExtension);
if (ext != null)
{
// open the key that indicates the GUID of the preview handler type
// Such as `Computer\HKEY_CLASSES_ROOT\.docx\shellex\{8895b1c6-b41f-4c1c-a562-0d564250836f}`
// Such as `Computer\HKEY_CLASSES_ROOT\.xlsx\shellex\{8895b1c6-b41f-4c1c-a562-0d564250836f}`
var test = ext.OpenSubKey(@"shellex\{8895b1c6-b41f-4c1c-a562-0d564250836f}", true);
test?.SetValue(null, guid.ToString("B"));
}
}
public static bool IsRunAsAdmin()
{
using WindowsIdentity identity = WindowsIdentity.GetCurrent();
WindowsPrincipal principal = new(identity);
return principal.IsInRole(WindowsBuiltInRole.Administrator);
}
}