-
Notifications
You must be signed in to change notification settings - Fork 15
/
APKIconUnit.pas
211 lines (182 loc) · 4.97 KB
/
APKIconUnit.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
unit APKIconUnit;
{$WARN SYMBOL_PLATFORM OFF}
interface
uses
Winapi.Windows, Winapi.ActiveX, System.Win.ComObj, APKIcon_TLB,
System.Win.StdVCL, Winapi.ShlObj;
type
TAPKIcon = class(TTypedComObject, IAPKIcon, IExtractIcon, IPersistFile)
private
FCurrFile: WideString;
protected
//IExtractIcon
function GetIconLocation(uFlags: UINT; szIconFile: LPWSTR; cchMax: UINT;
out piIndex: Integer; out pwFlags: UINT): HResult; stdcall;
function Extract(pszFile: LPCWSTR; nIconIndex: UINT;
out phiconLarge, phiconSmall: HICON; nIconSize: UINT): HResult; stdcall;
//IPersist
function GetClassID(out classID: TCLSID): HResult; stdcall;
//IPersistFile
function IsDirty: HResult; stdcall;
function Load(pszFileName: POleStr; dwMode: Longint): HResult;
stdcall;
function Save(pszFileName: POleStr; fRemember: BOOL): HResult;
stdcall;
function SaveCompleted(pszFileName: POleStr): HResult;
stdcall;
function GetCurFile(out pszFileName: POleStr): HResult;
stdcall;
end;
TIconHandlerFactory = class(TTypedComObjectFactory)
public
procedure UpdateRegistry(Register: Boolean); override;
end;
implementation
uses
System.SysUtils, System.Win.ComServ, Vcl.Graphics, System.Win.Registry,
System.Classes;
{ TAPKIcon }
function TAPKIcon.Extract(pszFile: LPCWSTR; nIconIndex: UINT; out phiconLarge,
phiconSmall: HICON; nIconSize: UINT): HResult;
var
vIconSize, I: Integer;
vMaskAnd, vMaskXor: TBitmap;
vIconInfo: TIconInfo;
vSL: TStringList;
begin
// Draw the large icon
vIconSize := Lo(nIconSize);
// Create and prepare AND mask
vMaskAnd := TBitmap.Create;
try
vMaskAnd.Monochrome := True;
vMaskAnd.Width := vIconSize;
vMaskAnd.Height := vIconSize;
vMaskAnd.Canvas.Brush.Color := clBlack;
vMaskAnd.Canvas.FillRect(Rect(0, 0, vIconSize, vIconSize));
// Create and prepare XOR mask
vMaskXor := TBitmap.Create;
try
vMaskXor.Width := vIconSize;
vMaskXor.Height := vIconSize;
vMaskXor.Canvas.Brush.Color := clWhite;
vMaskXor.Canvas.FillRect(Rect(0, 0, vIconSize, vIconSize));
vMaskXor.Canvas.Font.Color := clNavy;
{ TODO : Load icon from APK file - needs parsing androidmanifest.xml, get icon path, etc. }
// Load file FCurrFile
vSL := TStringList.Create;
try
// paint to icon vMaskXOR.canvas....
finally
vSL.Free;
end;
// Create icon for explorer
vIconInfo.fIcon := True;
vIconInfo.xHotspot := 0;
vIconInfo.yHotspot := 0;
vIconInfo.hbmMask := vMaskAnd.Handle;
vIconInfo.hbmColor := vMaskXor.Handle;
// Return large icon
phiconLarge := CreateIconIndirect(vIconInfo);
// Signal success
Result := S_OK;
finally
vMaskAnd.Free;
end;
finally
vMaskXor.Free;
end;
end;
function TAPKIcon.GetClassID(out classID: TCLSID): HResult;
begin
classID := CLASS_APKIcon_;
Result := S_OK;
end;
function TAPKIcon.GetCurFile(out pszFileName: POleStr): HResult;
begin
Result := E_NOTIMPL;
end;
function TAPKIcon.GetIconLocation(uFlags: UINT; szIconFile: LPWSTR;
cchMax: UINT; out piIndex: Integer; out pwFlags: UINT): HResult;
begin
piIndex := 0;
pwFlags := GIL_DONTCACHE or GIL_NOTFILENAME or GIL_PERINSTANCE;
Result := S_OK;
end;
function TAPKIcon.IsDirty: HResult;
begin
Result := E_NOTIMPL;
end;
function TAPKIcon.Load(pszFileName: POleStr; dwMode: Longint): HResult;
begin
FCurrFile := pszFileName;
Result := S_OK;
end;
function TAPKIcon.Save(pszFileName: POleStr; fRemember: BOOL): HResult;
begin
Result := E_NOTIMPL;
end;
function TAPKIcon.SaveCompleted(pszFileName: POleStr): HResult;
begin
Result := E_NOTIMPL;
end;
{ TIconHandlerFactory }
procedure TIconHandlerFactory.UpdateRegistry(Register: Boolean);
var
ClsID: string;
begin
ClsID := GUIDToString(ClassID);
inherited UpdateRegistry(Register);
if Register then
begin
with TRegistry.Create do
try
RootKey := HKEY_CLASSES_ROOT;
if OpenKey('apkfile\DefaultIcon', True) then
try
WriteString('backup', ReadString(''));
WriteString('', '%1');
finally
CloseKey;
end;
if OpenKey('apkfile\shellex\IconHandler', True) then
try
WriteString('', ClsID);
finally
CloseKey;
end;
finally
Free;
end;
end
else
begin
with TRegistry.Create do
try
RootKey := HKEY_CLASSES_ROOT;
if OpenKey('apkfile\DefaultIcon', True) then
try
if ValueExists('backup') then
begin
WriteString('', ReadString('backup'));
DeleteValue('backup');
end;
finally
CloseKey;
end;
if OpenKey('apkfile\shellex', True) then
try
if KeyExists('IconHandler') then
DeleteKey('IconHandler');
finally
CloseKey;
end;
finally
Free;
end;
end;
end;
initialization
TTypedComObjectFactory.Create(ComServer, TAPKIcon, CLASS_APKIcon_,
ciMultiInstance, tmApartment);
end.