Here's the solution that I developed for the ProcBrowser and WindowBrowser utilities that shipped on CRL3. It's easy to use and requires only minor changes to the window-handling code in your application. For efficiency, it retains & re-uses all the duplicates that it creates. It also automatically handles the deletion of obsolete duplicates when you update the master format.


As an example, assume you have a window format, wCustomer, that you would like to convert to a multiple-instance window: First, you need to ensure that wCustomer stores all of its data in format variables, i.e. no globals. It _can_ use CRB fields, but only for temporary or scratch purposes, such as reading/writing data to disk. (This encapsulation is necessary, regardless of how you implement multiple instances). Then follow these steps:

1) Rename wCustomer as wCustomer01. (This is the master format, and it also serves as instance #1).

2) Choose any menu format in your library (e.g. STARTUP ) and add the following two format vars and three procedures:

 Format variable fMaster  (char 10000000) = 'wCustomer'
 Format variable fAllocTable  (char 10000000)

Procedure Initialize

 Local variable  lWindows (List)
 Local variable  lWind_Name  (char  10000000)
 Local variable  lWind_ModDate  (Short date 1980-2079)

 Calculate lWindows as $clib.$windows.$makelist($ref.$name,$ref.$moddate)

 Set current list lWindows
 Redefine list {lWind_Name, lWind_ModDate}
  ;; Find and delete obsolete duplicates, if any, by comparing moddates

 Set search as calculation {mid(lWind_Name, 1, len(fMaster))=fMaster &

 Search list (From start, Select matches (OR), Deselect non-matches (AND))
 For each line in list (Selected lines only) from 1 to #LN step 1
    Delete format {[lst(lWind_Name)]
 End for
 Delete selected lines      ;; Now delete them from the list too
  ;; Build a string of zeros in fAllocTable to serve as a bitmap

 Calculate %NumDupes as totc(mid(lWind_Name,1,len(fMaster)))=fMaster
 Calculate fAllocTable as jst('',con(%NumDupes,'P0'))

Procedure GetInstance

 Local variable lBitPos  (Long integer)
 Calculate lBitPos as pos('0',fAllocTable)   ;; Look for unused format

 If not(lBitPos)   ;; If they're all in use
   Calculate lBitPos as len(fAllocTable)+1  ;; Get next format number
   Duplicate format {[$clib().$name].[fMaster]01/[con(fMaster,jst(lBitPos,'-2P0'))]} ;; Clone the master format

   If flag false   ;; If duplication failed
     OK message (Sound bell) {Unable to create new instance!}
     Set return value {''}   ;; Return empty name to indicate failure
     Quit procedure
   End if
 End if

 ;; Set the appropriate bit to 1 to indicate that the format is now in use
 Calculate fAllocTable as con(mid(fAllocTable,1,lBitPos-1),1,mid(fAllocTable,lBitPos+1,100))

 Set return value {con(fMaster,jst(lBitPos,'-2P0'))}  ;; Return the name of the new 'instance' 

Procedure FreeInstance

 Parameter pInstanceName  (Character 100)
 ;; Get the position of this format's bit in the allocation bitmap

 Calculate %BitPos as mid(pInstanceName, len(pInstanceName)-1,2)
 ;; Set it back to zero to indicate that it's available for use

 Calculate fAllocTable as

3) Ensure that the 'Initialize' procedure above is called when your library opens, i.e. add a "Call procedure Initialize" in your STARTUP/0.

4) This is how you create new instances: Search your library for all the places where you open the window wCustomer. These could be commands such as "Open window wCustomer" or "Call procedure wCustomer/Open", etc. Replace each such occurrence with:

 Call procedure STARTUP/GetInstance with return value %%InstanceName
 If len(%%instanceName)
   Open [%%InstanceName]     ;; or Call proc [%%InstanceName]/Open, etc
 End if

5) This is what you do when you're done with the instance: Modify your window control procedure in wCustomer01 as follows:

   Call procedure Close
   SNA Do not perform default action
 Else if #WCLICK; etc, etc.

Now add this procedure to wCustomer01:

 Close  ;; Do all the stuff you normally do upon closing your window, then
Call procedure STARTUP/FreeInstance ($cformat().$name) Close window $format

6) Make sure that there are no other "Close window wCustomer" commands anywhere in your library (This is generally a bad practice anyway). If you do have code that closes the top window or all open windows, have it call the window's Close routine instead. Whenever you need to make changes to your master format, just update and deploy wCustomer01. The next time the library is opened, it will automatically first delete any older duplicates of the format.

Go to top
JSN Boot template designed by