Skip to content

Commit 76465a9

Browse files
committed
CHANGE CHANGE CHANGE 🥶
1 parent ca4a90c commit 76465a9

File tree

3 files changed

+157
-49
lines changed

3 files changed

+157
-49
lines changed

src/Files.App/NativeMethods.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,10 @@ S_FALSE
100100
MSG
101101
E_NOTIMPL
102102
LOGFONTW
103+
AssocCreate
104+
IQueryAssociations
105+
UnregisterClass
106+
SetWindowLong
107+
GetModuleHandle
108+
RegisterClassEx
109+
CREATESTRUCTW

src/Files.App/UserControls/FilePreviews/ShellPreview.xaml.cs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
// Copyright (c) 2024 Files Community
2+
// Licensed under the MIT License. See the LICENSE.
3+
14
using Files.App.ViewModels.Previews;
25
using Microsoft.UI.Xaml;
36
using Microsoft.UI.Xaml.Controls;
4-
using Vanara.PInvoke;
57
using Windows.Foundation;
8+
using Windows.Win32.Foundation;
69

710
namespace Files.App.UserControls.FilePreviews
811
{
@@ -13,13 +16,15 @@ public sealed partial class ShellPreview : UserControl
1316
public ShellPreview(ShellPreviewViewModel model)
1417
{
1518
ViewModel = model;
16-
this.InitializeComponent();
19+
20+
InitializeComponent();
1721
}
1822

1923
private void PreviewHost_Loaded(object sender, RoutedEventArgs e)
2024
{
2125
ViewModel.LoadPreview(contentPresenter);
2226
ViewModel.SizeChanged(GetPreviewSize());
27+
2328
if (XamlRoot.Content is FrameworkElement element)
2429
{
2530
element.SizeChanged += PreviewHost_SizeChanged;
@@ -38,11 +43,13 @@ private RECT GetPreviewSize()
3843
var physicalSize = contentPresenter.RenderSize;
3944
var physicalPos = source.TransformPoint(new Point(0, 0));
4045
var scale = XamlRoot.RasterizationScale;
41-
var result = new RECT();
42-
result.Left = (int)(physicalPos.X * scale + 0.5);
43-
result.Top = (int)(physicalPos.Y * scale + 0.5);
44-
result.Width = (int)(physicalSize.Width * scale + 0.5);
45-
result.Height = (int)(physicalSize.Height * scale + 0.5);
46+
47+
var result = RECT.FromXYWH(
48+
(int)(physicalPos.X * scale + 0.5),
49+
(int)(physicalPos.Y * scale + 0.5),
50+
(int)(physicalSize.Width * scale + 0.5),
51+
(int)(physicalSize.Height * scale + 0.5));
52+
4653
return result;
4754
}
4855

@@ -53,6 +60,7 @@ private void PreviewHost_Unloaded(object sender, RoutedEventArgs e)
5360
element.SizeChanged -= PreviewHost_SizeChanged;
5461
element.PointerEntered -= PreviewHost_PointerEntered;
5562
}
63+
5664
ViewModel.UnloadPreview();
5765
}
5866

src/Files.App/ViewModels/UserControls/Previews/ShellPreviewViewModel.cs

Lines changed: 135 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,26 @@
1-
using Files.App.ViewModels.Properties;
1+
// Copyright (c) 2024 Files Community
2+
// Licensed under the MIT License. See the LICENSE.
3+
4+
using Files.App.ViewModels.Properties;
25
using Microsoft.UI.Content;
36
using Microsoft.UI.Xaml;
47
using Microsoft.UI.Xaml.Hosting;
58
using System.Runtime.InteropServices;
6-
using System.Text;
7-
using Vanara.PInvoke;
89
using Windows.Win32;
10+
using Windows.Win32.Foundation;
911
using Windows.Win32.Graphics.Direct3D;
1012
using Windows.Win32.Graphics.Direct3D11;
1113
using Windows.Win32.Graphics.Dxgi;
1214
using Windows.Win32.Graphics.DirectComposition;
13-
using WinRT;
14-
using Windows.Win32;
1515
using Windows.Win32.Graphics.Dwm;
16-
using static Vanara.PInvoke.ShlwApi;
17-
using static Vanara.PInvoke.User32;
16+
using Windows.Win32.System.Registry;
17+
using Windows.Win32.UI.Shell;
18+
using Windows.Win32.UI.WindowsAndMessaging;
19+
using WinRT;
20+
21+
// Description: Feature is for evaluation purposes only and is subject to change or removal in future updates.
22+
// Justification: We have to use ContentExternalOutputLink for shell previews.
23+
#pragma warning disable CS8305
1824

