Subject IDE halts for 1 minute when exiting app
From Paolo Baranzoni Esseduesoft <paolobaranzoni@aruba.it>
Date Tue, 31 Aug 2021 18:02:56 +0200
Newsgroups dbase.getting-started
Attachment(s) GenericMDIApp.ccsetup.prgstart.prgtutorial.mnu

I'm trying to build an mdi app following the dBase tutorial.
But when i exit the app and go back to dBase IDE and try to open a file
in the source code editor (or design) then IDE halts for almost a minute
waiting for "i dont know what" and finally opens the source code editor.
I use dBase2019 on Windows10 pro 64bit.
Attached the four files (but they are almost the same as the tutorial)
Is there something wrong?
Thanks

Paolo B.

--
Questa e-mail รจ stata controllata per individuare virus con Avast antivirus.
https://www.avast.com/antivirus



/*
     GenericMDIApp.CC
     From the dBASE Tutorial that was updated/maintained by
     Michael Nuwer for years ...
          
          Minor update, July 2014 by Geep Howell
          (as noted) in the Close method, for
     current versions of dBASE (9.x).

     A simple custom class file that contains
     a "generic" MDI application object. This
     object, when used properly, is subclassed
     and the subclass has the following:

     set procedure to genericMDIApp.cc additive
     class TestMDIApp of genericMDIApp()
        this.FrameWinText = "Some Text for _app.framewin"
        this.MenuClassName = "MenuClassname"
     endclass

     A startup program for this would assume that you
     have a "SETUP" program, which opens any custom
     control files necessary (and does whatever else
     may be needed), instantiates the subclassed
     MDI application object, and then starts it
     with the 'start' method:

     app = new TestMDIApp()
     return ( app.open() )
*/
class GenericMDIApp

   // This custom property should be overwritten
   // in a subclass, or after instantiation, but
   // before the Open() method is invoked:
   this.FrameWinText = "Generic MDI application"

   // The same goes for this custom property:
   this.MenuClassName = "MyMainMenu"

   // We assume here that every MDI app will have
   // a SETUP.PRG
   do setup

   // Assign a property to _app.frameWin, which is
   // a reference to this object: "this".
   _app.framewin.app = this

   function Open

      // set a reference to the menu
      private c
      c = 'this.rootMenu = new '+this.MenuClassName+'(_app.framewin,"Root")'
      &c.

      // Make sure no forms are open
      close forms

      // Make sure we're not in "design mode"
      set design off

      // set the <Escape> key "off" but store the
      // current setting:
      this.OldEscape = set("ESCAPE")
      set escape off

      // Turn off the dBASE Plus shell, but
      // leave the MDI frame window:
      shell( false, true )
      
      // Turn off the application's speedBar, statusBar, and tabBar
      // however, for a true MDI app, you may actually want
      // the tabBar turned on:
      _app.speedbar  := false
      _app.statusBar := false
      _app.tabBar    := false

      // Set the text property for the application's framewin
      _app.framewin.oldText = _app.framewin.text
      _app.framewin.text    := this.FrameWinText

   return

   Function close

      // close any forms that might have been left open
      close forms

      // set escape back to whatever it's previous
      // state was:
      cEscape = this.oldEscape
      set escape &cEscape.

      // set the shell back ...
      shell( true, true )

      // if we are in the "runtime" environment,
      // we want to "quit" (otherwise the framewin will
      // be left on screen)
      if ( "runtime" $ lower( version(0) ) )
         quit
      else
         // otherwise, let's reset some values:
         with ( _app )
            framewin.app  := null
            framewin.text := framewin.OldText
            speedBar      := true
            statusBar     := true
            tabBar        := true
         endwith

         // go back to design mode:
         set design on

              // close any open procedures
         set procedure to

         // release the menu
         _app.framewin.root.release()

      endif

   return

endclass // don't forget this!


/*
   ----------------------------------------------------------------------------
   setup.prg
   The setup program written for:
  
   The dBASE Plus Tutorial: Developing An Application
   January, 2017, Ken Mayer
  
   Permission is granted to use this in your own applications, with the caveat
   that credit be given appropriately.
  
   This program makes sure the environment is normal, but then sets up the
   application object (based on GenericMDIApp.cc), and more.
   ----------------------------------------------------------------------------
*/
// These always get me -- if the program
// crashes, and they usually do while developing --
// (due to programmer error), the speedBar, the
// statusBar, and the tabBar in the IDE is not available ...  
// this just puts them back. The MDI application class turns
// them back off and on as needed ...

