home *** CD-ROM | disk | FTP | other *** search
/ Softwarová Záchrana 3 / Softwarova-zachrana-3.bin / StartRight / source.zip / UnitStartupMover.pas < prev    next >
Pascal/Delphi Source File  |  2004-10-03  |  19KB  |  689 lines

  1. unit UnitStartupMover;
  2. {
  3.     Purpose:
  4.         Move all unexluded items into StartRight
  5.         or
  6.         Restore all items back to the system
  7.  
  8.         This object is responsible for the Windows Run key
  9.  
  10.     Updates:
  11.  
  12.         Startup shortcut items sometimes not recognized as previously existing
  13.  
  14.     -----------------
  15.         New method to test for first time moving...
  16.  
  17.         Using the new ItemManager for all Exclude/Include/Disable
  18.         operations
  19.  
  20.     Notes:
  21.         Moving runkeys installs StartRight in the system's Run key
  22.         Restoring runkeys removes StartRight from the system's Run key
  23.  
  24. }
  25.  
  26. interface
  27.  
  28. uses Windows, UnitMyRegistry, SysUtils, StrUtils, TLHelp32,
  29.     INIFiles, Contnrs, ShlObj, ShellAPI,
  30.     Forms {for Application object},
  31.     Classes {For TString objects},
  32.     dialogs, {showmessage debuggin}
  33.     UnitMyKeys;
  34.  
  35.  
  36.  
  37. //
  38. //
  39. //
  40.  
  41. type TRunkeyItem = Class(TObject)
  42.     RunKey : string;
  43.     RunValue : string;
  44.     RunEXE : string;
  45.     RunUser :  string;
  46.     RunHKEY : HKEY;
  47.     RunProcID : cardinal;
  48.     public
  49.         function ToString() : string;
  50. end;
  51.  
  52. type TStartupFolderItem = Class(Tobject)
  53.     FullName : String;
  54.     Location : string;
  55. end;
  56.  
  57.  
  58. type TStartupMover = class(TObject)
  59.     private
  60.         h : THandle;
  61.         r : TMyRegistry;
  62.         RunkeyList : TObjectList;
  63.         StartupFolderList : TObjectList;
  64.  
  65.         procedure GetRunkeyData;
  66.         procedure GenerateStartupFolderList;
  67.  
  68.     public
  69.         constructor Create(handle : THandle);
  70.         destructor Destroy(); override;
  71.  
  72.         procedure SetupSelfToRun(IncludeRunOnce : boolean = true);
  73.         procedure SetupSelfToRunOnce;
  74.         procedure RemoveSelfFromRun(IncludeRunOnce : boolean = true);
  75.         function UserHasPermission(var failedkey : string) : boolean;
  76.  
  77.         function GetRunkeyItemsCount : cardinal;
  78.         function GetRunkeyItem(index : cardinal) : TRunkeyItem;
  79.         function GetStartupFolderItemsCount : cardinal;
  80.         function GetStartupFolderItem(index : cardinal) : TStartupFolderItem;
  81.  
  82.         procedure MoveRunKeyItems(AutoDisable : boolean = false);
  83.         procedure MoveStartupFolderItems(AutoDisable : boolean = false);
  84.  
  85.  
  86.         procedure RestoreRunKeyItems;
  87.         procedure RestoreStartupFolderItems;
  88.         procedure DestroyHomekey;
  89.         function GetIsSetupToRun : boolean;
  90.  
  91.         function GetHasNewItemsAndClear : boolean;
  92.         function IsFirstMove : boolean;
  93. end;
  94.  
  95.  
  96. {////////////////////}
  97. {//}implementation{//}
  98. {////////////////////}
  99. uses UnitSpecialPaths, UnitItemManager, UnitFrmOptions, UnitUtils;
  100.  
  101. function TRunkeyItem.ToString() : string;
  102. begin
  103.     result := self.RunKey + '|' + self.RunValue + '|' + self.RunEXE + '|' + IntToStr(self.RunProcID);
  104. end;
  105.  
  106.  
  107.  
  108. ////////////////////////////////
  109. // Public Interface
  110. ////////////////////////////////
  111.  
  112. function TStartupMover.GetHasNewItemsAndClear : boolean;
  113. var s : string;
  114. begin
  115.     result := r.ValueExistsString(SR_HOME_KEY, SR_NEWRUNITEMS_VALUE, s);
  116.     result := result or r.ValueExistsString(SR_HOME_KEY, SR_NEWRUNITEMS_VALUE, s);
  117.  
  118.     r.DeleteDataString(SR_HOME_KEY, SR_NEWSTARTUPITEMS_VALUE);
  119.     r.DeleteDataString(SR_HOME_KEY, SR_NEWRUNITEMS_VALUE);
  120. end;
  121.  
  122. constructor TStartupMover.Create(handle : THandle);
  123. begin
  124.     h := handle;
  125.     r := TMyRegistry.Create();
  126.  
  127.  
  128.     RunkeyList := TObjectList.Create();
  129.     StartupFolderList := TObjectList.Create();
  130.  
  131.     //
  132.     // Purpose: Gather everything needed to create the RunkeyList
  133.     //          and the StartupFolderList
  134.     //
  135.  
  136.     self.GetRunkeyData;
  137.     self.GenerateStartupFolderList;
  138. end;
  139.  
  140. destructor TStartupMover.Destroy();
  141. begin
  142.     r.Free;
  143.  
  144.     //tsKeys.Free;
  145.     //tsVals.Free;
  146.     //tsEXEs.Free;
  147.  
  148.     //tsProc.Free;
  149.     //tsProcID.Free;
  150.  
  151.     RunkeyList.Clear;
  152.     RunkeyList.Free;
  153.  
  154.     StartupFolderList.Clear;
  155.     StartupFolderList.Free;
  156.  
  157.     inherited destroy;
  158. end;
  159.  
  160.  
  161. //--------------------------------------------------------------
  162. // Enumerate items in the RunkeyList/StartupFolderList
  163. //--------------------------------------------------------------
  164. function TStartupMover.GetRunkeyItemsCount : cardinal;
  165. begin
  166.     result := RunkeyList.Count;
  167. end;
  168. function TStartupMover.GetRunkeyItem(index : cardinal) : TRunkeyItem;
  169. begin
  170.     result := TRunkeyItem( RunkeyList.items[index] );
  171. end;
  172.  
  173. function TStartupMover.GetStartupFolderItemsCount : cardinal;
  174. begin
  175.     result := StartupFolderList.Count;
  176. end;
  177. function TStartupMover.GetStartupFolderItem(index : cardinal) : TStartupFolderItem;
  178. begin
  179.     result := TStartupFolderItem( StartupFolderList.items[index] );
  180. end;
  181.  
  182.  
  183.  
  184. function TStartupMover.UserHasPermission(var failedkey : string) : boolean;
  185.     function TestForValueCreation(key : string) : boolean;
  186.     const TEST_VALUE = 'StartRightTest';
  187.     begin
  188.         try
  189.             r.SetDataString(Key, TEST_VALUE, TEST_VALUE);
  190.             r.DeleteDataString(Key, TEST_VALUE);
  191.             result := true;
  192.         except
  193.         on E: Exception do
  194.             begin
  195.                 result := false;
  196.             end;
  197.         end;
  198.     end;
  199. begin
  200.     failedkey := SR_HOME_KEY;
  201.     result := TestForValueCreation(failedkey);
  202.     failedkey := 'HKEY_LOCAL_MACHINE' + failedkey;
  203.     if (result) then begin
  204.         failedkey := WINDOWS_RUN_KEY;
  205.         result := result and TestForValueCreation(failedkey);
  206.         failedkey := 'HKEY_LOCAL_MACHINE' + failedkey;
  207.     end;
  208.  
  209.     if (result) then begin
  210.         failedkey := WINDOWS_RUNONCE_KEY;
  211.         result := result and TestForValueCreation(failedkey);
  212.         failedkey := 'HKEY_LOCAL_MACHINE' + failedkey;
  213.     end;
  214. end;
  215.  
  216.  
  217. //--------------------------------------------------------------
  218. // Move(RunKey/StartupFolder)Items
  219. //
  220. // RunKey
  221. // - Move un-exluded keys to StartRight's runkey
  222. // - create a sort index for new items
  223. // - update locale RunKey info (since this changes it)
  224. //--------------------------------------------------------------
  225. procedure TStartupMover.MoveRunKeyItems(AutoDisable : boolean = false);
  226.     procedure DeleteOtherRunData(HKEYVal : HKEY);
  227.     var i : integer;
  228.         status : SR_STATUS;
  229.         rki : TRunkeyItem;
  230.     begin
  231.         for i := 0 to (RunkeyList.count - 1) do begin
  232.             rki := TRunkeyItem(RunkeyList.Items[i]);
  233.  
  234.             status := UnitMyKeys.GetRunkeyStatus(rki.RunKey);
  235.  
  236.             case status of
  237.             SR_STATUS_NORMAL, SR_STATUS_INCLUDED:
  238.                 begin
  239.                     r.DeleteDataString(HKEYVal, WINDOWS_RUN_KEY, rki.RunKey);
  240.                 end;
  241.             SR_STATUS_DISABLED :
  242.                 begin
  243.                     ItemManager.DisableRunkeyItem(rki.RunKey);
  244.                 end;
  245.             SR_STATUS_EXCLUDED :
  246.                 begin
  247.                     ItemManager.ExcludeRunkeyItem(rki.RunKey);
  248.                 end;
  249.             end;
  250.  
  251.         end;
  252.     end;
  253.  
  254. var i : integer;
  255.     sti : TRunkeyItem;
  256.     newdata : THashedStringList;
  257.     newvalues : THashedStringList;
  258.     status : SR_STATUS;
  259. begin
  260.     //UnitMyKeys.SetCurrentUsername(UnitUtils.GetUsername);
  261.  
  262.     newdata := THashedStringList.Create();
  263.     newvalues := THashedStringList.Create();
  264.     //
  265.     // Enumerate all existing windows run keys determin which keys
  266.     // are new values.
  267.     //
  268.     for i := 0 to (RunkeyList.Count - 1) do begin
  269.         sti := TRunkeyItem( RunkeyList.Items[i] );
  270.  
  271.         status := UnitMyKeys.GetRunkeyStatus(sti.runkey);
  272.  
  273.         case status of
  274.         SR_STATUS_NORMAL :
  275.             begin
  276.                 //
  277.                 // Try both current user and local machine
  278.                 // Include fails if item is not found
  279.                 //
  280.                 ItemManager.IncludeRunkeyItem(sti.Runkey, false);
  281.                 ItemManager.IncludeRunkeyItem(sti.Runkey, true);
  282.                 if (frmoptions.cbAutoDisable.checked) then begin
  283.                     ItemManager.DisableRunkeyItem(sti.runkey);
  284.                 end;
  285.                 newvalues.Add(sti.RunKey);
  286.                 newdata.Add(sti.RunValue);
  287.  
  288.                 UnitMyKeys.SetRunLocation(sti.RunKey, sti.RunUser);
  289.                 UnitMyKeys.SetRunLocationRootkey(sti.RunKey, sti.RunHKEY);
  290.             end;
  291.         end;
  292.  
  293.     end;
  294.  
  295.     //
  296.     // Record new items - flag when new items exist
  297.     //
  298.     r.EraseKey(SR_HOME_KEY, SR_SUB_RUNNEWITEMS);
  299.  
  300.     for i := 0 to (newvalues.Count - 1) do begin
  301.         r.SetDataString(SR_RUNNEWITEMS_KEY, newvalues.Strings[i], newdata.strings[i]);
  302.     end;
  303.     if (newvalues.Count > 0) then begin
  304.         r.SetDataString(SR_HOME_KEY, SR_NEWRUNITEMS_VALUE, SR_NEWRUNITEMS_VALUE);
  305.     end;
  306.  
  307.  
  308.     //
  309.     // delete the other run data
  310.     //
  311.     DeleteOtherRunData(HKEY_LOCAL_MACHINE);
  312.     DeleteOtherRunData(HKEY_CURRENT_USER);
  313.  
  314.  
  315.     self.GetRunkeyData;
  316.  
  317.  
  318.     newdata.Free;
  319.     newvalues.free;
  320. end;
  321.  
  322. procedure TStartupMover.MoveStartupFolderItems(AutoDisable : boolean = false);
  323. var si : TStartupFolderItem;
  324.     i : integer;
  325.     dest, s, newfilename : string;
  326.  
  327.     newvalues : THashedStringList;
  328.     status : SR_STATUS;
  329. begin
  330.     //
  331.     // build my startup path
  332.     //
  333.     newvalues := THashedStringList.Create();
  334.     dest := SpecialPaths.GetStartRightStartup ;
  335.     if not DirectoryExists(dest) then begin
  336.         MkDir(dest);
  337.     end;
  338.  
  339.  
  340.     //
  341.     // move everything excepts what's excluded
  342.     // don't add an entry to the startupsort key
  343.     // record new items
  344.     for i := 0 to StartupFolderList.Count - 1 do begin
  345.         si := TStartupFolderItem( StartupFolderList.items[i] );
  346.         s := ExtractFilename(si.FullName);
  347.         UnitMyKeys.SetStartupLocation(
  348.             dest +  ExtractFilename(si.FullName),
  349.             si.Location
  350.         );
  351.  
  352.         status := UnitMyKeys.GetStartupStatus(s);
  353.         case status of
  354.         SR_STATUS_NORMAL :
  355.             begin
  356.                 newfilename := ItemManager.IncludeStartupItem(si.FullName);
  357.                 if (FrmOptions.cbAutoDisable.Checked) then begin
  358.                     ItemManager.DisableStartupItem(newfilename);
  359.                 end;
  360.                 newvalues.Add(newfilename);
  361.             end;
  362.         SR_STATUS_INCLUDED :
  363.             begin
  364.                 // handle programs that keep adding themselves back
  365.                 // otherwise, replace missing items
  366.                 if fileexists(dest + s) then begin
  367.                     DeleteFile(si.FullName);
  368.                 end else begin
  369.                     ItemManager.IncludeStartupItem(si.FullName);
  370.                 end;
  371.  
  372.             end;
  373.         SR_STATUS_DISABLED :
  374.             begin
  375.                 s := ItemManager.IncludeStartupItem(si.fullname);
  376.                 ItemManager.DisableStartupItem(s);
  377.             end;
  378.         SR_STATUS_EXCLUDED :
  379.             begin
  380.                 ItemManager.EnableStartupItem(si.FullName);
  381.             end;
  382.         end;
  383.     end;
  384.     // record the new items
  385.     r.EraseKey(SR_HOME_KEY, SR_SUB_STARTUPNEW);
  386.  
  387.     for i := 0 to newvalues.Count - 1 do begin
  388.         s := SpecialPaths.GetStartRightStartup;
  389.         r.SetDataString(
  390.             SR_STARTUPNEW_KEY,
  391.             ExtractFilename(newvalues[i]),
  392.             s + ExtractFilename(newvalues[i])
  393.         );
  394.     end;
  395.  
  396.     if (newvalues.Count > 0) then begin
  397.         r.SetDataString(SR_HOME_KEY, SR_NEWSTARTUPITEMS_VALUE, SR_NEWSTARTUPITEMS_VALUE );
  398.     end;
  399.  
  400.  
  401.     //self.GetStartupFolderData;
  402.     self.GenerateStartupFolderList;
  403. end;
  404.  
  405.  
  406. procedure TStartupMover.RestoreRunKeyItems;
  407. var sl, sl2 : TStringList;
  408.     i : integer;
  409.     s : string;
  410. begin
  411.     //
  412.     // read the shadow copy
  413.     //
  414.     sl2 := TStringList.Create();
  415.     sl := TStringList.Create();
  416.  
  417.     r.GetValues(SR_RUN_KEY, sl );
  418.     for i := 0 to (sl.Count - 1) do begin
  419.         try
  420.            s := r.GetDataString(SR_RUN_KEY, sl[i]);
  421.            sl2.add(s);
  422.         finally
  423.         end;
  424.     end;
  425.  
  426.     //
  427.     // write it back to the system's RUN key
  428.     // Remove StartRight from the system'm run key
  429.     //
  430.     for i := 0 to (sl2.count - 1) do begin
  431.         r.SetDataString(WINDOWS_RUN_KEY, sl[i], sl2[i]);
  432.     end;
  433.     self.RemoveSelfFromRun;
  434.  
  435.     //
  436.     // Remove the shadowed data
  437.     // remove sort info
  438.     //
  439.     r.EraseKey(SR_HOME_KEY, SR_SUB_RUN);
  440.     r.EraseKey(SR_HOME_KEY, SR_SUB_RUNSORT);
  441.  
  442.     sl.free;
  443.     sl2.free;
  444.  
  445.     self.GetRunkeyData;
  446. end;
  447.  
  448. procedure TStartupMover.RestoreStartupFolderItems;
  449.     procedure MoveFile(FullName, ToPath : string);
  450.     var exeName : string;
  451.         dest : string;
  452.     begin
  453.         exeName := ExtractFileName(FullName);
  454.  
  455.         dest := IncludeTrailingPathDelimiter(ToPath) + exeName;
  456.         if FileExists( dest ) then begin
  457.            DeleteFile( dest );
  458.         end;
  459.  
  460.         if CopyFile(PChar(FullName), PChar(Dest), true) then begin
  461.             DeleteFile(FullName);
  462.         end;
  463.     end;
  464. var src, location, startup : string;
  465.     rec : TSearchRec;
  466.     rz : integer;
  467. begin
  468.     //
  469.     // get destination Startup folder
  470.     //
  471.     Startup := SpecialPaths.GetCommonStartupPath;
  472.     src := SpecialPaths.GetStartRightStartup;
  473.  
  474.     rz := FindFirst(src + '*.*', faHidden, rec);
  475.     while (rz = 0) do begin
  476.         location := UnitMykeys.GetStartupLocation(
  477.             IncludeTrailingPathDelimiter( src) + rec.name
  478.         );
  479.  
  480.         try
  481.             if (location = '') then begin
  482.                 MoveFile(src + rec.name, Startup);
  483.             end else begin
  484.                 movefile(src + rec.name, location);
  485.             end;
  486.         except
  487.             begin
  488.                 MoveFile(src + rec.name, Startup);
  489.             end;
  490.         end;
  491.         rz := FindNext(rec);
  492.     end;
  493.  
  494.     //
  495.     // delete the startup sort key
  496.     //
  497.     r.EraseKey(SR_HOME_KEY, SR_SUB_STARTUPSORT);
  498.  
  499.     //self.GetStartupFolderData;
  500.     self.GenerateStartupFolderList;
  501. end;
  502.  
  503.  
  504.  
  505.  
  506.  
  507.  
  508.  
  509. /////////////////////////////////////////////////////////////////////////////
  510. // Private Implemenation
  511. /////////////////////////////////////////////////////////////////////////////
  512.  
  513.  
  514.  
  515. procedure TStartupMover.SetupSelfToRun(IncludeRunOnce : boolean = true);
  516. begin
  517.     r.SetDataString(
  518.         WINDOWS_RUN_KEY,
  519.         SR_STARTRIGHT_VALUE,
  520.         '"' +Application.ExeName + '" -go '
  521.     );
  522.  
  523.     if (IncludeRunOnce) then begin
  524.         self.SetupSelfToRunOnce;
  525.     end;
  526. end;
  527.  
  528.  
  529. procedure TStartupMover.RemoveSelfFromRun(IncludeRunOnce : boolean = true);
  530. begin
  531.     r.DeleteDataString(WINDOWS_RUN_KEY, SR_STARTRIGHT_VALUE);
  532.  
  533.     if (IncludeRunOnce) then begin
  534.         r.DeleteDataString(WINDOWS_RUNONCE_KEY, SR_STARTRIGHT_VALUE);
  535.     end;
  536. end;
  537.  
  538.  
  539. //---------------------------------------------------------
  540. // Gather all the data from the Run key in the registry
  541. // (that's a String)
  542. //---------------------------------------------------------
  543. procedure TStartupMover.GetRunkeyData;
  544.     function GetEXEFromRunValue(value : string) : string;
  545.     var i : integer;
  546.     begin
  547.         value := lowercase(value);
  548.         i := pos('.exe', value);
  549.         result := '';
  550.  
  551.         if (i > 0) then begin
  552.             result := LeftStr(value, i + 3);
  553.  
  554.             if leftstr(result,1) ='"' then
  555.                 result := RightStr(result, length(result) - 1);
  556.  
  557.             result := UPPERCASE(ExtractFileName(result));
  558.         end;
  559.     end;
  560.  
  561.     procedure ExtractRunkeyData(HKEYVal : HKEY);
  562.     var i : integer;
  563.         s : string;
  564.         sl : TStringList;
  565.         rki : TRunKeyItem;
  566.         user : string;
  567.     begin
  568.         if HKEYVal = HKEY_CURRENT_USER then begin
  569.             user := UnitUtils.GetUsername;
  570.         end else begin
  571.             user := '';
  572.         end;
  573.         sl := TStringList.Create();
  574.         r.GetValues(HKEYVal, WINDOWS_RUN_KEY, sl);
  575.  
  576.         // skip any values that may be blanks
  577.         for i := 0 to (sl.Count - 1) do begin
  578.             if (trim(sl.Strings[i]) = '') then continue;
  579.  
  580.             try
  581.                 rki := TRunkeyItem.Create;
  582.  
  583.                 s := r.GetDataString(HKEYVal, WINDOWS_RUN_KEY, sl.Strings[i]);
  584.                 if (s <> '') then begin
  585.                     rki.RunKey := sl.strings[i];
  586.                     rki.RunValue := s;
  587.                     rki.RunEXE := GetEXEFromRunValue(s);
  588.                     rki.RunUser := '';
  589.                     rki.RunHKEY := HKEYVal;
  590.                     if (user <> UnitUtils.UNKNOWN_USER) then begin
  591.                         rki.RunUser := user;
  592.                     end;
  593.  
  594.                     RunkeyList.Add(rki);
  595.                 end;
  596.             finally
  597.             end;
  598.         end;
  599.         sl.free;
  600.     end;
  601. begin
  602.     RunkeyList.Clear;
  603.     ExtractRunkeyData(HKEY_CURRENT_USER);
  604.     ExtractRunkeyData(HKEY_LOCAL_MACHINE);
  605.  
  606.     // debug data
  607.     //tsKeys.SaveToFile(f + 'keys.txt');
  608.     //tsVals.SaveToFile(f + 'vals.txt');
  609.     //tsEXEs.SaveToFile(f + 'exes.txt');
  610. end;
  611.  
  612.  
  613.  
  614.  
  615.  
  616.  
  617.  
  618. //-----------------------------------------------------------------
  619. // Build(xxx)Info - compile all the gathered info into 2 lists
  620. //-----------------------------------------------------------------
  621.  
  622.  
  623. procedure TStartupMover.GenerateStartupFolderList;
  624.     procedure ScanForFiles(path : string);
  625.     var rec : TSearchRec;
  626.         r : integer;
  627.         si : TStartupFolderItem;
  628.     begin
  629.         if (trim(path) <> '') then begin
  630.             path := IncludeTrailingPathDelimiter(path);
  631.  
  632.             r := findfirst(path + '*.*', faHidden  , rec);
  633.             while r = 0 do begin
  634.                 si := TStartupFolderItem.Create();
  635.  
  636.                 si.FullName :=  path + rec.Name;
  637.                 si.Location := path;
  638.                 
  639.                 StartupFolderList.Add(si);
  640.  
  641.                 r := findnext(rec);
  642.             end;
  643.         end;
  644.     end;
  645. var Startup, CommonStartup, AltStartup : string;
  646. begin
  647.     Startup := SpecialPaths.GetStartupPath;
  648.     CommonStartup := SpecialPaths.GetCommonStartupPath;
  649.     AltStartup := SpecialPaths.GetAltStartupPath;
  650.  
  651.  
  652.     StartupFolderList.clear;
  653.     ScanForFiles(Startup);
  654.     ScanForFiles(CommonStartup);
  655.     ScanForFiles(AltStartup);
  656. end;
  657.  
  658.  
  659.  
  660. function TStartupMover.IsFirstMove: boolean;
  661. begin
  662.     result := not DirectoryExists(SpecialPaths.GetStartRightStartup);
  663. end;
  664.  
  665.  
  666.  
  667.  
  668.  
  669.  
  670. function TStartupMover.GetIsSetupToRun: boolean;
  671. var data : string;
  672. begin
  673.     result := r.ValueExistsString(WINDOWS_RUNONCE_KEY, SR_STARTRIGHT_VALUE, data);
  674. end;
  675.  
  676. procedure TStartupMover.SetupSelfToRunOnce;
  677. begin
  678.     r.SetDataString(WINDOWS_RUNONCE_KEY,
  679.             SR_STARTRIGHT_VALUE, '"' +Application.ExeName + '" -pre ' );
  680.  
  681. end;
  682.  
  683. procedure TStartupMover.DestroyHomekey;
  684. begin
  685.     r.EraseKey('\SOFTWARE\JackassArswareOrg', 'StartRight');
  686. end;
  687.  
  688. end.
  689.