Build a multi-document workspace
Host related document windows while keeping independent windows separate.
MDI is a Form relationship, not merely a window style. The sample distinguishes child documents from an independent Form. Track each instance’s lifetime and test how closing a document differs from closing the workspace.
Step 1Prepare a safe practice project#
Extract the archive into a new writable folder, separate from your own application. Open MdiForms.mcproj in McBasic™. Keep every declared source, layout, resource and migration file together.
To reconstruct it yourself, create a DesktopApp project and add the files declared below. In the complete project, follow these steps as a guided rebuild: replace each named source file once and Check after all its procedures are present.
Exact project configuration
{
"schemaVersion": 1,
"projectId": "357c7963-827f-484a-b5a8-3714b1d6ea04",
"name": "MdiForms",
"kind": "DesktopApp",
"language": {
"dialect": "McBasic1",
"requireExplicit": true,
"compare": "Binary",
"defaultArrayBase": 0
},
"application": {
"bundleIdentifier": "com.mcbasic.samples.mdiforms",
"version": "0.1.0",
"buildNumber": "1",
"startupFormId": "form-main",
"shutdownMode": "OnStartupFormClosed"
},
"forms": [
{
"id": "form-main",
"typeName": "frmMain",
"layout": "Forms/frmMain.form.json",
"code": "Forms/frmMain.bas"
},
{
"id": "form-details",
"typeName": "frmDetails",
"layout": "Forms/frmDetails.form.json",
"code": "Forms/frmDetails.bas"
},
{
"id": "form-independent",
"typeName": "frmIndependent",
"layout": "Forms/frmIndependent.form.json",
"code": "Forms/frmIndependent.bas"
},
{
"id": "form-other",
"typeName": "frmOther",
"layout": "Forms/frmOther.form.json",
"code": "Forms/frmOther.bas"
}
],
"modules": [],
"classes": [],
"tests": [],
"references": [],
"resources": [],
"targets": [
"osx-arm64"
],
"capabilities": []
}Step 2Build the Form and set its properties#
frmMain
Select the Form first and set its properties. Add containers before their children. These are initial Designer values, not statements to paste into a procedure.
| Form property | Value |
|---|---|
Caption | "MDI Forms" |
Width | 900 |
Height | 600 |
MinWidth | 520 |
MinHeight | 480 |
MDIForm | True |
MDIClientTop | 288 |
| Type | Name | Parent |
|---|---|---|
| Label | lblIntro | Form |
| CommandButton | cmdAlpha | Form |
| CommandButton | cmdBeta | Form |
| Label | lblStatus | Form |
| CommandButton | cmdClose | Form |
| CommandButton | cmdIndependent | Form |
lblIntro · exact Inspector values
| Property | Value |
|---|---|
Left | 24 |
Top | 24 |
Width | 500 |
Height | 44 |
Caption | "Two child forms share this window; another form stays independent." |
| Anchor edges | Left, Top |
cmdAlpha · exact Inspector values
| Property | Value |
|---|---|
Left | 24 |
Top | 92 |
Width | 160 |
Height | 38 |
Caption | "Open Alpha" |
TabIndex | 0 |
| Anchor edges | Left, Top |
cmdBeta · exact Inspector values
| Property | Value |
|---|---|
Left | 200 |
Top | 92 |
Width | 160 |
Height | 38 |
Caption | "Open Beta" |
TabIndex | 1 |
| Anchor edges | Left, Top |
lblStatus · exact Inspector values
| Property | Value |
|---|---|
Left | 24 |
Top | 158 |
Width | 500 |
Height | 52 |
Caption | "Ready. No secondary Forms are open." |
| Anchor edges | Left, Top |
cmdClose · exact Inspector values
| Property | Value |
|---|---|
Left | 24 |
Top | 236 |
Width | 160 |
Height | 38 |
Caption | "Close main Form" |
TabIndex | 2 |
| Anchor edges | Left, Top |
cmdIndependent · exact Inspector values
| Property | Value |
|---|---|
Left | 376 |
Top | 92 |
Width | 160 |
Height | 38 |
Caption | "Show independent" |
TabIndex | 3 |
| Anchor edges | Left, Top |
frmDetails
Select the Form first and set its properties. Add containers before their children. These are initial Designer values, not statements to paste into a procedure.
| Form property | Value |
|---|---|
Caption | "Details window" |
Width | 360 |
Height | 220 |
MinWidth | 320 |
MinHeight | 190 |
MDIChild | True |
| Type | Name | Parent |
|---|---|---|
| Label | lblName | Form |
| CommandButton | cmdHide | Form |
| CommandButton | cmdUnload | Form |
lblName · exact Inspector values
| Property | Value |
|---|---|
Left | 24 |
Top | 24 |
Width | 300 |
Height | 44 |
Caption | "Details window" |
| Anchor edges | Left, Top |
cmdHide · exact Inspector values
| Property | Value |
|---|---|
Left | 24 |
Top | 96 |
Width | 140 |
Height | 36 |
Caption | "Hide window" |
TabIndex | 0 |
| Anchor edges | Left, Top |
cmdUnload · exact Inspector values
| Property | Value |
|---|---|
Left | 176 |
Top | 96 |
Width | 140 |
Height | 36 |
Caption | "Unload window" |
TabIndex | 1 |
| Anchor edges | Left, Top |
frmIndependent
Select the Form first and set its properties. Add containers before their children. These are initial Designer values, not statements to paste into a procedure.
| Form property | Value |
|---|---|
Caption | "Independent form" |
Width | 420 |
Height | 420 |
MinWidth | 420 |
MinHeight | 420 |
| Type | Name | Parent |
|---|---|---|
| Label | lblName | Form |
| CommandButton | cmdHide | Form |
| CommandButton | cmdUnload | Form |
| CommandButton | cmdCascade | Form |
| CommandButton | cmdTileHorizontal | Form |
| CommandButton | cmdTileVertical | Form |
| CommandButton | cmdCheckActive | Form |
| CommandButton | cmdHideActive | Form |
lblName · exact Inspector values
| Property | Value |
|---|---|
Left | 24 |
Top | 24 |
Width | 300 |
Height | 44 |
Caption | "Details window" |
| Anchor edges | Left, Top |
cmdHide · exact Inspector values
| Property | Value |
|---|---|
Left | 24 |
Top | 96 |
Width | 140 |
Height | 36 |
Caption | "Hide window" |
TabIndex | 0 |
| Anchor edges | Left, Top |
cmdUnload · exact Inspector values
| Property | Value |
|---|---|
Left | 176 |
Top | 96 |
Width | 140 |
Height | 36 |
Caption | "Unload window" |
TabIndex | 1 |
| Anchor edges | Left, Top |
cmdCascade · exact Inspector values
| Property | Value |
|---|---|
Left | 24 |
Top | 160 |
Width | 220 |
Height | 36 |
Caption | "Cascade" |
TabIndex | 2 |
| Anchor edges | Left, Top |
cmdTileHorizontal · exact Inspector values
| Property | Value |
|---|---|
Left | 24 |
Top | 205 |
Width | 220 |
Height | 36 |
Caption | "Tile horizontal" |
TabIndex | 3 |
| Anchor edges | Left, Top |
cmdTileVertical · exact Inspector values
| Property | Value |
|---|---|
Left | 24 |
Top | 250 |
Width | 220 |
Height | 36 |
Caption | "Tile vertical" |
TabIndex | 4 |
| Anchor edges | Left, Top |
cmdCheckActive · exact Inspector values
| Property | Value |
|---|---|
Left | 24 |
Top | 295 |
Width | 220 |
Height | 30 |
Caption | "Check active child" |
TabIndex | 5 |
| Anchor edges | Left, Top |
cmdHideActive · exact Inspector values
| Property | Value |
|---|---|
Left | 24 |
Top | 340 |
Width | 220 |
Height | 32 |
Caption | "Hide active child" |
TabIndex | 6 |
| Anchor edges | Left, Top |
frmOther
Select the Form first and set its properties. Add containers before their children. These are initial Designer values, not statements to paste into a procedure.
| Form property | Value |
|---|---|
Caption | "Other child" |
Width | 360 |
Height | 220 |
MinWidth | 320 |
MinHeight | 190 |
MDIChild | True |
| Type | Name | Parent |
|---|---|---|
| Label | lblName | Form |
| CommandButton | cmdHide | Form |
| CommandButton | cmdUnload | Form |
| CommandButton | cmdCancelClose | Form |
| CommandButton | cmdFailClose | Form |
lblName · exact Inspector values
| Property | Value |
|---|---|
Left | 24 |
Top | 24 |
Width | 300 |
Height | 44 |
Caption | "Details window" |
| Anchor edges | Left, Top |
cmdHide · exact Inspector values
| Property | Value |
|---|---|
Left | 24 |
Top | 96 |
Width | 140 |
Height | 36 |
Caption | "Hide window" |
TabIndex | 0 |
| Anchor edges | Left, Top |
cmdUnload · exact Inspector values
| Property | Value |
|---|---|
Left | 176 |
Top | 96 |
Width | 140 |
Height | 36 |
Caption | "Unload window" |
TabIndex | 1 |
| Anchor edges | Left, Top |
cmdCancelClose · exact Inspector values
| Property | Value |
|---|---|
Left | 24 |
Top | 144 |
Width | 140 |
Height | 36 |
Caption | "Cancel next close" |
TabIndex | 2 |
| Anchor edges | Left, Top |
cmdFailClose · exact Inspector values
| Property | Value |
|---|---|
Left | 176 |
Top | 144 |
Width | 140 |
Height | 36 |
Caption | "Error next close" |
TabIndex | 3 |
| Anchor edges | Left, Top |
Step 3Connect the events explicitly#
frmMain
| Object | Event | Procedure | Parameters |
|---|---|---|---|
cmdAlpha | Click | cmdAlpha_Click | Click() |
cmdBeta | Click | cmdBeta_Click | Click() |
cmdClose | Click | cmdClose_Click | Click() |
cmdIndependent | Click | cmdIndependent_Click | Click() |
| Form | Shown | Form_Shown | () |
frmDetails
| Object | Event | Procedure | Parameters |
|---|---|---|---|
cmdHide | Click | cmdHide_Click | Click() |
cmdUnload | Click | cmdUnload_Click | Click() |
| Form | Initialize | Form_Initialize | () |
| Form | Load | Form_Load | () |
| Form | Shown | Form_Shown | () |
| Form | QueryUnload | Form_QueryUnload | (ByRef Cancel As Integer, ByVal UnloadMode As Integer) |
| Form | Unload | Form_Unload | () |
frmIndependent
| Object | Event | Procedure | Parameters |
|---|---|---|---|
cmdHide | Click | cmdHide_Click | Click() |
cmdUnload | Click | cmdUnload_Click | Click() |
cmdCascade | Click | cmdCascade_Click | Click() |
cmdTileHorizontal | Click | cmdTileHorizontal_Click | Click() |
cmdTileVertical | Click | cmdTileVertical_Click | Click() |
cmdCheckActive | Click | cmdCheckActive_Click | Click() |
cmdHideActive | Click | cmdHideActive_Click | Click() |
| Form | Initialize | Form_Initialize | () |
| Form | Load | Form_Load | () |
| Form | Shown | Form_Shown | () |
| Form | QueryUnload | Form_QueryUnload | (ByRef Cancel As Integer, ByVal UnloadMode As Integer) |
| Form | Unload | Form_Unload | () |
frmOther
| Object | Event | Procedure | Parameters |
|---|---|---|---|
cmdHide | Click | cmdHide_Click | Click() |
cmdUnload | Click | cmdUnload_Click | Click() |
cmdCancelClose | Click | cmdCancelClose_Click | Click() |
cmdFailClose | Click | cmdFailClose_Click | Click() |
| Form | Initialize | Form_Initialize | () |
| Form | Load | Form_Load | () |
| Form | Shown | Form_Shown | () |
| Form | QueryUnload | Form_QueryUnload | (ByRef Cancel As Integer, ByVal UnloadMode As Integer) |
| Form | Unload | Form_Unload | () |
Step 4Enter the complete behavior#
Open the named source file. Enter declarations first, then every procedure. Expand a procedure for its full body, or copy the complete file. Helpers are required: do not stop after entering the first Click handler.
Forms/frmMain.bas
Enter these declarations at file scope, before the procedures.
Option Explicit
Public ActiveAlpha As frmDetails
Public ActiveBeta As frmOtherPrivate Sub Form_Shown()
Initialize state before enabling dependent actions. Keep the shared declarations and startup dependencies with this procedure.
Private Sub Form_Shown()
Dim alpha As frmDetails
Dim beta As frmOther
Dim active As Form
Set alpha = New frmDetails
Set beta = New frmOther
Set ActiveAlpha = alpha
Set ActiveBeta = beta
alpha.DisplayName = "Alpha"
beta.DisplayName = "Beta"
Debug.Print "active-empty:" & (Me.ActiveForm Is Nothing)
alpha.Show
Set active = Me.ActiveForm
Debug.Print "active-alpha:" & (active Is alpha)
beta.Show
Set active = Me.ActiveForm
Debug.Print "active-beta:" & (active Is beta)
Me.Arrange vbCascade
frmIndependent.Show
lblStatus.Caption = "Two MDI children and one independent window."
End SubPrivate Sub cmdAlpha_Click()
Enter the complete action, including its input checks and calls to helper procedures.
Private Sub cmdAlpha_Click()
Dim alpha As frmDetails
Set alpha = New frmDetails
alpha.DisplayName = "Alpha"
alpha.Show
lblStatus.Caption = "Another Alpha child opened inside MDI Forms."
End SubPrivate Sub cmdBeta_Click()
Enter the complete action, including its input checks and calls to helper procedures.
Private Sub cmdBeta_Click()
Dim beta As frmOther
Set beta = New frmOther
beta.DisplayName = "Beta"
beta.Show
lblStatus.Caption = "Another Beta child opened inside MDI Forms."
End SubPrivate Sub cmdClose_Click()
Enter the complete action, including its input checks and calls to helper procedures.
Private Sub cmdClose_Click()
Unload Me
End SubPrivate Sub cmdIndependent_Click()
Enter the complete action, including its input checks and calls to helper procedures.
Private Sub cmdIndependent_Click()
frmIndependent.Show
lblStatus.Caption = "Independent window shown outside the MDI container."
End SubCopy the complete Forms/frmMain.bas file
Replace the file once; do not append duplicate procedures.
Option Explicit
Public ActiveAlpha As frmDetails
Public ActiveBeta As frmOther
Private Sub Form_Shown()
Dim alpha As frmDetails
Dim beta As frmOther
Dim active As Form
Set alpha = New frmDetails
Set beta = New frmOther
Set ActiveAlpha = alpha
Set ActiveBeta = beta
alpha.DisplayName = "Alpha"
beta.DisplayName = "Beta"
Debug.Print "active-empty:" & (Me.ActiveForm Is Nothing)
alpha.Show
Set active = Me.ActiveForm
Debug.Print "active-alpha:" & (active Is alpha)
beta.Show
Set active = Me.ActiveForm
Debug.Print "active-beta:" & (active Is beta)
Me.Arrange vbCascade
frmIndependent.Show
lblStatus.Caption = "Two MDI children and one independent window."
End Sub
Private Sub cmdAlpha_Click()
Dim alpha As frmDetails
Set alpha = New frmDetails
alpha.DisplayName = "Alpha"
alpha.Show
lblStatus.Caption = "Another Alpha child opened inside MDI Forms."
End Sub
Private Sub cmdBeta_Click()
Dim beta As frmOther
Set beta = New frmOther
beta.DisplayName = "Beta"
beta.Show
lblStatus.Caption = "Another Beta child opened inside MDI Forms."
End Sub
Private Sub cmdClose_Click()
Unload Me
End Sub
Private Sub cmdIndependent_Click()
frmIndependent.Show
lblStatus.Caption = "Independent window shown outside the MDI container."
End SubForms/frmDetails.bas
Enter these declarations at file scope, before the procedures.
Option Explicit
Public DisplayName As StringPrivate Sub Form_Initialize()
Initialize state before enabling dependent actions. Keep the shared declarations and startup dependencies with this procedure.
Private Sub Form_Initialize()
Debug.Print "initialize:" & DisplayName
End SubPrivate Sub Form_Load()
Initialize state before enabling dependent actions. Keep the shared declarations and startup dependencies with this procedure.
Private Sub Form_Load()
Debug.Print "load:" & DisplayName
End SubPrivate Sub Form_Shown()
Initialize state before enabling dependent actions. Keep the shared declarations and startup dependencies with this procedure.
Private Sub Form_Shown()
lblName.Caption = "Details window: " & DisplayName
Debug.Print "shown:" & DisplayName
End SubPrivate Sub cmdHide_Click()
Enter the complete action, including its input checks and calls to helper procedures.
Private Sub cmdHide_Click()
Me.Hide
Debug.Print "hidden:" & DisplayName
End SubPrivate Sub cmdUnload_Click()
Enter the complete action, including its input checks and calls to helper procedures.
Private Sub cmdUnload_Click()
Unload Me
End SubPrivate Sub Form_QueryUnload(ByRef Cancel As Integer, ByVal UnloadMode As Integer)
This is the lifetime boundary. Preserve the cancellation signature where present and release resources owned by this Form.
Private Sub Form_QueryUnload(ByRef Cancel As Integer, ByVal UnloadMode As Integer)
Debug.Print "query:" & DisplayName & ":" & UnloadMode
End SubPrivate Sub Form_Unload()
This is the lifetime boundary. Preserve the cancellation signature where present and release resources owned by this Form.
Private Sub Form_Unload()
Debug.Print "unload:" & DisplayName
End SubCopy the complete Forms/frmDetails.bas file
Replace the file once; do not append duplicate procedures.
Option Explicit
Public DisplayName As String
Private Sub Form_Initialize()
Debug.Print "initialize:" & DisplayName
End Sub
Private Sub Form_Load()
Debug.Print "load:" & DisplayName
End Sub
Private Sub Form_Shown()
lblName.Caption = "Details window: " & DisplayName
Debug.Print "shown:" & DisplayName
End Sub
Private Sub cmdHide_Click()
Me.Hide
Debug.Print "hidden:" & DisplayName
End Sub
Private Sub cmdUnload_Click()
Unload Me
End Sub
Private Sub Form_QueryUnload(ByRef Cancel As Integer, ByVal UnloadMode As Integer)
Debug.Print "query:" & DisplayName & ":" & UnloadMode
End Sub
Private Sub Form_Unload()
Debug.Print "unload:" & DisplayName
End SubForms/frmIndependent.bas
Enter these declarations at file scope, before the procedures.
Option Explicit
Public DisplayName As StringPrivate Sub Form_Initialize()
Initialize state before enabling dependent actions. Keep the shared declarations and startup dependencies with this procedure.
Private Sub Form_Initialize()
Debug.Print "initialize:" & DisplayName
End SubPrivate Sub Form_Load()
Initialize state before enabling dependent actions. Keep the shared declarations and startup dependencies with this procedure.
Private Sub Form_Load()
Debug.Print "load:" & DisplayName
End SubPrivate Sub Form_Shown()
Initialize state before enabling dependent actions. Keep the shared declarations and startup dependencies with this procedure.
Private Sub Form_Shown()
lblName.Caption = "Details window: " & DisplayName
Debug.Print "shown:" & DisplayName
End SubPrivate Sub cmdHide_Click()
Enter the complete action, including its input checks and calls to helper procedures.
Private Sub cmdHide_Click()
Me.Hide
Debug.Print "hidden:" & DisplayName
End SubPrivate Sub cmdUnload_Click()
Enter the complete action, including its input checks and calls to helper procedures.
Private Sub cmdUnload_Click()
Unload Me
End SubPrivate Sub cmdCascade_Click()
Enter the complete action, including its input checks and calls to helper procedures.
Private Sub cmdCascade_Click()
frmMain.Arrange vbCascade
Debug.Print "arrange:cascade"
End SubPrivate Sub cmdTileHorizontal_Click()
Enter the complete action, including its input checks and calls to helper procedures.
Private Sub cmdTileHorizontal_Click()
frmMain.Arrange vbTileHorizontal
Debug.Print "arrange:horizontal"
End SubPrivate Sub cmdTileVertical_Click()
Enter the complete action, including its input checks and calls to helper procedures.
Private Sub cmdTileVertical_Click()
frmMain.Arrange vbTileVertical
Debug.Print "arrange:vertical"
End SubPrivate Sub cmdCheckActive_Click()
Enter the complete action, including its input checks and calls to helper procedures.
Private Sub cmdCheckActive_Click()
Debug.Print "active-alpha-now:" & (frmMain.ActiveForm Is frmMain.ActiveAlpha)
Debug.Print "active-beta-now:" & (frmMain.ActiveForm Is frmMain.ActiveBeta)
Debug.Print "active-none-now:" & (frmMain.ActiveForm Is Nothing)
End SubPrivate Sub cmdHideActive_Click()
Enter the complete action, including its input checks and calls to helper procedures.
Private Sub cmdHideActive_Click()
If Not (frmMain.ActiveForm Is Nothing) Then
frmMain.ActiveForm.Hide
Debug.Print "hide-active"
End If
End SubPrivate Sub Form_QueryUnload(ByRef Cancel As Integer, ByVal UnloadMode As Integer)
This is the lifetime boundary. Preserve the cancellation signature where present and release resources owned by this Form.
Private Sub Form_QueryUnload(ByRef Cancel As Integer, ByVal UnloadMode As Integer)
Debug.Print "query:" & DisplayName & ":" & UnloadMode
End SubPrivate Sub Form_Unload()
This is the lifetime boundary. Preserve the cancellation signature where present and release resources owned by this Form.
Private Sub Form_Unload()
Debug.Print "unload:" & DisplayName
End SubCopy the complete Forms/frmIndependent.bas file
Replace the file once; do not append duplicate procedures.
Option Explicit
Public DisplayName As String
Private Sub Form_Initialize()
Debug.Print "initialize:" & DisplayName
End Sub
Private Sub Form_Load()
Debug.Print "load:" & DisplayName
End Sub
Private Sub Form_Shown()
lblName.Caption = "Details window: " & DisplayName
Debug.Print "shown:" & DisplayName
End Sub
Private Sub cmdHide_Click()
Me.Hide
Debug.Print "hidden:" & DisplayName
End Sub
Private Sub cmdUnload_Click()
Unload Me
End Sub
Private Sub cmdCascade_Click()
frmMain.Arrange vbCascade
Debug.Print "arrange:cascade"
End Sub
Private Sub cmdTileHorizontal_Click()
frmMain.Arrange vbTileHorizontal
Debug.Print "arrange:horizontal"
End Sub
Private Sub cmdTileVertical_Click()
frmMain.Arrange vbTileVertical
Debug.Print "arrange:vertical"
End Sub
Private Sub cmdCheckActive_Click()
Debug.Print "active-alpha-now:" & (frmMain.ActiveForm Is frmMain.ActiveAlpha)
Debug.Print "active-beta-now:" & (frmMain.ActiveForm Is frmMain.ActiveBeta)
Debug.Print "active-none-now:" & (frmMain.ActiveForm Is Nothing)
End Sub
Private Sub cmdHideActive_Click()
If Not (frmMain.ActiveForm Is Nothing) Then
frmMain.ActiveForm.Hide
Debug.Print "hide-active"
End If
End Sub
Private Sub Form_QueryUnload(ByRef Cancel As Integer, ByVal UnloadMode As Integer)
Debug.Print "query:" & DisplayName & ":" & UnloadMode
End Sub
Private Sub Form_Unload()
Debug.Print "unload:" & DisplayName
End SubForms/frmOther.bas
Enter these declarations at file scope, before the procedures.
Option Explicit
Public DisplayName As String
Private CancelNextClose As Boolean
Private FailNextClose As BooleanPrivate Sub Form_Initialize()
Initialize state before enabling dependent actions. Keep the shared declarations and startup dependencies with this procedure.
Private Sub Form_Initialize()
Debug.Print "initialize:" & DisplayName
End SubPrivate Sub Form_Load()
Initialize state before enabling dependent actions. Keep the shared declarations and startup dependencies with this procedure.
Private Sub Form_Load()
Debug.Print "load:" & DisplayName
End SubPrivate Sub Form_Shown()
Initialize state before enabling dependent actions. Keep the shared declarations and startup dependencies with this procedure.
Private Sub Form_Shown()
lblName.Caption = "Details window: " & DisplayName
Debug.Print "shown:" & DisplayName
End SubPrivate Sub cmdHide_Click()
Enter the complete action, including its input checks and calls to helper procedures.
Private Sub cmdHide_Click()
Me.Hide
Debug.Print "hidden:" & DisplayName
End SubPrivate Sub cmdUnload_Click()
Enter the complete action, including its input checks and calls to helper procedures.
Private Sub cmdUnload_Click()
Unload Me
End SubPrivate Sub cmdCancelClose_Click()
Enter the complete action, including its input checks and calls to helper procedures.
Private Sub cmdCancelClose_Click()
CancelNextClose = True
lblName.Caption = "Next close will be cancelled."
End SubPrivate Sub cmdFailClose_Click()
Enter the complete action, including its input checks and calls to helper procedures.
Private Sub cmdFailClose_Click()
FailNextClose = True
lblName.Caption = "Next close will report an error."
End SubPrivate Sub Form_QueryUnload(ByRef Cancel As Integer, ByVal UnloadMode As Integer)
This is the lifetime boundary. Preserve the cancellation signature where present and release resources owned by this Form.
Private Sub Form_QueryUnload(ByRef Cancel As Integer, ByVal UnloadMode As Integer)
Debug.Print "query:" & DisplayName & ":" & UnloadMode
If CancelNextClose Then
CancelNextClose = False
Cancel = 1
Debug.Print "cancel-close:" & DisplayName
End If
If FailNextClose Then
FailNextClose = False
Debug.Print "error-close:" & DisplayName
Err.Raise 513, "MdiForms", "Requested child close failure"
End If
End SubPrivate Sub Form_Unload()
This is the lifetime boundary. Preserve the cancellation signature where present and release resources owned by this Form.
Private Sub Form_Unload()
Debug.Print "unload:" & DisplayName
End SubCopy the complete Forms/frmOther.bas file
Replace the file once; do not append duplicate procedures.
Option Explicit
Public DisplayName As String
Private CancelNextClose As Boolean
Private FailNextClose As Boolean
Private Sub Form_Initialize()
Debug.Print "initialize:" & DisplayName
End Sub
Private Sub Form_Load()
Debug.Print "load:" & DisplayName
End Sub
Private Sub Form_Shown()
lblName.Caption = "Details window: " & DisplayName
Debug.Print "shown:" & DisplayName
End Sub
Private Sub cmdHide_Click()
Me.Hide
Debug.Print "hidden:" & DisplayName
End Sub
Private Sub cmdUnload_Click()
Unload Me
End Sub
Private Sub cmdCancelClose_Click()
CancelNextClose = True
lblName.Caption = "Next close will be cancelled."
End Sub
Private Sub cmdFailClose_Click()
FailNextClose = True
lblName.Caption = "Next close will report an error."
End Sub
Private Sub Form_QueryUnload(ByRef Cancel As Integer, ByVal UnloadMode As Integer)
Debug.Print "query:" & DisplayName & ":" & UnloadMode
If CancelNextClose Then
CancelNextClose = False
Cancel = 1
Debug.Print "cancel-close:" & DisplayName
End If
If FailNextClose Then
FailNextClose = False
Debug.Print "error-close:" & DisplayName
Err.Raise 513, "MdiForms", "Requested child close failure"
End If
End Sub
Private Sub Form_Unload()
Debug.Print "unload:" & DisplayName
End SubStep 5Keep resources and storage reproducible#
No external resource or migration files are declared. Any inline migration, seed data or local JSON is present in the code above. Runtime application data and private preferences are not included in the archive.
Step 6Check, run and test the result#
Save all files and run Check. Resolve diagnostics before Run. Developer CLI users can work from the extracted folder:
mcbasic check MdiForms.mcproj
mcbasic run MdiForms.mcprojAcceptance checklist
- Open two document Forms in the workspace.
- Open the independent Form and compare its behavior.
- Hide and unload a document, then reopen it.
- Close the workspace and inspect the resulting application lifetime.
Step 7Make one change and repeat the tests#
Give each document a distinct public title before showing it.
Save a working Git checkpoint first. Change one behavior, Check again and repeat the acceptance checklist. Compare with the downloaded solution if a regression appears.
20f4bfed6b · Build manifest