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 ;
25using Microsoft . UI . Content ;
36using Microsoft . UI . Xaml ;
47using Microsoft . UI . Xaml . Hosting ;
58using System . Runtime . InteropServices ;
6- using System . Text ;
7- using Vanara . PInvoke ;
89using Windows . Win32 ;
10+ using Windows . Win32 . Foundation ;
911using Windows . Win32 . Graphics . Direct3D ;
1012using Windows . Win32 . Graphics . Direct3D11 ;
1113using Windows . Win32 . Graphics . Dxgi ;
1214using Windows . Win32 . Graphics . DirectComposition ;
13- using WinRT ;
14- using Windows . Win32 ;
1515using 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
1925namespace 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