diff --git a/src/Files.App/NativeMethods.txt b/src/Files.App/NativeMethods.txt
index 38676b61de48d..ed83e399814ff 100644
--- a/src/Files.App/NativeMethods.txt
+++ b/src/Files.App/NativeMethods.txt
@@ -94,3 +94,17 @@ DesktopWallpaper
SHCreateShellItemArrayFromIDLists
ILCreateFromPath
CLSIDFromString
+E_FAIL
+S_OK
+S_FALSE
+MSG
+E_NOTIMPL
+LOGFONTW
+AssocCreate
+IQueryAssociations
+UnregisterClass
+SetWindowLong
+GetModuleHandle
+RegisterClassEx
+CREATESTRUCTW
+AssocQueryString
diff --git a/src/Files.App/UserControls/FilePreviews/ShellPreview.xaml.cs b/src/Files.App/UserControls/FilePreviews/ShellPreview.xaml.cs
index d0f09e7aed50c..935227a1cc076 100644
--- a/src/Files.App/UserControls/FilePreviews/ShellPreview.xaml.cs
+++ b/src/Files.App/UserControls/FilePreviews/ShellPreview.xaml.cs
@@ -1,8 +1,11 @@
+// Copyright (c) 2024 Files Community
+// Licensed under the MIT License. See the LICENSE.
+
using Files.App.ViewModels.Previews;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
-using Vanara.PInvoke;
using Windows.Foundation;
+using Windows.Win32.Foundation;
namespace Files.App.UserControls.FilePreviews
{
@@ -13,13 +16,15 @@ public sealed partial class ShellPreview : UserControl
public ShellPreview(ShellPreviewViewModel model)
{
ViewModel = model;
- this.InitializeComponent();
+
+ InitializeComponent();
}
private void PreviewHost_Loaded(object sender, RoutedEventArgs e)
{
ViewModel.LoadPreview(contentPresenter);
ViewModel.SizeChanged(GetPreviewSize());
+
if (XamlRoot.Content is FrameworkElement element)
{
element.SizeChanged += PreviewHost_SizeChanged;
@@ -38,11 +43,13 @@ private RECT GetPreviewSize()
var physicalSize = contentPresenter.RenderSize;
var physicalPos = source.TransformPoint(new Point(0, 0));
var scale = XamlRoot.RasterizationScale;
- var result = new RECT();
- result.Left = (int)(physicalPos.X * scale + 0.5);
- result.Top = (int)(physicalPos.Y * scale + 0.5);
- result.Width = (int)(physicalSize.Width * scale + 0.5);
- result.Height = (int)(physicalSize.Height * scale + 0.5);
+
+ var result = RECT.FromXYWH(
+ (int)(physicalPos.X * scale + 0.5),
+ (int)(physicalPos.Y * scale + 0.5),
+ (int)(physicalSize.Width * scale + 0.5),
+ (int)(physicalSize.Height * scale + 0.5));
+
return result;
}
@@ -53,6 +60,7 @@ private void PreviewHost_Unloaded(object sender, RoutedEventArgs e)
element.SizeChanged -= PreviewHost_SizeChanged;
element.PointerEntered -= PreviewHost_PointerEntered;
}
+
ViewModel.UnloadPreview();
}
diff --git a/src/Files.App/Utils/Shell/PreviewHandler.cs b/src/Files.App/Utils/Shell/PreviewHandler.cs
index 6cb5f40017981..e449e7374df6a 100644
--- a/src/Files.App/Utils/Shell/PreviewHandler.cs
+++ b/src/Files.App/Utils/Shell/PreviewHandler.cs
@@ -1,9 +1,13 @@
-using System;
-using System.Collections.Generic;
+// Copyright (c) 2024 Files Community
+// Licensed under the MIT License. See the LICENSE.
+
using System.Runtime.InteropServices;
-using System.Runtime.InteropServices.ComTypes;
-using Vanara.PInvoke;
using Windows.UI;
+using Windows.Win32;
+using Windows.Win32.Foundation;
+using Windows.Win32.Graphics.Gdi;
+using Windows.Win32.System.Com;
+using Windows.Win32.UI.WindowsAndMessaging;
namespace Files.App.Utils.Shell
{
@@ -17,7 +21,7 @@ public sealed class PreviewHandler : IDisposable
[StructLayout(LayoutKind.Sequential)]
public struct PreviewHandlerFrameInfo
{
- public IntPtr AcceleratorTableHandle;
+ public nint AcceleratorTableHandle;
public uint AcceleratorEntryCount;
}
@@ -49,7 +53,7 @@ public void Dispose()
public HRESULT GetWindowContext(out PreviewHandlerFrameInfo pinfo)
{
- pinfo.AcceleratorTableHandle = IntPtr.Zero;
+ pinfo.AcceleratorTableHandle = nint.Zero;
pinfo.AcceleratorEntryCount = 0;
if (disposed)
return HRESULT.E_FAIL;
@@ -72,7 +76,7 @@ public HRESULT TranslateAccelerator(ref MSG pmsg)
interface IPreviewHandler
{
[PreserveSig]
- HRESULT SetWindow(IntPtr hwnd, ref RECT prc);
+ HRESULT SetWindow(nint hwnd, ref RECT prc);
[PreserveSig]
HRESULT SetRect(ref RECT prc);
[PreserveSig]
@@ -82,7 +86,7 @@ interface IPreviewHandler
[PreserveSig]
HRESULT SetFocus();
[PreserveSig]
- HRESULT QueryFocus(out IntPtr phwnd);
+ HRESULT QueryFocus(out nint phwnd);
// TranslateAccelerator is not used here.
}
@@ -92,7 +96,7 @@ interface IPreviewHandlerVisuals
[PreserveSig]
HRESULT SetBackgroundColor(uint color);
[PreserveSig]
- HRESULT SetFont(ref LOGFONT plf);
+ HRESULT SetFont(ref LOGFONTW plf);
[PreserveSig]
HRESULT SetTextColor(uint color);
}
@@ -119,7 +123,7 @@ interface IObjectWithSite
nint hwnd;
IPreviewHandler previewHandler;
IPreviewHandlerVisuals visuals;
- IntPtr pPreviewHandler;
+ nint pPreviewHandler;
public PreviewHandler(Guid clsid, nint frame)
{
@@ -138,9 +142,9 @@ public PreviewHandler(Guid clsid, nint frame)
if (previewHandler != null)
Marshal.ReleaseComObject(previewHandler);
previewHandler = null;
- if (pPreviewHandler != IntPtr.Zero)
+ if (pPreviewHandler != nint.Zero)
Marshal.Release(pPreviewHandler);
- pPreviewHandler = IntPtr.Zero;
+ pPreviewHandler = nint.Zero;
comSite.Dispose();
comSite = null;
throw;
@@ -149,41 +153,51 @@ public PreviewHandler(Guid clsid, nint frame)
static readonly Guid IPreviewHandlerIid = Guid.ParseExact("8895b1c6-b41f-4c1c-a562-0d564250836f", "d");
- void SetupHandler(Guid clsid)
+ unsafe void SetupHandler(Guid clsid)
{
- IntPtr pph;
+ nint pph;
var iid = IPreviewHandlerIid;
var cannotCreate = "Cannot create class " + clsid.ToString() + " as IPreviewHandler.";
var cannotCast = "Cannot cast class " + clsid.ToString() + " as IObjectWithSite.";
var cannotSetSite = "Cannot set site to the preview handler object.";
- // Important: manully calling CoCreateInstance is necessary.
+
+ // Important: manually calling CoCreateInstance is necessary.
// If we use Activator.CreateInstance(Type.GetTypeFromCLSID(...)),
// CLR will allow in-process server, which defeats isolation and
// creates strange bugs.
- HRESULT hr = Win32PInvoke.CoCreateInstance(ref clsid, IntPtr.Zero, Win32PInvoke.ClassContext.LocalServer, ref iid, out pph);
+ HRESULT hr = PInvoke.CoCreateInstance(
+ clsid,
+ null,
+ CLSCTX.CLSCTX_LOCAL_SERVER,
+ ref iid,
+ out object previewHandlerObject);
+
// See https://blogs.msdn.microsoft.com/adioltean/2005/06/24/when-cocreateinstance-returns-0x80080005-co_e_server_exec_failure/
// CO_E_SERVER_EXEC_FAILURE also tends to happen when debugging in Visual Studio.
// Moreover, to create the instance in a server at low integrity level, we need
// to use another thread with low mandatory label. We keep it simple by creating
// a same-integrity object.
//if (hr == HRESULT.CO_E_SERVER_EXEC_FAILURE)
- // hr = CoCreateInstance(ref clsid, IntPtr.Zero, ClassContext.LocalServer, ref iid, out pph);
+ // hr = CoCreateInstance(ref clsid, nint.Zero, ClassContext.LocalServer, ref iid, out pph);
if ((int)hr < 0)
throw new COMException(cannotCreate, (int)hr);
- pPreviewHandler = pph;
- var previewHandlerObject = Marshal.GetUniqueObjectForIUnknown(pph);
- previewHandler = previewHandlerObject as IPreviewHandler;
+
+ pPreviewHandler = new(&previewHandlerObject);
+ previewHandler = (IPreviewHandler)previewHandlerObject;
if (previewHandler == null)
{
Marshal.ReleaseComObject(previewHandlerObject);
throw new COMException(cannotCreate);
}
+
var objectWithSite = previewHandlerObject as IObjectWithSite;
if (objectWithSite == null)
throw new COMException(cannotCast);
+
hr = objectWithSite.SetSite(comSite);
if ((int)hr < 0)
throw new COMException(cannotSetSite, (int)hr);
+
visuals = previewHandlerObject as IPreviewHandlerVisuals;
}
@@ -200,7 +214,7 @@ interface IInitializeWithStream
interface IInitializeWithStreamNative
{
[PreserveSig]
- HRESULT Initialize(IntPtr psi, STGM grfMode);
+ HRESULT Initialize(nint psi, STGM grfMode);
}
static readonly Guid IInitializeWithStreamIid = Guid.ParseExact("b824b49d-22ac-4161-ac8a-9916e8fa3f7f", "d");
@@ -218,7 +232,7 @@ interface IInitializeWithFile
interface IInitializeWithItem
{
[PreserveSig]
- HRESULT Initialize(IntPtr psi, STGM grfMode);
+ HRESULT Initialize(nint psi, STGM grfMode);
}
static readonly Guid IInitializeWithItemIid = Guid.ParseExact("7f73be3f-fb79-493c-a6c7-7ee14e245841", "d");
@@ -237,15 +251,19 @@ public bool InitWithStream(IStream stream, STGM mode)
{
if (mode != STGM.STGM_READ && mode != STGM.STGM_READWRITE)
throw new ArgumentOutOfRangeException("mode", mode, "The argument mode must be Read or ReadWrite.");
+
var iws = previewHandler as IInitializeWithStream;
if (iws == null)
return false;
+
var hr = iws.Initialize(stream, mode);
if (hr == HRESULT.E_NOTIMPL)
return false;
if ((int)hr < 0)
throw new COMException("IInitializeWithStream.Initialize failed.", (int)hr);
+
init = true;
+
return true;
}
@@ -257,21 +275,26 @@ public bool InitWithStream(IStream stream, STGM mode)
/// The native pointer to the IStream interface.
/// The storage mode.
/// True or false, see InitWithStream(IStream, STGM).
- public bool InitWithStream(IntPtr pStream, STGM mode)
+ public bool InitWithStream(nint pStream, STGM mode)
{
EnsureNotDisposed();
EnsureNotInitialized();
+
if (mode != STGM.STGM_READ && mode != STGM.STGM_READWRITE)
throw new ArgumentOutOfRangeException("mode", mode, "The argument mode must be Read or ReadWrite.");
+
var iws = previewHandler as IInitializeWithStreamNative;
if (iws == null)
return false;
+
var hr = iws.Initialize(pStream, mode);
if (hr == HRESULT.E_NOTIMPL)
return false;
if ((int)hr < 0)
throw new COMException("IInitializeWithStream.Initialize failed.", (int)hr);
+
init = true;
+
return true;
}
@@ -283,21 +306,26 @@ public bool InitWithStream(IntPtr pStream, STGM mode)
/// The native pointer to the IShellItem interface.
/// The storage mode.
/// True or false, see InitWithStream(IStream, STGM).
- public bool InitWithItem(IntPtr psi, STGM mode)
+ public bool InitWithItem(nint psi, STGM mode)
{
EnsureNotDisposed();
EnsureNotInitialized();
+
if (mode != STGM.STGM_READ && mode != STGM.STGM_READWRITE)
throw new ArgumentOutOfRangeException("mode", mode, "The argument mode must be Read or ReadWrite.");
+
var iwi = previewHandler as IInitializeWithItem;
if (iwi == null)
return false;
+
var hr = iwi.Initialize(psi, mode);
if (hr == HRESULT.E_NOTIMPL)
return false;
if ((int)hr < 0)
throw new COMException("IInitializeWithItem.Initialize failed.", (int)hr);
+
init = true;
+
return true;
}
@@ -313,17 +341,22 @@ public bool InitWithFile(string path, STGM mode)
{
EnsureNotDisposed();
EnsureNotInitialized();
+
if (mode != STGM.STGM_READ && mode != STGM.STGM_READWRITE)
throw new ArgumentOutOfRangeException("mode", mode, "The argument mode must be Read or ReadWrite.");
+
var iwf = previewHandler as IInitializeWithFile;
if (iwf == null)
return false;
+
var hr = iwf.Initialize(path, mode);
if (hr == HRESULT.E_NOTIMPL)
return false;
if ((int)hr < 0)
throw new COMException("IInitializeWithFile.Initialize failed.", (int)hr);
+
init = true;
+
return true;
}
@@ -335,7 +368,8 @@ public bool InitWithFile(string path, STGM mode)
public bool InitWithFileWithEveryWay(string path)
{
var exceptions = new List();
- var pobj = IntPtr.Zero;
+ var pobj = nint.Zero;
+
// Why should we try IStream first?
// Because that gives us the best security.
// If we initialize with string or IShellItem,
@@ -345,7 +379,7 @@ public bool InitWithFileWithEveryWay(string path)
try
{
pobj = ItemStreamHelper.IStreamFromPath(path);
- if (pobj != IntPtr.Zero
+ if (pobj != nint.Zero
&& InitWithStream(pobj, STGM.STGM_READ))
return true;
}
@@ -355,10 +389,12 @@ public bool InitWithFileWithEveryWay(string path)
}
finally
{
- if (pobj != IntPtr.Zero)
+ if (pobj != nint.Zero)
ItemStreamHelper.ReleaseObject(pobj);
- pobj = IntPtr.Zero;
+
+ pobj = nint.Zero;
}
+
// Next try file because that could save us some P/Invokes.
try
{
@@ -369,12 +405,14 @@ public bool InitWithFileWithEveryWay(string path)
{
exceptions.Add(ex);
}
+
try
{
pobj = ItemStreamHelper.IShellItemFromPath(path);
- if (pobj != IntPtr.Zero
+ if (pobj != nint.Zero
&& InitWithItem(pobj, STGM.STGM_READ))
return true;
+
if (exceptions.Count == 0)
throw new NotSupportedException("The object cannot be initialized at all.");
}
@@ -384,10 +422,12 @@ public bool InitWithFileWithEveryWay(string path)
}
finally
{
- if (pobj != IntPtr.Zero)
+ if (pobj != nint.Zero)
ItemStreamHelper.ReleaseObject(pobj);
- pobj = IntPtr.Zero;
+
+ pobj = nint.Zero;
}
+
throw new AggregateException(exceptions);
}
@@ -397,9 +437,12 @@ public bool InitWithFileWithEveryWay(string path)
public bool ResetWindow()
{
EnsureNotDisposed();
+
//EnsureInitialized();
+
if (!init)
return false;
+
var hr = previewHandler.SetWindow(hwnd, new());
return (int)hr >= 0;
}
@@ -410,9 +453,12 @@ public bool ResetWindow()
public bool ResetBounds(RECT previewerBounds)
{
EnsureNotDisposed();
+
//EnsureInitialized();
+
if (!init)
return false;
+
var hr = previewHandler.SetRect(previewerBounds);
return (int)hr >= 0;
}
@@ -444,7 +490,7 @@ public bool SetForeground(Color color)
///
/// The LogFontW reference.
/// Whether the call succeeds.
- public bool SetFont(ref LOGFONT font)
+ public bool SetFont(ref LOGFONTW font)
{
var hr = visuals?.SetFont(ref font);
return hr.HasValue && (int)hr.Value >= 0;
@@ -456,12 +502,18 @@ public bool SetFont(ref LOGFONT font)
public void DoPreview()
{
EnsureNotDisposed();
+
//EnsureInitialized();
+
if (!init)
return;
+
EnsureNotShown();
+
ResetWindow();
+
previewHandler.DoPreview();
+
shown = true;
}
@@ -471,9 +523,12 @@ public void DoPreview()
public void Focus()
{
EnsureNotDisposed();
+
//EnsureInitialized();
+
if (!init)
return;
+
EnsureShown();
previewHandler.SetFocus();
}
@@ -482,17 +537,23 @@ public void Focus()
/// Tells the preview handler to query focus.
///
/// The focused window.
- public IntPtr QueryFocus()
+ public nint QueryFocus()
{
EnsureNotDisposed();
+
//EnsureInitialized();
+
if (!init)
- return IntPtr.Zero;
+ return nint.Zero;
+
EnsureShown();
- IntPtr result;
+
+ nint result;
+
var hr = previewHandler.QueryFocus(out result);
if ((int)hr < 0)
- return IntPtr.Zero;
+ return nint.Zero;
+
return result;
}
@@ -534,7 +595,7 @@ void EnsureNotShown()
throw new InvalidOperationException("The preview handler must not be shown to call this method.");
}
- #region IDisposable pattern
+ // Dispose
void Dispose(bool disposing)
{
@@ -572,8 +633,5 @@ void IDisposable.Dispose()
Dispose(true);
GC.SuppressFinalize(this);
}
-
- #endregion
-
}
}
diff --git a/src/Files.App/ViewModels/UserControls/Previews/ShellPreviewViewModel.cs b/src/Files.App/ViewModels/UserControls/Previews/ShellPreviewViewModel.cs
index 4a932c1de4dfa..cf006728fb975 100644
--- a/src/Files.App/ViewModels/UserControls/Previews/ShellPreviewViewModel.cs
+++ b/src/Files.App/ViewModels/UserControls/Previews/ShellPreviewViewModel.cs
@@ -1,93 +1,116 @@
-using Files.App.ViewModels.Properties;
+// Copyright (c) 2024 Files Community
+// Licensed under the MIT License. See the LICENSE.
+
+using Files.App.ViewModels.Properties;
using Microsoft.UI.Content;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Hosting;
using System.Runtime.InteropServices;
-using System.Text;
-using Vanara.PInvoke;
using Windows.Win32;
+using Windows.Win32.Foundation;
using Windows.Win32.Graphics.Direct3D;
using Windows.Win32.Graphics.Direct3D11;
using Windows.Win32.Graphics.Dxgi;
using Windows.Win32.Graphics.DirectComposition;
-using WinRT;
-using Windows.Win32;
using Windows.Win32.Graphics.Dwm;
-using static Vanara.PInvoke.ShlwApi;
-using static Vanara.PInvoke.User32;
+using Windows.Win32.UI.Shell;
+using Windows.Win32.UI.WindowsAndMessaging;
+using WinRT;
+
+// Description: Feature is for evaluation purposes only and is subject to change or removal in future updates.
+// Justification: We have to use ContentExternalOutputLink for shell previews.
+#pragma warning disable CS8305
namespace Files.App.ViewModels.Previews
{
public sealed class ShellPreviewViewModel : BasePreviewModel
{
- public ShellPreviewViewModel(ListedItem item)
- : base(item)
+ PreviewHandler? currentHandler;
+ ContentExternalOutputLink? outputLink;
+ WNDCLASSEXW? wCls;
+ HWND hwnd = HWND.Null;
+ bool isOfficePreview = false;
+
+ public ShellPreviewViewModel(ListedItem item) : base(item)
{
}
public async override Task> LoadPreviewAndDetailsAsync()
=> [];
- private const string IPreviewHandlerIid = "{8895b1c6-b41f-4c1c-a562-0d564250836f}";
- private static readonly Guid QueryAssociationsClsid = new Guid(0xa07034fd, 0x6caa, 0x4954, 0xac, 0x3f, 0x97, 0xa2, 0x72, 0x16, 0xf9, 0x8a);
- private static readonly Guid IQueryAssociationsIid = Guid.ParseExact("c46ca590-3c3f-11d2-bee6-0000f805ca57", "d");
-
- PreviewHandler? currentHandler;
- ContentExternalOutputLink? outputLink;
- WindowClass? wCls;
- HWND hwnd = HWND.NULL;
- bool isOfficePreview = false;
-
- public static Guid? FindPreviewHandlerFor(string extension, IntPtr hwnd)
+ public static unsafe Guid? FindPreviewHandlerFor(string extension, nint hwnd)
{
if (string.IsNullOrEmpty(extension))
return null;
- var hr = AssocCreate(QueryAssociationsClsid, IQueryAssociationsIid, out var queryAssoc);
- if (!hr.Succeeded)
- return null;
+
try
{
- if (queryAssoc == null)
- return null;
- queryAssoc.Init(ASSOCF.ASSOCF_INIT_DEFAULTTOSTAR, extension, IntPtr.Zero, hwnd);
- var sb = new StringBuilder(128);
- uint cch = 64;
- queryAssoc.GetString(ASSOCF.ASSOCF_NOTRUNCATE, ASSOCSTR.ASSOCSTR_SHELLEXTENSION, IPreviewHandlerIid, sb, ref cch);
- Debug.WriteLine($"Preview handler for {extension}: {sb}");
- return Guid.Parse(sb.ToString());
+ fixed (char* pszOutput = new char[1024])
+ {
+ PWSTR pwszOutput = new(pszOutput);
+ uint cchOutput = 512u;
+
+ // Try to find registered preview handler associated with specified extension name
+ var res = PInvoke.AssocQueryString(
+ ASSOCF.ASSOCF_NOTRUNCATE,
+ ASSOCSTR.ASSOCSTR_SHELLEXTENSION,
+ extension,
+ "{8895b1c6-b41f-4c1c-a562-0d564250836f}",
+ pszOutput,
+ ref cchOutput);
+
+ return Guid.Parse(pwszOutput.ToString());
+ }
}
catch
{
return null;
}
- finally
- {
- Marshal.ReleaseComObject(queryAssoc);
- }
}
public void SizeChanged(RECT size)
{
- if (hwnd != HWND.NULL)
- SetWindowPos(hwnd, HWND.HWND_TOP, size.Left, size.Top, size.Width, size.Height, SetWindowPosFlags.SWP_NOACTIVATE);
+ if (hwnd != HWND.Null)
+ PInvoke.SetWindowPos(hwnd, (HWND)0, size.left, size.top, size.Width, size.Height, SET_WINDOW_POS_FLAGS.SWP_NOACTIVATE);
+
if (currentHandler != null)
currentHandler.ResetBounds(new(0, 0, size.Width, size.Height));
+
if (outputLink is not null)
outputLink.PlacementVisual.Size = new(size.Width, size.Height);
}
- private IntPtr WndProc(HWND hwnd, uint msg, IntPtr wParam, IntPtr lParam)
+ private unsafe LRESULT WndProc(HWND hwnd, uint msg, WPARAM wParam, LPARAM lParam)
{
- if (msg == (uint)WindowMessage.WM_CREATE)
+ //if (msg == 0x0081 /*WM_NCCREATE*/)
+ //{
+ // try
+ // {
+ // var cp = Marshal.PtrToStructure(lParam).lpCreateParams;
+ // var pCreateParams = new nint(cp);
+ // if (pCreateParams != nint.Zero && GCHandle.FromIntPtr(pCreateParams).Target is IWindowInit wnd)
+ // return wnd.InitWndProcOnNCCreate(
+ // hwnd,
+ // msg,
+ // Marshal.GetFunctionPointerForDelegate(wndProc ?? throw new NullReferenceException()),
+ // lParam);
+ // }
+ // catch { }
+ //}
+ //else
+ if (msg == 0x0001 /*WM_CREATE*/)
{
- var clsid = FindPreviewHandlerFor(Item.FileExtension, hwnd.DangerousGetHandle());
+ var clsid = FindPreviewHandlerFor(Item.FileExtension, hwnd.Value);
+
isOfficePreview = new Guid?[] {
- Guid.Parse("84F66100-FF7C-4fb4-B0C0-02CD7FB668FE"),
+ Guid.Parse("84F66100-FF7C-4fb4-B0C0-02CD7FB668FE"), //
Guid.Parse("65235197-874B-4A07-BDC5-E65EA825B718"),
- Guid.Parse("00020827-0000-0000-C000-000000000046") }.Contains(clsid);
+ Guid.Parse("00020827-0000-0000-C000-000000000046")
+ }.Contains(clsid);
+
try
{
- currentHandler = new PreviewHandler(clsid.Value, hwnd.DangerousGetHandle());
+ currentHandler = new PreviewHandler(clsid.Value, hwnd.Value);
currentHandler.InitWithFileWithEveryWay(Item.ItemPath);
currentHandler.DoPreview();
}
@@ -96,7 +119,7 @@ private IntPtr WndProc(HWND hwnd, uint msg, IntPtr wParam, IntPtr lParam)
UnloadPreview();
}
}
- else if (msg == (uint)WindowMessage.WM_DESTROY)
+ else if (msg == 0x0002 /*WM_DESTROY*/)
{
if (currentHandler is not null)
{
@@ -104,21 +127,53 @@ private IntPtr WndProc(HWND hwnd, uint msg, IntPtr wParam, IntPtr lParam)
currentHandler = null;
}
}
- return DefWindowProc(hwnd, msg, wParam, lParam);
+
+ return PInvoke.DefWindowProc(hwnd, msg, wParam, lParam);
}
- public void LoadPreview(UIElement presenter)
+ public unsafe void LoadPreview(UIElement presenter)
{
var parent = MainWindow.Instance.WindowHandle;
+ var hInst = PInvoke.GetModuleHandle(default(PWSTR));
+ var szClassName = $"{GetType().Name}-{Guid.NewGuid()}";
+ var szWindowName = $"Preview";
- HINSTANCE hInst = Kernel32.GetModuleHandle();
- wCls = new WindowClass($"{GetType().Name}{Guid.NewGuid()}", hInst, WndProc);
- hwnd = CreateWindowEx(WindowStylesEx.WS_EX_LAYERED | WindowStylesEx.WS_EX_COMPOSITED, wCls.ClassName, "Preview", WindowStyles.WS_CHILD | WindowStyles.WS_CLIPSIBLINGS | WindowStyles.WS_VISIBLE, 0, 0, 0, 0, hWndParent: parent, hInstance: hInst);
+ fixed (char* pszClassName = szClassName)
+ {
+ wCls = new WNDCLASSEXW
+ {
+ cbSize = (uint)Marshal.SizeOf(typeof(WNDCLASSEXW)),
+ lpfnWndProc = new(WndProc),
+ hInstance = hInst,
+ lpszClassName = pszClassName,
+ style = 0,
+ hIcon = default,
+ hIconSm = default,
+ hCursor = default,
+ hbrBackground = default,
+ lpszMenuName = null,
+ cbClsExtra = 0,
+ cbWndExtra = 0,
+ };
+
+ fixed (char* pszWindowName = szWindowName)
+ {
+ hwnd = PInvoke.CreateWindowEx(
+ WINDOW_EX_STYLE.WS_EX_LAYERED | WINDOW_EX_STYLE.WS_EX_COMPOSITED,
+ wCls.Value.lpszClassName,
+ pszWindowName,
+ WINDOW_STYLE.WS_CHILD | WINDOW_STYLE.WS_CLIPSIBLINGS | WINDOW_STYLE.WS_VISIBLE,
+ 0, 0, 0, 0,
+ new(parent),
+ HMENU.Null,
+ hInst);
+ }
+ }
_ = ChildWindowToXaml(parent, presenter);
}
- private unsafe bool ChildWindowToXaml(IntPtr parent, UIElement presenter)
+ private unsafe bool ChildWindowToXaml(nint parent, UIElement presenter)
{
D3D_DRIVER_TYPE[] driverTypes =
[
@@ -134,7 +189,7 @@ private unsafe bool ChildWindowToXaml(IntPtr parent, UIElement presenter)
var hr = PInvoke.D3D11CreateDevice(
null,
driveType,
- new(IntPtr.Zero),
+ new(nint.Zero),
D3D11_CREATE_DEVICE_FLAG.D3D11_CREATE_DEVICE_BGRA_SUPPORT,
null,
0,
@@ -149,13 +204,15 @@ private unsafe bool ChildWindowToXaml(IntPtr parent, UIElement presenter)
if (d3d11Device is null)
return false;
+
IDXGIDevice dxgiDevice = (IDXGIDevice)d3d11Device;
if (PInvoke.DCompositionCreateDevice(dxgiDevice, typeof(IDCompositionDevice).GUID, out var compDevicePtr).Failed)
return false;
+
IDCompositionDevice compDevice = (IDCompositionDevice)compDevicePtr;
compDevice.CreateVisual(out var childVisual);
- compDevice.CreateSurfaceFromHwnd(new(hwnd.DangerousGetHandle()), out var controlSurface);
+ compDevice.CreateSurfaceFromHwnd(hwnd, out var controlSurface);
childVisual.SetContent(controlSurface);
if (childVisual is null || controlSurface is null)
return false;
@@ -196,12 +253,13 @@ private unsafe bool ChildWindowToXaml(IntPtr parent, UIElement presenter)
public void UnloadPreview()
{
- if (hwnd != HWND.NULL)
- DestroyWindow(hwnd);
- if (outputLink is not null)
- outputLink.Dispose();
+ if (hwnd != HWND.Null)
+ PInvoke.DestroyWindow(hwnd);
+
+ outputLink?.Dispose();
+
if (wCls is not null)
- UnregisterClass(wCls.ClassName, Kernel32.GetModuleHandle());
+ PInvoke.UnregisterClass(wCls.Value.lpszClassName, PInvoke.GetModuleHandle(default(PWSTR)));
}
public void PointerEntered(bool onPreview)
@@ -220,12 +278,14 @@ public void PointerEntered(bool onPreview)
}
if (isOfficePreview)
- Win32Helper.SetWindowLong(hwnd, WindowLongFlags.GWL_EXSTYLE, 0);
+ PInvoke.SetWindowLong(hwnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, 0);
}
else
{
- Win32Helper.SetWindowLong(hwnd, WindowLongFlags.GWL_EXSTYLE,
- (nint)(WindowStylesEx.WS_EX_LAYERED | WindowStylesEx.WS_EX_COMPOSITED));
+ PInvoke.SetWindowLong(
+ hwnd,
+ WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE,
+ (int)(WINDOW_EX_STYLE.WS_EX_LAYERED | WINDOW_EX_STYLE.WS_EX_COMPOSITED));
unsafe
{