1925
namespace Files.App.ViewModels.Previews
2026
{
@@ -34,60 +40,105 @@ public async override Task<List<FileProperty>> LoadPreviewAndDetailsAsync()
3440

3541
PreviewHandler? currentHandler;
3642
ContentExternalOutputLink? outputLink;
37-
WindowClass? wCls;
38-
HWND hwnd = HWND.NULL;
43+
WNDCLASSEXW? wCls;
44+
HWND hwnd = HWND.Null;
3945
bool isOfficePreview = false;
4046

41-
public static Guid? FindPreviewHandlerFor(string extension, IntPtr hwnd)
47+
public static unsafe Guid? FindPreviewHandlerFor(string extension, nint hwnd)
4248
{
4349
if (string.IsNullOrEmpty(extension))
4450
return null;
45-
var hr = AssocCreate(QueryAssociationsClsid, IQueryAssociationsIid, out var queryAssoc);
51+
52+
var hr = PInvoke.AssocCreate(QueryAssociationsClsid, IQueryAssociationsIid, out var queryAssocObject);
4653
if (!hr.Succeeded)
4754
return null;
55+
4856
try
4957
{
50-
if (queryAssoc == null)
58+
if (queryAssocObject is not IQueryAssociations queryAssoc)
5159
return null;
52-
queryAssoc.Init(ASSOCF.ASSOCF_INIT_DEFAULTTOSTAR, extension, IntPtr.Zero, hwnd);
53-
var sb = new StringBuilder(128);
54-
uint cch = 64;
55-
queryAssoc.GetString(ASSOCF.ASSOCF_NOTRUNCATE, ASSOCSTR.ASSOCSTR_SHELLEXTENSION, IPreviewHandlerIid, sb, ref cch);
56-
Debug.WriteLine($"Preview handler for {extension}: {sb}");
57-
return Guid.Parse(sb.ToString());
60+
61+
fixed (char* pszExtension = extension)
62+
{
63+
PWSTR lpwszExtension = new(pszExtension);
64+
65+
queryAssoc.Init(ASSOCF.ASSOCF_INIT_DEFAULTTOSTAR, lpwszExtension, HKEY.Null, new(hwnd));
66+
67+
fixed (char* pszIPreviewHandlerIID = IPreviewHandlerIid)
68+
{
69+
PWSTR lpwszIPreviewHandlerIID = new(pszIPreviewHandlerIID);
70+
71+
fixed (char* pszOutput = new char[256])
72+
{
73+
PWSTR lpwszOutput = new(pszOutput);
74+
uint cchOutput = 256u;
75+
76+
queryAssoc.GetString(
77+
ASSOCF.ASSOCF_NOTRUNCATE,
78+
ASSOCSTR.ASSOCSTR_SHELLEXTENSION,
79+
lpwszIPreviewHandlerIID,
80+
lpwszOutput,
81+
ref cchOutput);
82+
83+
Debug.WriteLine($"Preview handler for {lpwszExtension.ToString()}: {lpwszOutput.ToString()}");
84+
85+
return Guid.Parse(lpwszOutput.ToString());
86+
}
87+
}
88+
}
5889
}
5990
catch
6091
{
6192
return null;
6293
}
6394
finally
6495
{
65-
Marshal.ReleaseComObject(queryAssoc);
96+
Marshal.ReleaseComObject(queryAssocObject);
6697
}
6798
}
6899

69100
public void SizeChanged(RECT size)
70101
{
71-
if (hwnd != HWND.NULL)
72-
SetWindowPos(hwnd, HWND.HWND_TOP, size.Left, size.Top, size.Width, size.Height, SetWindowPosFlags.SWP_NOACTIVATE);
102+
if (hwnd != HWND.Null)
103+
PInvoke.SetWindowPos(hwnd, (HWND)0, size.left, size.top, size.Width, size.Height, SET_WINDOW_POS_FLAGS.SWP_NOACTIVATE);
104+
73105
if (currentHandler != null)
74106
currentHandler.ResetBounds(new(0, 0, size.Width, size.Height));
107+
75108
if (outputLink is not null)
76109
outputLink.PlacementVisual.Size = new(size.Width, size.Height);
77110
}
78111

79-
private IntPtr WndProc(HWND hwnd, uint msg, IntPtr wParam, IntPtr lParam)
112+
private unsafe LRESULT WndProc(HWND hwnd, uint msg, WPARAM wParam, LPARAM lParam)
80113
{
81-
if (msg == (uint)WindowMessage.WM_CREATE)
114+
//if (msg == 0x0081 /*WM_NCCREATE*/)
115+
//{
116+
// try
117+
// {
118+
// var cp = Marshal.PtrToStructure<CREATESTRUCTW>(lParam).lpCreateParams;
119+
// var pCreateParams = new nint(cp);
120+
// if (pCreateParams != nint.Zero && GCHandle.FromIntPtr(pCreateParams).Target is IWindowInit wnd)
121+
// return wnd.InitWndProcOnNCCreate(
122+
// hwnd,
123+
// msg,
124+
// Marshal.GetFunctionPointerForDelegate(wndProc ?? throw new NullReferenceException()),
125+
// lParam);
126+
// }
127+
// catch { }
128+
//}
129+
//else
130+
if (msg == 0x0001 /*WM_CREATE*/)
82131
{
83-
var clsid = FindPreviewHandlerFor(Item.FileExtension, hwnd.DangerousGetHandle());
132+
var clsid = FindPreviewHandlerFor(Item.FileExtension, hwnd.Value);
133+
84134
isOfficePreview = new Guid?[] {
85135
Guid.Parse("84F66100-FF7C-4fb4-B0C0-02CD7FB668FE"),
86136
Guid.Parse("65235197-874B-4A07-BDC5-E65EA825B718"),
87137
Guid.Parse("00020827-0000-0000-C000-000000000046") }.Contains(clsid);
138+
88139
try
89140
{
90-
currentHandler = new PreviewHandler(clsid.Value, hwnd.DangerousGetHandle());
141+
currentHandler = new PreviewHandler(clsid.Value, hwnd.Value);
91142
currentHandler.InitWithFileWithEveryWay(Item.ItemPath);
92143
currentHandler.DoPreview();
93144
}
@@ -96,29 +147,66 @@ private IntPtr WndProc(HWND hwnd, uint msg, IntPtr wParam, IntPtr lParam)
96147
UnloadPreview();
97148
}
98149
}
99-
else if (msg == (uint)WindowMessage.WM_DESTROY)
150+
else if (msg == 0x0002 /*WM_DESTROY*/)
100151
{
101152
if (currentHandler is not null)
102153
{
103154
currentHandler.UnloadPreview();
104155
currentHandler = null;
105156
}
106157
}
107-
return DefWindowProc(hwnd, msg, wParam, lParam);
158+
159+
return PInvoke.DefWindowProc(hwnd, msg, wParam, lParam);
108160
}
109161

