Subversion Repositories userdetect2

Rev

Rev 84 | Rev 86 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. unit UD2_Main;
  2.  
  3. interface
  4.  
  5. {$IF CompilerVersion >= 25.0}
  6. {$LEGACYIFEND ON}
  7. {$IFEND}
  8.  
  9. {$INCLUDE 'UserDetect2.inc'}
  10.  
  11. uses
  12.   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  13.   Dialogs, StdCtrls, Grids, ValEdit, UD2_Obj, ComCtrls, ImgList, ExtCtrls,
  14.   CommCtrl, Menus, VTSListView, VTSCompat;
  15.  
  16. const
  17.   DefaultIniFile = 'UserDetect2.ini';
  18.   DefaultWarnIfNothingMatches = 'false';
  19.   TagWarnIfNothingMatches = 'WarnIfNothingMatches';
  20.   DefaultCloseAfterLaunching = 'false';
  21.   TagCloseAfterLaunching = 'CloseAfterLaunching';
  22.   TagIcon = 'Icon';
  23.  
  24. type
  25.   TUD2MainForm = class(TForm)
  26.     OpenDialog1: TOpenDialog;
  27.     PageControl1: TPageControl;
  28.     TasksTabSheet: TTabSheet;
  29.     TabSheet2: TTabSheet;
  30.     TabSheet3: TTabSheet;
  31.     IniTemplateMemo: TMemo;
  32.     TabSheet4: TTabSheet;
  33.     TasksListView: TVTSListView;
  34.     TasksImageList: TImageList;
  35.     SaveDialog1: TSaveDialog;
  36.     TabSheet5: TTabSheet;
  37.     Image1: TImage;
  38.     Label1: TLabel;
  39.     Label2: TLabel;
  40.     Label3: TLabel;
  41.     Label4: TLabel;
  42.     Label5: TLabel;
  43.     Label6: TLabel;
  44.     Label7: TLabel;
  45.     Label8: TLabel;
  46.     LoadedPluginsListView: TVTSListView;
  47.     IdentificationsListView: TVTSListView;
  48.     ErrorsTabSheet: TTabSheet;
  49.     ErrorsMemo: TMemo;
  50.     Memo1: TMemo;
  51.     Panel1: TPanel;
  52.     Button1: TButton;
  53.     Button2: TButton;
  54.     TasksPopupMenu: TPopupMenu;
  55.     Run1: TMenuItem;
  56.     Properties1: TMenuItem;
  57.     IdentificationsPopupMenu: TPopupMenu;
  58.     CopyTaskDefinitionExample1: TMenuItem;
  59.     Button3: TButton;
  60.     VersionLabel: TLabel;
  61.     LoadedPluginsPopupMenu: TPopupMenu;
  62.     MenuItem1: TMenuItem;
  63.     Panel2: TPanel;
  64.     Image2: TImage;
  65.     Button5: TButton;
  66.     procedure FormDestroy(Sender: TObject);
  67.     procedure TasksListViewDblClick(Sender: TObject);
  68.     procedure TasksListViewKeyPress(Sender: TObject; var Key: Char);
  69.     procedure Button1Click(Sender: TObject);
  70.     procedure Button2Click(Sender: TObject);
  71.     procedure URLLabelClick(Sender: TObject);
  72.     procedure TasksPopupMenuPopup(Sender: TObject);
  73.     procedure Run1Click(Sender: TObject);
  74.     procedure Properties1Click(Sender: TObject);
  75.     procedure IdentificationsPopupMenuPopup(Sender: TObject);
  76.     procedure CopyTaskDefinitionExample1Click(Sender: TObject);
  77.     procedure ListViewCompare(Sender: TObject; Item1, Item2: TListItem; Data: Integer; var Compare: Integer);
  78.     procedure Button3Click(Sender: TObject);
  79.     procedure LoadedPluginsPopupMenuPopup(Sender: TObject);
  80.     procedure MenuItem1Click(Sender: TObject);
  81.     procedure FormCreate(Sender: TObject);
  82.     procedure Button5Click(Sender: TObject);
  83.   protected
  84.     ud2: TUD2;
  85.     procedure LoadTaskList;
  86.     procedure LoadDetectedIDs;
  87.     procedure LoadINITemplate;
  88.     procedure LoadLoadedPluginList;
  89.     function GetIniFileName: string;
  90.     procedure DoRun(ShortTaskName: string);
  91.     procedure CheckForErrors;
  92.   public
  93.     procedure Run;
  94.   end;
  95.  
  96. var
  97.   UD2MainForm: TUD2MainForm;
  98.  
  99. implementation
  100.  
  101. {$R *.dfm}
  102.  
  103. uses
  104.   ShellAPI, Clipbrd, Math, AlphaNumSort, UD2_Utils, UD2_TaskProperties, UD2_Parsing;
  105.  
  106. type
  107.   TUD2ListViewEntry = class(TObject)
  108.     ShortTaskName: string;
  109.     CloseAfterLaunching: boolean;
  110.     TaskPropertiesForm: TForm;
  111.   end;
  112.  
  113. function AddIconRecToImageList(rec: TIconFileIdx; ImageList: TImageList): integer;
  114. var
  115.   icon: TIcon;
  116. begin
  117.   icon := TIcon.Create;
  118.   try
  119.     icon.Handle := ExtractIcon(Application.Handle, PChar(rec.FileName), rec.IconIndex);
  120.  
  121.     // result := ImageList.AddIcon(ico);
  122.     result := AddTransparentIconToImageList(ImageList, icon);
  123.   finally
  124.     icon.Free;
  125.   end;
  126. end;
  127.  
  128. { TUD2MainForm }
  129.  
  130. function TUD2MainForm.GetIniFileName: string;
  131. resourcestring
  132.   LNG_FILE_NOT_FOUND = 'File "%s" not found.';
  133. begin
  134.   if (ParamCount >= 1) and not CheckBoolParam(1, 'C') then
  135.   begin
  136.     if FileExists(ParamStr(1)) then
  137.     begin
  138.       result := ParamStr(1);
  139.     end
  140.     else
  141.     begin
  142.       ExitCode := EXITCODE_INI_NOT_FOUND;
  143.       MessageDlg(Format(LNG_FILE_NOT_FOUND, [ParamStr(1)]), mtError, [mbOK], 0);
  144.       result := '';
  145.     end;
  146.     Exit;
  147.   end
  148.   else
  149.   begin
  150.     if FileExists(DefaultIniFile) then
  151.     begin
  152.       result := DefaultIniFile;
  153.       Exit;
  154.     end;
  155.  
  156.     if FileExists(GetOwnCmdName + '.ini') then
  157.     begin
  158.       result := GetOwnCmdName + '.ini';
  159.       Exit;
  160.     end;
  161.  
  162.     if CompatOpenDialogExecute(OpenDialog1) then
  163.     begin
  164.       result := OpenDialog1.FileName;
  165.       Exit;
  166.     end;
  167.  
  168.     result := '';
  169.     Exit;
  170.   end;
  171. end;
  172.  
  173. procedure TUD2MainForm.LoadTaskList;
  174. var
  175.   sl: TStringList;
  176.   i: integer;
  177.   ShortTaskName, iconString: string;
  178.   iconIndex: integer;
  179.   obj: TUD2ListViewEntry;
  180. begin
  181.   TasksListView.Clear;
  182.   sl := TStringList.Create;
  183.   try
  184.     ud2.GetTaskListing(sl);
  185.     for i := 0 to sl.Count-1 do
  186.     begin
  187.       ShortTaskName := sl.Names[i];
  188.  
  189.       Obj := TUD2ListViewEntry.Create;
  190.       Obj.ShortTaskName := ShortTaskName;
  191.       Obj.CloseAfterLaunching := ud2.ReadMetatagBool(ShortTaskName, TagCloseAfterLaunching, DefaultCloseAfterLaunching);
  192.  
  193.       TasksListView.AddItem(sl.Values[ShortTaskName], TObject(Obj));
  194.  
  195.       iconString := ud2.ReadMetatagString(ShortTaskName, TagIcon, '');
  196.       if iconString <> '' then
  197.       begin
  198.         iconIndex := AddIconRecToImageList(SplitIconString(iconString), TasksImageList);
  199.         if iconIndex <> -1 then
  200.         begin
  201.           TasksListView.Items.Item[TasksListView.Items.Count-1].ImageIndex := iconIndex;
  202.         end;
  203.       end;
  204.     end;
  205.   finally
  206.     sl.Free;
  207.   end;
  208. end;
  209.  
  210. procedure TUD2MainForm.DoRun(ShortTaskName: string);
  211. resourcestring
  212.   LNG_TASK_NOT_EXISTS = 'The task "%s" does not exist in the INI file.';
  213.   LNG_NOTHING_MATCHES = 'No identification string matches to your environment. No application was launched. Please check the Task Definition File.';
  214. var
  215.   i: integer;
  216.   cmds: TUD2CommandArray;
  217. begin
  218.   if not ud2.TaskExists(ShortTaskName) then
  219.   begin
  220.     // This can happen if the task name is taken from command line
  221.     MessageDlg(Format(LNG_TASK_NOT_EXISTS, [ShortTaskName]), mtError, [mbOK], 0);
  222.     ExitCode := EXITCODE_TASK_NOT_EXISTS;
  223.     Exit;
  224.   end;
  225.  
  226.   SetLength(cmds, 0);
  227.   cmds := ud2.GetCommandList(ShortTaskName);
  228.  
  229.   if (Length(cmds) = 0) and ud2.ReadMetatagBool(ShortTaskName, TagWarnIfNothingMatches, DefaultWarnIfNothingMatches) then
  230.   begin
  231.     MessageDlg(LNG_NOTHING_MATCHES, mtWarning, [mbOK], 0);
  232.     ExitCode := EXITCODE_TASK_NOTHING_MATCHES;
  233.   end;
  234.  
  235.   for i := Low(cmds) to High(cmds) do
  236.   begin
  237.     UD2_RunCMD(cmds[i]);
  238.   end;
  239. end;
  240.  
  241. procedure TUD2MainForm.FormDestroy(Sender: TObject);
  242. var
  243.   i: integer;
  244. begin
  245.   if Assigned(ud2) then ud2.Free;
  246.   for i := 0 to TasksListView.Items.Count-1 do
  247.   begin
  248.     TUD2ListViewEntry(TasksListView.Items.Item[i].Data).Free;
  249.   end;
  250. end;
  251.  
  252. procedure TUD2MainForm.CheckForErrors;
  253. begin
  254.   ErrorsTabSheet.TabVisible := ud2.Errors.Count > 0;
  255.   if ErrorsTabSheet.TabVisible then
  256.   begin
  257.     ErrorsMemo.Lines.Assign(ud2.Errors);
  258.     PageControl1.ActivePage := ErrorsTabSheet;
  259.   end;
  260. end;
  261.  
  262. procedure TUD2MainForm.LoadDetectedIDs;
  263. var
  264.   i, j: integer;
  265.   pl: TUD2Plugin;
  266.   ude: TUD2IdentificationEntry;
  267. begin
  268.   IdentificationsListView.Clear;
  269.   for i := 0 to ud2.LoadedPlugins.Count-1 do
  270.   begin
  271.     pl := ud2.LoadedPlugins.Items[i] as TUD2Plugin;
  272.     for j := 0 to pl.DetectedIdentifications.Count-1 do
  273.     begin
  274.       ude := pl.DetectedIdentifications.Items[j] as TUD2IdentificationEntry;
  275.       with IdentificationsListView.Items.Add do
  276.       begin
  277.         Caption := pl.PluginName;
  278.         if ude.DynamicDataUsed then
  279.           SubItems.Add(ude.DynamicData)
  280.         else
  281.           SubItems.Add('');
  282.         SubItems.Add(pl.IdentificationMethodName);
  283.         SubItems.Add(ude.IdentificationString);
  284.         SubItems.Add(GUIDToString(pl.PluginGUID));
  285.       end;
  286.     end;
  287.   end;
  288.  
  289.   for i := 0 to IdentificationsListView.Columns.Count-1 do
  290.   begin
  291.     IdentificationsListView.Columns.Items[i].Width := LVSCW_AUTOSIZE_USEHEADER;
  292.   end;
  293. end;
  294.  
  295. procedure TUD2MainForm.LoadINITemplate;
  296. var
  297.   i, j: integer;
  298.   pl: TUD2Plugin;
  299.   ude: TUD2IdentificationEntry;
  300.   idNames: TStringList;
  301. begin
  302.   IniTemplateMemo.Clear;
  303.   IniTemplateMemo.Lines.Add('[ExampleTask1]');
  304.   IniTemplateMemo.Lines.Add('; Description: Optional but recommended');
  305.   IniTemplateMemo.Lines.Add('Description=Run Task #1');
  306.   IniTemplateMemo.Lines.Add('; WarnIfNothingMatches: Warns when no application was launched. Default: false.');
  307.   IniTemplateMemo.Lines.Add('WarnIfNothingMatches=false');
  308.   IniTemplateMemo.Lines.Add('; Optional: IconDLL + IconIndex');
  309.   IniTemplateMemo.Lines.Add('Icon=%SystemRoot%\system32\Shell32.dll,3');
  310.   IniTemplateMemo.Lines.Add('; Optional: Can be true or false');
  311.   IniTemplateMemo.Lines.Add(TagCloseAfterLaunching+'=true');
  312.  
  313.   for i := 0 to ud2.LoadedPlugins.Count-1 do
  314.   begin
  315.     pl := ud2.LoadedPlugins.Items[i] as TUD2Plugin;
  316.     for j := 0 to pl.DetectedIdentifications.Count-1 do
  317.     begin
  318.       ude := pl.DetectedIdentifications.Items[j] as TUD2IdentificationEntry;
  319.       IniTemplateMemo.Lines.Add(Format('; %s', [ude.Plugin.PluginName]));
  320.  
  321.       idNames := TStringList.Create;
  322.       try
  323.         ude.GetIdNames(idNames);
  324.         if idNames.Count >= 1 then
  325.           IniTemplateMemo.Lines.Add(idNames.Strings[0]+'=calc.exe');
  326.       finally
  327.         idNames.Free;
  328.       end;
  329.  
  330.     end;
  331.   end;
  332. end;
  333.  
  334. procedure TUD2MainForm.LoadLoadedPluginList;
  335. resourcestring
  336.   LNG_MS = '%dms';
  337. var
  338.   i: integer;
  339.   pl: TUD2Plugin;
  340. begin
  341.   LoadedPluginsListView.Clear;
  342.   for i := 0 to ud2.LoadedPlugins.Count-1 do
  343.   begin
  344.     pl := ud2.LoadedPlugins.Items[i] as TUD2Plugin;
  345.     with LoadedPluginsListView.Items.Add do
  346.     begin
  347.       Caption := pl.PluginDLL;
  348.       SubItems.Add(pl.PluginVendor);
  349.       SubItems.Add(pl.PluginName);
  350.       SubItems.Add(pl.PluginVersion);
  351.       SubItems.Add(pl.IdentificationMethodName);
  352.       SubItems.Add(IntToStr(pl.DetectedIdentifications.Count));
  353.       SubItems.Add(Format(LNG_MS, [Max(1,pl.time)])); // at least show 1ms, otherwise it would be unloggical
  354.       SubItems.Add(pl.IdentificationProcedureStatusCodeDescribed);
  355.       SubItems.Add(pl.PluginGUIDString);
  356.     end;
  357.   end;
  358.  
  359.   for i := 0 to LoadedPluginsListView.Columns.Count-1 do
  360.   begin
  361.     LoadedPluginsListView.Columns.Items[i].Width := LVSCW_AUTOSIZE_USEHEADER;
  362.   end;
  363. end;
  364.  
  365. procedure TUD2MainForm.TasksListViewDblClick(Sender: TObject);
  366. var
  367.   obj: TUD2ListViewEntry;
  368. begin
  369.   if TasksListView.ItemIndex = -1 then exit;
  370.   obj := TUD2ListViewEntry(TasksListView.Selected.Data);
  371.   DoRun(obj.ShortTaskName);
  372.   if obj.CloseAfterLaunching then Close;
  373. end;
  374.  
  375. procedure TUD2MainForm.TasksListViewKeyPress(Sender: TObject; var Key: Char);
  376. begin
  377.   if Key = #13 then
  378.   begin
  379.     TasksListViewDblClick(Sender);
  380.   end;
  381. end;
  382.  
  383. procedure TUD2MainForm.Button1Click(Sender: TObject);
  384. var
  385.   cmd: TUD2Command;
  386. begin
  387.   cmd.executable := ud2.IniFileName;
  388.   cmd.runAsAdmin := false;
  389.   cmd.runInOwnDirectory := false;
  390.   cmd.windowMode := SW_NORMAL;
  391.   UD2_RunCMD(cmd);
  392. end;
  393.  
  394. procedure TUD2MainForm.Button2Click(Sender: TObject);
  395. begin
  396.   if CompatSaveDialogExecute(SaveDialog1) then
  397.   begin
  398.     IniTemplateMemo.Lines.SaveToFile(SaveDialog1.FileName);
  399.   end;
  400. end;
  401.  
  402. procedure TUD2MainForm.URLLabelClick(Sender: TObject);
  403. var
  404.   cmd: TUD2Command;
  405. begin
  406.   cmd.executable := TLabel(Sender).Caption;
  407.   if Pos('@', cmd.executable) > 0 then
  408.     cmd.executable := 'mailto:' + cmd.executable
  409.   else
  410.     cmd.executable := 'http://' + cmd.executable;
  411.  
  412.   cmd.runAsAdmin := false;
  413.   cmd.runInOwnDirectory := false;
  414.   cmd.windowMode := SW_NORMAL;
  415.  
  416.   UD2_RunCMD(cmd);
  417. end;
  418.  
  419. procedure TUD2MainForm.TasksPopupMenuPopup(Sender: TObject);
  420. begin
  421.   Run1.Enabled := TasksListView.ItemIndex <> -1;
  422.   Properties1.Enabled := TasksListView.ItemIndex <> -1;
  423. end;
  424.  
  425. procedure TUD2MainForm.Run1Click(Sender: TObject);
  426. begin
  427.   TasksListViewDblClick(Sender);
  428. end;
  429.  
  430. procedure TUD2MainForm.Properties1Click(Sender: TObject);
  431. var
  432.   obj: TUD2ListViewEntry;
  433. begin
  434.   if TasksListView.ItemIndex = -1 then exit;
  435.   obj := TUD2ListViewEntry(TasksListView.Selected.Data);
  436.   if obj.TaskPropertiesForm = nil then
  437.   begin
  438.     obj.TaskPropertiesForm := TUD2TaskPropertiesForm.Create(Self, ud2, obj.ShortTaskName);
  439.   end;
  440.   obj.TaskPropertiesForm.Show;
  441. end;
  442.  
  443. procedure TUD2MainForm.IdentificationsPopupMenuPopup(Sender: TObject);
  444. begin
  445.   CopyTaskDefinitionExample1.Enabled := IdentificationsListView.ItemIndex <> -1;
  446. end;
  447.  
  448. procedure TUD2MainForm.CopyTaskDefinitionExample1Click(Sender: TObject);
  449. var
  450.   s: string;
  451. begin
  452.   s := '; '+IdentificationsListView.Selected.Caption+#13#10+
  453.        IdentificationsListView.Selected.SubItems[0] + ':' + IdentificationsListView.Selected.SubItems[1] + '=calc.exe'+#13#10+
  454.        #13#10+
  455.        '; Alternatively:'+#13#10+
  456.        IdentificationsListView.Selected.SubItems[2] + ':' + IdentificationsListView.Selected.SubItems[1] + '=calc.exe'+#13#10;
  457.   Clipboard.AsText := s;
  458. end;
  459.  
  460. procedure TUD2MainForm.ListViewCompare(Sender: TObject; Item1,
  461.   Item2: TListItem; Data: Integer; var Compare: Integer);
  462. var
  463.   ListView: TVTSListView;
  464. begin
  465.   ListView := Sender as TVTSListView;
  466.   if ListView.CurSortedColumn = 0 then
  467.   begin
  468.     Compare := AlphaNumCompare(Item1.Caption, Item2.Caption);
  469.   end
  470.   else
  471.   begin
  472.     Compare := AlphaNumCompare(Item1.SubItems[ListView.CurSortedColumn-1],
  473.                                Item2.SubItems[ListView.CurSortedColumn-1]);
  474.   end;
  475.   if ListView.CurSortedDesc then Compare := -Compare;
  476. end;
  477.  
  478. procedure TUD2MainForm.Button3Click(Sender: TObject);
  479. begin
  480.   VTS_CheckUpdates('userdetect2', VersionLabel.Caption);
  481. end;
  482.  
  483. procedure TUD2MainForm.LoadedPluginsPopupMenuPopup(Sender: TObject);
  484. begin
  485.   MenuItem1.Enabled := LoadedPluginsListView.ItemIndex <> -1;
  486. end;
  487.  
  488. procedure TUD2MainForm.MenuItem1Click(Sender: TObject);
  489. var
  490.   s: string;
  491. begin
  492.   s := '; ' + LoadedPluginsListView.Selected.SubItems.Strings[6];
  493.   Clipboard.AsText := s;
  494. end;
  495.  
  496. procedure TUD2MainForm.Run;
  497. resourcestring
  498.   LNG_SYNTAX = 'Syntax: %s [TaskDefinitionFile [/T TaskName] | /C IdentificationTerm [Command] | /?]';
  499. var
  500.   LoadedIniFile: string;
  501. begin
  502.   ExitCode := EXITCODE_OK;
  503.  
  504.   if ((ParamCount = 1) and CheckBoolParam(1, '?')) or
  505.      (CheckBoolParam(2, 'T') and (ParamCount > 3)) or
  506.      (CheckBoolParam(1, 'C') and (ParamCount > 3)) or
  507.      (not CheckBoolParam(2, 'T') and not CheckBoolParam(1, 'C') and (ParamCount > 1)) then
  508.   begin
  509.     ExitCode := EXITCODE_SYNTAX_ERROR;
  510.     MessageDlg(Format(LNG_SYNTAX, [GetOwnCmdName]), mtInformation, [mbOK], 0);
  511.  
  512.     Visible := false;
  513.     Close;
  514.     Exit;
  515.   end;
  516.  
  517.   LoadedIniFile := GetIniFileName;
  518.   if LoadedIniFile = '' then
  519.   begin
  520.     Visible := false;
  521.     Close;
  522.     Exit;
  523.   end;
  524.   ud2 := TUD2.Create(LoadedIniFile);
  525.  
  526.   ud2.HandlePluginDir('',        '*.udp');
  527.   ud2.HandlePluginDir('Plugins', '*.udp');
  528.   ud2.HandlePluginDir('Plugins', '*.dll');
  529.  
  530.   if CheckBoolParam(1, 'C') then
  531.   begin
  532.     if ud2.FulfilsEverySubterm(ParamStr(2)) then
  533.     begin
  534.       ExitCode := EXITCODE_OK;
  535.  
  536.       if ParamStr(3) <> '' then
  537.       begin
  538.         UD2_RunCMD(UD2P_DecodeCommand(ParamStr(3)));
  539.       end;
  540.     end
  541.     else
  542.     begin
  543.       ExitCode := EXITCODE_TASK_NOTHING_MATCHES;
  544.     end;
  545.  
  546.     Visible := false;
  547.     Close;
  548.     Exit;
  549.   end
  550.   else if CheckBoolParam(2, 'T') then
  551.   begin
  552.     DoRun(ParamStr(3));
  553.  
  554.     Visible := false;
  555.     Close;
  556.     Exit;
  557.   end
  558.   else
  559.   begin
  560.     LoadTaskList;
  561.     LoadDetectedIDs;
  562.     LoadINITemplate;
  563.     LoadLoadedPluginList;
  564.     CheckForErrors;
  565.  
  566.     Visible := true;
  567.     Exit;
  568.   end;
  569. end;
  570.  
  571. procedure TUD2MainForm.FormCreate(Sender: TObject);
  572. begin
  573.   // To avoid accidental change of the default tab from the IDE VCL Designer
  574.   PageControl1.ActivePage := TasksTabSheet;
  575. end;
  576.  
  577. procedure TUD2MainForm.Button5Click(Sender: TObject);
  578. var
  579.   idTerm: string;
  580.   cmds: TUD2CommandArray;
  581.   sCmds: string;
  582.   i: integer;
  583. begin
  584.   // TODO xxx: Auch eine Möglichkeit geben, einfach nur "Testecho(abc)" einzugeben und es kommt was bei raus
  585.  
  586.   if InputQuery('Enter example term', 'Example: Testecho(abc):abc=calc.exe', idTerm) then
  587.   begin
  588.     SetLength(cmds, 0);
  589.     cmds := ud2.CheckTerm(idTerm);
  590.  
  591.     sCmds := '';
  592.     for i := Low(cmds) to High(cmds) do
  593.     begin
  594.       sCmds := sCmds + cmds[i].executable + #13#10;
  595.     end;
  596.  
  597.     if Length(cmds) = 0 then
  598.       ShowMessage('No commands would be executed.')
  599.     else
  600.       showmessage('Following commands would be executed:' + #13#10#13#10 + sCmds);
  601.   end;
  602.   LoadDetectedIDs;
  603. end;
  604.  
  605. end.
  606.