Componentes.Terceros.jcl/official/2.1.1/install/JediProfiles.pas
2010-01-18 16:51:36 +00:00

297 lines
10 KiB
ObjectPascal

{**************************************************************************************************}
{ }
{ Project JEDI Code Library (JCL) extension }
{ }
{ The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); }
{ you may not use this file except in compliance with the License. You may obtain a copy of the }
{ License at http://www.mozilla.org/MPL/ }
{ }
{ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF }
{ ANY KIND, either express or implied. See the License for the specific language governing rights }
{ and limitations under the License. }
{ }
{ The Original Code is JediProfiles.pas. }
{ }
{ The Initial Developer of the Original Code is Florent Ouchet. Portions created by Florent Ouchet }
{ are Copyright (C) of Florent Ouchet. All Rights Reserved. }
{ }
{ Contributors: }
{ }
{**************************************************************************************************}
{ }
{ Core unit to manipulate multiple users' profiles at install time }
{ }
{**************************************************************************************************}
{ }
{ Last modified: $Date:: 2008-09-09 21:32:17 +0200 (mar., 09 sept. 2008) $ }
{ Revision: $Rev:: 2461 $ }
{ Author: $Author:: outchy $ }
{ }
{**************************************************************************************************}
unit JediProfiles;
{$I jcl.inc}
interface
uses
{$IFDEF MSWINDOWS}
Windows,
{$ENDIF MSWINDOWS}
SysUtils,
Classes,
JediInstall;
type
{$IFDEF MSWINDOWS}
TJediProfile = record
UserName: string;
SID: string;
LocalProfile: string;
UserKey: HKEY;
CloseKey: Boolean;
UnloadKey: Boolean;
end;
{$ENDIF MSWINDOWS}
TJediProfilesManager = class(TInterfacedObject, IJediProfilesManager)
private
FMultipleProfileMode: Boolean;
{$IFDEF MSWINDOWS}
FProfiles: array of TJediProfile;
procedure LoadProfiles;
{$ENDIF MSWINDOWS}
public
destructor Destroy; override;
{ IJediProfileManager }
function CheckPrerequisites: Boolean;
function GetMultipleProfileMode: Boolean;
function GetProfileKey(Index: Integer): LongWord; // HKEY is Windows specific
function GetProfileCount: Integer;
function GetProfileName(Index: Integer): string;
procedure SetMultipleProfileMode(Value: Boolean);
property MultipleProfileMode: Boolean read GetMultipleProfileMode write SetMultipleProfileMode;
end;
implementation
{$IFDEF MSWINDOWS}
uses
JclAnsiStrings,
JclFileUtils,
JclRegistry,
JclSecurity,
JclShell,
JclSysInfo,
JclWin32;
const
RegProfileListKey = 'SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList';
{$ENDIF MSWINDOWS}
//=== { TJediProfileManager } ================================================
destructor TJediProfilesManager.Destroy;
{$IFDEF MSWINDOWS}
var
Index: Integer;
{$ENDIF MSWINDOWS}
begin
{$IFDEF MSWINDOWS}
for Index := Low(FProfiles) to High(FProfiles) do
begin
if FProfiles[Index].CloseKey then
begin
Windows.RegFlushKey(FProfiles[Index].UserKey);
Windows.RegCloseKey(FProfiles[Index].UserKey);
end;
if FProfiles[Index].UnloadKey then
Windows.RegUnLoadKey(HKUS, PChar(FProfiles[Index].SID));
end;
SetLength(FProfiles, 0);
{$ENDIF MSWINDOWS}
inherited Destroy;
end;
function TJediProfilesManager.CheckPrerequisites: Boolean;
{$IFDEF MSWINDOWS}
var
InstallGUI: IJediInstallGUI;
Fork: Boolean;
Parameters: string;
Index: Integer;
{$ENDIF MSWINDOWS}
begin
{$IFDEF MSWINDOWS}
FMultipleProfileMode := FMultipleProfileMode and IsWinNT;
Result := not FMultipleProfileMode;
if not Result then
begin
Result := IsElevated;
if not Result then
begin
// attempt to fork as an administrator
InstallGUI := InstallCore.InstallGUI;
if Assigned(InstallGUI) then
Fork := InstallGUI.Dialog('Installation requires administrator privilege, do you want to run installer with' +
' administrator rights?', dtConfirmation, [drYes, drNo]) = drYes
else
Fork := True;
if Fork then
begin
Parameters := '';
for Index := 1 to ParamCount do
Parameters := Parameters + AnsiQuotedStr(ParamStr(Index), AnsiDoubleQuote);
ShellExecEx(ParamStr(0), Parameters, 'runas');
Result := False;
end
else
begin
// single profile installation for current user
FMultipleProfileMode := False;
Result := True;
end;
end;
end;
if FMultipleProfileMode and Result then
LoadProfiles;
{$ENDIF MSWINDOWS}
{$IFDEF UNIX}
// don't know how to enumerate profiles on Linux
Result := not FMultipleProfileMode;
FMultipleProfileMode := False;
{$ENDIF UNIX}
end;
function TJediProfilesManager.GetMultipleProfileMode: Boolean;
begin
Result := FMultipleProfileMode;
end;
function TJediProfilesManager.GetProfileCount: Integer;
begin
{$IFDEF MSWINDOWS}
if FMultipleProfileMode then
Result := Length(FProfiles)
else
{$ENDIF MSWINDOWS}
Result := 0;
end;
function TJediProfilesManager.GetProfileKey(Index: Integer): LongWord;
{$IFDEF MSWINDOWS}
var
NtUserFileName: string;
Key: HKEY;
{$ENDIF MSWINDOWS}
begin
{$IFDEF MSWINDOWS}
if FMultipleProfileMode then
begin
if FProfiles[Index].UserKey = 0 then
begin
if AnsiSameText(FProfiles[Index].UserName, GetLocalUserName) then
FProfiles[Index].UserKey := HKCU
else
begin
NtUserFileName := PathAddSeparator(FProfiles[Index].LocalProfile) + 'NTUSER.DAT';
if not RegKeyExists(HKUS, '\' + FProfiles[Index].SID) then
begin
EnableProcessPrivilege(True, SE_RESTORE_NAME);
EnableProcessPrivilege(True, SE_BACKUP_NAME);
if RegLoadKey(HKUS, PChar(FProfiles[Index].SID), PChar(NtUserFileName)) = ERROR_SUCCESS then
FProfiles[Index].UnloadKey := True
else
{$IFDEF COMPILER5}
RaiseLastWin32Error;
{$ELSE ~COMPILER5}
RaiseLastOSError;
{$ENDIF ~COMPILER5}
end;
if RegOpenKey(HKUS, PChar(FProfiles[Index].SID), Key) = ERROR_SUCCESS then
FProfiles[Index].CloseKey := True
else
raise EJclSecurityError.CreateFmt('Unable to load profile for user "%s"', [FProfiles[Index].UserName]);
FProfiles[Index].UserKey := Key;
end;
end;
Result := FProfiles[Index].UserKey;
end
else
Result := HKCU;
{$ENDIF MSWINDOWS}
{$IFDEF LINUX}
Result := 0;
{$ENDIF LINUX}
end;
function TJediProfilesManager.GetProfileName(Index: Integer): string;
begin
{$IFDEF MSWINDOWS}
if FMultipleProfileMode then
Result := FProfiles[Index].UserName
else
{$ENDIF MSWINDOWS}
Result := '';
end;
{$IFDEF MSWINDOWS}
procedure TJediProfilesManager.LoadProfiles;
var
Index: Integer;
SID: PSID;
DataSize: Cardinal;
Name, Domain: WideString;
KeyName, SIDStr, ProfileDir: string;
RegProfiles: TStrings;
begin
if FMultipleProfileMode then
begin
RegProfiles := TStringList.Create;
try
GetMem(SID, SECURITY_MAX_SID_SIZE);
try
if RegGetKeyNames(HKLM, RegProfileListKey, RegProfiles) then
for Index := 0 to RegProfiles.Count - 1 do
begin
KeyName := RegProfileListKey + '\' + RegProfiles.Strings[Index];
if RegReadBinaryEx(HKLM, KeyName, 'Sid', SID^, SECURITY_MAX_SID_SIZE, DataSize, False)
and RegReadStringEx(HKLM, KeyName, 'ProfileImagePath', ProfileDir, False) then
begin
try
SIDStr := SIDToString(SID);
LookupAccountBySid(SID, Name, Domain);
if SameText(Domain, GetLocalComputerName) then
begin
SetLength(FProfiles, Length(FProfiles) + 1);
FProfiles[High(FProfiles)].UserName := Name;
FProfiles[High(FProfiles)].SID := SIDStr;
FProfiles[High(FProfiles)].LocalProfile := ProfileDir;
FProfiles[High(FProfiles)].UserKey := 0;
FProfiles[High(FProfiles)].CloseKey := False;
FProfiles[High(FProfiles)].UnloadKey := False;
end;
except
// trap deleted accounts
end;
end;
end;
finally
FreeMem(SID);
end;
finally
RegProfiles.Free;
end;
end;
end;
{$ENDIF MSWINDOWS}
procedure TJediProfilesManager.SetMultipleProfileMode(Value: Boolean);
begin
FMultipleProfileMode := Value;
end;
end.