Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Windows Post Install and 64 bit Registry tweaks

0.00/5 (No votes)
3 Jul 2012 1  
WPI and 64 bit Registry integration.

Introduction

When Microsoft started out to build an x64 version of their OS that could also run 32 bit applications they needed to find a way to unify the Registry so it could serve either one on a transparent basis. Since this was never foreseen, a typical Microsoft afterthought kludge was cobbled together to make it work. And it does, quite well given the rather messy nature of the thing. However importing Registry tweaks across 32 and 64 bit versions is problematic.

Background

A friend of mine discovered to his dismay that adding registry tweaks using WPI calling Regedit.exe didn't work as expected when applied in a 64 bit environment, whilst they worked fine in 32 bit. Not being versed he asked me to look at it. What was happening was that WPI is a 32bit application so the registry entries under a 64 bit environment didn't get written to the registry rootkey HKEY_LOCAL_MACHINE, whilst all other keys did. Which stood to reason since the WPI called the 32 bit cmd.exe to execute Regedit.exe only the general keys are written.

Using the code

Since he wanted to continue using the 32 bit WPI I came up with the following solution. The basic principle is to write a Regedit 'Light' compiled to 64 bit that does the registry writing. The code is in Delphi since i only have a Delphi 64bit CrossCompiler. As i am myself a C programmer who never ever even looked at Delphi i wrote this using a site with Delphi for Beginners so as Delphi code goes it might not be the very best. But it does the trick. A snippet:

if Pos('[',Temp)>0 then
    begin
      Rootkeyflag:=true;
      Delim:=Pos(']',Temp);
      Slash:=Pos('\',Temp);
      Rootkey:=MidStr(Temp,2,slash-2);
      if Rootkey='HKEY_LOCAL_MACHINE' then OurReg.RootKey:=HKEY_LOCAL_MACHINE;
      if Rootkey='HKEY_CURRENT_USER' then OurReg.RootKey:=HKEY_CURRENT_USER;
      if Rootkey='HKEY_CLASSES_ROOT' then OurReg.RootKey:=HKEY_CLASSES_ROOT;
      if Rootkey='HKEY_CURRENT_CONFIG' then OurReg.RootKey:=HKEY_CURRENT_CONFIG;
      if Rootkey='HKEY_USERS' then OurReg.RootKey:=HKEY_USERS;
      Subkey:=MidStr(Temp,slash+1,Length(Temp));
      Subkey:=LeftStr(Subkey,Length(Subkey)-1);
      if Pos('-',Rootkey)>0 then
       begin
        Rootkey:=RightStr(Rootkey,Length(Rootkey)-1);
        Deleteflag:=true;
       end
      else
        begin
         Deleteflag:=false;
        end;
       end;

    if (Rootkeyflag) and (not Addvalueflag) then
// {by now we have read all lines of complete instruction and can see what to do}   
      begin
       if Deleteflag then
        begin
         if Length(Value)>0 then
           begin
            openResult := OurReg.OpenKey(Subkey,True);
            if DeleteKeyflag then 
             begin
               OurReg.GetDataAsString(Temp);
               Equalsign:=Pos('=',Temp);
               Value:=RightStr(Temp,Length(Temp)-Equalsign);
             end;
              if openResult then OurReg.DeleteValue(Value);
              Key:='';
              ActionTaken:=true;
           end;
          end;
 //        { we can't put an ELSE directive here since we want to end in the reset variables code} 
         if (not Deleteflag) or (Key='') then
          begin
           if Length(Key)>0 then
            begin
             openResult := OurReg.OpenKey(Subkey,True);
             if openResult then
              begin
               ActionTaken:=true;
               if Key='@' then Key:='';
               case Keytype of
 //              { for some odd reason sometimes the StrToInt and StrToFloat conversion routines 
 //                fail (only sometimes) in the debugger if the string contains 000000. Go figure}
               1: try
                    OurReg.WriteInteger(Key,StrToInt(Value));
                  except on E: Exception do
                    OurReg.WriteInteger(Key,0);
                  end;
               2: OurReg.WriteExpandString(Key,Value);
               4: OurReg.WriteBinaryData(Key,Value,Length(Value));
               5: try
                    OurReg.WriteFloat(Key,StrToFloat(Value));
                  except on E: Exception do
                    OurReg.WriteFloat(Key,0);
                  end;
               6: OurReg.WriteString(Key,Value);
              end;
              Rootkeyflag:=false;
             end;
            end;

However using unmodified WPI to make it run, by just adding the resulting 64bit exe to the script doesn't work because the WPI script will load the 32bit command shell which will choke on the 64bit code. Some out of the box thinking by my friend made him create an selfexecutable Winrar file with the files in it needed to enter the registry keys and call that in the WPI script which worked like a charm since Winrar executes it correctly. I assume it'll work with Winzip as well but never tried. This way one can write all keys regardless of which OS version it is using unmodified WPI.

Points of Interest 

The nature of Microsoft's kludges are often cause for bewilderment, certainly for those of us who had to suffer through the older api's to get an application to work. They are poorly documented and usually all over the place. To get this to work really took me to the depths of Microsoft MSDN hell in order to make sense of the whole thing. Why the registry is kludged as it is is beyond me. Many more elegant solutions are imaginable but i guess it was a case of quick fix that worked most of time so the ostrich algorithm was applied writing it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here