Subversion Repositories autosfx

Rev

Blame | Last modification | View Log | RSS feed

  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.
  501.