_app.speedbar  := true
_app.statusBar := true
_app.tabBar    := true

// this can also cause problems:
set design on

// Set procedures ...:
set procedure to start

// make sure the menu is available:
set procedure to tutorial.mnu

// custom controls used by the application

// add others as needed here:



/*
    START.PRG
    Author: Ken Mayer
    Date  : January 13, 2017

    Tutorial project START program

    This program is used to start the TUTORIAL
    application.

    There is a reference to another .CC, which is
    the genericMDIApp.CC file -- this contains
    the generic application object, and below we
    subclass it ...

    The idea is that you have a lot of "things" that
    you always do for any application that is
    an MDI app. You create one object that handles
    all of that, and then you subclass that for
    the specifics for an application, as each is
    at least slightly different.
*/

   //update this for application version changes:
   #define AppVersion "4.0" // Version 4 of this tutorial project
   set talk off

   // set the private directory for the BDE
   // uses BDE (IDAPI) API Code below the TutorialApp
   // definition -- this uses a default folder,
   // no need to pass a value:
   setPrivateDir()

   // set up the application object:
   local app
   set procedure to GenericMDIApp.cc
   app = new TutorialApp()
   app.open()

return

/*
   TutorialApp is a subclass of the "GenericMDIApp" contained
   in the .cc file of the same name:
*/
class TutorialApp of GenericMDIApp
   // set any specific code for the subclassed
   // MDI application here - note this uses the AppVersion constant
   // created above for the version number:
   this.FrameWinText = "dBASE Plus Tutorial Project -- vers. " + AppVersion

   // note this is not the file name -- the
   // SETUP program must execute "set procedure ..." that
   // will open the file "Tutorial.mnu" ... the class
   // will be available from that point on. This is
   // the classname of the menu:
   this.MenuClassName = "TutorialMenu"

endclass

/*
   Code that deals with setting the private folder for the BDE
   to write _QSQLnnnn.dbf files, this is API code and a bit involved.
   Provided by Wian in the dBASE newsgroups, but appears to have
   been originally provided by Rick Miller.
*/
function setPrivateDir( cPath )
   if not type("DbiSetPrivateDir") == "FP"
      extern CUSHORT DbiSetPrivateDir(CSTRING) idapi32 from "DbiSetPrivateDir"
   endif

   Local cDir
   if type("argVector(1)") == "C"
      cDir  =  cPath
   else
      // when cDir == null, reset to default.
      cDir  =  null
   endif
return iif( DbiSetPrivateDir( cDir ) == 0, true, false )


/*
   ----------------------------------------------------------------------------
   tutorial.mnu
   A basic menu, written for:
  
   The dBASE Plus Tutorial: Developing An Application
   January, 2017, Ken Mayer
  
   Permission is granted to use this in your own applications, with the caveat
   that credit be given appropriately.
   ----------------------------------------------------------------------------
*/
** END HEADER -- do not remove this line
//
// Generated on 01/13/2017
//
parameter formObj
new TUTORIALMENU(formObj, "root")

