Files
kolmck/Addons/Lnk.pas
dkolmck 1d0a035e7c 3.04
git-svn-id: https://svn.code.sf.net/p/kolmck/code@98 91bb2d04-0c0c-4d2d-88a5-bbb6f4c1fa07
2011-01-01 09:32:36 +00:00

760 lines
28 KiB
ObjectPascal

unit Lnk;
{* Additional unit. Has two procedures to get system folder by its CSIDL and
to create shortcut to the specified file object. Sources are from public place.
Actually, made on base of sample from MSDN.
Adapted to use with KOL.
Last update: 17-May-2007 (with KOL v 2.61)
}
interface
{$I KOLDEF.INC}
uses windows, shlobj, ShellAPI, ActiveX, {OLE2,} KOL;
function GetSystemFolder(Const Folder:integer):string;
{* Returns specified system folder location. Following constant can be passed
as a parameter:
|<pre>
CSIDL_DESKTOP <desktop> (root of namespace)
CSIDL_PROGRAMS Start Menu\Programs
CSIDL_STARTMENU Settings\username\Start Menu
CSIDL_PERSONAL Settings\username\My Documents
CSIDL_FAVORITES
CSIDL_STARTUP
CSIDL_INTERNET
CSIDL_CONTROLS
CSIDL_PRINTERS
CSIDL_RECENT
CSIDL_SENDTO
CSIDL_BITBUCKET
|</pre> see other in documentation on API "CSIDL Values" }
function CreateLinkDesc(const FileName,Arguments,WorkDir,IconFile:String;
IconNumber:integer; LinkName:String;
Description:String
): Boolean;
{* Creates a shortcut with description. }
function CreateLink(const FileName,Arguments,WorkDir,IconFile:String;
IconNumber:integer; LinkName:String
): Boolean;
{* Creates a shortcut to specified file object. An example:
!
! CreateLink( ParamStr( 0 ), '', '', '', 1, GetSystemFolder(CSIDL_DESKTOP)+
! '\MyProg.lnk' );
}
function ResolveLink( const LinkName: KOLString; var FileName, Arguments, WorkDir,
Description: KOLString; var IconSmall, IconLarge: HIcon; need_icons: Boolean;
DialogParentWnd: HWND ): Boolean;
{* Attempts to resolve given link (given by a path to link file). If a link is
resolved, TRUE returned and FileName, Arguments, WorkDir, Description, Icon(s)
fields are containing resolved parameters of the link. Set ParentDialogWnd to
a handle of your window (or 0), if a dialog is allowed to appear if linked
file is absent (moved or renamed). If DialogParentWnd = THandle(-1) and linked
file is not found, FALSE is returned silently, without showing dialog box.
|<br>
Note: if IconSmall and / or IconLarge are returned <> 0, your code is responsible
for releasing it calling DestroyIcon function(s). }
function IsLink2RecycleBin( const LinkName: String ): Boolean;
{* Returns TRUE, if the link is a link to Recycle Bin. }
//shlobj.h
//some CSIDL_XXX like CSIDL_PROGRAM_FILES need version 5.00
//(Shlwapi.dll, Microsoft� Internet Explorer 5)
const
CSIDL_DESKTOP =$0000; // <desktop>
CSIDL_INTERNET =$0001; // Internet Explorer (icon on desktop)
CSIDL_PROGRAMS =$0002; // Start Menu\Programs
CSIDL_CONTROLS =$0003; // My Computer\Control Panel
CSIDL_PRINTERS =$0004; // My Computer\Printers
CSIDL_PERSONAL =$0005; // My Documents
CSIDL_FAVORITES =$0006; // <user name>\Favorites
CSIDL_STARTUP =$0007; // Start Menu\Programs\Startup
CSIDL_RECENT =$0008; // <user name>\Recent
CSIDL_SENDTO =$0009; // <user name>\SendTo
CSIDL_BITBUCKET =$000a; // <desktop>\Recycle Bin
CSIDL_STARTMENU =$000b; // <user name>\Start Menu
CSIDL_MYDOCUMENTS =$000c; // logical "My Documents" desktop icon
CSIDL_MYMUSIC =$000d; // "My Music" folder
CSIDL_MYVIDEO =$000e; // "My Videos" folder
CSIDL_DESKTOPDIRECTORY =$0010; // <user name>\Desktop
CSIDL_DRIVES =$0011; // My Computer
CSIDL_NETWORK =$0012; // Network Neighborhood
CSIDL_NETHOOD =$0013; // <user name>\nethood
CSIDL_FONTS =$0014; // windows\fonts
CSIDL_TEMPLATES =$0015;
CSIDL_COMMON_STARTMENU =$0016; // All Users\Start Menu
CSIDL_COMMON_PROGRAMS =$0017; // All Users\Programs
CSIDL_COMMON_STARTUP =$0018; // All Users\Startup
CSIDL_COMMON_DESKTOPDIRECTORY =$0019; // All Users\Desktop
CSIDL_APPDATA =$001a; // <user name>\Application Data
CSIDL_PRINTHOOD =$001b; // <user name>\PrintHood
CSIDL_LOCAL_APPDATA =$001c; // <user name>\Local Settings\Applicaiton Data (non roaming)
CSIDL_ALTSTARTUP =$001d; // non localized startup
CSIDL_COMMON_ALTSTARTUP =$001e; // non localized common startup
CSIDL_COMMON_FAVORITES =$001f;
CSIDL_INTERNET_CACHE =$0020;
CSIDL_COOKIES =$0021;
CSIDL_HISTORY =$0022;
CSIDL_COMMON_APPDATA =$0023; // All Users\Application Data
CSIDL_WINDOWS =$0024; // GetWindowsDirectory()
CSIDL_SYSTEM =$0025; // GetSystemDirectory()
CSIDL_PROGRAM_FILES =$0026; // C:\Program Files
CSIDL_MYPICTURES =$0027; // C:\Program Files\My Pictures
CSIDL_PROFILE =$0028; // USERPROFILE
CSIDL_SYSTEMX86 =$0029; // x86 system directory on RISC
CSIDL_PROGRAM_FILESX86 =$002a; // x86 C:\Program Files on RISC
CSIDL_PROGRAM_FILES_COMMON =$002b; // C:\Program Files\Common
CSIDL_PROGRAM_FILES_COMMONX86 =$002c; // x86 Program Files\Common on RISC
CSIDL_COMMON_TEMPLATES =$002d; // All Users\Templates
CSIDL_COMMON_DOCUMENTS =$002e; // All Users\Documents
CSIDL_COMMON_ADMINTOOLS =$002f; // All Users\Start Menu\Programs\Administrative Tools
CSIDL_ADMINTOOLS =$0030; // <user name>\Start Menu\Programs\Administrative Tools
CSIDL_CONNECTIONS =$0031; // Network and Dial-up Connections
CSIDL_FLAG_CREATE =$8000; // combine with CSIDL_ value to force folder creation in SHGetFolderPath()
CSIDL_FLAG_DONT_VERIFY =$4000; // combine with CSIDL_ value to return an unverified folder path
CSIDL_FLAG_NO_ALIAS =$1000; // combine with CSIDL_ value to insure non-alias versions of the pidl
CSIDL_FLAG_MASK =$FF00; // mask for all possible flag values
procedure FileTypeReg(FExt,Desc,Cmd,Exe: string; IconIndex: integer; Default,Run: boolean);
{* By Dimaxx. Registers file type association.
|<pre>
FExt - file extension ���������� �����
Desc - file type description �������� ���� �����
Cmd - context menu command ������� ��� ������������ ����
Exe - path to executable ���� � ������������ �����
Default - if command is default ����������� ��������� �� ���������
Run - if reaction needed when clicked ����� �� �������� ��� ������ �� ����� � ����� �����������
|</pre>
Example:
! FileTypeReg('.abc','ABC Data File','Open','d:\abc_edit.exe',True);
}
function FileTypeGetReg(const FExt,Cmd: KOLString; var Desc, OldIcoExe: KOLString;
var OldIcoIdx: Integer; var OldId: KOLString ): KOLString;
{* Get registered file type association, if any (by command).
|<pre>
in:
FExt - file extension ���������� �����
Cmd - context menu command ������� ��� ������������ ����
out:
Desc - file type description �������� ���� �����
Result - path to executable ���� � ������������ �����
|</pre>
Shell is always notified about file association changes. See also FileTypeRegEx.
}
procedure FileTypeRegEx(FExt,Desc,Cmd,Exe: string; IconIndex: integer; Default,Run: boolean;
const IcoExe: String; NotifyShell: Boolean );
{* The same as FileTypeReg, but additional parameters are available:
IcoExe - file where the icon is stored;
NotifyShell - TRUE if to notify shell about changes. }
procedure FileTypeReg2(FExt,Desc,Cmd,Exe,Id: string;
IconIndex: integer; Default,Run: boolean;
const IcoExe: String; DfltIcoExe: String; NotifyShell: Boolean );
{* The same as above (FileTypeRegEx), but should also work in XP.
Provide ID string in form 'Vendor.Appname.Version', e.g. 'Litcorp Inc.My App.5'.
DfltIcoExe and DfltIcoIndex are used to set default application icon,
this does affect associations of other files with the application,
not having its own DefaultIcon settings in the registry. }
function FileTypeReg2Ex(FExt,Desc,Cmd,Exe,Id: string;
IconIndex: integer; Default,Run: boolean;
const IcoExe: String; DfltIcoExe: String; NotifyShell: Boolean ): String;
{* The same as above (FileTypeReg2), but also returs a string which can be
passed later to FileTypeUnreg as a parameter to undo registration to a
previous state. }
procedure FileTypeUnreg( const UndoStr: String; NotifyShell: Boolean );
{* Pass as UndoStr a string returned by FileTypeReg2Ex to undo the association
made with it. }
function RegKeyDeleteAll( Key: HKey; const Subkey: KOLString ): Boolean;
{* In addition to RegKeyXXXXX functions in KOL.pas, allows to delete entire
key with all nested keys and values (careful, please!) }
implementation
function GetSystemFolder(Const Folder:integer):string;
var
PIDL: PItemIDList;
Path: array[ 0..MAX_PATH ] of Char;
begin
Result := '';
if SHGetSpecialFolderLocation(0, Folder, PIDL) = NOERROR then
begin
if SHGetPathFromIDList(PIDL, Path) then Result := IncludeTrailingPathDelimiter( Path );
CoTaskMemFree( PIDL );
end;
end;
const
IID_IPersistFile: TGUID = (
D1:$0000010B;D2:$0000;D3:$0000;D4:($C0,$00,$00,$00,$00,$00,$00,$46));
function CreateLink(const FileName,Arguments,WorkDir,IconFile:String;
IconNumber:integer; LinkName:String ): Boolean;
begin
Result := CreateLinkDesc( FileName, Arguments, WorkDir, IconFile, IconNumber,
LinkName, '' );
end;
function CreateLinkDesc(const FileName,Arguments,WorkDir,IconFile:String;
IconNumber:integer; LinkName:String;
Description:String): Boolean;
var
SLink : IShellLink;
PFile : IPersistFile;
WFileName : WideString;
begin
Result := FALSE;
CoInitialize( nil );
if CoCreateInstance( TGUID( CLSID_ShellLink ), nil, CLSCTX_INPROC_SERVER,
TGUID( IID_IShellLinkA ), SLink ) <> S_OK then Exit;
if SLink.QueryInterface( System.TGUID( IID_IPersistFile ), PFile ) <> S_OK then Exit;
SLink.SetArguments(PChar(Arguments));
SLink.SetPath(PChar(FileName));
SLink.SetWorkingDirectory(PChar(WorkDir));
SLink.SetDescription(PChar(Description));
SLink.SetIconLocation(PChar(IconFile),IconNumber);
if not DirectoryExists(ExtractFilePath(LinkName)) then
CreateDir( ExtractFilePath(LinkName) );
WFileName := LinkName;
PFile.Save(PWChar(WFileName),False);
Result := TRUE;
end;
{$IFDEF UNICODE_CTRLS}
type IShellLink_ = IShellLinkW;
{$ELSE}
type IShellLink_ = IShellLinkA;
{$ENDIF}
function ResolveLink( const LinkName: KOLString; var FileName, Arguments, WorkDir,
Description: KOLString; var IconSmall, IconLarge: HIcon; need_icons: Boolean;
DialogParentWnd: HWND ): Boolean;
var
SLink : IShellLink_;
PFile : IPersistFile;
WFileName : WideString;
Wnd: HWnd;
Flg: DWORD;
Buf: array[ 0..4095 ] of KOLChar;
FD: TWin32FindData;
I: Integer;
begin
Result := FALSE;
CoInitialize( nil );
if CoCreateInstance( TGUID( CLSID_ShellLink ), nil, CLSCTX_INPROC_SERVER,
TGUID( IID_IShellLinkA ), SLink ) <> S_OK then Exit;
if SLink.QueryInterface( System.TGUID( IID_IPersistFile ), PFile )
<> S_OK then Exit;
WFileName := LinkName;
PFile.Load(PWChar(WFileName),STGM_READ);
Wnd := DialogParentWnd;
if Wnd = THandle( -1 ) then
Wnd := 0;
Flg := SLR_UPDATE;
if DialogParentWnd = THandle(-1) then
Flg := SLR_NO_UI;
if SLink.Resolve( Wnd, Flg ) = NOERROR then
begin
if SLink.GetPath( Buf, Sizeof( Buf ) div Sizeof( KOLChar ),
PWin32FindDataA(@ FD)^ {error in ShlObj.pas !}
, 0 ) <> NOERROR then
FileName := ''
else FileName := Buf;
if SLink.GetArguments( Buf, Sizeof( Buf ) ) <> NOERROR then Exit;
Arguments := Buf;
if SLink.GetWorkingDirectory( Buf, Sizeof( Buf ) div Sizeof( KOLChar ) )
<> NOERROR then Exit;
WorkDir := Buf;
if SLink.GetDescription( Buf, Sizeof( Buf ) div Sizeof( KOLChar ) )
<> NOERROR then Exit;
Description := Buf;
IconSmall := 0;
IconLarge := 0;
if need_icons
and (SLink.GetIconLocation( Buf, Sizeof( Buf ) div Sizeof( KOLChar ), I )
= NOERROR) then
{$IFDEF UNICODE_CTRLS}
ExtractIconExW( Buf, I, IconLarge, IconSmall, 1 );
{$ELSE}
ExtractIconExA( Buf, I, IconLarge, IconSmall, 1 );
{$ENDIF}
Result := TRUE;
end;
end;
function IsLink2RecycleBin( const LinkName: String ): Boolean;
var
SLink : IShellLink;
PFile : IPersistFile;
WFileName : WideString;
Flg: DWORD;
ppidl, ppidl1, p, p1: PItemIDList;
begin
Result := FALSE;
CoInitialize( nil );
if CoCreateInstance( TGUID( CLSID_ShellLink ), nil, CLSCTX_INPROC_SERVER,
TGUID( IID_IShellLinkA ), SLink ) <> S_OK then Exit;
if SLink.QueryInterface( System.TGUID( IID_IPersistFile ), PFile ) <> S_OK then Exit;
WFileName := LinkName;
PFile.Load(PWChar(WFileName),STGM_READ);
Flg := SLR_NO_UI;
if SLink.Resolve( 0, Flg ) = NOERROR then
begin
if SLink.GetIDList( ppidl ) = NOERROR then
begin
if SHGetSpecialFolderLocation( 0, CSIDL_BITBUCKET, ppidl1 ) = NOERROR then
begin
Result := TRUE;
p := ppidl;
p1 := ppidl1;
while TRUE do
begin
if (p1.mkid.cb = p.mkid.cb) and (p1.mkid.cb = 0) then
break;
if (p1.mkid.cb <> p.mkid.cb) or
not CompareMem( @ p.mkid.abID[ 0 ], @ p1.mkid.abID[ 0 ],
p.mkid.cb ) then
begin
Result := FALSE;
break;
end;
p := Pointer( Integer( p ) + p.mkid.cb );
p1 := Pointer( Integer( p1 ) + p1.mkid.cb );
end;
CoTaskMemFree( ppidl1 );
end;
CoTaskMemFree( ppidl );
end;
end;
end;
function RegKeyDeleteAll( Key: HKey; const Subkey: KOLString ): Boolean;
type TSHDeleteKey = function( Key: HKey; Subkey: PKOLChar ): DWORD; stdcall;
var SHDeleteKey: TSHDeleteKey;
M: THandle;
begin
Result := FALSE;
M := LoadLibrary( 'shlwapi.dll' );
if M <> 0 then
TRY
SHDeleteKey := GetProcAddress( M,
{$IFDEF UNICODE_CTRLS} 'SHDeleteKeyW' {$ELSE} 'SHDeleteKeyA' {$ENDIF} );
if Assigned( SHDeleteKey ) then
Result := SHDeleteKey( Key, PKOLChar( SubKey ) ) = 0;
FINALLY
FreeLibrary( M );
END;
end;
procedure FileTypeRegEx(FExt,Desc,Cmd,Exe: string; IconIndex: integer; Default,Run: boolean;
const IcoExe: String; NotifyShell: Boolean );
begin
FileTypeRegEx( FExt, Desc, Cmd, Exe, IconIndex,
Default, Run, IcoExe, NotifyShell );
end;
//[procedure FileTypeReg]
procedure FileTypeReg(FExt,Desc,Cmd,Exe: string; IconIndex: integer; Default,Run: boolean);
begin
FileTypeRegEx( Fext,Desc,Cmd,Exe, IconIndex, Default, Run, Exe, TRUE );
end;
procedure FileTypeReg2(FExt,Desc,Cmd,Exe,Id: string;
IconIndex: integer;
Default,Run: boolean;
const IcoExe: String; DfltIcoExe: String; NotifyShell: Boolean );
var Reg: HKey;
Key: string;
begin
Reg:=RegKeyOpenWrite(HKEY_CLASSES_ROOT,'Applications');
//if not RegKeyExists(Reg,ExtractFileName(Exe)) then
begin
RegKeyClose(Reg);
Reg := RegKeyOpenCreate(HKEY_CLASSES_ROOT,
'Applications\'+ExtractFileName(Exe)+'\Shell\Open\Command');
RegKeySetStr(Reg,'',Exe+' "%1"');
RegKeyClose(Reg);
end;
//else RegKeyClose( Reg ); // {VK}
if Id <> '' then
begin
Reg := RegKeyOpenCreate(HKEY_CURRENT_USER,
'Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\' + FExt);
RegKeySetStr( Reg, 'Progid', Id );
RegKeyClose( Reg );
end;
// HKCR\.ext Default=extfile
Reg:=RegKeyOpenCreate(HKEY_CLASSES_ROOT,FExt);
Key:=LowerCase(FExt)+'file';
Delete(Key,1,1);
RegKeySetStr(Reg,'',Key);
RegKeyClose(Reg);
// HKCR\extfile Default=id
if Id <> '' then
begin
Reg:=RegKeyOpenCreate(HKEY_CLASSES_ROOT,Key);
RegKeySetStr(Reg,'',Id);
RegKeyClose(Reg);
end;
// HKCR\id Default=pathto.exe
if Id <> '' then
begin
Reg:=RegKeyOpenCreate(HKEY_CLASSES_ROOT,Id);
RegKeySetStr(Reg,'',Exe);
RegKeyClose(Reg);
end;
if DfltIcoExe <> '' then
begin
// HKCR\id\DefaultIcon Default=DfltIcoExe
Reg := RegKeyOpenCreate(HKEY_CLASSES_ROOT,Id + '\DefaultIcon');
RegKeySetStr(Reg,'',DfltIcoExe);
RegKeyClose( Reg );
end;
if (IcoExe <> '') {or (IconIndex<>-1)} then
begin
Reg:=RegKeyOpenCreate(HKEY_CLASSES_ROOT,Key+'\DefaultIcon');
if IconIndex = -1 then
RegKeySetStr(Reg,'',IcoExe + ',0' )
else RegKeySetStr(Reg,'',IcoExe + ',' + Int2Str(IconIndex) );
RegKeyClose(Reg);
end;
if Run then
begin
{Reg:=RegKeyOpenCreate(HKEY_CLASSES_ROOT,Key+'\Shell');
if Default then RegKeySetStr(Reg,'',Cmd)
else RegKeySetStr(Reg,'','');
RegKeyClose(Reg);
Reg:=RegKeyOpenCreate(HKEY_CLASSES_ROOT,Key+'\Shell\'+Cmd);
RegKeyClose(Reg);}
{$IFNDEF LNK_NODELETE_OLDCMD}
Reg := RegKeyOpenCreate(HKEY_CLASSES_ROOT,Key+'\Shell\');
RegKeyDeleteAll( Reg, Cmd );
if Default then
RegKeySetStr(Reg,'',Cmd);
RegKeyClose( Reg );
{$ENDIF}
Reg:=RegKeyOpenCreate(HKEY_CLASSES_ROOT,Key+'\Shell\'+Cmd+'\Command');
RegKeySetStr(Reg,'',Exe+' "%1"');
RegKeyClose(Reg);
end;
//+ {VK}
if NotifyShell then
begin
SHChangeNotify( SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nil, nil );
//SHChangeNotify( SHCNE_ALLEVENTS, SHCNF_IDLIST, nil, nil );
end;
end;
function FileTypeReg2Ex(FExt,Desc,Cmd,Exe,Id: string;
IconIndex: integer; Default,Run: boolean;
const IcoExe: String; DfltIcoExe: String; NotifyShell: Boolean ): String;
var Reg: HKey;
Key: string;
Strm: PStream;
procedure add4Undo( const RegClass, RegKey, Cmd, Value: String );
var s: String;
begin
s := RegClass+',';
if RegKey <> '' then
s := s +Int2Str(Length(RegKey))+'('+RegKey+'),';
s := s+Cmd;
if Value <> '' then
s := s + ',' + Int2Str(Length(Value))+'('+Value+')';
Strm.WriteStr( s+#13 );
end;
procedure DeleteAllSubKeys( const RegClass, RegKey: String; Reg: THandle; const SubKey: String );
var SL: PKOLStrList;
i: Integer;
Reg1: THandle;
procedure not_supported;
asm
nop
end;
begin
SL := NewKOLStrList;
Reg1 := RegKeyOpenWrite( Reg, SubKey );
TRY
RegKeyGetSubKeys(Reg1, SL);
for i := 0 to SL.Count-1 do
begin
DeleteAllSubKeys( RegClass, RegKey + '\' + SL.Items[ i ], Reg1, SL.Items[ i ] );
end;
SL.Clear;
RegKeyGetValueNames( Reg1, SL );
for i := 0 to SL.Count-1 do
begin //todo: support more types of values
CASE RegKeyGetValueTyp(Reg1, SL.Items[ i ]) OF
REG_BINARY: not_supported;
REG_DWORD : // = REG_DWORD_LITTLE_ENDIAN
add4Undo( RegClass, RegKey, 'd=' + SL.Items[i], Int2Str( RegKeyGetDw(Reg1,SL.Items[i]) ) );
REG_DWORD_BIG_ENDIAN:
add4Undo( RegClass, RegKey, 'D=' + SL.Items[i], Int2Str( RegKeyGetDw(Reg1,SL.Items[i]) ) );
REG_EXPAND_SZ:
add4Undo( RegClass, RegKey, 'X=' + SL.Items[i], RegKeyGetStr(Reg1,SL.Items[i]) );
REG_LINK: not_supported;
REG_MULTI_SZ: not_supported;
REG_NONE: not_supported;
REG_RESOURCE_LIST: not_supported;
REG_SZ:
add4Undo( RegClass, RegKey, 'S=' + SL.Items[i], RegKeyGetStr(Reg1,SL.Items[i]) );
END;
end;
FINALLY
SL.Free;
RegKeyClose( Reg1 );
add4Undo( RegClass, RegKey, 'K-', SubKey );
RegKeyDelete( Reg, SubKey );
END;
end;
function q( const s: String ): String;
begin
if pos( ' ', s ) > 0 then Result := '"' + s + '"'
else Result := s;
end;
begin
Result := '';
Strm := NewMemoryStream;
TRY
Reg:=RegKeyOpenWrite(HKEY_CLASSES_ROOT,'Applications');
if not RegKeyExists( Reg, ExtractFileName(Exe) ) then
add4Undo( 'HKCR', 'Applications', 'K+',
ExtractFileName(Exe)+'\Shell\Open\Command' );
//if not RegKeyExists(Reg,ExtractFileName(Exe)) then
begin
RegKeyClose(Reg);
Reg := RegKeyOpenCreate(HKEY_CLASSES_ROOT,
'Applications\'+ExtractFileName(Exe)+'\Shell\Open\Command');
add4Undo( 'HKCR',
'Applications\'+ExtractFileName(Exe)+'\Shell\Open\Command',
'S=', RegKeyGetStr(Reg,'') );
RegKeySetStr(Reg,'',q(Exe)+' "%1"');
RegKeyClose(Reg);
end;
//else RegKeyClose( Reg ); // {VK}
if Id <> '' then
begin
if not RegKeyExists( HKEY_CURRENT_USER,
'Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\' + FExt ) then
add4Undo( 'HKCU', '', 'K+',
'Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\' + FExt );
Reg := RegKeyOpenCreate(HKEY_CURRENT_USER,
'Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\' + FExt);
if not RegKeyValExists( Reg, 'ProgId' ) then
add4Undo( 'HKCU',
'Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\' + FExt,
'V+', 'ProgId' )
else
add4Undo( 'HKCU',
'Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\' + FExt,
'S=ProgId', RegKeyGetStr(Reg,'ProgId') );
RegKeySetStr( Reg, 'Progid', Id );
RegKeyClose( Reg );
end;
// HKCR\.ext Default=extfile
if not RegKeyExists( HKEY_CLASSES_ROOT, FExt ) then
add4Undo( 'HKCR', '', 'K+', FExt );
Reg:=RegKeyOpenCreate(HKEY_CLASSES_ROOT,FExt);
Key:=LowerCase(FExt)+'file';
Delete(Key,1,1);
add4Undo( 'HKCR', FExt, 'S=', RegKeyGetStr( Reg, '' ) );
RegKeySetStr(Reg,'',Key);
RegKeyClose(Reg);
// HKCR\extfile Default=id
if Id <> '' then
begin
if not RegKeyExists( HKEY_CLASSES_ROOT, Key ) then
add4Undo( 'HKCR', '', 'K+', Key );
Reg:=RegKeyOpenCreate(HKEY_CLASSES_ROOT,Key);
add4Undo( 'HKCR', Key, 'S=', RegKeyGetStr( Reg, '' ) );
RegKeySetStr(Reg,'',Id);
RegKeyClose(Reg);
end;
// HKCR\id Default=pathto.exe
if Id <> '' then
begin
if not RegKeyExists( HKEY_CLASSES_ROOT, Id ) then
add4Undo( 'HKCR', '', 'K+', Id );
Reg:=RegKeyOpenCreate(HKEY_CLASSES_ROOT,Id);
add4Undo( 'HKCR', Id, 'S=', RegKeyGetStr( Reg, '' ) );
RegKeySetStr(Reg,'',Exe);
RegKeyClose(Reg);
end;
if DfltIcoExe <> '' then
begin
// HKCR\id\DefaultIcon Default=DfltIcoExe
if not RegKeyExists( HKEY_CLASSES_ROOT, Id + '\DefaultIcon' ) then
add4Undo( 'HKCR', '', 'K+', Id + '\DefaultIcon' );
Reg := RegKeyOpenCreate(HKEY_CLASSES_ROOT,Id + '\DefaultIcon');
add4Undo( 'HKCR', Id+'\DefaultIcon', 'S=', RegKeyGetStr( Reg, '' ) );
RegKeySetStr(Reg,'',DfltIcoExe);
RegKeyClose( Reg );
end;
if (IcoExe <> '') then
begin
if not RegKeyExists( HKEY_CLASSES_ROOT, Key + '\DefaultIcon' ) then
add4Undo( 'HKCR', '', 'K+', Key + '\DefaultIcon' );
Reg:=RegKeyOpenCreate(HKEY_CLASSES_ROOT,Key+'\DefaultIcon');
add4Undo( 'HKCR', Key+'\DefaultIcon', 'S=', RegKeyGetStr( Reg, '' ) );
if IconIndex = -1 then
RegKeySetStr(Reg,'',IcoExe + ',0' )
else
RegKeySetStr(Reg,'',IcoExe + ',' + Int2Str(IconIndex) );
RegKeyClose(Reg);
end;
if Run then
begin
{$IFNDEF LNK_NODELETE_OLDCMD}
if not RegKeyExists( HKEY_CLASSES_ROOT, Key + '\Shell' ) then
add4Undo( 'HKCR', '', 'K+', Key + '\Shell' );
Reg := RegKeyOpenCreate(HKEY_CLASSES_ROOT,Key+'\Shell\');
DeleteAllSubKeys( 'HKCR', Key + '\Shell', Reg, Cmd );
if Default then
begin
add4Undo( 'HKCR', Key+'\Shell', 'S=', RegKeyGetStr( Reg, '' ) );
RegKeySetStr(Reg,'',Cmd);
end;
RegKeyClose( Reg );
{$ENDIF}
if not RegKeyExists( HKEY_CLASSES_ROOT, Key+'\Shell\'+Cmd+'\Command' ) then
add4Undo( 'HKCR', '', 'K+', Key+'\Shell\'+Cmd+'\Command' );
Reg:=RegKeyOpenCreate(HKEY_CLASSES_ROOT,Key+'\Shell\'+Cmd+'\Command');
add4Undo( 'HKCR', Key+'\Shell\'+Cmd+'\Command', 'S=', RegKeyGetStr( Reg, '' ) );
RegKeySetStr(Reg,'',Exe+' "%1"');
RegKeyClose(Reg);
end;
if NotifyShell then
SHChangeNotify( SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nil, nil );
SetString( Result, PChar( Strm.Memory ), Strm.Size );
FINALLY
Strm.Free;
END;
end;
procedure FileTypeUnreg( const UndoStr: String; NotifyShell: Boolean );
var SL: PStrList;
i: Integer;
s: KOLString;
RegClass, RegKey, Cmd, Value, ValName: KOLString;
R: THandle;
Cls: DWORD;
procedure ExtractStr( var s: KOLString );
var i: Integer;
begin
if s = '' then Exit;
i := Str2Int( s );
if i = 0 then Exit;
Parse( s, '(' );
s := Copy( s, 1, i );
end;
begin
SL := NewStrList;
TRY
SL.Text := UndoStr;
for i := SL.Count-1 downto 0 do
begin
s := SL.Items[ i ];
RegClass := Parse( S, ',' );
RegKey := Parse( S, ',' );
ExtractStr( RegKey );
Cmd := Parse( s, ',' );
Value := s; ExtractStr( Value );
if RegClass = 'HKCU' then Cls := HKEY_CURRENT_USER
else if RegClass = 'HKLM' then Cls := HKEY_LOCAL_MACHINE
else if RegClass = 'HKCR' then Cls := HKEY_CLASSES_ROOT
else Cls := HKEY_CURRENT_USER;
if Cmd = 'K+' then // ������� ����
RegKeyDelete( Cls, RegKey )
else
if Cmd = 'K-' then // ������������ ����
begin
R := RegKeyOpenCreate( Cls, RegKey + '\' + Value );
RegKeyClose( R );
end
else
begin
R := RegKeyOpenWrite( Cls, RegKey );
ValName := CopyEnd( Cmd, 3 );
TRY
if Cmd = 'V+' then // ������� ��������
RegKeyDeleteValue( R, Value )
else if Cmd[1] = 'S' then // ������������ ��������� ��������
RegKeySetStr( R, ValName, Value )
else if Cmd[1] = 'd' then // ������������ �������� ���� DWORD:
RegKeySetDw( R, ValName, Str2Int( Value ) )
else if Cmd[1] = 'X' then
RegKeySetStrEx( R, ValName, Value, TRUE );
FINALLY
RegKeyClose( R );
END;
end;
end;
if NotifyShell then
SHChangeNotify( SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nil, nil );
FINALLY
SL.Free;
END;
end;
function FileTypeGetReg(const FExt,Cmd: KOLString; var Desc, OldIcoExe: KOLString;
var OldIcoIdx: Integer; var OldId: KOLString ): KOLString;
var Reg: HKey;
Key: KOLString;
S: KOLString;
begin
Result := '';
Desc := '';
Reg := RegKeyOpenRead(HKEY_CLASSES_ROOT,FExt);
if Reg = 0 then Exit;
OldId := RegKeyGetStr( Reg, '' );
Key:=LowerCase(FExt)+'file';
Delete(Key,1,1);
Key := RegKeyGetStr(Reg,'');
RegKeyClose(Reg);
Reg:=RegKeyOpenRead(HKEY_CLASSES_ROOT,Key);
Desc := RegKeyGetStr(Reg,'');
RegKeyClose(Reg);
Reg:=RegKeyOpenRead(HKEY_CLASSES_ROOT,Key+'\Shell\'+Cmd+'\Command');
Result := Trim( RegKeyGetStr(Reg,'') );
RegKeyClose(Reg);
if CopyTail( Result, 4 ) = '"%1"' then
Result := Trim( Copy( Result, 1, Length( Result )-4 ) );
Reg:=RegKeyOpenRead(HKEY_CLASSES_ROOT,Key+'\DefaultIcon');
S := RegKeyGetStr(Reg,'' );
OldIcoExe := Parse( S, ',' );
OldIcoIdx := Str2Int( S );
RegKeyClose(Reg);
end;
end.