2
2
// Licensed under the MIT License.
3
3
4
4
using System . Runtime . CompilerServices ;
5
+ using System . Runtime . InteropServices ;
5
6
using System . Text ;
6
7
using Windows . Win32 ;
7
8
using Windows . Win32 . Foundation ;
8
9
using Windows . Win32 . System . Com ;
9
10
using Windows . Win32 . System . SystemServices ;
10
11
using Windows . Win32 . UI . Shell ;
12
+ using Windows . Win32 . UI . Shell . Common ;
11
13
using Windows . Win32 . UI . Shell . PropertiesSystem ;
12
14
using Windows . Win32 . UI . WindowsAndMessaging ;
13
15
14
16
namespace Files . App . Storage
15
17
{
16
- public static partial class WindowsStorableHelpers
18
+ public unsafe static partial class WindowsStorableHelpers
17
19
{
18
- public unsafe static HRESULT GetPropertyValue < TValue > ( this IWindowsStorable storable , string propKey , out TValue value )
20
+ public static HRESULT GetPropertyValue < TValue > ( this IWindowsStorable storable , string propKey , out TValue value )
19
21
{
20
22
using ComPtr < IShellItem2 > pShellItem2 = default ;
21
23
HRESULT hr = storable . ThisPtr ->QueryInterface ( IID . IID_IShellItem2 , ( void * * ) pShellItem2 . GetAddressOf ( ) ) ;
@@ -47,12 +49,12 @@ public unsafe static HRESULT GetPropertyValue<TValue>(this IWindowsStorable stor
47
49
}
48
50
}
49
51
50
- public unsafe static bool HasShellAttributes ( this IWindowsStorable storable , SFGAO_FLAGS attributes )
52
+ public static bool HasShellAttributes ( this IWindowsStorable storable , SFGAO_FLAGS attributes )
51
53
{
52
54
return storable . ThisPtr ->GetAttributes ( attributes , out var dwRetAttributes ) . Succeeded && dwRetAttributes == attributes ;
53
55
}
54
56
55
- public unsafe static string GetDisplayName ( this IWindowsStorable storable , SIGDN options = SIGDN . SIGDN_FILESYSPATH )
57
+ public static string GetDisplayName ( this IWindowsStorable storable , SIGDN options = SIGDN . SIGDN_FILESYSPATH )
56
58
{
57
59
using ComHeapPtr < PWSTR > pszName = default ;
58
60
HRESULT hr = storable . ThisPtr ->GetDisplayName ( options , ( PWSTR * ) pszName . GetAddressOf ( ) ) ;
@@ -62,7 +64,7 @@ public unsafe static string GetDisplayName(this IWindowsStorable storable, SIGDN
62
64
: string . Empty ;
63
65
}
64
66
65
- public unsafe static HRESULT TryInvokeContextMenuVerb ( this IWindowsStorable storable , string verbName )
67
+ public static HRESULT TryInvokeContextMenuVerb ( this IWindowsStorable storable , string verbName )
66
68
{
67
69
Debug . Assert ( Thread . CurrentThread . GetApartmentState ( ) is ApartmentState . STA ) ;
68
70
@@ -87,7 +89,7 @@ public unsafe static HRESULT TryInvokeContextMenuVerb(this IWindowsStorable stor
87
89
}
88
90
}
89
91
90
- public unsafe static HRESULT TryInvokeContextMenuVerbs ( this IWindowsStorable storable , string [ ] verbNames , bool earlyReturnOnSuccess )
92
+ public static HRESULT TryInvokeContextMenuVerbs ( this IWindowsStorable storable , string [ ] verbNames , bool earlyReturnOnSuccess )
91
93
{
92
94
Debug . Assert ( Thread . CurrentThread . GetApartmentState ( ) is ApartmentState . STA ) ;
93
95
@@ -118,7 +120,7 @@ public unsafe static HRESULT TryInvokeContextMenuVerbs(this IWindowsStorable sto
118
120
return hr ;
119
121
}
120
122
121
- public unsafe static HRESULT TryGetShellTooltip ( this IWindowsStorable storable , out string ? tooltip )
123
+ public static HRESULT TryGetShellTooltip ( this IWindowsStorable storable , out string ? tooltip )
122
124
{
123
125
tooltip = null ;
124
126
@@ -137,7 +139,7 @@ public unsafe static HRESULT TryGetShellTooltip(this IWindowsStorable storable,
137
139
return HRESULT . S_OK ;
138
140
}
139
141
140
- public unsafe static HRESULT TryPinFolderToQuickAccess ( this IWindowsFolder @this )
142
+ public static HRESULT TryPinFolderToQuickAccess ( this IWindowsFolder @this )
141
143
{
142
144
HRESULT hr = default ;
143
145
@@ -168,7 +170,7 @@ public unsafe static HRESULT TryPinFolderToQuickAccess(this IWindowsFolder @this
168
170
return HRESULT . S_OK ;
169
171
}
170
172
171
- public unsafe static HRESULT TryUnpinFolderFromQuickAccess ( this IWindowsFolder @this )
173
+ public static HRESULT TryUnpinFolderFromQuickAccess ( this IWindowsFolder @this )
172
174
{
173
175
HRESULT hr = default ;
174
176
@@ -198,5 +200,105 @@ public unsafe static HRESULT TryUnpinFolderFromQuickAccess(this IWindowsFolder @
198
200
199
201
return HRESULT . S_OK ;
200
202
}
203
+
204
+ public static IEnumerable < ContextMenuItem > GetShellNewItems ( this IWindowsFolder @this )
205
+ {
206
+ HRESULT hr = default ;
207
+
208
+ IContextMenu * pNewMenu = default ;
209
+ using ComPtr < IShellExtInit > pShellExtInit = default ;
210
+ using ComPtr < IContextMenu2 > pContextMenu2 = default ;
211
+
212
+ hr = PInvoke . CoCreateInstance ( CLSID . CLSID_NewMenu , null , CLSCTX . CLSCTX_INPROC_SERVER , IID . IID_IContextMenu , ( void * * ) & pNewMenu ) ;
213
+ if ( hr . ThrowIfFailedOnDebug ( ) . Failed )
214
+ return [ ] ;
215
+
216
+ hr = pNewMenu ->QueryInterface ( IID . IID_IContextMenu2 , ( void * * ) pContextMenu2 . GetAddressOf ( ) ) ;
217
+ if ( hr . ThrowIfFailedOnDebug ( ) . Failed )
218
+ return [ ] ;
219
+
220
+ hr = pNewMenu ->QueryInterface ( IID . IID_IShellExtInit , ( void * * ) pShellExtInit . GetAddressOf ( ) ) ;
221
+ if ( hr . ThrowIfFailedOnDebug ( ) . Failed )
222
+ return [ ] ;
223
+
224
+ @this . ShellNewMenu = pNewMenu ;
225
+
226
+ ITEMIDLIST * pFolderPidl = default ;
227
+ hr = PInvoke . SHGetIDListFromObject ( ( IUnknown * ) @this . ThisPtr , & pFolderPidl ) ;
228
+ if ( hr . ThrowIfFailedOnDebug ( ) . Failed )
229
+ return [ ] ;
230
+
231
+ hr = pShellExtInit . Get ( ) ->Initialize ( pFolderPidl , null , default ) ;
232
+ if ( hr . ThrowIfFailedOnDebug ( ) . Failed )
233
+ return [ ] ;
234
+
235
+ // Inserts "New (&W)"
236
+ HMENU hMenu = PInvoke . CreatePopupMenu ( ) ;
237
+ hr = pNewMenu ->QueryContextMenu ( hMenu , 0 , 1 , 256 , 0 ) ;
238
+ if ( hr . ThrowIfFailedOnDebug ( ) . Failed )
239
+ return [ ] ;
240
+
241
+ // Invokes CNewMenu::_InitMenuPopup(), which populates the hSubMenu
242
+ HMENU hSubMenu = PInvoke . GetSubMenu ( hMenu , 0 ) ;
243
+ hr = pContextMenu2 . Get ( ) ->HandleMenuMsg ( PInvoke . WM_INITMENUPOPUP , ( WPARAM ) ( nuint ) hSubMenu . Value , 0 ) ;
244
+ if ( hr . ThrowIfFailedOnDebug ( ) . Failed )
245
+ return [ ] ;
246
+
247
+ uint dwCount = unchecked ( ( uint ) PInvoke . GetMenuItemCount ( hSubMenu ) ) ;
248
+ if ( dwCount is unchecked ( ( uint ) - 1 ) )
249
+ return [ ] ;
250
+
251
+ // Enumerates and populates the list
252
+ List < ContextMenuItem > shellNewItems = [ ] ;
253
+ for ( uint dwIndex = 0 ; dwIndex < dwCount ; dwIndex ++ )
254
+ {
255
+ MENUITEMINFOW mii = default ;
256
+ mii . cbSize = ( uint ) sizeof ( MENUITEMINFOW ) ;
257
+ mii . fMask = MENU_ITEM_MASK . MIIM_STRING | MENU_ITEM_MASK . MIIM_ID | MENU_ITEM_MASK . MIIM_STATE ;
258
+ mii . dwTypeData = ( char * ) NativeMemory . Alloc ( 256U ) ;
259
+ mii . cch = 256 ;
260
+
261
+ if ( PInvoke . GetMenuItemInfo ( hSubMenu , dwIndex , true , & mii ) )
262
+ {
263
+ shellNewItems . Add ( new ( )
264
+ {
265
+ Id = mii . wID ,
266
+ Name = mii . dwTypeData . ToString ( ) ,
267
+ Type = ( ContextMenuType ) mii . fState ,
268
+ } ) ;
269
+ }
270
+
271
+ NativeMemory . Free ( mii . dwTypeData ) ;
272
+ }
273
+
274
+ return shellNewItems ;
275
+ }
276
+
277
+ public static bool InvokeShellNewItem ( this IWindowsFolder @this , ContextMenuItem item )
278
+ {
279
+ HRESULT hr = default ;
280
+
281
+ if ( @this . ShellNewMenu is null )
282
+ {
283
+ IContextMenu * pNewMenu = default ;
284
+
285
+ hr = PInvoke . CoCreateInstance ( CLSID . CLSID_NewMenu , null , CLSCTX . CLSCTX_INPROC_SERVER , IID . IID_IContextMenu , ( void * * ) & pNewMenu ) ;
286
+ if ( hr . ThrowIfFailedOnDebug ( ) . Failed )
287
+ return false ;
288
+
289
+ @this . ShellNewMenu = pNewMenu ;
290
+ }
291
+
292
+ CMINVOKECOMMANDINFO cmici = default ;
293
+ cmici . cbSize = ( uint ) sizeof ( CMINVOKECOMMANDINFO ) ;
294
+ cmici . lpVerb = ( PCSTR ) ( byte * ) item . Id ;
295
+ cmici . nShow = ( int ) SHOW_WINDOW_CMD . SW_SHOWNORMAL ;
296
+
297
+ hr = @this . ShellNewMenu ->InvokeCommand ( & cmici ) ;
298
+ if ( hr . ThrowIfFailedOnDebug ( ) . Failed )
299
+ return false ;
300
+
301
+ return false ;
302
+ }
201
303
}
202
304
}
0 commit comments