mirror of
https://github.com/QL-Win/QuickLook.git
synced 2025-09-13 19:19:10 +00:00
New AppViewer plugin for .msi
This commit is contained in:
27
QuickLook.Plugin/QuickLook.Plugin.AppViewer/IAppInfoPanel.cs
Normal file
27
QuickLook.Plugin/QuickLook.Plugin.AppViewer/IAppInfoPanel.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright © 2017-2025 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace QuickLook.Plugin.AppViewer;
|
||||
|
||||
public interface IAppInfoPanel
|
||||
{
|
||||
public void DisplayInfo(string path);
|
||||
|
||||
public object Tag { get; set; }
|
||||
|
||||
public bool Stop { get; set; }
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
// Copyright © 2017-2025 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace QuickLook.Plugin.AppViewer.MsiImageParser;
|
||||
|
||||
public sealed class MsiInfo
|
||||
{
|
||||
public string ProductVersion { get; set; }
|
||||
|
||||
public string ProductName { get; set; }
|
||||
|
||||
public string Manufacturer { get; set; }
|
||||
|
||||
public string ProductCode { get; set; }
|
||||
|
||||
public string UpgradeCode { get; set; }
|
||||
}
|
@@ -0,0 +1,45 @@
|
||||
// Copyright © 2017-2025 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using WixToolset.Dtf.WindowsInstaller;
|
||||
|
||||
namespace QuickLook.Plugin.AppViewer.MsiImageParser;
|
||||
|
||||
public static class MsiParser
|
||||
{
|
||||
public static MsiInfo Parse(string path)
|
||||
{
|
||||
MsiInfo info = new();
|
||||
using var database = new Database(path, DatabaseOpenMode.ReadOnly);
|
||||
|
||||
info.ProductVersion = database.ReadPropertyString(nameof(MsiInfo.ProductVersion));
|
||||
info.ProductName = database.ReadPropertyString(nameof(MsiInfo.ProductName));
|
||||
info.Manufacturer = database.ReadPropertyString(nameof(MsiInfo.Manufacturer));
|
||||
info.ProductCode = database.ReadPropertyString(nameof(MsiInfo.ProductCode));
|
||||
info.UpgradeCode = database.ReadPropertyString(nameof(MsiInfo.UpgradeCode));
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
private static string ReadPropertyString(this Database database, string propertyName)
|
||||
{
|
||||
using View view = database.OpenView($"SELECT `Value` FROM `Property` WHERE `Property`='{propertyName}'");
|
||||
view.Execute(null);
|
||||
using Record record = view.Fetch();
|
||||
return record?.GetString(1);
|
||||
}
|
||||
}
|
171
QuickLook.Plugin/QuickLook.Plugin.AppViewer/MsiInfoPanel.xaml
Normal file
171
QuickLook.Plugin/QuickLook.Plugin.AppViewer/MsiInfoPanel.xaml
Normal file
@@ -0,0 +1,171 @@
|
||||
<UserControl x:Class="QuickLook.Plugin.AppViewer.MsiInfoPanel"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:QuickLook.Plugin.AppViewer"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
Height="230"
|
||||
FontSize="14"
|
||||
UseLayoutRounding="True"
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="/QuickLook.Common;component/Styles/MainWindowStyles.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="15" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="150" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Image x:Name="image"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Width="128"
|
||||
Height="128"
|
||||
Margin="0,-20,0,0"
|
||||
Opacity="0"
|
||||
Stretch="Fill">
|
||||
<Image.Style>
|
||||
<Style TargetType="{x:Type Image}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Source, ElementName=image}" Value="{x:Null}">
|
||||
<DataTrigger.ExitActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation BeginTime="0:0:0"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
From="0"
|
||||
To="1"
|
||||
Duration="0:0:0.05" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.ExitActions>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Image.Style>
|
||||
</Image>
|
||||
<Grid Grid.Row="1" Grid.Column="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="5" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="10" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="10" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="10" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Grid.ColumnSpan="2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
MaxHeight="60"
|
||||
Padding="3"
|
||||
FontSize="19"
|
||||
FontWeight="SemiBold"
|
||||
LineHeight="25"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
TextWrapping="Wrap">
|
||||
<TextBlock.Inlines>
|
||||
<Run x:Name="filename" Text="FilenameFilenameFilenameFilenameFilenameFilenameFilenameFilenameFilenameFilename.ext" />
|
||||
</TextBlock.Inlines>
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
<!-- Product Name -->
|
||||
<TextBlock x:Name="productNameTitle"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Padding="3"
|
||||
Foreground="{DynamicResource WindowTextForegroundAlternative}"
|
||||
Text="Product Name" />
|
||||
<TextBlock x:Name="productName"
|
||||
Grid.Row="3"
|
||||
Grid.Column="2"
|
||||
Margin="8,0,0,0"
|
||||
Padding="3"
|
||||
Foreground="{DynamicResource WindowTextForegroundAlternative}"
|
||||
Text="Searching..."
|
||||
TextTrimming="CharacterEllipsis"
|
||||
TextWrapping="Wrap" />
|
||||
<!-- Product Version -->
|
||||
<TextBlock x:Name="productVersionTitle"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Padding="3"
|
||||
Foreground="{DynamicResource WindowTextForegroundAlternative}"
|
||||
Text="Product Version" />
|
||||
<TextBlock x:Name="productVersion"
|
||||
Grid.Row="4"
|
||||
Grid.Column="2"
|
||||
Margin="8,0,0,0"
|
||||
Padding="3"
|
||||
Foreground="{DynamicResource WindowTextForegroundAlternative}"
|
||||
Text="Searching..."
|
||||
TextTrimming="CharacterEllipsis"
|
||||
TextWrapping="Wrap" />
|
||||
<!-- Manufacturer -->
|
||||
<TextBlock x:Name="manufacturerTitle"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Padding="3"
|
||||
Foreground="{DynamicResource WindowTextForegroundAlternative}"
|
||||
Text="Manufacturer" />
|
||||
<TextBlock x:Name="manufacturer"
|
||||
Grid.Row="5"
|
||||
Grid.Column="2"
|
||||
Margin="8,0,0,0"
|
||||
Padding="3"
|
||||
Foreground="{DynamicResource WindowTextForegroundAlternative}"
|
||||
Text="Searching..."
|
||||
TextTrimming="CharacterEllipsis"
|
||||
TextWrapping="Wrap" />
|
||||
<!-- Total Size -->
|
||||
<TextBlock x:Name="totalSizeTitle"
|
||||
Grid.Row="6"
|
||||
Grid.Column="1"
|
||||
Padding="3"
|
||||
Foreground="{DynamicResource WindowTextForegroundAlternative}"
|
||||
Text="Total Size" />
|
||||
<TextBlock x:Name="totalSize"
|
||||
Grid.Row="6"
|
||||
Grid.Column="2"
|
||||
Margin="8,0,0,0"
|
||||
Padding="3"
|
||||
Foreground="{DynamicResource WindowTextForegroundAlternative}"
|
||||
Text="Calculating size..." />
|
||||
<!-- Last Modified -->
|
||||
<TextBlock x:Name="modDateTitle"
|
||||
Grid.Row="7"
|
||||
Grid.Column="1"
|
||||
Padding="3"
|
||||
Foreground="{DynamicResource WindowTextForegroundAlternative}"
|
||||
Text="Last Modified" />
|
||||
<TextBlock x:Name="modDate"
|
||||
Grid.Row="7"
|
||||
Grid.Column="2"
|
||||
Margin="8,0,0,0"
|
||||
Padding="3"
|
||||
Foreground="{DynamicResource WindowTextForegroundAlternative}"
|
||||
Text="Searching..."
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -0,0 +1,97 @@
|
||||
// Copyright © 2017-2025 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using QuickLook.Common.ExtensionMethods;
|
||||
using QuickLook.Common.Helpers;
|
||||
using QuickLook.Plugin.AppViewer.MsiImageParser;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace QuickLook.Plugin.AppViewer;
|
||||
|
||||
public partial class MsiInfoPanel : UserControl, IAppInfoPanel
|
||||
{
|
||||
private bool _stop;
|
||||
|
||||
public MsiInfoPanel()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// apply global theme
|
||||
Resources.MergedDictionaries[0].Clear();
|
||||
|
||||
string translationFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Translations.config");
|
||||
productNameTitle.Text = TranslationHelper.Get("PRODUCT_NAME", translationFile);
|
||||
productVersionTitle.Text = TranslationHelper.Get("PRODUCT_VERSION", translationFile);
|
||||
manufacturerTitle.Text = TranslationHelper.Get("MANUFACTURER", translationFile);
|
||||
totalSizeTitle.Text = TranslationHelper.Get("TOTAL_SIZE", translationFile);
|
||||
modDateTitle.Text = TranslationHelper.Get("LAST_MODIFIED", translationFile);
|
||||
}
|
||||
|
||||
public bool Stop
|
||||
{
|
||||
set => _stop = value;
|
||||
get => _stop;
|
||||
}
|
||||
|
||||
public void DisplayInfo(string path)
|
||||
{
|
||||
_ = Task.Run(() =>
|
||||
{
|
||||
var scale = DisplayDeviceHelper.GetCurrentScaleFactor();
|
||||
|
||||
var icon =
|
||||
WindowsThumbnailProvider.GetThumbnail(path,
|
||||
(int)(128 * scale.Horizontal),
|
||||
(int)(128 * scale.Vertical),
|
||||
ThumbnailOptions.ScaleUp);
|
||||
|
||||
var source = icon?.ToBitmapSource();
|
||||
icon?.Dispose();
|
||||
|
||||
Dispatcher.BeginInvoke(new Action(() => image.Source = source));
|
||||
});
|
||||
|
||||
var name = Path.GetFileName(path);
|
||||
filename.Text = string.IsNullOrEmpty(name) ? path : name;
|
||||
|
||||
Stop = false;
|
||||
|
||||
_ = Task.Run(() =>
|
||||
{
|
||||
if (File.Exists(path))
|
||||
{
|
||||
var size = new FileInfo(path).Length;
|
||||
MsiInfo msiInfo = MsiParser.Parse(path);
|
||||
var last = File.GetLastWriteTime(path);
|
||||
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
productName.Text = msiInfo.ProductName;
|
||||
productVersion.Text = msiInfo.ProductVersion;
|
||||
manufacturer.Text = msiInfo.Manufacturer;
|
||||
totalSize.Text = size.ToPrettySize(2);
|
||||
modDate.Text = last.ToString(CultureInfo.CurrentCulture);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
99
QuickLook.Plugin/QuickLook.Plugin.AppViewer/Plugin.cs
Normal file
99
QuickLook.Plugin/QuickLook.Plugin.AppViewer/Plugin.cs
Normal file
@@ -0,0 +1,99 @@
|
||||
// Copyright © 2017-2025 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using QuickLook.Common.Plugin;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
|
||||
namespace QuickLook.Plugin.AppViewer;
|
||||
|
||||
public class Plugin : IViewer
|
||||
{
|
||||
private static readonly string[] _extensions =
|
||||
[
|
||||
// Android
|
||||
//".apk", ".apk.1", // Android Package
|
||||
//".aar", // Android Archive
|
||||
//".aab", // Android App Bundle
|
||||
|
||||
// Windows
|
||||
//".appx", ".appxbundle", // Windows APPX installer
|
||||
".msi", // Windows MSI installer
|
||||
//".msix", ".msixbundle", // Windows MSIX installer
|
||||
|
||||
// macOS
|
||||
//".dmg", // macOS DMG
|
||||
|
||||
// iOS
|
||||
//".ipa", // iOS IPA
|
||||
|
||||
// HarmonyOS
|
||||
//".hap", // HarmonyOS Package
|
||||
//".har", // HarmonyOS Archive
|
||||
|
||||
// Others
|
||||
//".wgt", ".wgtu", // UniApp Widget
|
||||
];
|
||||
|
||||
private IAppInfoPanel _ip;
|
||||
private string _path;
|
||||
|
||||
public int Priority => 0;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
}
|
||||
|
||||
public bool CanHandle(string path)
|
||||
{
|
||||
return !Directory.Exists(path) && _extensions.Any(path.ToLower().EndsWith);
|
||||
}
|
||||
|
||||
public void Prepare(string path, ContextObject context)
|
||||
{
|
||||
context.PreferredSize = Path.GetExtension(path) switch
|
||||
{
|
||||
".msi" => new Size { Width = 520, Height = 230 },
|
||||
_ => throw new NotSupportedException("Extension is not supported."),
|
||||
};
|
||||
}
|
||||
|
||||
public void View(string path, ContextObject context)
|
||||
{
|
||||
_path = path;
|
||||
_ip = Path.GetExtension(path) switch
|
||||
{
|
||||
".msi" => new MsiInfoPanel(),
|
||||
_ => throw new NotSupportedException("Extension is not supported."),
|
||||
};
|
||||
|
||||
_ip.DisplayInfo(_path);
|
||||
_ip.Tag = context;
|
||||
|
||||
context.ViewerContent = _ip;
|
||||
context.IsBusy = false;
|
||||
}
|
||||
|
||||
public void Cleanup()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
_ip = null;
|
||||
}
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
// Copyright © 2017-2025 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("QuickLook.Plugin.AppViewer")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("pooi.moe")]
|
||||
[assembly: AssemblyProduct("QuickLook.Plugin.AppViewer")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2017-2025 QL-Win Contributors")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("00d8f3b1-5be9-4ab8-ae68-16374001887a")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
@@ -0,0 +1,79 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
<TargetFramework>net462</TargetFramework>
|
||||
<RootNamespace>QuickLook.Plugin.AppViewer</RootNamespace>
|
||||
<AssemblyName>QuickLook.Plugin.AppViewer</AssemblyName>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<SignAssembly>false</SignAssembly>
|
||||
<UseWPF>true</UseWPF>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<ProjectGuid>{00D8F3B1-5BE9-4AB8-AE68-16374001887A}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>..\..\Build\Debug\QuickLook.Plugin\QuickLook.Plugin.AppViewer\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>..\..\Build\Release\QuickLook.Plugin\QuickLook.Plugin.AppViewer\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<OutputPath>..\..\Build\Debug\QuickLook.Plugin\QuickLook.Plugin.AppViewer\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<OutputPath>..\..\Build\Release\QuickLook.Plugin\QuickLook.Plugin.AppViewer\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\QuickLook.Common\QuickLook.Common.csproj">
|
||||
<Project>{85FDD6BA-871D-46C8-BD64-F6BB0CB5EA95}</Project>
|
||||
<Name>QuickLook.Common</Name>
|
||||
<Private>False</Private>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\..\GitVersion.cs">
|
||||
<Link>Properties\GitVersion.cs</Link>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<PackageReference Include="WixToolset.Dtf.WindowsInstaller" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Translations.config">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<Translations>
|
||||
<en>
|
||||
<PRODUCT_VERSION>Product Version</PRODUCT_VERSION>
|
||||
<PRODUCT_NAME>Product Name</PRODUCT_NAME>
|
||||
<MANUFACTURER>Manufacturer</MANUFACTURER>
|
||||
<TOTAL_SIZE>Total Size</TOTAL_SIZE>
|
||||
<LAST_MODIFIED>Last Modified</LAST_MODIFIED>
|
||||
</en>
|
||||
<pt-BR>
|
||||
<PRODUCT_VERSION>Versão do produto</PRODUCT_VERSION>
|
||||
<PRODUCT_NAME>Nome do produto</PRODUCT_NAME>
|
||||
<MANUFACTURER>Fabricante</MANUFACTURER>
|
||||
<TOTAL_SIZE>Tamanho total</TOTAL_SIZE>
|
||||
<LAST_MODIFIED>Modificado em</LAST_MODIFIED>
|
||||
</pt-BR>
|
||||
<zh-CN>
|
||||
<PRODUCT_VERSION>产品版本</PRODUCT_VERSION>
|
||||
<PRODUCT_NAME>产品名称</PRODUCT_NAME>
|
||||
<MANUFACTURER>制造商</MANUFACTURER>
|
||||
<TOTAL_SIZE>总大小</TOTAL_SIZE>
|
||||
<LAST_MODIFIED>修改时间</LAST_MODIFIED>
|
||||
</zh-CN>
|
||||
<zh-TW>
|
||||
<PRODUCT_VERSION>產品版本</PRODUCT_VERSION>
|
||||
<PRODUCT_NAME>產品名稱</PRODUCT_NAME>
|
||||
<MANUFACTURER>製造商</MANUFACTURER>
|
||||
<TOTAL_SIZE>縂大小</TOTAL_SIZE>
|
||||
<LAST_MODIFIED>修改時間</LAST_MODIFIED>
|
||||
</zh-TW>
|
||||
<ja>
|
||||
<PRODUCT_VERSION>製品バージョン</PRODUCT_VERSION>
|
||||
<PRODUCT_NAME>製品名</PRODUCT_NAME>
|
||||
<MANUFACTURER>製造元</MANUFACTURER>
|
||||
<TOTAL_SIZE>合計サイズ</TOTAL_SIZE>
|
||||
<LAST_MODIFIED>更新日時</LAST_MODIFIED>
|
||||
</ja>
|
||||
</Translations>
|
@@ -0,0 +1,225 @@
|
||||
// Copyright © 2017-2025 QL-Win Contributors
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace QuickLook.Plugin.AppViewer;
|
||||
|
||||
[Flags]
|
||||
internal enum ThumbnailOptions
|
||||
{
|
||||
None = 0x00,
|
||||
BiggerSizeOk = 0x01,
|
||||
InMemoryOnly = 0x02,
|
||||
IconOnly = 0x04,
|
||||
ThumbnailOnly = 0x08,
|
||||
InCacheOnly = 0x10,
|
||||
IconBackground = 0x80,
|
||||
ScaleUp = 0x100
|
||||
}
|
||||
|
||||
internal static class WindowsThumbnailProvider
|
||||
{
|
||||
private const string IShellItem2Guid = "7E9FB0D3-919F-4307-AB2E-9B1860310C93";
|
||||
|
||||
[DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
private static extern int SHCreateItemFromParsingName(
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string path,
|
||||
// The following parameter is not used - binding context.
|
||||
IntPtr pbc,
|
||||
ref Guid riid,
|
||||
[MarshalAs(UnmanagedType.Interface)] out IShellItem shellItem);
|
||||
|
||||
[DllImport("gdi32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool DeleteObject(IntPtr hObject);
|
||||
|
||||
public static Bitmap GetThumbnail(string fileName, int width, int height, ThumbnailOptions options)
|
||||
{
|
||||
var hBitmap = GetHBitmap(Path.GetFullPath(fileName), width, height, options);
|
||||
|
||||
if (hBitmap == IntPtr.Zero)
|
||||
return null!;
|
||||
|
||||
try
|
||||
{
|
||||
// return a System.Drawing.Bitmap from the hBitmap
|
||||
return GetBitmapFromHBitmap(hBitmap);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// delete HBitmap to avoid memory leaks
|
||||
DeleteObject(hBitmap);
|
||||
}
|
||||
}
|
||||
|
||||
internal static Bitmap GetBitmapFromHBitmap(IntPtr nativeHBitmap)
|
||||
{
|
||||
var bmp = Image.FromHbitmap(nativeHBitmap);
|
||||
|
||||
if (Image.GetPixelFormatSize(bmp.PixelFormat) < 32)
|
||||
return bmp;
|
||||
|
||||
return CreateAlphaBitmap(bmp, PixelFormat.Format32bppArgb);
|
||||
}
|
||||
|
||||
internal static Bitmap CreateAlphaBitmap(Bitmap srcBitmap, PixelFormat targetPixelFormat)
|
||||
{
|
||||
var result = new Bitmap(srcBitmap.Width, srcBitmap.Height, targetPixelFormat);
|
||||
|
||||
var bmpBounds = new Rectangle(0, 0, srcBitmap.Width, srcBitmap.Height);
|
||||
|
||||
var srcData = srcBitmap.LockBits(bmpBounds, ImageLockMode.ReadOnly, srcBitmap.PixelFormat);
|
||||
|
||||
var isAlplaBitmap = false;
|
||||
|
||||
try
|
||||
{
|
||||
for (var y = 0; y <= srcData.Height - 1; y++)
|
||||
for (var x = 0; x <= srcData.Width - 1; x++)
|
||||
{
|
||||
var pixelColor = Color.FromArgb(
|
||||
Marshal.ReadInt32(srcData.Scan0, srcData.Stride * y + 4 * x));
|
||||
|
||||
if ((pixelColor.A > 0) & (pixelColor.A < 255))
|
||||
isAlplaBitmap = true;
|
||||
|
||||
result.SetPixel(x, y, pixelColor);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
srcBitmap.UnlockBits(srcData);
|
||||
}
|
||||
|
||||
if (isAlplaBitmap)
|
||||
return result;
|
||||
return srcBitmap;
|
||||
}
|
||||
|
||||
private static IntPtr GetHBitmap(string fileName, int width, int height, ThumbnailOptions options)
|
||||
{
|
||||
var shellItem2Guid = new Guid(IShellItem2Guid);
|
||||
var retCode =
|
||||
SHCreateItemFromParsingName(fileName, IntPtr.Zero, ref shellItem2Guid, out var nativeShellItem);
|
||||
|
||||
if (retCode != 0)
|
||||
return IntPtr.Zero;
|
||||
|
||||
var nativeSize = new NativeSize
|
||||
{
|
||||
Width = width,
|
||||
Height = height
|
||||
};
|
||||
|
||||
var hr = ((IShellItemImageFactory)nativeShellItem).GetImage(nativeSize, options, out var hBitmap);
|
||||
|
||||
Marshal.ReleaseComObject(nativeShellItem);
|
||||
|
||||
return hr == HResult.Ok ? hBitmap : IntPtr.Zero;
|
||||
}
|
||||
|
||||
[ComImport]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
[Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")]
|
||||
internal interface IShellItem
|
||||
{
|
||||
void BindToHandler(IntPtr pbc,
|
||||
[MarshalAs(UnmanagedType.LPStruct)] Guid bhid,
|
||||
[MarshalAs(UnmanagedType.LPStruct)] Guid riid,
|
||||
out IntPtr ppv);
|
||||
|
||||
void GetParent(out IShellItem ppsi);
|
||||
|
||||
void GetDisplayName(SIGDN sigdnName, out IntPtr ppszName);
|
||||
|
||||
void GetAttributes(uint sfgaoMask, out uint psfgaoAttribs);
|
||||
|
||||
void Compare(IShellItem psi, uint hint, out int piOrder);
|
||||
}
|
||||
|
||||
internal enum SIGDN : uint
|
||||
{
|
||||
NORMALDISPLAY = 0,
|
||||
PARENTRELATIVEPARSING = 0x80018001,
|
||||
PARENTRELATIVEFORADDRESSBAR = 0x8001c001,
|
||||
DESKTOPABSOLUTEPARSING = 0x80028000,
|
||||
PARENTRELATIVEEDITING = 0x80031001,
|
||||
DESKTOPABSOLUTEEDITING = 0x8004c000,
|
||||
FILESYSPATH = 0x80058000,
|
||||
URL = 0x80068000
|
||||
}
|
||||
|
||||
internal enum HResult
|
||||
{
|
||||
Ok = 0x0000,
|
||||
False = 0x0001,
|
||||
InvalidArguments = unchecked((int)0x80070057),
|
||||
OutOfMemory = unchecked((int)0x8007000E),
|
||||
NoInterface = unchecked((int)0x80004002),
|
||||
Fail = unchecked((int)0x80004005),
|
||||
ElementNotFound = unchecked((int)0x80070490),
|
||||
TypeElementNotFound = unchecked((int)0x8002802B),
|
||||
NoObject = unchecked((int)0x800401E5),
|
||||
Win32ErrorCanceled = 1223,
|
||||
Canceled = unchecked((int)0x800704C7),
|
||||
ResourceInUse = unchecked((int)0x800700AA),
|
||||
AccessDenied = unchecked((int)0x80030005)
|
||||
}
|
||||
|
||||
[ComImport]
|
||||
[Guid("bcc18b79-ba16-442f-80c4-8a59c30c463b")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
internal interface IShellItemImageFactory
|
||||
{
|
||||
[PreserveSig]
|
||||
HResult GetImage(
|
||||
[In][MarshalAs(UnmanagedType.Struct)] NativeSize size,
|
||||
[In] ThumbnailOptions flags,
|
||||
[Out] out IntPtr phbm);
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct NativeSize
|
||||
{
|
||||
private int width;
|
||||
private int height;
|
||||
|
||||
public int Width
|
||||
{
|
||||
set => width = value;
|
||||
}
|
||||
|
||||
public int Height
|
||||
{
|
||||
set => height = value;
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct RGBQUAD
|
||||
{
|
||||
public byte rgbBlue;
|
||||
public byte rgbGreen;
|
||||
public byte rgbRed;
|
||||
public byte rgbReserved;
|
||||
}
|
||||
}
|
@@ -52,7 +52,7 @@ public partial class PEInfoPanel : UserControl
|
||||
|
||||
public void DisplayInfo(string path)
|
||||
{
|
||||
Task.Run(() =>
|
||||
_ = Task.Run(() =>
|
||||
{
|
||||
var scale = DisplayDeviceHelper.GetCurrentScaleFactor();
|
||||
|
||||
|
@@ -52,6 +52,7 @@ Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "QuickLook.Installer", "Quic
|
||||
{8D50A1DA-601C-4C26-9A7E-7D477EA8430A} = {8D50A1DA-601C-4C26-9A7E-7D477EA8430A}
|
||||
{CE40160D-5E3C-4A41-9BDA-C4F414C174EB} = {CE40160D-5E3C-4A41-9BDA-C4F414C174EB}
|
||||
{538FD6BA-2AF1-4DDA-93A2-6C0A12B00843} = {538FD6BA-2AF1-4DDA-93A2-6C0A12B00843}
|
||||
{EB7D1F10-6E04-4F7E-96A0-4E18359FBD30} = {EB7D1F10-6E04-4F7E-96A0-4E18359FBD30}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QuickLook.Native64", "QuickLook.Native\QuickLook.Native64\QuickLook.Native64.vcxproj", "{794E4DCF-F715-4836-9D30-ABD296586D23}"
|
||||
@@ -80,6 +81,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Plugin.FontViewer
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Plugin.CLSIDViewer", "QuickLook.Plugin\QuickLook.Plugin.CLSIDViewer\QuickLook.Plugin.CLSIDViewer.csproj", "{538FD6BA-2AF1-4DDA-93A2-6C0A12B00843}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Plugin.AppViewer", "QuickLook.Plugin\QuickLook.Plugin.AppViewer\QuickLook.Plugin.AppViewer.csproj", "{EB7D1F10-6E04-4F7E-96A0-4E18359FBD30}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -234,6 +237,14 @@ Global
|
||||
{538FD6BA-2AF1-4DDA-93A2-6C0A12B00843}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{538FD6BA-2AF1-4DDA-93A2-6C0A12B00843}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{538FD6BA-2AF1-4DDA-93A2-6C0A12B00843}.Release|x86.Build.0 = Release|Any CPU
|
||||
{EB7D1F10-6E04-4F7E-96A0-4E18359FBD30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EB7D1F10-6E04-4F7E-96A0-4E18359FBD30}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EB7D1F10-6E04-4F7E-96A0-4E18359FBD30}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{EB7D1F10-6E04-4F7E-96A0-4E18359FBD30}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{EB7D1F10-6E04-4F7E-96A0-4E18359FBD30}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EB7D1F10-6E04-4F7E-96A0-4E18359FBD30}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{EB7D1F10-6E04-4F7E-96A0-4E18359FBD30}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{EB7D1F10-6E04-4F7E-96A0-4E18359FBD30}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -255,6 +266,7 @@ Global
|
||||
{8D50A1DA-601C-4C26-9A7E-7D477EA8430A} = {06EFDBE0-6408-4B37-BCF2-0CF9EBEA2E93}
|
||||
{CE40160D-5E3C-4A41-9BDA-C4F414C174EB} = {06EFDBE0-6408-4B37-BCF2-0CF9EBEA2E93}
|
||||
{538FD6BA-2AF1-4DDA-93A2-6C0A12B00843} = {06EFDBE0-6408-4B37-BCF2-0CF9EBEA2E93}
|
||||
{EB7D1F10-6E04-4F7E-96A0-4E18359FBD30} = {06EFDBE0-6408-4B37-BCF2-0CF9EBEA2E93}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {D3761C32-8C5F-498A-892B-3B0882994B62}
|
||||
|
Reference in New Issue
Block a user