110-
public void LoadPreview(UIElement presenter)
162+
public unsafe void LoadPreview(UIElement presenter)
111163
{
112164
var parent = MainWindow.Instance.WindowHandle;
113165

114-
HINSTANCE hInst = Kernel32.GetModuleHandle();
115-
wCls = new WindowClass($"{GetType().Name}{Guid.NewGuid()}", hInst, WndProc);
116-
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);
166+
HINSTANCE hInst = PInvoke.GetModuleHandle(default(PWSTR));
167+
168+
string className = $"{GetType().Name}{Guid.NewGuid()}";
169+
170+
fixed (char* pszClassName = className)
171+
{
172+
PWSTR pwszClassName = new(pszClassName);
173+
174+
wCls = new WNDCLASSEXW
175+
{
176+
cbSize = (uint)Marshal.SizeOf(typeof(WNDCLASSEXW)),
177+
lpfnWndProc = new(WndProc),
178+
hInstance = hInst,
179+
lpszClassName = pwszClassName,
180+
style = 0,
181+
hIcon = default,
182+
hIconSm = default,
183+
hCursor = default,
184+
hbrBackground = default,
185+
lpszMenuName = null,
186+
cbClsExtra = 0,
187+
cbWndExtra = 0,
188+
};
189+
190+
fixed (char* pszWindowName = "Preview")
191+
{
192+
PWSTR lpwszWindowName = new(pszWindowName);
193+
194+
hwnd = PInvoke.CreateWindowEx(
195+
WINDOW_EX_STYLE.WS_EX_LAYERED | WINDOW_EX_STYLE.WS_EX_COMPOSITED,
196+
wCls.Value.lpszClassName,
197+
lpwszWindowName,
198+
WINDOW_STYLE.WS_CHILD | WINDOW_STYLE.WS_CLIPSIBLINGS | WINDOW_STYLE.WS_VISIBLE,
199+
0, 0, 0, 0,
200+
new(parent),
201+
HMENU.Null,
202+
hInst);
203+
}
204+
}
117205

