Subversion Repositories autosfx

Rev

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.