Mega Code Archive

 
Categories / Delphi / System
 

Moving from 9598ME to NT2000

Title: Moving from 95/98/ME to NT/2000 Question: Putting your registry entries under HKEY_CURRENT_USER might not be the thing to do under NT or 2000. Answer: We started developing an application using Delphi 1 in the months just prior to the release of Windows 95; at the time, NT seemed to be completely off our radar screen. We had used INI files for storing certain configuration parameters in Windows 3, and so when we moved to '95 and Delphi 2, we took advantage of the TRegIniFile object to move these parameters into the registry. There are are couple of "gotcha's" in using this object. For one thing, all of the various type-specific methods - WriteInteger, etc. - actually insert values into the registry as strings, which is consistent with the way they're written to an INI file. But if you use TRegIniFile.WriteInteger to write a number, and TRegistry.ReadInteger to read it, an exception will be raised. The solution to that problem is to use TRegistry.ReadString to read the value, and pass that to StrToInt(). The more serious problem we discovered was that the fact that the default RootKey for TRegIniFile is HKEY_CURRENT_USER means that on NT/2000 systems, only the user who was logged in at the time of installation of our software could use it; when another user logged in, HKEY_CURRENT_USER wouldn't contain the necessary entries. Of course, if you want your installation to be user-specific, that might be OK, but we didn't. So, we decided to use HKEY_LOCAL_MACHINE instead. The "SOFTWARE" key under HKEY_LOCAL_MACHINE apparently grants full control to all users, so permissions aren't a problem. For existing systems, we wanted to be able to move the existing branch of registry entries from HKEY_CURRENT_USER to HKEY_LOCAL_MACHINE. Unfortunately, the seemingly-obvious method, MoveKey, won't move entire branches under NT/2000 as it does under 95/98 (and I presume, ME). Being stupid as well as lazy, I was willing to put more time into figuring out how to move the entire branch in one fell swoop than it would have taken to move the individual keys. It turns out that the SaveKey and RestoreKey (NOT LoadKey) functions would do the trick, but using them under NT/2000 requires that the program secure the appropriate "Privileges" - something I'd not heard of before. Fortunately, there are examples in the MSDN library that are easily translated into Pascal. Here's the code I ultimately came up with (D5): procedure UpdateRegistryLocation; var reg: TRegistry; kee: HKEY; priv: string; filnam: string; res: integer; osv: TOSVersionInfo; tp: TTokenPrivileges; hToken: THandle; luid: TLargeInteger; len: cardinal; begin // find out if it's NT/2000 fillchar(osv,sizeof(osv),0); osv.dwOSVersionInfoSize := sizeof(TOSVersionInfo); GetVersionEx(osv); // if so, obtain the required priviledges if (osv.dwPlatformId = VER_PLATFORM_WIN32_NT) then begin priv := 'SeBackupPrivilege'; if OpenProcessToken(GetCurrentProcess,TOKEN_ADJUST_PRIVILEGES,hToken) then begin if LookupPrivilegeValue(NIL,pchar(priv1),luid) then begin tp.PrivilegeCount := 1; tp.Privileges[0].Luid := luid; tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED; AdjustTokenPrivileges(hToken, FALSE,tp,0,NIL,len); res := GetLastError(); if (res ERROR_SUCCESS) then begin ShowMessage('Ouch! Can''t get backup privilege!'); exit end end end; priv := 'SeRestorePrivilege'; if OpenProcessToken(GetCurrentProcess,TOKEN_ADJUST_PRIVILEGES,hToken) then begin if LookupPrivilegeValue(NIL,pchar(priv1),luid) then begin tp.PrivilegeCount := 1; tp.Privileges[0].Luid := luid; tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED; AdjustTokenPrivileges(hToken, FALSE,tp,0,NIL,len); res := GetLastError(); if (res ERROR_SUCCESS) then begin ShowMessage('Ouch! Can''t get restore privilege!'); exit end end end end; filnam := 'C:\MyTemp'; reg := TRegistry.Create; try reg.LazyWrite := false; reg.RootKey := HKEY_LOCAL_MACHINE; if (not reg.KeyExists('Software\OurCompany\OurProgram')) then begin if FileExists(filnam) then DeleteFile(filnam); reg.RootKey := HKEY_CURRENT_USER; if reg.OpenKey('Software\OurCompany\OurProgram',false) then begin kee := reg.CurrentKey; res := RegSaveKey(kee,pchar(filnam),NIL); if (res = ERROR_SUCCESS) then begin reg.CloseKey; reg.RootKey := HKEY_LOCAL_MACHINE; reg.OpenKey('SOFTWARE\OurCompany\OurProgram',true); kee := reg.CurrentKey; res := RegRestoreKey(kee,pchar(filnam),0); reg.CloseKey; if (res = ERROR_SUCCESS) then begin DeleteFile(filnam); DeleteFile(Concat(filnam,'.LOG')); end else begin ShowMessage('Bummer! No joy! Registry move failed!') end end end end finally reg.free end end; Note that the name of the temporary file has no extension, as it cannot under Windows 95 - nor can you use a long filename with 95. The SaveKey function also creates a log file, hence the additional file deletion on success. I'd like to know who at Microsoft came up with the constant name "ERROR_SUCCESS"...