This repository has been archived by the owner on Nov 27, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
/
EvilWorks.WinApi.Shell.pas
254 lines (225 loc) · 6.9 KB
/
EvilWorks.WinApi.Shell.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
(*============================================================================================================
EvilLibrary by Vedran Vuk 2010-2012
Name: EvilWorks.WinApi.Shell
Description: Various shell related functions.
File last change date: August 21th. 2012
File version: 0.1.1
Licence: Free as in beer.
===========================================================================================================*)
unit EvilWorks.WinApi.Shell;
interface
uses
Winapi.Windows,
Winapi.ActiveX,
Winapi.ShLwApi,
Winapi.ShellAPi,
Winapi.ShlObj,
Winapi.SHFolder,
Winapi.KnownFolders,
System.SysUtils;
function GetUserDocumentsDir: string;
function GetAllUsersDocumentsDir: string;
function GetUserDocumentsPath: string;
function GetAllUsersDocumentsPath: string;
function GetUserAppDataDir: string;
function GetUserAppDataPath: string;
function GetCommonAppDataDir: string;
function GetCommonAppDataPath: string;
function GetClsIDDisplayName(const aClsID: string): string;
function GetAssociatedIconFileName(const aFileName: string; out aIconFileName: string; out aIconIndex: integer): boolean;
function LoadIcon(const aIconString: string; const aSmallIcon: boolean = False): HICON;
function LoadAssociatedIcon(const aFileName: string; const aSmallIcon: boolean = False): HICON;
function PickIconDlg(const aParent: HWND; var aPath: string): integer;
implementation
uses
EvilWorks.System.SysUtils, EvilWorks.System.StrUtils;
{ Retrieves a shell path. }
function GetShlPath(aCSIDL: integer; aFID: KNOWNFOLDERID): string;
var
buffer: pointer;
begin
Result := EmptyStr;
if (TOSVersion.Check(6, 1)) then
begin
// Vista+
if (SHGetKnownFolderPath(aFID, 0, 0, PChar(buffer)) = S_OK) then
begin
Result := PChar(buffer);
CoTaskMemFree(buffer);
end;
end
else
// XP
begin
buffer := AllocMem(MAX_PATH * SizeOf(char));
try
if (SHGetFolderPath(0, aCSIDL, 0, 0, buffer) = S_OK) then
Result := PChar(buffer);
finally
FreeMem(buffer);
end;
end;
end;
{ Gets "My Documents" directory for current user. }
function GetUserDocumentsDir: string;
begin
Result := GetShlPath(CSIDL_PERSONAL, FOLDERID_Documents);
end;
{ Gets "Documents" directory for all users. }
function GetAllUsersDocumentsDir: string;
begin
Result := GetShlPath(CSIDL_COMMON_DOCUMENTS, FOLDERID_PublicDocuments);
end;
{ Gets "My Documents" path for current user. }
function GetUserDocumentsPath: string;
begin
Result := IncludeTrailingPathDelimiter(GetUserDocumentsDir);
end;
{ Gets "Documents" path for all users. }
function GetAllUsersDocumentsPath: string;
begin
Result := IncludeTrailingPathDelimiter(GetAllUsersDocumentsDir);
end;
{ Gets "Application data" directory for current user. }
function GetUserAppDataDir: string;
begin
Result := GetShlPath(CSIDL_APPDATA, FOLDERID_RoamingAppData);
end;
{ Gets "Application data" path for current user. }
function GetUserAppDataPath: string;
begin
Result := IncludeTrailingPathDelimiter(GetUserAppDataDir);
end;
{ Gets "Application data" directory for all users (ProgramData on Vista+). }
function GetCommonAppDataDir: string;
begin
Result := GetShlPath(CSIDL_COMMON_APPDATA, FOLDERID_ProgramData);
end;
{ Gets "Application data" path for all users (ProgramData on Vista+). }
function GetCommonAppDataPath: string;
begin
Result := IncludeTrailingPathDelimiter(GetCommonAppDataDir);
end;
{ Returns a display name associated with a classID. For instance shl folders. }
function GetClsIDDisplayName(const aClsID: string): string;
var
ShlFolder: IShellFolder;
PIDL : PItemIDList;
STR : STRRET;
name : LPTSTR;
begin
if (Succeeded(SHGetDesktopFolder(ShlFolder))) then
begin
if (ShlFolder.ParseDisplayName(0, nil, PChar(aClsID), ULONG(nil^), PIDL, ULONG(nil^)) = S_OK) then
begin
if (ShlFolder.GetDisplayNameOf(PIDL, SHGDN_FORADDRESSBAR, STR) = S_OK) then
begin
StrRetToStr(@STR, PIDL, name);
Result := name;
CoTaskMemFree(name);
CoTaskMemFree(STR.pOleStr);
CoTaskMemFree(STR.pStr);
end;
CoTaskMemFree(PIDL);
end;
end;
end;
{ Returns the filename of the icon associated with aFileName or ClsID. }
function GetAssociatedIconFileName(const aFileName: string; out aIconFileName: string; out aIconIndex: integer): boolean;
var
SFI: TSHFileInfo;
begin
aIconFileName := CEmpty;
aIconIndex := 0;
ZeroMemory(@SFI, SizeOf(SFI));
Result := (SHGetFileInfo(PChar(aFileName), FILE_ATTRIBUTE_NORMAL, SFI, SizeOf(SFI), SHGFI_ICONLOCATION or SHGFI_USEFILEATTRIBUTES) = 0);
if (Result) then
begin
aIconFileName := string(PChar(@SFI.szDisplayName[0]));
aIconIndex := SFI.iIcon;
end;
end;
{ Loads an icon from an executable, dll or an Icon file. }
{ aIconString is in the format: }
{ C:\PathToMyFile.exe,1 or C:\PathToMyFile.exe,AppIcon }
function LoadIcon(const aIconString: string; const aSmallIcon: boolean = False): HICON; overload;
var
FileName : string;
Resource : string;
IconIndex: integer;
SmallIcon: HICON;
LargeIcon: HICON;
begin
Result := 0;
Resource := aIconString;
FileName := TextExtractLeft(Resource, CComma);
IconIndex := StrToIntDef(Resource, - 1);
if (IconIndex <> - 1) then
begin
if (aSmallIcon) then
begin
LargeIcon := 0;
SmallIcon := 1;
end
else
begin
LargeIcon := 1;
SmallIcon := 0;
end;
if (ExtractIconEx(PChar(FileName), cardinal(IconIndex), LargeIcon, SmallIcon, 1) > 0) then
begin
if (aSmallIcon) then
Result := SmallIcon
else
Result := LargeIcon;
end;
end;
end;
{ Returns the associated icon for a file, path or a ClsID. }
function LoadAssociatedIcon(const aFileName: string; const aSmallIcon: boolean = False): HICON;
var
SFI : TSHFileInfo;
ShlFolder: IShellFolder;
PIDL : PItemIDList;
begin
Result := 0;
ZeroMemory(@PIDL, SizeOf(TItemIDList));
ZeroMemory(@SFI, SizeOf(SFI));
if (Succeeded(SHGetDesktopFolder(ShlFolder))) then
begin
if (ShlFolder.ParseDisplayName(0, nil, PChar(aFileName), ULONG(nil^), PIDL, ULONG(nil^)) = S_OK) then
begin
if (aSmallIcon) then
begin
if (Succeeded(SHGetFileInfo(PChar(PIDL), 0, SFI, SizeOf(SFI), SHGFI_PIDL or SHGFI_ICON or SHGFI_SMALLICON))) then
Result := SFI.HICON;
end
else
begin
if (Succeeded(SHGetFileInfo(PChar(PIDL), 0, SFI, SizeOf(SFI), SHGFI_PIDL or SHGFI_ICON))) then
Result := SFI.HICON;
end;
CoTaskMemFree(PIDL);
end;
end;
end;
{ Windows Pick Icon dialog. }
{ If user picked an icon Return is IconIndex (>= 0), or -1 on cancel. }
{ Set aPath to initially selected resource path, will return selected file path (Icon, Exe, resource...) }
function PickIconDlg(const aParent: HWND; var aPath: string): integer;
var
buffer : array [0 .. MAX_PATH] of char;
IconIndex: integer;
begin
FillChar(buffer, MAX_PATH + 1, 0);
if (aPath <> CEmpty) then
CopyMemory(@buffer[0], @aPath[1], Length(aPath) * StringElementSize(aPath));
if (Winapi.ShlObj.PickIconDlg(aParent, buffer, MAX_PATH + 1, IconIndex) = 1) then
begin
Result := IconIndex;
aPath := PChar(@buffer[0]);
end
else
Result := - 1;
end;
end.