6
6
using Microsoft . UI . Xaml ;
7
7
using Microsoft . UI . Xaml . Hosting ;
8
8
using System . Runtime . InteropServices ;
9
- using System . Text ;
10
- using Vanara . PInvoke ;
11
9
using Windows . Win32 ;
12
- using Windows . Win32 . System . Com ;
10
+ using Windows . Win32 . Foundation ;
13
11
using Windows . Win32 . Graphics . Direct3D ;
14
12
using Windows . Win32 . Graphics . Direct3D11 ;
15
13
using Windows . Win32 . Graphics . DirectComposition ;
16
14
using Windows . Win32 . Graphics . Dwm ;
17
15
using Windows . Win32 . Graphics . Dxgi ;
16
+ using Windows . Win32 . System . Com ;
17
+ using Windows . Win32 . UI . Shell ;
18
18
using Windows . Win32 . UI . WindowsAndMessaging ;
19
19
using WinRT ;
20
- using static Vanara . PInvoke . ShlwApi ;
21
- using static Vanara . PInvoke . User32 ;
22
- using System . Runtime . InteropServices . Marshalling ;
23
-
24
20
25
21
#pragma warning disable CS8305 // Type is for evaluation purposes only and is subject to change or removal in future updates.
26
22
27
23
namespace Files . App . ViewModels . Previews
28
24
{
29
25
public sealed partial class ShellPreviewViewModel : BasePreviewModel
30
26
{
31
- private const string IPreviewHandlerIid = "{8895b1c6-b41f-4c1c-a562-0d564250836f}" ;
32
- private static readonly Guid QueryAssociationsClsid = new Guid ( 0xa07034fd , 0x6caa , 0x4954 , 0xac , 0x3f , 0x97 , 0xa2 , 0x72 , 0x16 , 0xf9 , 0x8a ) ;
33
- private static readonly Guid IQueryAssociationsIid = Guid . ParseExact ( "c46ca590-3c3f-11d2-bee6-0000f805ca57" , "d" ) ;
34
-
35
- PreviewHandler ? currentHandler ;
36
- ContentExternalOutputLink ? outputLink ;
37
- WindowClass ? wCls ;
38
- HWND hwnd = HWND . NULL ;
39
- bool isOfficePreview = false ;
27
+ // Fields
28
+
29
+ ContentExternalOutputLink ? _contentExternalOutputLink ;
30
+ PreviewHandler ? _previewHandler ;
31
+ WNDCLASSEXW _windowClass ;
32
+ WNDPROC _windProc = null ! ;
33
+ HWND _hWnd = HWND . Null ;
34
+ bool _isOfficePreview = false ;
40
35
ComPtr < IDCompositionVisual > pChildVisual = default ;
41
36
42
- [ GeneratedComInterface , Guid ( "EACDD04C-117E-4E17-88F4-D1B12B0E3D89" ) , InterfaceType ( ComInterfaceType . InterfaceIsIUnknown ) ]
43
- public partial interface IDCompositionTarget
44
- {
45
- [ PreserveSig ]
46
- int SetRoot ( nint visual ) ;
47
- }
37
+ // Constructor
48
38
49
39
public ShellPreviewViewModel ( ListedItem item ) : base ( item )
50
40
{
51
41
}
52
42
53
- public async override Task < List < FileProperty > > LoadPreviewAndDetailsAsync ( )
54
- => [ ] ;
43
+ // Methods
44
+
45
+ public override Task < List < FileProperty > > LoadPreviewAndDetailsAsync ( )
46
+ => Task . FromResult < List < FileProperty > > ( [ ] ) ;
55
47
56
- public static Guid ? FindPreviewHandlerFor ( string extension , nint hwnd )
48
+ public static unsafe Guid ? FindPreviewHandlerFor ( string extension , nint hwnd )
57
49
{
58
50
if ( string . IsNullOrEmpty ( extension ) )
59
51
return null ;
60
52
61
- var hr = AssocCreate ( QueryAssociationsClsid , IQueryAssociationsIid , out var queryAssoc ) ;
62
- if ( ! hr . Succeeded )
63
- return null ;
64
-
65
53
try
66
54
{
67
- if ( queryAssoc == null )
68
- return null ;
69
-
70
- queryAssoc . Init ( ASSOCF . ASSOCF_INIT_DEFAULTTOSTAR , extension , nint . Zero , hwnd ) ;
71
-
72
- var sb = new StringBuilder ( 128 ) ;
73
- uint cch = 64 ;
74
-
75
- queryAssoc . GetString ( ASSOCF . ASSOCF_NOTRUNCATE , ASSOCSTR . ASSOCSTR_SHELLEXTENSION , IPreviewHandlerIid , sb , ref cch ) ;
76
-
77
- Debug . WriteLine ( $ "Preview handler for { extension } : { sb } ") ;
78
- return Guid . Parse ( sb . ToString ( ) ) ;
55
+ fixed ( char * pszAssoc = extension ,
56
+ pszExtra = "{8895b1c6-b41f-4c1c-a562-0d564250836f}" ,
57
+ pszOutput = new char [ 1024 ] )
58
+ {
59
+ PWSTR pwszAssoc = new ( pszAssoc ) ;
60
+ PWSTR pwszExtra = new ( pszExtra ) ;
61
+ PWSTR pwszOutput = new ( pszOutput ) ;
62
+ uint cchOutput = 2024 ;
63
+
64
+ // Try to find registered preview handler associated with specified extension name
65
+ var res = PInvoke . AssocQueryString (
66
+ ASSOCF . ASSOCF_NOTRUNCATE ,
67
+ ASSOCSTR . ASSOCSTR_SHELLEXTENSION ,
68
+ pwszAssoc ,
69
+ pwszExtra ,
70
+ pwszOutput ,
71
+ & cchOutput ) ;
72
+
73
+ return Guid . Parse ( pwszOutput . ToString ( ) ) ;
74
+ }
79
75
}
80
76
catch
81
77
{
82
78
return null ;
83
79
}
84
- finally
85
- {
86
- Marshal . ReleaseComObject ( queryAssoc ) ;
87
- }
88
80
}
89
81
90
82
public void SizeChanged ( RECT size )
91
83
{
92
- if ( hwnd != HWND . NULL )
93
- SetWindowPos ( hwnd , HWND . HWND_TOP , size . Left , size . Top , size . Width , size . Height , SetWindowPosFlags . SWP_NOACTIVATE ) ;
84
+ if ( _hWnd != HWND . Null )
85
+ PInvoke . SetWindowPos ( _hWnd , new ( 0 ) , size . left , size . top , size . Width , size . Height , SET_WINDOW_POS_FLAGS . SWP_NOACTIVATE ) ;
94
86
95
- currentHandler ? . ResetBounds ( new ( 0 , 0 , size . Width , size . Height ) ) ;
87
+ _previewHandler ? . ResetBounds ( new ( 0 , 0 , size . Width , size . Height ) ) ;
96
88
97
- if ( outputLink is not null )
98
- outputLink . PlacementVisual . Size = new ( size . Width , size . Height ) ;
89
+ if ( _contentExternalOutputLink is not null )
90
+ _contentExternalOutputLink . PlacementVisual . Size = new ( size . Width , size . Height ) ;
99
91
}
100
92
101
- private nint WndProc ( HWND hwnd , uint msg , nint wParam , nint lParam )
93
+ private unsafe LRESULT WndProc ( HWND hwnd , uint msg , WPARAM wParam , LPARAM lParam )
102
94
{
103
- if ( msg == ( uint ) WindowMessage . WM_CREATE )
95
+ if ( msg is PInvoke . WM_CREATE )
104
96
{
105
- var clsid = FindPreviewHandlerFor ( Item . FileExtension , hwnd . DangerousGetHandle ( ) ) ;
97
+ var clsid = FindPreviewHandlerFor ( Item . FileExtension , hwnd ) ;
106
98
107
- isOfficePreview = new Guid ? [ ]
99
+ _isOfficePreview = new Guid ? [ ]
108
100
{
109
101
Guid . Parse ( "84F66100-FF7C-4fb4-B0C0-02CD7FB668FE" ) , // preview handler for Word files
110
102
Guid . Parse ( "65235197-874B-4A07-BDC5-E65EA825B718" ) , // preview handler for PowerPoint files
@@ -113,43 +105,71 @@ private nint WndProc(HWND hwnd, uint msg, nint wParam, nint lParam)
113
105
114
106
try
115
107
{
116
- currentHandler = new PreviewHandler ( clsid . Value , hwnd . DangerousGetHandle ( ) ) ;
117
- currentHandler . InitWithFileWithEveryWay ( Item . ItemPath ) ;
118
- currentHandler . DoPreview ( ) ;
108
+ _previewHandler = new PreviewHandler ( clsid ! . Value , hwnd ) ;
109
+ _previewHandler . InitWithFileWithEveryWay ( Item . ItemPath ) ;
110
+ _previewHandler . DoPreview ( ) ;
119
111
}
120
112
catch
121
113
{
122
114
UnloadPreview ( ) ;
123
115
}
124
116
}
125
- else if ( msg == ( uint ) WindowMessage . WM_DESTROY )
117
+ else if ( msg is PInvoke . WM_DESTROY )
126
118
{
127
- if ( currentHandler is not null )
119
+ if ( _previewHandler is not null )
128
120
{
129
- currentHandler . Dispose ( ) ;
130
- currentHandler = null ;
121
+ _previewHandler . Dispose ( ) ;
122
+ _previewHandler = null ;
131
123
}
132
124
}
133
125
134
- return DefWindowProc ( hwnd , msg , wParam , lParam ) ;
126
+ return PInvoke . DefWindowProc ( hwnd , msg , wParam , lParam ) ;
135
127
}
136
128
137
- public void LoadPreview ( UIElement presenter )
129
+ public unsafe void LoadPreview ( UIElement presenter )
138
130
{
139
131
var parent = MainWindow . Instance . WindowHandle ;
132
+ var hInst = PInvoke . GetModuleHandle ( default ( PWSTR ) ) ;
133
+ var szClassName = $ "{ GetType ( ) . Name } -{ Guid . NewGuid ( ) } ";
134
+ var szWindowName = $ "Preview";
140
135
141
- HINSTANCE hInst = Kernel32 . GetModuleHandle ( ) ;
142
-
143
- wCls = new WindowClass ( $ "{ GetType ( ) . Name } { Guid . NewGuid ( ) } ", hInst , WndProc ) ;
136
+ fixed ( char * pszClassName = szClassName )
137
+ {
138
+ _windProc = new ( WndProc ) ;
139
+ var pWindProc = Marshal . GetFunctionPointerForDelegate ( _windProc ) ;
140
+ var pfnWndProc = ( delegate * unmanaged[ Stdcall] < HWND , uint , WPARAM , LPARAM , LRESULT > ) pWindProc ;
144
141
145
- hwnd = CreateWindowEx (
146
- WindowStylesEx . WS_EX_LAYERED | WindowStylesEx . WS_EX_COMPOSITED ,
147
- wCls . ClassName ,
148
- "Preview" ,
149
- WindowStyles . WS_CHILD | WindowStyles . WS_CLIPSIBLINGS | WindowStyles . WS_VISIBLE ,
150
- 0 , 0 , 0 , 0 ,
151
- hWndParent : parent ,
152
- hInstance : hInst ) ;
142
+ _windowClass = new WNDCLASSEXW ( )
143
+ {
144
+ cbSize = ( uint ) sizeof ( WNDCLASSEXW ) ,
145
+ lpfnWndProc = pfnWndProc ,
146
+ hInstance = hInst ,
147
+ lpszClassName = pszClassName ,
148
+ style = 0 ,
149
+ hIcon = default ,
150
+ hIconSm = default ,
151
+ hCursor = default ,
152
+ hbrBackground = default ,
153
+ lpszMenuName = null ,
154
+ cbClsExtra = 0 ,
155
+ cbWndExtra = 0 ,
156
+ } ;
157
+
158
+ PInvoke . RegisterClassEx ( _windowClass ) ;
159
+
160
+ fixed ( char * pszWindowName = szWindowName )
161
+ {
162
+ _hWnd = PInvoke . CreateWindowEx (
163
+ WINDOW_EX_STYLE . WS_EX_LAYERED | WINDOW_EX_STYLE . WS_EX_COMPOSITED ,
164
+ pszClassName ,
165
+ pszWindowName ,
166
+ WINDOW_STYLE . WS_CHILD | WINDOW_STYLE . WS_CLIPSIBLINGS | WINDOW_STYLE . WS_VISIBLE ,
167
+ 0 , 0 , 0 , 0 ,
168
+ new ( parent ) ,
169
+ HMENU . Null ,
170
+ hInst ) ;
171
+ }
172
+ }
153
173
154
174
_ = ChildWindowToXaml ( parent , presenter ) ;
155
175
}
@@ -198,21 +218,21 @@ private unsafe bool ChildWindowToXaml(nint parent, UIElement presenter)
198
218
199
219
// Create the visual
200
220
hr = pDCompositionDevice . Get ( ) ->CreateVisual ( pChildVisual . GetAddressOf ( ) ) ;
201
- hr = pDCompositionDevice . Get ( ) ->CreateSurfaceFromHwnd ( new ( hwnd . DangerousGetHandle ( ) ) , pControlSurface . GetAddressOf ( ) ) ;
221
+ hr = pDCompositionDevice . Get ( ) ->CreateSurfaceFromHwnd ( _hWnd , pControlSurface . GetAddressOf ( ) ) ;
202
222
hr = pChildVisual . Get ( ) ->SetContent ( pControlSurface . Get ( ) ) ;
203
223
if ( pChildVisual . IsNull || pControlSurface . IsNull )
204
224
return false ;
205
225
206
226
// Get the compositor and set the visual on it
207
227
var compositor = ElementCompositionPreview . GetElementVisual ( presenter ) . Compositor ;
208
- outputLink = ContentExternalOutputLink . Create ( compositor ) ;
228
+ _contentExternalOutputLink = ContentExternalOutputLink . Create ( compositor ) ;
209
229
210
- var target = outputLink . As < IDCompositionTarget > ( ) ;
230
+ var target = _contentExternalOutputLink . As < Windows . Win32 . Extras . IDCompositionTarget > ( ) ;
211
231
target . SetRoot ( ( nint ) pChildVisual . Get ( ) ) ;
212
232
213
- outputLink . PlacementVisual . Size = new ( 0 , 0 ) ;
214
- outputLink . PlacementVisual . Scale = new ( 1 / ( float ) presenter . XamlRoot . RasterizationScale ) ;
215
- ElementCompositionPreview . SetElementChildVisual ( presenter , outputLink . PlacementVisual ) ;
233
+ _contentExternalOutputLink . PlacementVisual . Size = new ( 0 , 0 ) ;
234
+ _contentExternalOutputLink . PlacementVisual . Scale = new ( 1 / ( float ) presenter . XamlRoot . RasterizationScale ) ;
235
+ ElementCompositionPreview . SetElementChildVisual ( presenter , _contentExternalOutputLink . PlacementVisual ) ;
216
236
217
237
// Commit the all pending DComp commands
218
238
pDCompositionDevice . Get ( ) ->Commit ( ) ;
@@ -221,7 +241,7 @@ private unsafe bool ChildWindowToXaml(nint parent, UIElement presenter)
221
241
222
242
return
223
243
PInvoke . DwmSetWindowAttribute (
224
- new ( ( nint ) hwnd ) ,
244
+ new ( ( nint ) _hWnd ) ,
225
245
DWMWINDOWATTRIBUTE . DWMWA_CLOAK ,
226
246
& dwAttrib ,
227
247
( uint ) Marshal . SizeOf ( dwAttrib ) )
@@ -230,16 +250,15 @@ private unsafe bool ChildWindowToXaml(nint parent, UIElement presenter)
230
250
231
251
public void UnloadPreview ( )
232
252
{
233
- if ( hwnd != HWND . NULL )
234
- DestroyWindow ( hwnd ) ;
253
+ if ( _hWnd != HWND . Null )
254
+ PInvoke . DestroyWindow ( _hWnd ) ;
235
255
236
- outputLink ? . Dispose ( ) ;
237
- outputLink = null ;
256
+ _contentExternalOutputLink ? . Dispose ( ) ;
257
+ _contentExternalOutputLink = null ;
238
258
239
259
pChildVisual . Dispose ( ) ;
240
260
241
- if ( wCls is not null )
242
- UnregisterClass ( wCls . ClassName , Kernel32 . GetModuleHandle ( ) ) ;
261
+ PInvoke . UnregisterClass ( _windowClass . lpszClassName , PInvoke . GetModuleHandle ( default ( PWSTR ) ) ) ;
243
262
}
244
263
245
264
public unsafe void PointerEntered ( bool onPreview )
@@ -249,25 +268,25 @@ public unsafe void PointerEntered(bool onPreview)
249
268
var dwAttrib = Convert . ToUInt32 ( false ) ;
250
269
251
270
PInvoke . DwmSetWindowAttribute (
252
- new ( ( nint ) hwnd ) ,
271
+ new ( ( nint ) _hWnd ) ,
253
272
DWMWINDOWATTRIBUTE . DWMWA_CLOAK ,
254
273
& dwAttrib ,
255
274
( uint ) Marshal . SizeOf ( dwAttrib ) ) ;
256
275
257
- if ( isOfficePreview )
258
- PInvoke . SetWindowLongPtr ( new ( ( nint ) hwnd ) , WINDOW_LONG_PTR_INDEX . GWL_EXSTYLE , 0 ) ;
276
+ if ( _isOfficePreview )
277
+ PInvoke . SetWindowLongPtr ( new ( ( nint ) _hWnd ) , WINDOW_LONG_PTR_INDEX . GWL_EXSTYLE , 0 ) ;
259
278
}
260
279
else
261
280
{
262
281
PInvoke . SetWindowLongPtr (
263
- new ( ( nint ) hwnd ) ,
282
+ new ( ( nint ) _hWnd ) ,
264
283
WINDOW_LONG_PTR_INDEX . GWL_EXSTYLE ,
265
284
( nint ) ( WINDOW_EX_STYLE . WS_EX_LAYERED | WINDOW_EX_STYLE . WS_EX_COMPOSITED ) ) ;
266
285
267
286
var dwAttrib = Convert . ToUInt32 ( true ) ;
268
287
269
288
PInvoke . DwmSetWindowAttribute (
270
- new ( ( nint ) hwnd ) ,
289
+ new ( ( nint ) _hWnd ) ,
271
290
DWMWINDOWATTRIBUTE . DWMWA_CLOAK ,
272
291
& dwAttrib ,
273
292
( uint ) Marshal . SizeOf ( dwAttrib ) ) ;
@@ -276,4 +295,4 @@ public unsafe void PointerEntered(bool onPreview)
276
295
}
277
296
}
278
297
279
- #pragma warning restore CS8305 // Type is for evaluation purposes only and is subject to change or removal in future updates.
298
+ #pragma warning restore CS8305 // Type is for evaluation purposes only and is subject to change or removal in future updates.
0 commit comments