class TUTORIALMENU(formObj, name) of MENUBAR(formObj, name)
   this.FILE = new MENU(this)
   with (this.FILE)
      text = "&File"
   endwith

   this.FILE.OPEN = new MENU(this.FILE)
   with (this.FILE.OPEN)
      text = "&Open"
   endwith

   this.FILE.OPEN.CUSTOMERS = new MENU(this.FILE.OPEN)
   with (this.FILE.OPEN.CUSTOMERS)
      text = "Customers"
   endwith

   this.FILE.OPEN.INVENTORY = new MENU(this.FILE.OPEN)
   with (this.FILE.OPEN.INVENTORY)
      text = "Inventory"
   endwith

   this.FILE.OPEN.SUPPLIER = new MENU(this.FILE.OPEN)
   with (this.FILE.OPEN.SUPPLIER)
      text = "Supplier"
   endwith

   this.FILE.OPEN.INVOICES = new MENU(this.FILE.OPEN)
   with (this.FILE.OPEN.INVOICES)
      text = "Invoices"
   endwith

   this.FILE.OPEN.LOOKUPS = new MENU(this.FILE.OPEN)
   with (this.FILE.OPEN.LOOKUPS)
      text = "Lookups"
   endwith

   this.FILE.OPEN.LOOKUPS.STATE = new MENU(this.FILE.OPEN.LOOKUPS)
   with (this.FILE.OPEN.LOOKUPS.STATE)
      text = "State"
   endwith

   this.FILE.OPEN.LOOKUPS.COUNTRY = new MENU(this.FILE.OPEN.LOOKUPS)
   with (this.FILE.OPEN.LOOKUPS.COUNTRY)
      text = "Country"
   endwith

   this.FILE.CLOSE = new MENU(this.FILE)
   with (this.FILE.CLOSE)
      onClick = class::CLOSE_ONCLICK
      text = "&Close"
   endwith

   this.FILE.SEPARATOR1 = new MENU(this.FILE)
   with (this.FILE.SEPARATOR1)
      text = ""
      separator = true
   endwith

   this.FILE.EXIT = new MENU(this.FILE)
   with (this.FILE.EXIT)
      onClick = class::EXIT_ONCLICK
      text = "E&xit"
   endwith

   this.REPORTS = new MENU(this)
   with (this.REPORTS)
      text = "&Reports"
   endwith

   this.REPORTS.SUPPLIER = new MENU(this.REPORTS)
   with (this.REPORTS.SUPPLIER)
      text = "Supplier Information"
   endwith

   this.REPORTS.INVENTORY = new MENU(this.REPORTS)
   with (this.REPORTS.INVENTORY)
      text = "Inventory Summary"
   endwith

   this.REPORTS.STATEMENTS = new MENU(this.REPORTS)
   with (this.REPORTS.STATEMENTS)
      text = "Customer Statements"
   endwith

   this.REPORTS.SEPARATOR2 = new MENU(this.REPORTS)
   with (this.REPORTS.SEPARATOR2)
      text = ""
      separator = true
   endwith

   this.REPORTS.LABELS = new MENU(this.REPORTS)
   with (this.REPORTS.LABELS)
      text = "Customer Address Labels"
   endwith

   this.WINDOW = new MENU(this)
   with (this.WINDOW)
      text = "&Window"
   endwith

   this.WINDOW.MENU10 = new MENU(this.WINDOW)
   with (this.WINDOW.MENU10)
      text = "&Cascade"
      windowMenuItem = 1        // Cascade
   endwith

   this.WINDOW.MENU9 = new MENU(this.WINDOW)
   with (this.WINDOW.MENU9)
      text = "Tile &Vertically"
      windowMenuItem = 3        // Tile Vertically
   endwith

   this.WINDOW.MENU8 = new MENU(this.WINDOW)
   with (this.WINDOW.MENU8)
      text = "&Tile Horizontally"
      windowMenuItem = 2        // Tile Horizontally
   endwith

   this.WINDOW.MENU7 = new MENU(this.WINDOW)
   with (this.WINDOW.MENU7)
      text = "Arrange &Icons"
      windowMenuItem = 4        // Arrange Icons
   endwith

   this.WINDOW.CLOSEALL = new MENU(this.WINDOW)
   with (this.WINDOW.CLOSEALL)
      onClick = {; close forms}
      text = "Close &All"
      windowMenuItem = 5        // Close All
   endwith

   this.HELP = new MENU(this)
   with (this.HELP)
      text = "&Help"
   endwith

   this.HELP.ABOUT = new MENU(this.HELP)
   with (this.HELP.ABOUT)
      text = "&About Tutorial"
   endwith

   this.windowMenu = this.window
        
   function CLOSE_onClick()
      // close current form if there is one
      if type( "_app.framewin.currentForm" ) == "O"
         _app.framewin.currentForm.close()
      else
         msgbox( "The currently active form cannot be closed "+;
                 "with this option.","Can't do it!", 64 )
      endif
   return

   function EXIT_onClick()
   return( _app.framewin.app.close() )

   function OpenForm( oForm )
     // set the top/left properties so the form isn't
     // *right* on top of the current one ...
     if type( "_app.framewin.currentForm" ) == "O"
        oForm.top  := _app.framewin.currentForm.top + 40
        oForm.left := _app.framewin.currentForm.left + 40
     else
        oForm.top  := 0
        oForm.left := 10
     endif
     oForm.open()
     oForm.setFocus()
   return
  
endclass