home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR4 / PASSCA.ZIP / PASSCAN.PAS < prev    next >
Pascal/Delphi Source File  |  1993-12-19  |  19KB  |  644 lines

  1. {************************************************}
  2. {   PASSCAN.PAS                                  }
  3. {   Originally:                                  }
  4. {   Turbo Pascal for Windows                     }
  5. {   Demo program  FConvert.pas                   }
  6. {   Copyright (c) 1991 by Borland International  }
  7. {************************************************}
  8. {   Quick and Dirty Modification by              }
  9. {   Mike Carey - 76450,1030   12/19/93           }
  10. {************************************************}
  11. {   This program will scan one or more *.pas     }
  12. {   files for compiler directives, getmems and   }
  13. {   freemems.  It will output the results to     }
  14. {   the screen, and optionally to a disk file    }
  15. {   named PASSCAN.LOG.  If output to file, it    }
  16. {   will launch Notepad so that the results may  }
  17. {   be printed (ok, so I'm lazy).  This code is  }
  18. {   cobbled together and inefficient, but I      }
  19. {   needed something easier to use than GREP     }
  20. {   that would show me the compiler directives   }
  21. {   in each of my units, as well as a safety     }
  22. {   check of memory allocations.  Be forwarned   }
  23. {   that if what you're scanning for stradles    }
  24. {   the read buffer, the results will be         }
  25. {   inaccurate.  Also, memory allocations        }
  26. {   quantified by variables/constants will not   }
  27. {   be totaled.                                  }
  28. {                                                }
  29. {   Feel free to use, modify, improve, or        }
  30. {   discard as you see fit.                      }
  31. {************************************************}
  32.  
  33.  
  34. {$X+} {$I-,S-}
  35. program PasScan;
  36.  
  37.  
  38. uses WinTypes, WinProcs, WinDos, WObjects, Strings, BWCC;
  39.  
  40.  
  41. {$R PasScan}
  42.  
  43. const
  44.  
  45. { Resource IDs }
  46.  
  47.   id_Dialog = 100;
  48.  
  49. { Scan dialog item IDs }
  50.  
  51.   id_FileName   = 100;
  52.   id_FilePath   = 101;
  53.   id_FileList   = 102;
  54.   id_DirList    = 103;
  55.   id_fileOutput = 105;
  56.   id_Scan       = 106;
  57.  
  58. { File specifier maximum length }
  59.  
  60.   fsFileSpec = fsFileName + fsExtension;
  61.  
  62. { Scan Buffer size }
  63.  
  64.   BufSize = 32768;
  65.  
  66. var
  67.   Buffer: PChar;
  68.  
  69. type
  70.  
  71. { TScanDialog is the main window of the application. }
  72.  
  73.   PScanDialog = ^TScanDialog;
  74.   TScanDialog = object(TDlgWindow)
  75.     FileName,TempName: array[0..fsPathName] of Char;
  76.     Extension: array[0..fsExtension] of Char;
  77.     FileSpec: array[0..fsFileSpec] of Char;
  78.     ResultList: pListBox;
  79.     FileCount: word;
  80.     FirstPass: bool;
  81.     OutputFile: file;
  82.     FileOut: bool;
  83.  
  84.     constructor Init;
  85.     destructor Done; virtual;
  86.     procedure SetupWindow; virtual;
  87.     function GetClassName: PChar; virtual;
  88.     function GetFileName(index: integer): Boolean;
  89.     procedure SelectFileName;
  90.     procedure UpdateFileName;
  91.     function UpdateListBoxes: Boolean;
  92.     function  ScanFile: Boolean;
  93.     procedure DoFileName(var Msg: TMessage);
  94.       virtual id_First + id_FileName;
  95.     procedure DoFileList(var Msg: TMessage);
  96.       virtual id_First + id_FileList;
  97.     procedure DoDirList(var Msg: TMessage);
  98.       virtual id_First + id_DirList;
  99.     procedure DoScan(var Msg: TMessage);
  100.       virtual id_First + id_Scan;
  101.   end;
  102.  
  103. { TScanApp is the application object. It creates a main window of
  104.   type TScanDialog. }
  105.  
  106.   TScanApp = object(TApplication)
  107.     procedure InitMainWindow; virtual;
  108.   end;
  109.  
  110.  
  111. { Return a pointer to the file name part of a file path. }
  112.  
  113. function GetFileName(FilePath: PChar): PChar;
  114. var
  115.   P: PChar;
  116. begin
  117.   P := StrRScan(FilePath, '\');
  118.   if P = nil then P := StrRScan(FilePath, ':');
  119.   if P = nil then GetFileName := FilePath else GetFileName := P + 1;
  120. end;
  121.  
  122. { Return a pointer to the extension part of a file path. }
  123.  
  124. function GetExtension(FilePath: PChar): PChar;
  125. var
  126.   P: PChar;
  127. begin
  128.   P := StrScan(GetFileName(FilePath), '.');
  129.   if P = nil then GetExtension := StrEnd(FilePath) else GetExtension := P;
  130. end;
  131.  
  132. { Return True if the specified file path contains wildcards. }
  133.  
  134. function HasWildCards(FilePath: PChar): Boolean;
  135. begin
  136.   HasWildCards := (StrScan(FilePath, '*') <> nil) or
  137.     (StrScan(FilePath, '?') <> nil);
  138. end;
  139.  
  140. { Copy Source file name to Dest, changing the extension to Ext. }
  141.  
  142. function MakeFileName(Dest, Source, Ext: PChar): PChar;
  143. begin
  144.   MakeFileName := StrLCat(StrLCopy(Dest, Source,
  145.     GetExtension(Source) - Source), Ext, fsPathName);
  146. end;
  147.  
  148. { Delete a file. }
  149.  
  150. procedure FileDelete(FileName: PChar);
  151. var
  152.   F: file;
  153. begin
  154.   Assign(F, FileName);
  155.   Erase(F);
  156.   InOutRes := 0;
  157. end;
  158.  
  159. { Rename a file. }
  160.  
  161. procedure FileRename(CurName, NewName: PChar);
  162. var
  163.   F: file;
  164. begin
  165.   Assign(F, CurName);
  166.   Rename(F, NewName);
  167.   InOutRes := 0;
  168. end;
  169.  
  170. { TScanDialog }
  171.  
  172. { Scan dialog constructor. }
  173.  
  174. constructor TScanDialog.Init;
  175. begin
  176.   TDlgWindow.Init(nil, PChar(id_Dialog));
  177.   StrCopy(FileName, '*.pas');
  178.   Extension[0] := #0;
  179.   FileSpec[0] := #0;
  180.   New(ResultList,InitResource(@self,425));
  181. end;
  182.  
  183. destructor TScanDialog.Done;
  184. begin
  185.   if ResultList <> nil then dispose(ResultList,done);
  186.   TDlgWindow.Done;
  187. end;
  188.  
  189. { SetupWindow is called right after the Scan dialog is created.
  190.   Limit the file name edit control to 79 characters, update the file
  191.   and directory list boxes, and select the file name edit control. }
  192.  
  193. procedure TScanDialog.SetupWindow;
  194. begin
  195.   TDlgWindow.setupWindow;
  196.   SendDlgItemMessage(HWindow, id_FileName, em_LimitText, fsPathName, 0);
  197.   UpdateListBoxes;
  198.   SelectFileName;
  199.   FirstPass := true;
  200. end;
  201.  
  202. { Return window class name. This name corresponds to the class name
  203.   specified for the Scan dialog in the resource file. }
  204.  
  205. function TScanDialog.GetClassName: PChar;
  206. begin
  207.   GetClassName := 'BorDlgWindow';
  208. end;
  209.  
  210. { Return True if the name in the file name edit control is not a
  211.   directory and does not contain wildcards. Otherwise, update the
  212.   file and directory list boxes as required. }
  213.  
  214. function TScanDialog.GetFileName(index: integer): Boolean;
  215. var
  216.   FileLen: Word;
  217. begin
  218.   GetFileName := False;
  219.   sendmessage(getitemhandle(id_FileList),lb_gettext,word(index),longint(@FileName));
  220.   setdlgitemtext(hWindow,id_FileName,FileName);
  221.   FileExpand(FileName, FileName);
  222.   FileLen := StrLen(FileName);
  223.   if (FileName[FileLen - 1] = '\') or HasWildCards(FileName) or
  224.     (GetFocus = GetDlgItem(HWindow, id_DirList)) then
  225.   begin
  226.     if FileName[FileLen - 1] = '\' then
  227.       StrLCat(FileName, FileSpec, fsPathName);
  228.     if not UpdateListBoxes then
  229.     begin
  230.       MessageBeep(0);
  231.       SelectFileName;
  232.     end;
  233.     Exit;
  234.   end;
  235.   StrLCat(StrLCat(FileName, '\', fsPathName), FileSpec, fsPathName);
  236.   if UpdateListBoxes then Exit;
  237.   FileName[FileLen] := #0;
  238.   if GetExtension(FileName)[0] = #0 then
  239.     StrLCat(FileName, Extension, fsPathName);
  240.   AnsiLower(FileName);
  241.   GetFileName := True;
  242. end;
  243.  
  244. { Select the file name edit control. }
  245.  
  246. procedure TScanDialog.SelectFileName;
  247. begin
  248.   SendDlgItemMessage(HWindow, id_FileName, em_SetSel, 0, $7FFF0000);
  249.   SetFocus(GetDlgItem(HWindow, id_FileName));
  250. end;
  251.  
  252. { Update the file name edit control. }
  253.  
  254. procedure TScanDialog.UpdateFileName;
  255. begin
  256.   if sendmessage(getitemhandle(id_FileList),lb_getselcount,0,0) > 1 then
  257.     SetDlgItemText(HWindow, id_FileName,'* Multiple *')
  258.   else
  259.     begin
  260.       SetDlgItemText(HWindow, id_FileName, AnsiLower(FileName));
  261.       SendDlgItemMessage(HWindow, id_FileName, em_SetSel, 0, $7FFF0000);
  262.     end;
  263. end;
  264.  
  265. { Update the file and directory list boxes. }
  266.  
  267. function TScanDialog.UpdateListBoxes: Boolean;
  268. var
  269.   Result: Integer;
  270.   Path: array[0..fsFileName] of Char;
  271. begin
  272.   UpdateListBoxes := False;
  273.   if DlgDirList(HWindow, FileName, id_FileList, id_FilePath, 0) <> 0 then
  274.   begin
  275.     DlgDirList(HWindow, '*.pas', id_DirList, 0, $C010);
  276.     StrLCopy(FileSpec, FileName, fsFileSpec);
  277.     UpdateFileName;
  278.     UpdateListBoxes := True;
  279.   end;
  280. end;
  281.  
  282. { Scan file from Oem to Ansi or from Ansi to Oem. }
  283.  
  284. function TScanDialog.ScanFile: Boolean;
  285. const
  286.   CRLF: array[0..1] of char = #13#10;
  287. var
  288.   N,R,memval: Word;
  289.   okok,x,y: integer;
  290.   L,GM,FM: Longint;
  291.   TheString: PChar;
  292.   P,P1,P2,P3,P4,PG,PF: PChar;
  293.   BakName: array[0..fsPathName] of Char;
  294.   InputFile: file;
  295.   memch: array[0..50] of char;
  296.   startline,lines,curline: word;
  297.   oldcursor: hCursor;
  298.   memstr: array[0..7] of char;
  299.   memidx: byte;
  300.  
  301.   function Error(Stop: Boolean; Message: PChar): Boolean;
  302.   begin
  303.     if Stop then
  304.     begin
  305.       if TheString <> nil then freemem(TheString,100);
  306.       if Buffer <> nil then FreeMem(Buffer, BufSize+1);
  307.       if TFileRec(InputFile).Mode <> fmClosed then Close(InputFile);
  308.       if TFileRec(OutputFile).Mode <> fmClosed then
  309.       begin
  310.         Close(OutputFile);
  311.         Erase(OutputFile);
  312.       end;
  313.       InOutRes := 0;
  314.       Setcursor(oldCursor);
  315.       MessageBox(HWindow, Message, 'Error', mb_IconStop + mb_Ok);
  316.     end;
  317.     Error := Stop;
  318.   end;
  319.  
  320.   procedure GetCurrentLine;
  321.   begin
  322.     {get current line ---------------------------------}
  323.     P3 := strscan(P4,#13);
  324.     while (P3 <> nil) and (P3 <= P1) do
  325.       begin
  326.         inc(CurLine);
  327.         P4 := P3+1;
  328.         P3 := strscan(P4,#13);
  329.       end;
  330.     wvsprintf(@memch,'%03u',FileCount);
  331.     strcat(memch,#9);
  332.     strcopy(TheString,memch);
  333.     wvsprintf(@memch,'%05u',CurLine);
  334.     strcat(memch,#9);
  335.     strcat(TheString,memch);
  336.     {-------------------------------------------------}
  337.   end;
  338.  
  339. begin
  340.   ScanFile := False;
  341.   oldCursor := setcursor(LoadCursor(0,idc_Wait));
  342.   getmem(TheString,200);
  343.   if Error(Buffer = nil, 'Not enough memory for copy buffer.') then Exit;
  344.   Assign(InputFile, FileName);
  345.   Reset(InputFile,1);
  346.   if Error(IOResult <> 0, 'Cannot open input file.') then Exit;
  347.   if FileOut and FirstPass then
  348.     begin
  349.       MakeFileName(TempName, 'PasScan', '.Log');
  350.       Assign(OutputFile, TempName);
  351.       Rewrite(OutputFile,1);
  352.       FirstPass := false;
  353.       if Error(IOResult <> 0, 'Cannot create output file.') then Exit;
  354.     end;
  355.   L := FileSize(InputFile);
  356.   wvsprintf(TheString,'%03u',FileCount);
  357.   strcat(TheString,#9);
  358.   strcat(TheString,#32#0);
  359.   ResultList^.Addstring(TheString);
  360.   wvsprintf(TheString,'%03u',FileCount);
  361.   strcat(TheString,#9);
  362.   strcat(TheString,#42#9#0);
  363.   strLcat(TheString,strupper(FileName),99);
  364.   ResultList^.Addstring(TheString);
  365.   wvsprintf(TheString,'%03u',FileCount);
  366.   strcat(TheString,#9);
  367.   strcat(TheString,#42#42#9#32#0);
  368.   ResultList^.Addstring(TheString);
  369.   FM := 0; GM := 0; Lines := 0; CurLine := 0; startline := 0;
  370.   while L > 0 do
  371.   begin
  372.     StartLine := Lines;
  373.     if L > BufSize then N := BufSize else N := L;
  374.     BlockRead(InputFile, Buffer^, N, R);
  375.     Buffer[R] := #0;
  376.     if Error(IOResult <> 0, 'Error reading input file.') then Exit;
  377.     if strlen(Buffer) > 0 then
  378.       begin
  379.         {get total lines}
  380.         P1 := Buffer; P := nil;
  381.         P := strscan(P1,#13);
  382.         while (P <> nil) and (P1 <> nil) do
  383.           begin
  384.             inc(Lines);
  385.             P1 := P+1;
  386.             P := strscan(P1,#13);
  387.           end;
  388.  
  389.         {get compiler directives -----------------------------------------}
  390.         P1 := Buffer; P := nil;
  391.         P4 := Buffer; CurLine := 1 + StartLine;
  392.         P := strscan(P1,'{');
  393.         while (P <> nil) and (P1 <> nil) do
  394.           begin
  395.             P1 := strscan(P,'}');
  396.             if (P[1] = '$') and (P1 <> nil) then
  397.               begin
  398.                 GetCurrentLine;
  399.                 x := strlen(TheString);
  400.                 strmove(@TheString[x],P,(P1-P)+1);
  401.                 TheString[x+(P1-P)+1] := #0;
  402.                 ResultList^.addstring(TheString);
  403.                 updatewindow(ResultList^.hWindow);
  404.               end;
  405.             if P1 <> nil then
  406.               P := strscan(P1,'{');
  407.           end;
  408.  
  409.         {get getmems/freemems-------------------------------------------------}
  410.         P1 := Buffer; P := nil;
  411.         P4 := Buffer; CurLine := 1 + StartLine;
  412.         PG := strpos(P1,'getmem');
  413.         PF := strpos(P1,'freemem');
  414.         if ((PG <> nil) and (PF = nil)) or ((PG <> nil) and (PG < PF)) then
  415.           begin P := PG; PF := nil; strcopy(memstr,'getmem'); memidx := 6; end
  416.         else
  417.         if ((PF <> nil) and (PG = nil)) or ((PF <> nil) and (PF < PG)) then
  418.           begin P := PF; PG := nil; strcopy(memstr,'freemem'); memidx := 7; end
  419.         else
  420.           P := nil;
  421.         if P <> nil then P := strpos(P1,memstr);
  422.         while (P <> nil) and (P1 <> nil) do
  423.           begin
  424.             P1 := strscan(P,')');
  425.             if (P[memidx] = '(') and (P1 <> nil) then
  426.               begin
  427.                 GetCurrentLine;
  428.                 x := strlen(TheString);
  429.                 strmove(@TheString[x],P,(P1-P)+1);
  430.                 TheString[x+(P1-P)+1] := #0;
  431.                 ResultList^.addstring(TheString);
  432.                 updatewindow(ResultList^.hWindow);
  433.                 P2 := strscan(P,',');
  434.                 if P2 <> nil then
  435.                   begin
  436.                     strLcopy(memch,@P2[1],(P1-P2)-1);
  437.                     val(memch,memval,okok);
  438.                     if okok = 0 then
  439.                       case memidx of
  440.                       6: inc(GM,memval);
  441.                       7: inc(FM,memval);
  442.                       end;
  443.                   end;
  444.               end;
  445.             if P1 <> nil then
  446.               begin
  447.                 PG := strpos(P1,'getmem');
  448.                 PF := strpos(P1,'freemem');
  449.                 if ((PG <> nil) and (PF = nil)) or ((PG <> nil) and (PG < PF)) then
  450.                   begin P := PG; PF := nil; strcopy(memstr,'getmem'); memidx := 6; end
  451.                 else
  452.                 if ((PF <> nil) and (PG = nil)) or ((PF <> nil) and (PF < PG)) then
  453.                   begin P := PF; PG := nil; strcopy(memstr,'freemem'); memidx := 7; end
  454.                 else
  455.                   P := nil;
  456.                 if P <> nil then P := strpos(P1,memstr);
  457.               end;
  458.           end;
  459.       end;
  460.     Dec(L, N);
  461.   end;
  462.  
  463.   {finish up ------------------------------------------------------------}
  464.   if GM >= 0 then
  465.     begin
  466.       wvsprintf(TheString,'%03u',FileCount);
  467.       strcat(TheString,#9);
  468.       wvsprintf(@memch,'%lu% bytes allocated with GETMEM',GM);
  469.       strcat(TheString,#42#42#42#42#9#0);
  470.       strLcat(TheString,memch,99);
  471.       ResultList^.addstring(TheString);
  472.     end;
  473.   if FM >= 0 then
  474.     begin
  475.       wvsprintf(TheString,'%03u',FileCount);
  476.       strcat(TheString,#9);
  477.       wvsprintf(@memch,'%lu% bytes freed with FREEMEM',FM);
  478.       strcat(TheString,#42#42#42#42#9#0);
  479.       strLcat(TheString,memch,99);
  480.       ResultList^.addstring(TheString);
  481.     end;
  482.   if Lines >= 0 then
  483.     begin
  484.       wvsprintf(TheString,'%03u',FileCount);
  485.       strcat(TheString,#9);
  486.       wvsprintf(@memch,'%u% total lines',Lines);
  487.       strcat(TheString,#42#42#42#42#9#0);
  488.       strLcat(TheString,memch,99);
  489.       ResultList^.addstring(TheString);
  490.     end;
  491.   wvsprintf(TheString,'%03u',FileCount);
  492.   strcat(TheString,#9);
  493.   strcat(TheString,#42#42#42#42#42#9#45#45#45#45#45#0);
  494.   ResultList^.addstring(TheString);
  495.  
  496.   wvsprintf(TheString,'%03u',FileCount);
  497.   strcat(TheString,#9); strcat(TheString,'99999');
  498.   strcat(TheString,#9); strcat(TheString,'END - - - - - - - -');
  499.   strcat(TheString,#12);
  500.   x := ResultList^.addstring(TheString);
  501.   sendmessage(ResultList^.hWindow,lb_settopindex,word(x),0);
  502.   Close(InputFile);
  503.   strcopy(FileName,#0);
  504.  
  505.   if FileOut then
  506.     begin
  507.       y := ResultList^.getcount;
  508.       if y > 0 then
  509.         begin
  510.           getdlgitemtext(hWindow,380,Buffer,99);
  511.           strcat(Buffer,#9);
  512.           getdlgitemtext(hWindow,381,TheString,99);
  513.           strcat(Buffer,TheString); strcat(Buffer,#9);
  514.           getdlgitemtext(hWindow,382,TheString,99);
  515.           strcat(Buffer,TheString); strcat(Buffer,#13#10);
  516.         end;
  517.       x := 0;
  518.       TheString[0] := #0;
  519.       while x < y do
  520.         begin
  521.           ResultList^.getstring(TheString,x);
  522.           strLcat(Buffer,TheString,Bufsize);
  523.           strLcat(Buffer,#13#10,Bufsize);
  524.           inc(x);
  525.         end;
  526.       ResultList^.clearlist;
  527.       BlockWrite(OutputFile, Buffer^, strlen(Buffer));
  528.       if Error(IOResult <> 0, 'Error writing output file.') then Exit;
  529.     end;
  530.   freemem(TheString,200);
  531.   ScanFile := FileOut;
  532.  
  533.   Setcursor(oldCursor);
  534. end;
  535.  
  536. { File name edit control response method. }
  537.  
  538. procedure TScanDialog.DoFileName(var Msg: TMessage);
  539. begin
  540.   if Msg.LParamHi = en_Change then
  541.     EnableWindow(GetDlgItem(HWindow, id_Scan),
  542.       SendMessage(Msg.LParamLo, wm_GetTextLength, 0, 0) <> 0);
  543. end;
  544.  
  545. { File list box response method. }
  546.  
  547. procedure TScanDialog.DoFileList(var Msg: TMessage);
  548. begin
  549.   case Msg.LParamHi of
  550.     lbn_SelChange, lbn_DblClk:
  551.       begin
  552.         DlgDirSelect(HWindow, FileName, id_FileList);
  553.         UpdateFileName;
  554.       end;
  555.     lbn_KillFocus:
  556.       SendMessage(Msg.LParamLo, lb_SetCurSel, Word(-1), 0);
  557.   end;
  558. end;
  559.  
  560. { Directory list box response method. }
  561.  
  562. procedure TScanDialog.DoDirList(var Msg: TMessage);
  563. begin
  564.   case Msg.LParamHi of
  565.     lbn_SelChange, lbn_DblClk:
  566.       begin
  567.         DlgDirSelect(HWindow, FileName, id_DirList);
  568.         StrCat(FileName, FileSpec);
  569.         if Msg.LParamHi = lbn_DblClk then
  570.           UpdateListBoxes else
  571.           UpdateFileName;
  572.       end;
  573.     lbn_KillFocus:
  574.       SendMessage(Msg.LParamLo, lb_SetCurSel, Word(-1), 0);
  575.   end;
  576. end;
  577.  
  578. { Scan button response method. }
  579.  
  580. procedure TScanDialog.DoScan(var Msg: TMessage);
  581. var
  582.   OemToAnsi: Boolean;
  583.   P: array[0..1] of PChar;
  584.   S: array[0..127] of Char;
  585.   InputFile : File;
  586.   x,y: integer;
  587. begin
  588.   FileOut := isdlgbuttonchecked(hWindow,id_FileOutput) > 0;
  589.   ResultList^.clearList;
  590.   FileCount := 1;
  591.   getmem(Buffer,BufSize+1);
  592.  
  593.   y := sendmessage(getitemhandle(id_FileList),lb_getcount,0,0);
  594.   x := 0;
  595.   while x < y do
  596.     begin
  597.       if sendmessage(getitemhandle(id_FileList),lb_getsel,word(x),0) > 0 then
  598.         begin
  599.           if not GetFileName(x) then Exit;
  600.           sendmessage(getitemhandle(id_FileList),lb_settopindex,word(x),0);
  601.           ScanFile;
  602.           inc(FileCount);
  603.         end;
  604.       inc(x);
  605.     end;
  606.   if y > 0 then sendmessage(ResultList^.hWindow,lb_settopindex,word(0),0);
  607.   messagebeep(0);
  608.  
  609.   if FileOut then
  610.     Close(OutputFile);
  611.   FileOut := false;
  612.   if Buffer <> nil then FreeMem(Buffer, BufSize+1);
  613.  
  614.   if isdlgbuttonchecked(hWindow,id_FileOutput) > 0 then
  615.     begin
  616.       strcopy(S,'Notepad.exe ');
  617.       strcat(S,TempName);
  618.       WinExec(@S,sw_shownormal);
  619.     end
  620.   else
  621.     begin
  622.       UpdateListBoxes;
  623.       SelectFileName;
  624.     end;
  625. end;
  626.  
  627. { TScanApp }
  628.  
  629. { Create a Scan dialog as the application's main window. }
  630.  
  631. procedure TScanApp.InitMainWindow;
  632. begin
  633.   MainWindow := New(PScanDialog, Init);
  634. end;
  635.  
  636. var
  637.   ScanApp: TScanApp;
  638.  
  639. begin
  640.   ScanApp.Init('ScanApp');
  641.   ScanApp.Run;
  642.   ScanApp.Done;
  643. end.
  644.