2
2
using System . ComponentModel ;
3
3
using System . Diagnostics ;
4
4
using System . Drawing ;
5
+ using System . Drawing . Imaging ;
5
6
using System . IO ;
6
7
using System . Linq ;
7
8
using System . Runtime . InteropServices ;
@@ -93,13 +94,13 @@ public static string[] CommandLineToArgs(string commandLine)
93
94
}
94
95
}
95
96
96
- public static ( string icon , bool isCustom ) GetFileOverlayIcon ( string path )
97
+ public static ( string icon , string overlay , bool isCustom ) GetFileIconAndOverlay ( string path , int thumbnailSize )
97
98
{
98
99
var shfi = new Shell32 . SHFILEINFO ( ) ;
99
100
var ret = Shell32 . SHGetFileInfo ( path , 0 , ref shfi , Shell32 . SHFILEINFO . Size , Shell32 . SHGFI . SHGFI_OVERLAYINDEX | Shell32 . SHGFI . SHGFI_ICON | Shell32 . SHGFI . SHGFI_SYSICONINDEX | Shell32 . SHGFI . SHGFI_ICONLOCATION ) ;
100
101
if ( ret == IntPtr . Zero )
101
102
{
102
- return ( null , false ) ;
103
+ return ( null , null , false ) ;
103
104
}
104
105
105
106
bool isCustom = ! shfi . szDisplayName . StartsWith ( Environment . GetFolderPath ( Environment . SpecialFolder . Windows ) ) ;
@@ -108,26 +109,43 @@ public static (string icon, bool isCustom) GetFileOverlayIcon(string path)
108
109
using var imageList = ComCtl32 . SafeHIMAGELIST . FromIImageList ( tmp ) ;
109
110
if ( imageList . IsNull || imageList . IsInvalid )
110
111
{
111
- return ( null , isCustom ) ;
112
+ return ( null , null , isCustom ) ;
112
113
}
113
114
115
+ string iconStr = null , overlayStr = null ;
114
116
var overlay_idx = shfi . iIcon >> 24 ;
115
- //var icon_idx = shfi.iIcon & 0xFFFFFF;
116
- if ( overlay_idx == 0 )
117
+ if ( overlay_idx != 0 )
117
118
{
118
- return ( null , isCustom ) ;
119
+ var overlay_image = imageList . Interface . GetOverlayImage ( overlay_idx ) ;
120
+ using var hOverlay = imageList . Interface . GetIcon ( overlay_image , ComCtl32 . IMAGELISTDRAWFLAGS . ILD_TRANSPARENT ) ;
121
+ if ( ! hOverlay . IsNull && ! hOverlay . IsInvalid )
122
+ {
123
+ using var image = hOverlay . ToIcon ( ) . ToBitmap ( ) ;
124
+ byte [ ] bitmapData = ( byte [ ] ) new ImageConverter ( ) . ConvertTo ( image , typeof ( byte [ ] ) ) ;
125
+ overlayStr = Convert . ToBase64String ( bitmapData , 0 , bitmapData . Length ) ;
126
+ }
119
127
}
120
128
121
- var overlay_image = imageList . Interface . GetOverlayImage ( overlay_idx ) ;
122
- using var hIcon = imageList . Interface . GetIcon ( overlay_image , ComCtl32 . IMAGELISTDRAWFLAGS . ILD_TRANSPARENT ) ;
123
- if ( hIcon . IsNull || hIcon . IsInvalid )
129
+ // The following only returns the icon (not thumbnail) and it's difficult to get a high-res icon
130
+ //var icon_idx = shfi.iIcon & 0xFFFFFF;
131
+ //using var hIcon = imageList.Interface.GetIcon(icon_idx, ComCtl32.IMAGELISTDRAWFLAGS.ILD_TRANSPARENT);
132
+
133
+ using var shellItem = new Vanara . Windows . Shell . ShellItem ( path ) ;
134
+ if ( shellItem . IShellItem is Shell32 . IShellItemImageFactory fctry )
124
135
{
125
- return ( null , isCustom ) ;
136
+ var flags = Shell32 . SIIGBF . SIIGBF_BIGGERSIZEOK ;
137
+ if ( thumbnailSize < 80 ) flags |= Shell32 . SIIGBF . SIIGBF_ICONONLY ;
138
+ var hres = fctry . GetImage ( new SIZE ( thumbnailSize , thumbnailSize ) , flags , out var hbitmap ) ;
139
+ if ( hres == HRESULT . S_OK )
140
+ {
141
+ using var image = GetBitmapFromHBitmap ( hbitmap ) ;
142
+ byte [ ] bitmapData = ( byte [ ] ) new ImageConverter ( ) . ConvertTo ( image , typeof ( byte [ ] ) ) ;
143
+ iconStr = Convert . ToBase64String ( bitmapData , 0 , bitmapData . Length ) ;
144
+ }
145
+ //Marshal.ReleaseComObject(fctry);
126
146
}
127
147
128
- using var image = hIcon . ToIcon ( ) . ToBitmap ( ) ;
129
- byte [ ] bitmapData = ( byte [ ] ) new ImageConverter ( ) . ConvertTo ( image , typeof ( byte [ ] ) ) ;
130
- return ( Convert . ToBase64String ( bitmapData , 0 , bitmapData . Length ) , isCustom ) ;
148
+ return ( iconStr , overlayStr , isCustom ) ;
131
149
}
132
150
133
151
private static void RunPowershellCommand ( string command , bool runAsAdmin )
@@ -171,6 +189,63 @@ public static void SetVolumeLabel(string driveName, string newLabel)
171
189
RunPowershellCommand ( $ "-command \" $Signature = '[DllImport(\\ \" kernel32.dll\\ \" , SetLastError = false)]public static extern bool SetVolumeLabel(string lpRootPathName, string lpVolumeName);'; $SetVolumeLabel = Add-Type -MemberDefinition $Signature -Name \" Win32SetVolumeLabel\" -Namespace Win32Functions -PassThru; $SetVolumeLabel::SetVolumeLabel('{ driveName } ', '{ newLabel } ')\" ", true ) ;
172
190
}
173
191
192
+ private static Bitmap GetBitmapFromHBitmap ( HBITMAP hBitmap )
193
+ {
194
+ Bitmap bmp = hBitmap . ToBitmap ( ) ;
195
+
196
+ if ( Bitmap . GetPixelFormatSize ( bmp . PixelFormat ) < 32 )
197
+ {
198
+ return bmp ;
199
+ }
200
+
201
+ if ( IsAlphaBitmap ( bmp , out var bmpData ) )
202
+ {
203
+ return GetAlphaBitmapFromBitmapData ( bmpData ) ;
204
+ }
205
+
206
+ return bmp ;
207
+ }
208
+
209
+ private static Bitmap GetAlphaBitmapFromBitmapData ( BitmapData bmpData )
210
+ {
211
+ return new Bitmap (
212
+ bmpData . Width ,
213
+ bmpData . Height ,
214
+ bmpData . Stride ,
215
+ PixelFormat . Format32bppArgb ,
216
+ bmpData . Scan0 ) ;
217
+ }
218
+
219
+ private static bool IsAlphaBitmap ( Bitmap bmp , out BitmapData bmpData )
220
+ {
221
+ Rectangle bmBounds = new Rectangle ( 0 , 0 , bmp . Width , bmp . Height ) ;
222
+
223
+ bmpData = bmp . LockBits ( bmBounds , ImageLockMode . ReadOnly , bmp . PixelFormat ) ;
224
+
225
+ try
226
+ {
227
+ for ( int y = 0 ; y <= bmpData . Height - 1 ; y ++ )
228
+ {
229
+ for ( int x = 0 ; x <= bmpData . Width - 1 ; x ++ )
230
+ {
231
+ Color pixelColor = Color . FromArgb (
232
+ Marshal . ReadInt32 ( bmpData . Scan0 , ( bmpData . Stride * y ) + ( 4 * x ) ) ) ;
233
+
234
+ if ( pixelColor . A > 0 & pixelColor . A < 255 )
235
+ {
236
+ return true ;
237
+ }
238
+ }
239
+ }
240
+ }
241
+ finally
242
+ {
243
+ bmp . UnlockBits ( bmpData ) ;
244
+ }
245
+
246
+ return false ;
247
+ }
248
+
174
249
// There is usually no need to define Win32 COM interfaces/P-Invoke methods here.
175
250
// The Vanara library contains the definitions for all members of Shell32.dll, User32.dll and more
176
251
// The ones below are due to bugs in the current version of the library and can be removed once fixed
0 commit comments