home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1994 #1 / monster.zip / monster / PROG_GEN / TCYBER.ZIP / CYBASE.PAS < prev    next >
Pascal/Delphi Source File  |  1994-01-15  |  17KB  |  732 lines

  1. {
  2. Turbo Vision CyberTools 1.0
  3. (C) 1994 Steve Goldsmith
  4. All Rights Reserved
  5.  
  6. CyberBase Application using PX Browse unit to edit multiple Paradox tables
  7. on single user or network systems.  Table passwords, encryption, decryption,
  8. delete and empty are supported.  Status bar on status lines reports what
  9. the app is doing during table operations.
  10.  
  11. Borland Pascal 7.x or Turbo Pascal 7.x, Turbo Vision 2.x and Paradox
  12. Engine 3.x Database Framework are required to compile.
  13.  
  14. Set IDE directories to
  15.  
  16. \BP\UNITS;
  17. \BP\EXAMPLES\DOS\TVDEMO;
  18. \BP\EXAMPLES\DOS\TVFM;
  19. \BP\PXENGINE\PASCAL\SOURCE;
  20. \BP\PXENGINE\PASCAL;
  21.  
  22. I used \BP\PXENGINE when I installed Paradox Engine 3.0.  The rest of the
  23. path names use BP 7.x defaults.  If you changed any of these then use the
  24. correct paths in Options|Directories...  See APP.INC for global compiler
  25. switches.
  26. }
  27.  
  28. {$I APP.INC}
  29. {$X+}
  30.  
  31. program CyberBase;
  32.  
  33. uses
  34.  
  35.   Dos,                           {system units}
  36.   OOPXEng, PXEngine,             {paradox engine 3.0 and framework units}
  37.   Memory, Drivers, Objects,      {tv units}
  38.   Views, Menus, Dialogs,
  39.   App, MsgBox, StdDlg,
  40.   Gadgets, Calendar, Calc,       {tv demo units}
  41.   ViewText,                      {tvfm units}
  42.   CBCmds, PXBrowse;              {cybertools units}
  43.  
  44. type
  45.  
  46.   TCyberBase = object(TApplication)
  47.     appEnv : TEnv;
  48.     appEngine : TEngine;
  49.     appDatabase : TDatabase;
  50.     appStatus : PInputLine;
  51.     Clock : PClockView;
  52.     Heap : PHeapView;
  53.     constructor Init;
  54.     destructor Done; virtual;
  55.     procedure UpdateStatus (S : string);
  56.     function ErrorBox (ErrCode : integer) : boolean;
  57.     procedure AboutBox;
  58.     procedure Idle; virtual;
  59.     procedure ClearDeskTop;
  60.     function SelectFile (Title : string; WildCard : PathStr; ReadFlag : boolean) : PathStr;
  61.     procedure SaveConfig;
  62.     procedure LoadConfig;
  63.     procedure AddPassword;
  64.     procedure NewBrowser;
  65.     procedure HandleEvent(var Event: TEvent); virtual;
  66.     procedure InitMenuBar; virtual;
  67.     procedure InitStatusLine; virtual;
  68.     procedure OutOfMemory; virtual;
  69.   end;
  70.  
  71. const
  72.  
  73.   appRecords = 4;            {use 4 record browser}
  74.   appIndex = 0;              {open tables on primary index}
  75.   appViewDocBuf = 8192;      {buffer size for viewing doc file}
  76.   appDocName  = 'CYBER.DOC'; {doc file name}
  77.   appCfgName = 'CYBASE.CFG'; {config file name}
  78.   appReadyMsg = 'READY';     {ready status}
  79.  
  80. {
  81. Init app, engine and database.
  82. }
  83.  
  84. constructor TCyberBase.Init;
  85.  
  86. var
  87.  
  88.   R : TRect;
  89.  
  90. begin
  91.   LowMemSize := 2048; {32768 byte safety pool}
  92.   inherited Init;
  93.  
  94.   R.Assign (64,0,70,1);
  95.   Heap := New (PHeapView,Init(R));
  96.   Insert (Heap);
  97.  
  98.   R.Assign (71,0,79,1);
  99.   Clock := New (PClockView,Init (R)); {gadgets included with tvdemo}
  100.   Insert (Clock);
  101.  
  102.   R.Assign (70,24,80,25);
  103.   appStatus := New (PInputLine,Init (R,10));
  104.   appStatus^.Options := appStatus^.Options and not ofSelectable;
  105.   appStatus^.GrowMode := gfGrowAll;
  106.   Insert (appStatus);
  107.  
  108.   LoadConfig;                         {load engine config}
  109.   appEngine.Init (@appEnv);           {init engine}
  110.   ErrorBox (appEngine.lastError);
  111.   appDatabase.Init (@appEngine);      {init database}
  112.   ErrorBox (appDataBase.lastError)
  113. end;
  114.  
  115. {
  116. Close database and engine if open before calling inherited done.
  117. }
  118.  
  119. destructor TCyberBase.Done;
  120.  
  121. begin
  122.   if appDataBase.isOpen then
  123.     appDatabase.Done;
  124.   if appEngine.isOpen then
  125.     appEngine.Done;
  126.   inherited Done
  127. end;
  128.  
  129. {
  130. Update dialog status line.
  131. }
  132.  
  133. procedure TCyberBase.UpdateStatus (S : string);
  134.  
  135. begin
  136.   appStatus^.SetData (S)
  137. end;
  138.  
  139. {
  140. Display error and return true if error <> PXSUCCESS.  If error = PXSUCCESS
  141. then no error is diaplayed and false is returned.
  142. }
  143.  
  144. function TCyberBase.ErrorBox (ErrCode : integer) : boolean;
  145.  
  146. begin
  147.   if ErrCode <> PxSuccess then
  148.   begin
  149.     MessageBox (appEngine.getErrorMessage (ErrCode),nil, mfError or mfOKButton);
  150.     ErrorBox := true
  151.   end
  152.   else
  153.     ErrorBox := false
  154. end;
  155.  
  156. {
  157. Tells what the app is about and what mode it is running in.
  158. }
  159.  
  160. procedure TCyberBase.AboutBox;
  161.  
  162. begin
  163.   MessageBox(
  164.     #3'Turbo Vision CyberTools 1.0'#13+
  165.     #3'(C) 1994 Steve Goldsmith'#13+
  166. {$IFDEF DPMI}
  167.     #3'CyberBase »> PROTECTED <«',
  168. {$ELSE}
  169.     #3'CyberBase »> REAL <«',
  170. {$ENDIF}
  171.     nil, mfInformation or mfOKButton)
  172. end;
  173.  
  174. {
  175. Update status line and gadgets during idle processing.
  176. }
  177.  
  178. procedure TCyberBase.Idle;
  179.  
  180. function IsTileable (P : PView) : Boolean; far;
  181.  
  182. begin
  183.   IsTileable := (P^.Options and ofTileable <> 0) and
  184.   (P^.State and sfVisible <> 0)
  185. end;
  186.  
  187. function IsThere (P : PView) : Boolean; far;
  188.  
  189. begin
  190.   IsThere := (P^.State and sfActive = sfActive)
  191. end;
  192.  
  193. function IsModal (P : PView) : Boolean; far;
  194.  
  195. begin
  196.   IsModal := (P^.State and sfModal = sfModal)
  197. end;
  198.  
  199. begin
  200.   inherited Idle;
  201.   Clock^.Update;                               {update tvdemo gadgets}
  202.   Heap^.Update;
  203.   if Desktop^.FirstThat (@IsThere) <> nil then {see if anything is}
  204.   begin                                        {on the desk top}
  205.     EnableCommands ([cmCloseAll]);
  206.     if Desktop^.FirstThat (@IsTileable) <> nil then {see if any tileable}
  207.       EnableCommands ([cmTile,cmCascade])           {windows are on the}
  208.     else                                            {desk top}
  209.       DisableCommands ([cmTile,cmCascade]);
  210.   end
  211.   else
  212.     DisableCommands ([cmCloseAll,cmTile,cmCascade]);
  213.   if (Desktop^.FirstThat (@IsModal) <> nil) then    {see if modal view}
  214.     DisableCommands ([cmQuit,cmOpenTable])          {is on the desk top}
  215.   else
  216.   begin
  217.     if appStatus^.Data^ <> appReadyMsg then
  218.       UpdateStatus (appReadyMsg);
  219.     EnableCommands ([cmQuit,cmOpenTable])
  220.   end
  221. end;
  222.  
  223. {
  224. Close all windows on desk top.
  225. }
  226.  
  227. procedure TCyberBase.ClearDeskTop;
  228.  
  229. procedure CloseDlg (P : PView); far;
  230.  
  231. begin
  232.   Message (P,evCommand,cmClose,nil)
  233. end;
  234.  
  235. begin
  236.   UpdateStatus ('CLOSE');
  237.   Desktop^.ForEach (@CloseDlg)
  238. end;
  239.  
  240. {
  241. Select file from wild card with overwrite warning.
  242. }
  243.  
  244. function TCyberBase.SelectFile (Title : string; WildCard : PathStr; ReadFlag : boolean) : PathStr;
  245.  
  246. var
  247.  
  248.   F : file;
  249.  
  250. begin
  251.   if ExecuteDialog (New (PFileDialog,Init (WildCard,Title,
  252.     '~N~ame',fdOkButton,100)),@WildCard) <> cmCancel then
  253.   begin
  254.     if ReadFlag then
  255.       SelectFile := WildCard
  256.     else
  257.     begin
  258.       Assign (F,WildCard);
  259.       {$I-} Reset (F); {$I+}
  260.       if IoResult = 0 then {see if file exists before writes}
  261.       begin
  262.         {$I-} Close (F); {$I+}
  263.         if MessageBox (WildCard+' already exists.  Erase and continue?',
  264.         nil,mfConfirmation or mfYesNoCancel) = cmYes then
  265.           SelectFile := WildCard
  266.         else
  267.           SelectFile := ''
  268.       end
  269.       else
  270.         SelectFile := WildCard
  271.     end
  272.   end
  273.   else
  274.     SelectFile := ''
  275. end;
  276.  
  277. {
  278. Save engine config.
  279. }
  280.  
  281. procedure TCyberBase.SaveConfig;
  282.  
  283. var
  284.  
  285.   CfgFile : file of TEnv;
  286.  
  287. begin
  288.   UpdateStatus ('SAVE');
  289.   Assign (CfgFile,appCfgName);
  290.   {$I-} Rewrite (CfgFile); {$I+}
  291.   if IoResult = 0 then
  292.   begin
  293.     Write (CfgFile,appEnv);
  294.     Close (CfgFile)
  295.   end
  296. end;
  297.  
  298. {
  299. Load engine config.
  300. }
  301.  
  302. procedure TCyberBase.LoadConfig;
  303.  
  304. var
  305.  
  306.   CfgFile : file of TEnv;
  307.  
  308. begin
  309.   UpdateStatus ('LOAD');
  310.   Assign (CfgFile,appCfgName);
  311.   {$I-} Reset (CfgFile); {$I+}
  312.   if IoResult = 0 then
  313.   begin
  314.     Read (CfgFile,appEnv);
  315.     Close (CfgFile)
  316.   end
  317. end;
  318.  
  319. {
  320. Add master password to engine.
  321. }
  322.  
  323. procedure TCyberBase.AddPassword;
  324.  
  325. var
  326.  
  327.   Password : string;
  328.  
  329. begin
  330.   Password := '';
  331.   if InputBox ('','Password',Password,15) <> cmCancel then
  332.     ErrorBox (appEngine.addPassword (Password))
  333. end;
  334.  
  335. {
  336. Open new table browser on primary index.  Any existing index can be used
  337. though.  Handles encrypted tables too.
  338. }
  339.  
  340. procedure TCyberBase.NewBrowser;
  341.  
  342. var
  343.  
  344.   FileName : PathStr;
  345.   BrowseCur : PCursor;
  346.  
  347. begin
  348.   FileName := SelectFile ('Open Table','*.DB',true);
  349.   if FileName <> '' then
  350.   begin
  351.     UpdateStatus ('OPEN');
  352.     BrowseCur := New (PCursor,InitAndOpen (@appDataBase,FileName,appIndex,true));
  353.     if BrowseCur^.lastError = PXERR_INSUFRIGHTS then
  354.     begin
  355.       AddPassword;
  356.       BrowseCur^.Open (@appDataBase,FileName,appIndex,true)
  357.     end;
  358.     if not ErrorBox (BrowseCur^.lastError) then
  359.       InsertWindow (New (PpxbDialog,Init (appRecords,
  360.       FileName,@appEngine,@appDataBase,BrowseCur,appIndex)))
  361.     else
  362.       Dispose (BrowseCur,Done)
  363.   end
  364. end;
  365.  
  366. procedure TCyberBase.HandleEvent(var Event: TEvent);
  367.  
  368. {
  369. Configure and save engine setup.  Be careful when modifing engine values,
  370. since incorrect values can crash the engine with a internal error!
  371. }
  372.  
  373. procedure EngineConfig;
  374.  
  375. var
  376.  
  377.   D : PpxbEngineCfg;
  378.   CfgRec : TpxbEngineCfgRec;
  379.  
  380. begin
  381.   EngCfgToDlgCfg (appEnv,CfgRec);
  382.   D := New (PpxbEngineCfg,Init);
  383.   if ExecuteDialog (D,@CfgRec) <> cmCancel then
  384.   begin
  385.     DlgCfgToEngCfg (CfgRec,appEnv);
  386.     SaveConfig;
  387.     MessageBox(#3'Changes will not take effect until you reload program.',
  388.     nil, mfInformation or mfOKButton)
  389.   end
  390. end;
  391.  
  392. {
  393. Lock, delete and unlock table.
  394. }
  395.  
  396. procedure DeleteTable;
  397.  
  398. var
  399.  
  400.   FileName : PathStr;
  401.  
  402. begin
  403.   FileName := SelectFile ('Delete Table','*.DB',true);
  404.   if FileName <> '' then
  405.   begin
  406.     UpdateStatus ('DELETE');
  407.     if appEngine.engineType <> pxLocal then
  408.     begin
  409.       if not ErrorBox (appDataBase.lockNetFile (FileName,pxFL)) then
  410.       begin
  411.         if appDataBase.deleteTable (FileName) = PXERR_INSUFRIGHTS then
  412.         begin
  413.           AddPassword;
  414.           ErrorBox (appDataBase.deleteTable (FileName))
  415.         end
  416.         else
  417.           ErrorBox (appDataBase.lastError);
  418.         ErrorBox (appDataBase.unlockNetFile (FileName,pxFL))
  419.       end
  420.     end
  421.     else
  422.       if appDataBase.emptyTable (FileName) = PXERR_INSUFRIGHTS then
  423.       begin
  424.         AddPassword;
  425.         ErrorBox (appDataBase.deleteTable (FileName))
  426.       end
  427.       else
  428.         ErrorBox (appDataBase.lastError)
  429.   end
  430. end;
  431.  
  432. {
  433. Lock, empty and unlock table.
  434. }
  435.  
  436. procedure EmptyTable;
  437.  
  438. var
  439.  
  440.   FileName : PathStr;
  441.  
  442. begin
  443.   FileName := SelectFile ('Empty Table','*.DB',true);
  444.   if FileName <> '' then
  445.   begin
  446.     UpdateStatus ('EMPTY');
  447.     if appEngine.engineType <> pxLocal then
  448.     begin
  449.       if not ErrorBox (appDataBase.lockNetFile (FileName,pxFL)) then
  450.       begin
  451.         if appDataBase.emptyTable (FileName) = PXERR_INSUFRIGHTS then
  452.         begin
  453.           AddPassword;
  454.           ErrorBox (appDataBase.emptyTable (FileName))
  455.         end
  456.         else
  457.           ErrorBox (appDataBase.lastError);
  458.         ErrorBox (appDataBase.unlockNetFile (FileName,pxFL))
  459.       end
  460.     end
  461.     else
  462.       if appDataBase.emptyTable (FileName) = PXERR_INSUFRIGHTS then
  463.       begin
  464.         AddPassword;
  465.         ErrorBox (appDataBase.emptyTable (FileName))
  466.       end
  467.       else
  468.         ErrorBox (appDataBase.lastError)
  469.   end
  470. end;
  471.  
  472. {
  473. Get password, lock, encrypt and unlock table.
  474. }
  475.  
  476. procedure EncryptTable;
  477.  
  478. var
  479.  
  480.   FileName : PathStr;
  481.   Password : string;
  482.  
  483. begin
  484.   FileName := SelectFile ('Encrypt Table','*.DB',true);
  485.   if FileName <> '' then
  486.   begin
  487.     Password := '';
  488.     if InputBox ('Encrypt','Password',Password,15) <> cmCancel then
  489.     begin
  490.       UpdateStatus ('ENCRYPT');
  491.       if appEngine.engineType <> pxLocal then
  492.       begin
  493.         if not ErrorBox (appDataBase.lockNetFile (FileName,pxFL)) then
  494.         begin
  495.           if appDataBase.encryptTable (FileName,Password) = PXERR_INSUFRIGHTS then
  496.           begin
  497.             AddPassword;
  498.             ErrorBox (appDataBase.encryptTable (FileName,Password))
  499.           end
  500.           else
  501.             ErrorBox (appDataBase.lastError);
  502.           ErrorBox (appDataBase.unlockNetFile (FileName,pxFL))
  503.         end
  504.       end
  505.       else
  506.         if appDataBase.encryptTable (FileName,Password) = PXERR_INSUFRIGHTS then
  507.         begin
  508.           AddPassword;
  509.           ErrorBox (appDataBase.encryptTable (FileName,Password))
  510.         end
  511.         else
  512.           ErrorBox (appDataBase.lastError)
  513.       end
  514.     end
  515. end;
  516.  
  517. {
  518. Lock, decrypt and unlock table.  Password must be in effect for decrypt to
  519. work.
  520. }
  521.  
  522. procedure DecryptTable;
  523.  
  524. var
  525.  
  526.   FileName : PathStr;
  527.  
  528. begin
  529.   FileName := SelectFile ('Decrypt Table','*.DB',true);
  530.   if FileName <> '' then
  531.   begin
  532.     UpdateStatus ('DECRYPT');
  533.     if appEngine.engineType <> pxLocal then
  534.     begin
  535.       if not ErrorBox (appDataBase.lockNetFile (FileName,pxFL)) then
  536.       begin
  537.         if appDataBase.decryptTable (FileName) = PXERR_INSUFRIGHTS then
  538.         begin
  539.           AddPassword;
  540.           ErrorBox (appDataBase.decryptTable (FileName))
  541.         end
  542.         else
  543.           ErrorBox (appDataBase.lastError);
  544.         ErrorBox (appDataBase.unlockNetFile (FileName,pxFL))
  545.       end
  546.     end
  547.     else
  548.       if appDataBase.decryptTable (FileName) = PXERR_INSUFRIGHTS then
  549.       begin
  550.         AddPassword;
  551.         ErrorBox (appDataBase.decryptTable (FileName))
  552.       end
  553.       else
  554.         ErrorBox (appDataBase.lastError)
  555.   end
  556. end;
  557.  
  558. {
  559. Switch between 25 and 43/50 line mode.
  560. }
  561.  
  562. procedure ToggleVideo;
  563.  
  564. var
  565.  
  566.   NewMode : word;
  567.   R : TRect;
  568.  
  569. begin
  570.   NewMode := ScreenMode xor smFont8x8;
  571.   if NewMode and smFont8x8 <> 0 then
  572.     ShadowSize.X := 1
  573.   else
  574.     ShadowSize.X := 2;
  575.   SetScreenMode (NewMode);
  576.   Desktop^.GetExtent (R)
  577. end;
  578.  
  579. {
  580. TV Demo calendar.
  581. }
  582.  
  583. procedure Calendar;
  584.  
  585. var
  586.  
  587.   P : PCalendarWindow;
  588.  
  589. begin
  590.   P := New(PCalendarWindow, Init);
  591.   InsertWindow(P)
  592. end;
  593.  
  594. {
  595. TV Demo calculator.
  596. }
  597.  
  598. procedure Calculator;
  599.  
  600. var
  601.  
  602.   P : PCalculator;
  603. begin
  604.   P := New(PCalculator, Init);
  605.   InsertWindow(P)
  606. end;
  607.  
  608. {
  609. View doc file.
  610. }
  611.  
  612. procedure ViewTextFile (FileName : PathStr);
  613.  
  614. var
  615.  
  616.   T : PTextWindow;
  617.   R : TRect;
  618.  
  619. begin
  620.   GetExtent (R);
  621.   R.Grow (-5,-4);
  622.   T := New(PTextWindow, Init(R, FileName));
  623.   T^.Options := T^.Options or ofCentered;
  624.   InsertWindow (T)
  625. end;
  626.  
  627. begin
  628.   if (Event.What = evCommand) and
  629.   (Event.Command = cmQuit) then
  630.     ClearDeskTop;
  631.   inherited HandleEvent (Event);
  632.   case Event.What of
  633.     evCommand:
  634.     case Event.Command of             {process commands}
  635.       cmOpenTable    : NewBrowser;
  636.       cmDeleteTable  : DeleteTable;
  637.       cmEmptyTable   : EmptyTable;
  638.       cmEncryptTable : EncryptTable;
  639.       cmDecryptTable : DecryptTable;
  640.       cmAddPassword  : AddPassword;
  641.       cmEngineConfig : EngineConfig;
  642.       cmToggleVideo  : ToggleVideo;
  643.       cmViewDoc      : ViewTextFile (appDocName);
  644.       cmCalendar     : Calendar;
  645.       cmCalculator   : Calculator;
  646.       cmAbout        : AboutBox;
  647.       cmCloseAll     : ClearDeskTop
  648.     end
  649.     else
  650.       Exit;
  651.     ClearEvent (Event)
  652.   end
  653. end;
  654.  
  655. procedure TCyberBase.InitMenuBar;
  656.  
  657. var
  658.  
  659.   R : TRect;
  660.  
  661. begin
  662.   GetExtent (R);
  663.   R.B.Y := R.A.Y+1;
  664.   MenuBar := New (PMenuBar,Init (R,NewMenu (
  665.     NewSubMenu ('~F~ile',hcNoContext,NewMenu (
  666.     NewSubMenu ('~T~able',hcNoContext,NewMenu (
  667.       NewItem ('~O~pen','F3',kbF3,cmOpenTable,hcNoContext,
  668.       NewItem ('~D~elete','',kbNoKey,cmDeleteTable,hcNoContext,
  669.       NewItem ('~E~mpty','',kbNoKey,cmEmptyTable,hcNoContext,
  670.       nil)))),
  671.     NewSubMenu ('~S~ecurity',hcNoContext,NewMenu (
  672.       NewItem ('~A~dd password','',kbNoKey,cmAddPassword,hcNoContext,
  673.       NewItem ('~E~ncrypt','',kbNoKey,cmEncryptTable,hcNoContext,
  674.       NewItem ('~D~ecrypt','',kbNoKey,cmDecryptTable,hcNoContext,
  675.       nil)))),
  676.       NewLine (
  677.       NewItem ('~C~alendar','',kbNoKey,cmCalendar,hcNoContext,
  678.       NewItem ('Ca~l~culator','',kbNoKey,cmCalculator,hcNoContext,
  679.       NewItem ('~V~iew doc','',kbNoKey,cmViewDoc,hcNoContext,
  680.       NewItem ('~A~bout','',kbNoKey,cmAbout,hcNoContext,
  681.       NewLine (
  682.       NewItem ('E~x~it','Alt-X',kbAltX,cmQuit,hcExit,
  683.       nil)))))))))),
  684.     NewSubMenu ('~O~ptions',hcNoContext,NewMenu (
  685.       NewItem ('~E~ngine','',kbNoKey,cmEngineConfig,hcNoContext,
  686.       NewItem ('~T~oggle video','',kbNoKey,cmToggleVideo,hcNoContext,
  687.       nil))),
  688.     NewSubMenu ('~W~indow',hcNoContext,NewMenu(
  689.       StdWindowMenuItems (
  690.       nil)),nil))))))
  691. end;
  692.  
  693. procedure TCyberBase.InitStatusLine;
  694.  
  695. var
  696.  
  697.   R : TRect;
  698.  
  699. begin
  700.   GetExtent (R);
  701.   R.A.Y := R.B.Y-1;
  702.   StatusLine := New (PStatusLine,Init(R,
  703.     NewStatusDef (0,$FFFF,
  704.       NewStatusKey ('~F3~ Open',kbF3,cmOpenTable,
  705.       NewStatusKey ('~Alt-F3~ Close',kbAltF3,cmClose,
  706.       NewStatusKey ('~Alt-X~ Exit',kbAltX,cmQuit,
  707.       NewStatusKey ('',kbCtrlF5,cmResize,
  708.       NewStatusKey ('',kbF10,cmMenu,
  709.       nil))))),nil)))
  710. end;
  711.  
  712. {
  713. Let user know if heap allocation cuts into the safety pool.
  714. }
  715.  
  716. procedure TCyberBase.OutOfMemory;
  717.  
  718. begin
  719.   MessageBox ('Not enough memory available to complete operation.  Try closing some windows!',
  720.   nil,mfError+mfOkButton);
  721. end;
  722.  
  723. var
  724.  
  725.   CBApp : TCyberBase;
  726.  
  727. begin
  728.   CBApp.Init;
  729.   CBApp.Run;
  730.   CBApp.Done
  731. end.
  732.