118206
_ = ChildWindowToXaml(parent, presenter);
119207
}
120208

121-
private unsafe bool ChildWindowToXaml(IntPtr parent, UIElement presenter)
209+
private unsafe bool ChildWindowToXaml(nint parent, UIElement presenter)
122210
{
123211
D3D_DRIVER_TYPE[] driverTypes =
124212
[
@@ -134,7 +222,7 @@ private unsafe bool ChildWindowToXaml(IntPtr parent, UIElement presenter)
134222
var hr = PInvoke.D3D11CreateDevice(
135223
null,
136224
driveType,
137-
new(IntPtr.Zero),
225+
new(nint.Zero),
138226
D3D11_CREATE_DEVICE_FLAG.D3D11_CREATE_DEVICE_BGRA_SUPPORT,
139227
null,
140228
0,
@@ -149,13 +237,15 @@ private unsafe bool ChildWindowToXaml(IntPtr parent, UIElement presenter)
149237

150238
if (d3d11Device is null)
151239
return false;
240+
152241
IDXGIDevice dxgiDevice = (IDXGIDevice)d3d11Device;
153242
if (PInvoke.DCompositionCreateDevice(dxgiDevice, typeof(IDCompositionDevice).GUID, out var compDevicePtr).Failed)
154243
return false;
244+
155245
IDCompositionDevice compDevice = (IDCompositionDevice)compDevicePtr;
156246

157247
compDevice.CreateVisual(out var childVisual);
158-
compDevice.CreateSurfaceFromHwnd(new(hwnd.DangerousGetHandle()), out var controlSurface);
248+
compDevice.CreateSurfaceFromHwnd(hwnd, out var controlSurface);
159249
childVisual.SetContent(controlSurface);
160250
if (childVisual is null || controlSurface is null)
161251
return false;
@@ -196,12 +286,13 @@ private unsafe bool ChildWindowToXaml(IntPtr parent, UIElement presenter)
196286

197287
public void UnloadPreview()
198288
{
199-
if (hwnd != HWND.NULL)
200-
DestroyWindow(hwnd);
201-
if (outputLink is not null)
202-
outputLink.Dispose();
289+
if (hwnd != HWND.Null)
290+
PInvoke.DestroyWindow(hwnd);
291+
292+
outputLink?.Dispose();
293+
203294
if (wCls is not null)
204-
UnregisterClass(wCls.ClassName, Kernel32.GetModuleHandle());
295+
PInvoke.UnregisterClass(wCls.Value.lpszClassName, PInvoke.GetModuleHandle(default(PWSTR)));
205296
}
206297

207298
public void PointerEntered(bool onPreview)
@@ -220,12 +311,14 @@ public void PointerEntered(bool onPreview)
220311
}
221312

222313
if (isOfficePreview)
223-
Win32Helper.SetWindowLong(hwnd, WindowLongFlags.GWL_EXSTYLE, 0);
314+
PInvoke.SetWindowLong(hwnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, 0);
224315
}
225316
else
226317
{
227-
Win32Helper.SetWindowLong(hwnd, WindowLongFlags.GWL_EXSTYLE,
228-
(nint)(WindowStylesEx.WS_EX_LAYERED | WindowStylesEx.WS_EX_COMPOSITED));
318+
PInvoke.SetWindowLong(
319+
hwnd,
320+
WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE,
321+
(int)(WINDOW_EX_STYLE.WS_EX_LAYERED | WINDOW_EX_STYLE.WS_EX_COMPOSITED));
229322

230323
unsafe
231324
{

0 commit comments

Comments
 (0)