Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | daniel-mar | 1 | unit InstUnit; |
2 | { InstUnit - part of DELZIP demo #4. Freeware by Eric W. Engler and Chris Vleghert} |
||
3 | (************************************************************************ |
||
4 | Copyright (C) 2009, 2010 by Russell J. Peters, Roger Aelbrecht, |
||
5 | Eric W. Engler and Chris Vleghert. |
||
6 | |||
7 | This file is part of TZipMaster Version 1.9. |
||
8 | |||
9 | TZipMaster is free software: you can redistribute it and/or modify |
||
10 | it under the terms of the GNU Lesser General Public License as published by |
||
11 | the Free Software Foundation, either version 3 of the License, or |
||
12 | (at your option) any later version. |
||
13 | |||
14 | TZipMaster is distributed in the hope that it will be useful, |
||
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
17 | GNU Lesser General Public License for more details. |
||
18 | |||
19 | You should have received a copy of the GNU Lesser General Public License |
||
20 | along with TZipMaster. If not, see <http://www.gnu.org/licenses/>. |
||
21 | |||
22 | contact: problems@delphizip.org (include ZipMaster in the subject). |
||
23 | updates: http://www.delphizip.org |
||
24 | DelphiZip maillist subscribe at http://www.freelists.org/list/delphizip |
||
25 | ************************************************************************) |
||
26 | |||
27 | interface |
||
28 | |||
29 | uses |
||
30 | Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, |
||
31 | Dialogs, StdCtrls, Registry, ShlObj |
||
32 | {$IfDef VER90} // Delphi2 |
||
33 | ,Ole2; |
||
34 | {$Else} // Delphi3+ |
||
35 | ,ComObj, ActiveX; |
||
36 | {$EndIf} |
||
37 | |||
38 | {$IfDef VER90} // Delphi2 |
||
39 | type LongWord = Cardinal; |
||
40 | type WideString = Array[0..MAX_PATH] of WideChar; |
||
41 | |||
42 | type pShLinkType = ^IShellLink; |
||
43 | type ppShLinkType = ^pShLinkType; |
||
44 | type pFileType = ^IPersistFile; |
||
45 | type ppFileType = ^pFileType; |
||
46 | {$EndIf} |
||
47 | |||
48 | type |
||
49 | TInstForm = class( TForm ) |
||
50 | GroupBox1: TGroupBox; |
||
51 | StartMenuCB: TCheckBox; |
||
52 | DesktopCB: TCheckBox; |
||
53 | RegistryCB: TCheckBox; |
||
54 | AssocCB: TCheckBox; |
||
55 | SendToCB: TCheckBox; |
||
56 | KillCB: TCheckBox; |
||
57 | UninstBut: TButton; |
||
58 | CancelBut: TButton; |
||
59 | InstBut: TButton; |
||
60 | Label1: TLabel; |
||
61 | Label2: TLabel; |
||
62 | Label3: TLabel; |
||
63 | ProgramNameLabel: TLabel; |
||
64 | StartMenuRB: TRadioButton; |
||
65 | ProgramRB: TRadioButton; |
||
66 | |||
67 | procedure FormCreate( Sender: TObject) ; |
||
68 | procedure InstButClick( Sender: TObject ); |
||
69 | procedure SetValInReg( RKey:HKey; KeyPath: String; ValName: String; NewVal: String ); |
||
70 | procedure MakeAssociation( Ext: String; PgmToLinkTo: String ); |
||
71 | procedure MakeLink( PgmPath, PgmArgs, LinkPath, Descr: String ); |
||
72 | procedure CancelButClick( Sender: TObject ); |
||
73 | procedure UninstButClick( Sender: TObject ); |
||
74 | procedure RegDeleteKey( RKey:HKey; KeyPath: String ); |
||
75 | procedure RemoveAssociation( Ext: String ); |
||
76 | procedure FormActivate( Sender: TObject ); |
||
77 | function AddBackslash( str_in: string ): string; |
||
78 | procedure StartMenuCBClick( Sender: TObject ); |
||
79 | |||
80 | private |
||
81 | { Private declarations } |
||
82 | |||
83 | public |
||
84 | { Public declarations } |
||
85 | EXEName, EXETitle: String; |
||
86 | |||
87 | function GetSpecialFolder( aFolder: Integer; var Location: String ): LongWord; |
||
88 | end; |
||
89 | |||
90 | var |
||
91 | InstForm: TInstForm; |
||
92 | |||
93 | implementation |
||
94 | |||
95 | uses unit1; |
||
96 | |||
97 | {$R *.DFM} |
||
98 | |||
99 | procedure TInstForm.FormCreate( Sender: TObject ); |
||
100 | begin |
||
101 | EXEName := ExtractFileName( ParamStr( 0 ) ); |
||
102 | EXETitle := 'ViewZip - Delphi ZIP Auto Install Application Example'; |
||
103 | ProgramNameLabel.Caption := ParamStr( 0 ); |
||
104 | |||
105 | if Form1.AutoUninstall then |
||
106 | begin |
||
107 | ShowMessage( 'Now beginning ViewZip auto uninstall' ); |
||
108 | UnInstButClick( Self ); |
||
109 | end; |
||
110 | end; |
||
111 | |||
112 | procedure TInstForm.InstButClick( Sender: TObject ); |
||
113 | var |
||
114 | path: String; |
||
115 | MenuDir: Integer; |
||
116 | begin |
||
117 | Screen.Cursor := crHourGlass; |
||
118 | |||
119 | if StartMenuCB.Checked then |
||
120 | begin |
||
121 | if StartMenuRB.Checked then |
||
122 | MenuDir := CSIDL_STARTMENU |
||
123 | else |
||
124 | MenuDir := CSIDL_PROGRAMS; |
||
125 | GetSpecialFolder( MenuDir, path ); |
||
126 | MakeLink( ParamStr( 0 ), // the full pathname of this executable program |
||
127 | '', // no arguments |
||
128 | path + EXETitle + '.lnk', |
||
129 | 'Sample Self-install Program' ); |
||
130 | end; |
||
131 | |||
132 | if DesktopCB.Checked then |
||
133 | begin |
||
134 | GetSpecialFolder( CSIDL_DESKTOPDIRECTORY, path ); |
||
135 | MakeLink( ParamStr( 0 ), // the full pathname of this executable program |
||
136 | '', // no arguments |
||
137 | path + EXETitle + '.lnk', |
||
138 | 'Sample Install Program' ); |
||
139 | end; |
||
140 | |||
141 | if SendToCB.Checked then |
||
142 | begin |
||
143 | GetSpecialFolder( CSIDL_SENDTO, path ); |
||
144 | MakeLink( ParamStr( 0 ), // the full pathname of this executable program |
||
145 | '', // no arguments |
||
146 | path + EXETitle + '.lnk', |
||
147 | 'Sample Install Program' ); |
||
148 | end; |
||
149 | |||
150 | if RegistryCB.Checked then |
||
151 | begin |
||
152 | { define the application path } |
||
153 | SetValInReg( HKEY_LOCAL_MACHINE, |
||
154 | 'SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\' + EXEName, |
||
155 | '', { specify the default data item } |
||
156 | ParamStr( 0 ) ); { Full pathname with program name } |
||
157 | path:=ExtractFilePath(ParamStr(0)); |
||
158 | SetValInReg( HKEY_LOCAL_MACHINE, |
||
159 | 'SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\' + EXEName, |
||
160 | 'Path', { specify the Path data item } |
||
161 | Copy( path, 1, Length( path )- 1 ) ); { Full pathname without end slash } |
||
162 | |||
163 | { define the un-install command line } |
||
164 | SetValInReg( HKEY_LOCAL_MACHINE, |
||
165 | 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' + EXEName, |
||
166 | 'DisplayName', |
||
167 | EXETitle ); { show user this name in control panel } |
||
168 | SetValInReg( HKEY_LOCAL_MACHINE, |
||
169 | 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' + EXEName, |
||
170 | 'UninstallString', |
||
171 | ParamStr( 0 ) + ' /UNINSTALL' ); { pgm name and parameter } |
||
172 | |||
173 | |||
174 | { define the main application program settings key } |
||
175 | SetValInReg( HKEY_LOCAL_MACHINE, |
||
176 | 'SOFTWARE\' + EXEName, |
||
177 | 'InstalledVersion', |
||
178 | '1.51' ); |
||
179 | |||
180 | { these are settings that only apply to the current logged-in user } |
||
181 | SetValInReg( HKEY_CURRENT_USER, |
||
182 | 'SOFTWARE\' + EXEName, |
||
183 | 'InstalledVersion', |
||
184 | '1.51' ); |
||
185 | SetValInReg( HKEY_CURRENT_USER, |
||
186 | 'SOFTWARE\' + EXEName, |
||
187 | 'Setting1', |
||
188 | 'y' ); |
||
189 | SetValInReg( HKEY_CURRENT_USER, |
||
190 | 'SOFTWARE\' + EXEName, |
||
191 | 'Setting2', |
||
192 | 'n' ); |
||
193 | end; |
||
194 | |||
195 | if AssocCB.Checked then |
||
196 | MakeAssociation( 'zip', ParamStr( 0 ) ); |
||
197 | |||
198 | Screen.Cursor := crDefault; |
||
199 | |||
200 | {$ifdef NEVER} |
||
201 | if KillCB.Checked then |
||
202 | KillMySelf( 0, False ); |
||
203 | {$endif} |
||
204 | |||
205 | Close; |
||
206 | end; |
||
207 | |||
208 | { Create a Win95 file association in the registry. This uses the Quick-and- |
||
209 | Dirty method used by Explorer when you right click on a file and choose |
||
210 | "Open With...". Basically, the file extension is created as a class, and |
||
211 | a dummy file type is created for that class to tell Win95 which program to |
||
212 | run. Once this is done, you can easily test it from a DOS Shell by typing: |
||
213 | START FILENAME.EXT |
||
214 | Be advised: This is where I expected file associations to be (because |
||
215 | there are already some associations there), but they seem to have no effect: |
||
216 | HKEY_CURRENT_USER,'Software\Microsoft\Windows\CurrentVersion\Extensions' |
||
217 | } |
||
218 | procedure TInstForm.MakeAssociation( Ext: String; PgmToLinkTo: String ); |
||
219 | begin |
||
220 | { ALL extensions must be in lowercase to avoid trouble! } |
||
221 | Ext := LowerCase( Ext ); |
||
222 | if FileExists( PgmToLinkTo ) then |
||
223 | begin |
||
224 | SetValInReg( HKEY_CLASSES_ROOT, |
||
225 | '.' + ext, { extension we want to define } |
||
226 | '', { specify the default data item } |
||
227 | ext + '_auto_file' ); { This is the value of the default data item - |
||
228 | this referances our new type to be defined } |
||
229 | SetValInReg( HKEY_CLASSES_ROOT, |
||
230 | ext + '_auto_file', { this is the type we want to define } |
||
231 | '', { specify the default data item } |
||
232 | ext + ' Files'); { This is the value of the default data item - |
||
233 | this is the English description of the file type } |
||
234 | |||
235 | SetValInReg( HKEY_CLASSES_ROOT, |
||
236 | Ext + '_auto_file\DefaultIcon', { Create a file...DefaultIcon.} |
||
237 | '', { Specify the default data item.} |
||
238 | PgmToLinkTo + ',0' ); { Executable where icon is in and it's Sequence number.} |
||
239 | SHChangeNotify( SHCNE_ASSOCCHANGED, SHCNF_FLUSH, nil, nil ); |
||
240 | |||
241 | // un-comment this if your file type can be viewed by Quick View |
||
242 | // SetValInReg( HKEY_CLASSES_ROOT, |
||
243 | // ext + '_auto_file\QuickView', { create a key for QuickView compat. } |
||
244 | // '', { specify the default data item } |
||
245 | // '*' ); { flag to tell Explorer that QuickView is OK } |
||
246 | |||
247 | SetValInReg( HKEY_CLASSES_ROOT, |
||
248 | ext + '_auto_file\shell\open\command', { create a file...open key } |
||
249 | '', { specify the default data item } |
||
250 | PgmToLinkTo + ' %1' ); { command line to open file with } |
||
251 | end |
||
252 | else |
||
253 | ShowMessage( 'Error: Program not found: ' + PgmToLinkTo ); |
||
254 | end; |
||
255 | |||
256 | procedure TInstForm.RemoveAssociation( Ext: String ); |
||
257 | begin |
||
258 | Ext := LowerCase( Ext ); |
||
259 | RegDeleteKey( HKEY_CLASSES_ROOT, |
||
260 | '.' + ext ); { extension we want to undefine } |
||
261 | RegDeleteKey( HKEY_CLASSES_ROOT, |
||
262 | Ext + '_auto_file\DefaultIcon' ); |
||
263 | RegDeleteKey( HKEY_CLASSES_ROOT, |
||
264 | ext + '_auto_file\shell\open\command' ); |
||
265 | RegDeleteKey( HKEY_CLASSES_ROOT, |
||
266 | ext + '_auto_file' ); |
||
267 | SHChangeNotify( SHCNE_ASSOCCHANGED, SHCNF_FLUSH, nil, nil ); |
||
268 | end; |
||
269 | |||
270 | procedure TInstForm.RegDeleteKey( RKey: HKey; KeyPath: String ); |
||
271 | begin |
||
272 | with TRegistry.Create do |
||
273 | try |
||
274 | RootKey := RKey; |
||
275 | // Under Win95, all keys under this one are auto. deleted also. |
||
276 | // But, under WinNT, the keys under this one will be left alone. |
||
277 | DeleteKey( KeyPath ); |
||
278 | finally |
||
279 | Free; |
||
280 | end; |
||
281 | end; |
||
282 | |||
283 | { Set a value in the registry. This is NOT related to the .LNK code. |
||
284 | This will create a new registry key if it doesn't already exist. } |
||
285 | procedure TInstForm.SetValInReg( RKey: HKey; KeyPath: String; ValName: String; NewVal: String ); |
||
286 | begin |
||
287 | with TRegistry.Create do |
||
288 | try |
||
289 | RootKey := RKey; |
||
290 | OpenKey( KeyPath, True ); |
||
291 | WriteString( ValName, NewVal ); |
||
292 | finally |
||
293 | Free; |
||
294 | end; |
||
295 | end; |
||
296 | |||
297 | {$IfNDef VER90} // Delphi 3+ |
||
298 | {* Make a Shell Link, also called a "shortcut". |
||
299 | * MakeLink - uses the shell's IShellLink and IPersistFile interfaces |
||
300 | * to create and store a shortcut to the specified object. |
||
301 | * |
||
302 | * PgmPath - address of a buffer containing the path of the object. |
||
303 | * LinkPath - address of a buffer containing the path where the shell link is to be stored. |
||
304 | * Descr - address of a buffer containing the description of the shell link. |
||
305 | * PgmArgs - address of a buffer containing the arguments for the shell link. |
||
306 | *} |
||
307 | procedure TInstForm.MakeLink( PgmPath, PgmArgs, LinkPath, Descr: String ); |
||
308 | var |
||
309 | AnObj: IUnknown; |
||
310 | ShLink: IShellLink; |
||
311 | PFile: IPersistFile; |
||
312 | WFileName: WideString; |
||
313 | begin |
||
314 | if UpperCase( ExtractFileExt( LinkPath ) ) <> '.LNK' then |
||
315 | begin |
||
316 | ShowMessage( 'Error: link path extension must be .LNK' ); |
||
317 | Exit; |
||
318 | end; |
||
319 | |||
320 | // access to the two interfaces of the object |
||
321 | AnObj := CreateComObject( CLSID_ShellLink ); |
||
322 | ShLink := AnObj as IShellLink; |
||
323 | PFile := AnObj as IPersistFile; |
||
324 | |||
325 | // NOTE: We're using a COM Object, so all string args must be PChar |
||
326 | |||
327 | // set the link properties |
||
328 | ShLink.SetPath( PChar( PgmPath ) ); // also called the link target |
||
329 | ShLink.SetArguments( PChar( PgmArgs ) ); |
||
330 | ShLink.SetWorkingDirectory( PChar( ExtractFilePath( PgmPath ) ) ); |
||
331 | ShLink.SetDescription( PChar( Descr ) ); |
||
332 | |||
333 | // Save with a WideString filename |
||
334 | WFileName := LinkPath; |
||
335 | PFile.Save( PWChar( WFileName ), False ); |
||
336 | end; |
||
337 | |||
338 | {$Else} |
||
339 | // Delphi 2 |
||
340 | procedure TInstForm.MakeLink( PgmPath, PgmArgs, LinkPath, Descr: String ); |
||
341 | var |
||
342 | ShLink: pShLinkType; |
||
343 | pShLink: ppShLinkType; |
||
344 | hRes: HRESULT; |
||
345 | pFile: pFileType; |
||
346 | ppFile: ppFileType; |
||
347 | WFileName: Array[0..MAX_PATH] of WideChar; |
||
348 | begin |
||
349 | if UpperCase( ExtractFileExt( LinkPath ) ) <> '.LNK' then |
||
350 | begin |
||
351 | ShowMessage( 'Error: link path extension must be .LNK' ); |
||
352 | Exit; |
||
353 | end; |
||
354 | hRes := CoInitialize( nil ); |
||
355 | if (hRes = S_OK) or (hRes = S_FALSE) then |
||
356 | begin |
||
357 | if hRes = S_OK then |
||
358 | begin |
||
359 | // Get a pointer to the IShellLink interface. |
||
360 | hRes := CoCreateInstance( CLSID_ShellLink, nil, CLSCTX_INPROC_SERVER, IID_IShellLink, pShLink ); |
||
361 | if SUCCEEDED( hRes ) then |
||
362 | begin |
||
363 | // Set the path to the shortcut target, and add the description. |
||
364 | ShLink := @pShLink; |
||
365 | ShLink.SetPath( PChar( PgmPath ) ); |
||
366 | ShLink.SetDescription( PChar( Descr ) ); |
||
367 | ShLink.SetArguments( PChar( PgmArgs ) ); |
||
368 | ShLink.SetIconLocation( PChar( PgmPath ), 0 ); |
||
369 | ShLink.SetWorkingDirectory( PChar( ExtractFilePath( PgmPath ) ) ); |
||
370 | |||
371 | // Query IShellLink for the IPersistFile interface for saving the |
||
372 | // shortcut in persistent storage. |
||
373 | hRes := ShLink.QueryInterface( IID_IPersistFile, ppFile ); |
||
374 | if SUCCEEDED( hRes ) then |
||
375 | begin |
||
376 | pFile := @ppFile; |
||
377 | // Ensure that the string is ANSI. |
||
378 | MultiByteToWideChar( CP_ACP, 0, PChar( LinkPath ), -1, WFileName, MAX_PATH ); |
||
379 | |||
380 | // Save the link by calling IPersistFile::Save. |
||
381 | pFile.Save( WFileName, False ); |
||
382 | PFile.SaveCompleted( WFileName ); |
||
383 | pFile.Release; |
||
384 | end; |
||
385 | ShLink.Release; |
||
386 | end; |
||
387 | end else |
||
388 | ShowMessage( 'COM already initialized' ); |
||
389 | CoUninitialize; |
||
390 | end else // E_INVALIDARG, E_OUTOFMEMORY, o E_UNEXPECTED. |
||
391 | ShowMessage( 'COM library could not initialize' ); |
||
392 | end; |
||
393 | {$EndIf} |
||
394 | |||
395 | procedure TInstForm.CancelButClick( Sender: TObject ); |
||
396 | begin |
||
397 | Close; |
||
398 | end; |
||
399 | |||
400 | procedure TInstForm.UninstButClick( Sender: TObject ); |
||
401 | var |
||
402 | path: String; |
||
403 | MenuDir: Integer; |
||
404 | begin |
||
405 | Screen.Cursor := crHourGlass; |
||
406 | if StartMenuCB.Checked then |
||
407 | begin |
||
408 | if StartMenuRB.Checked then |
||
409 | MenuDir := CSIDL_STARTMENU |
||
410 | else |
||
411 | MenuDir := CSIDL_PROGRAMS; |
||
412 | GetSpecialFolder( MenuDir, path ); |
||
413 | DeleteFile( path + EXETitle + '.lnk' ); |
||
414 | end; |
||
415 | |||
416 | if DesktopCB.Checked then |
||
417 | begin |
||
418 | GetSpecialFolder( CSIDL_DESKTOPDIRECTORY, path ); |
||
419 | DeleteFile( path + EXETitle + '.lnk' ); |
||
420 | end; |
||
421 | |||
422 | if SendToCB.Checked then |
||
423 | begin |
||
424 | GetSpecialFolder( CSIDL_SENDTO, path ); |
||
425 | DeleteFile( path + EXETitle + '.lnk' ); |
||
426 | end; |
||
427 | |||
428 | if RegistryCB.Checked then |
||
429 | begin |
||
430 | RegDeleteKey( HKEY_LOCAL_MACHINE, |
||
431 | 'SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\' + EXEName ); |
||
432 | RegDeleteKey( HKEY_LOCAL_MACHINE, |
||
433 | 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' + EXEName ); |
||
434 | RegDeleteKey( HKEY_LOCAL_MACHINE, |
||
435 | 'SOFTWARE\' + EXEName ); |
||
436 | RegDeleteKey( HKEY_CURRENT_USER, |
||
437 | 'SOFTWARE\' + EXEName ); |
||
438 | end; |
||
439 | |||
440 | if AssocCB.Checked then |
||
441 | RemoveAssociation( 'zip' ); |
||
442 | |||
443 | Screen.Cursor := crDefault; |
||
444 | |||
445 | if NOT Form1.AutoUnInstall then |
||
446 | { if we are auto-uninstalling, then we are still in OnCreate, |
||
447 | so we can't close this form yet. } |
||
448 | Close; |
||
449 | end; |
||
450 | |||
451 | procedure TInstForm.FormActivate( Sender: TObject ); |
||
452 | begin |
||
453 | if Form1.AutoUnInstall then |
||
454 | PostMessage( Handle, WM_CLOSE, 0, 0 ); |
||
455 | end; |
||
456 | |||
457 | // Add a backslash to a string if it doesn't already end in one, |
||
458 | // AND if the string has a non-zero length. |
||
459 | function TInstForm.AddBackslash( str_in: string ): string; |
||
460 | begin |
||
461 | Result := str_in; |
||
462 | if Result = '' then |
||
463 | Exit; |
||
464 | if Result[Length( Result )] <> '\' then |
||
465 | Result := Result + '\'; |
||
466 | end; |
||
467 | |||
468 | procedure TInstForm.StartMenuCBClick( Sender: TObject ); |
||
469 | begin |
||
470 | StartMenuRB.Enabled := StartMenuCB.Checked; |
||
471 | ProgramRB.Enabled := StartMenuCB.Checked; |
||
472 | end; |
||
473 | |||
474 | //--------------------------------------------------------------------------- |
||
475 | {* Folder types are a.o. |
||
476 | * CSIDL_DESKTOPDIRECTORY, CSIDL_STARTMENU, CSIDL_SENDTO, |
||
477 | * CSIDL_PROGRAMS, CSIDL_STARTUP etc. |
||
478 | *} |
||
479 | function TInstForm.GetSpecialFolder( aFolder: Integer; var Location: String ): LongWord; |
||
480 | var |
||
481 | pidl: PItemIDList; |
||
482 | hRes: HRESULT; |
||
483 | RealPath: Array[0..MAX_PATH] of Char; |
||
484 | Success: Boolean; |
||
485 | begin |
||
486 | Result := 0; |
||
487 | hRes := SHGetSpecialFolderLocation( Handle, aFolder, pidl ); |
||
488 | if hRes = NO_ERROR then |
||
489 | begin |
||
490 | Success := SHGetPathFromIDList( pidl, RealPath ); |
||
491 | if Success then |
||
492 | Location := String( RealPath ) + '\' |
||
493 | else |
||
494 | Result := LongWord( E_UNEXPECTED ); |
||
495 | GlobalFreePtr( pidl ); |
||
496 | end else |
||
497 | Result := hRes; |
||
498 | end; |
||
499 | |||
500 | end. |