Multi-Document Interface (MDI)
Author: Linux
Multi-Document Interface (MDI) (http://www.linuxdiyf.com/1/article/2006/0701/article_599.html)
This tutorial shows you how to create an MDI application. In fact, it is not very difficult. Download the example.
Theory:
The multi-Document Interface (MDI) is a specification for applications that process multiple documents at the same time. You are familiar with notepad. It is a single document interface.
(SDI) example. notepad can only process one document at a time. If you want to open another document, you must first close your previous
You can imagine how troublesome it is. Compared with Microsoft Word, word can open any task at any time.
Meaning multiple documents, and allows users to select which document to use. Microsoft Word is an example of multi-Document Interface (MDI.
The MDI application has several notable features: I list some of them:
There is a main window, and there can be multiple subwindows in the customer area. All subwindows are located in the customer area.
Minimizes a subwindow to the lower left corner of the customer area in the main window.
Maximize A subwindow. Its title and the title of the main window are merged.
You can close the subwindow by pressing CTRL + F4, and switch between subwindows by pressing CTRL + TAB.
The main window that contains the Child Window is called the frame window. The customer area of the main window is the place where the child window is active, so the name of the main window is 'framework '.
The window task is finer than the normal window because it needs to handle some coordination work for the MDI.
To control any number of sub-windows in your customer zone, you need a special window: Customer window. You can view the customer window
Is a transparent window covering the entire customer area of the Framework Window. The customer window is the actual father of all MDI child windows. The customer window is
Real supervisor of the MDI subwindow.
Frame window
|
Customer window
|
--------------------------------------------------------------------------------
|
|
|
|
|
MDI self-Window 1
MDI self-window 2
MDI self-window 3
MDI self-Window 4
MDI self-window n
Figure 1. Hierarchy of an MDI Application
Create Framework Window
Now let's focus on the details. First, you need to create a framework window. The method for creating a framework window is the same as that for a common window:
Createmediawex is used. There are two major differences compared with normal windows.
The first difference is that you must call defframeproc to process the window information you do not want to process, instead of calling defwindowproc.
Is a way for Windows to maintain a junk task of an MDI Application for you. If you forget to use defframeproc, you should
The program will not have the MDI function. defframeproc has the following syntax:
Defframeproc proc hwndframe: DWORD,
Hwndclient: DWORD,
Umsg: DWORD,
Wparam: DWORD,
Lparam: DWORD
If you compare defframeproc with defwindowproc, you will notice that the only difference between them is that
Defframeproc has five parameters, and defwindowproc has only four. The added parameter is the handle of the client window. This handle is required.
With windows, you can send an MDI-related message to the client window.
The second difference is that you must call translatemdisysaccel in the message loop of your Framework Window. If you want windows
It is required to process the MDI-related acceleration keys, such as Ctrl + F4 and CTRL + TAB. It has the following syntax:
Translatemdisysaccel proc hwndclient: DWORD,
Lpmsg: DWORD
The first parameter is the handle of the customer window. You should not be surprised about this because the customer window is the father of all MDI child windows. The second parameter
The parameter is the MSG Framework address you obtain by calling getmessage. Our idea is to pass the MSG structure to the customer window, so that the customer window
The interface can check whether the MDI-related buttons contained in the MSG structure are pressed. If yes, the customer window will process this information.
Returns a non-zero value. Otherwise, returns a false value ..
The steps for creating a framework window are summarized as follows:
Enter the wndclassex structure as usual.
Register the framework window class by calling registerclassex.
Call createmediawex to create the framework window.
Call translatemdisysaccel in the message loop.
In the window process, the unprocessed message is passed to defframeproc instead of defwindowproc.
Create Customer window
Now that we have the framework window, we can start to create the customer window. The customer window class is pre-registered by Windows. The class name is
"Mdiclient". You also need to pass the clientcreatestruct address to createmediawex. This structure has the following
Definition:
Clientcreatestruct struct
Hwindowmenu dd?
Idfirstchild dd?
Clientcreatestruct ends
Hwindowmenu is the sub-menu handle. This sub-Menu displays the list of MDI sub-window names to be added in windows.
If you have used an MDI Application similar to Microsoft Word before, you will notice a name
It is a sub-menu of the "window". Once activated, various menu items related to window management are displayed at the bottom.
There is a list of opened MDI subwindows. This list is maintained by Windows itself. You do not need to do anything special for it.
. You only need to pass the sub-menu handle of the list you want to display in the hwindowmenu. Windows will handle the remaining tasks.
Note that this sub-menu can be any sub-menu: it is not necessarily a sub-menu named "window". What's important is that you should pass
You want to display the sub-menu handle of the window list. If you do not want this list, you just need to assign a null value to hwindowmenu.
. You can call getsubmenu to obtain the sub-menu handle.
Idfirstchild is the ID number of the first MDI sub-window. Windows is the corresponding addition of each new MDI sub-window created by the application.
Add the ID number. For example, if you pass 100 to this domain, the first MDI subwindow will have an identifier with a value of 100
The two MDI child windows will have an identifier with a value of 101. In this way, when the MDI child window is selected from the window list
The identifier of the selected MDI child window is passed to the frame window through wm_command. Normally, you will pass the wm_command that is "not processed" to the frame window
To defframeproc. I use the word "unprocessed" because the menu items in the window list are not created by your application.
Your application does not know their identifiers and does not have their handles. This is another special place in the MDI frame window. Suppose
If you have a window list, you must modify your wm_command handle as follows:
. Elseif umsg = wm_command
. If lparam = 0; this message is generated by the menu.
MoV eax, wparam
. If AX = idm_cascade
.....
. Elseif AX = idm_tilevert
.....
. Else
Invoke defframeproc, hwndframe, hwndclient, umsg, wparam, lparam
RET
. Endif
In general, you can ignore unprocessed messages, but in the case of MDI, if you ignore them, when the user clicks
The window will not be activated when it is the name of an MDI child window. You need to pass these messages to defframeproc so that they will get
Appropriate processing.
Note about idfirstchild assignment: you cannot use 0. Your window list will be abnormal. For example, even if
If the MDI child window is activated, the check mark before the name of the child window in the window list will not appear.
Full value, such as 100 or a value greater than 100.
After assigning values to the clientcreatestruct structure, you can call createmediawex to use the pre-registered class.
The name is "mdiclient", and the address of the clientcreatestruct structure is passed in lparam to create the customer window. You also need
Specify the Framework Window handle in the hwndparent parameter so that Windows can know the parent-child relationship between the framework window and the customer window.
You can use the following window styles: ws_child, ws_visiblehe ws_clipchildren. If you forget ws_visible, that is
The MDI child window is successfully created, and you cannot see them either.
Follow these steps to create a customer window:
Obtain the sub-menu handle of the window list you want to display.
Send the value of the menu handle to the clientcreatestruct structure together with the value you want to use as the first MDI sub-window identifier.
Call createjavaswex and use the class name "mdiclient". The lparam parameter is the address of the clientcreatestruct structure,
Create an MDI subwindow
Now we have both a framework window and a customer window. In the next stage, we can start to create an MDI subwindow. There are two methods:
You can send the wm_mdicreate message to the client window and transmit the address of the mdicreatestruct type in the wparam parameter.
It is a common and simplest method for creating an MDI subwindow.
. Data?
Mdicreate mdicreatestruct <>
....
. Code
.....
[Fill the members of mdicreate]
......
Invoke sendmessage, hwndclient, wm_mdicreate, ADDR mdicreate, 0
If it is successfully created, sendmessage will return the handle of the newly created MDI sub-window. You do not need to save this handle. If
If you need it, you can use other methods to obtain it. mdicreatestruct is as defined below.
Mdicreatestruct struct
Szclass DWORD?
Sztitle DWORD?
Howner DWORD?
X dword?
Y dword?
Lx DWORD?
Ly DWORD?
Style DWORD?
Lparam DWORD?
Mdicreatestruct ends
Szclass: Address of the window class used as the MDI self-window Template
Sztitle the address of the text you want to appear in the title bar of the subwindow
Howner application routine handle
Coordinates, width, and height of the upper left corner of the X, Y, lx, and Ly subwindows
Style subwindow style. If you use mdis_allchildstyles to create a subwindow, you can use any window style.
Lparam is a 32-bit value defined by an application. This is a way to share the value in the MDI window. If you do not need it, set it
Null.
You can call createmdiwindow. This function has the following syntax:
Createmdiwindow proto lpclassname: DWORD
Lpwindowname: DWORD
Dwstyle: DWORD
X: DWORD
Y: DWORD
Nwidth: DWORD
Nheight: DWORD
Hwndparent: DWORD
Hinstance: DWORD
Lparam: DWORD
If you take a closer look at these parameters, you will find that they are the same as members of the mdicreatestruct structure,
Outside of hwndparent. It is essentially the same as the number of parameters you transmit using wm_mdicreate. mdicreatestruct is not required
Hwndparent field, because you must use sendmessage to send the entire structure to the correct subwindow ..
Here, you may have some questions: Which method should I use? What is the difference between the two? The answer is as follows:
The MDI subwindow created by the wm_mdicreate method is the same thread as the calling code. This means that if the application has only one main line
All MDI subwindows run in the main thread. This is not a big problem. But if one or more of your
If the MDI sub-window executes some long operations, the problem arises. Imagine that your entire application suddenly stops.
The Operation continues until the end of the MDI subwindow.
This problem is exactly what createmdiwindow designed to solve. createmdiwindow creates a single
Independent thread. In this way, if an MDI sub-window is busy, it will not drag down the entire application ..
The Window Process of the MDI sub-window must be explained. For the frame window, you cannot call defwindowproc to handle
The message to be processed. In contrast, you must use defmdichildproc in the window process. This function has
Defwindowproc has the same parameters.
Besides wm_mdicreate, there are other MDI-related window messages. The list is as follows:
The message wm_mdiactivate is sent by the application to the customer window, telling the customer window to activate the selected MDI subwindow.
After receiving a message, it activates the selected MDI sub-window and sends the wm_mdiactivate message to the activated sub-window and
The subwindow of the activity window. This message is used in two ways: the application can use it to activate the desired subwindow. At the same time, it can
The Child Window of MDI is used as the indicator of the active/inactive window. For example, if each child window of MDI has different menus
When it changes to an active or inactive window, it can use this opportunity to change the menu of the Framework Window.
Wm_mdicascade
Wm_mditile
How to arrange the message processing in wm_mdiiconarrange. For example, if you want the MDI subwindow to be arranged in a stacked manner
To send the wm_mdicascade message to the customer window.
Wm_mdidestroy sends this message to the customer window to close an MDI subwindow. You should use this message instead of calling
Destroywindow: If this MDI subwindow is maximized, the message th restores the title of the Framework Window. If you use
Destroywindow, the title of the Framework Window will not be restored.
Wm_mdigetactive sends this message to retrieve the handle of the active MDI subwindow.
Wm_mdimaximize
Wm_mdirestore sends wm_mdimaximize to maximize the MDI subwindow and wm_mdirestore to restore it to the previous state.
These messages are always used for these operations. If you use sw_maximize as the parameter to call showwindow, the MDI sub-window is maximized and
No problem, but when you try to restore it to the previous state, the problem will come. But you can call showwindow to minimize it.
MDI child window.
Wm_mdinext sends this message to the customer window. The next or previous MDI sub-window is activated based on the corresponding values in wparam and lparam.
Port.
Wm_mdirefreshmenu sends this message to the client window to refresh the menu of the Framework Window. Note that after this message is sent, you must
You must call drawmenubar to update the menu bar.
Wm_mdisetmenu sends this message to the customer window to replace the entire menu or window sub-menu of the Framework Window. You must use this
Instead of using setmenu. After sending this message, you must call drawmenubar to update the menu bar. Normally, when the activity
The MDI sub-window has its own menu and you want to replace the menu of the frame window with the sub-window of this activity, you will
Use this message.
We will review the steps for creating an MDI application.
Register the window class, including the Framework window class and the MDI child window class.
Call createmediawex to create the framework window.
Call translatemdisysaccel in the message loop to process the MDI-related acceleration key.
In the Framework Window, call defframeproc to process all messages not processed by your code.
Use the pre-defined window class name "mdiclient" to call createcustomwex to create a customer window and pass it in the lparam Parameter
The address of the clientcreatestruct structure. Normally, you can use the wm_create handle in the Framework Window to create a customer.
Window.
Create an MDI subwindow. You can call createmdiwindow to send the wm_mdicreate message to the customer window.
In the window of the MDI subwindow, we send all unprocessed messages to defmdichildproc.
If a message has its MDI version, we use its MDI version. For example, we use the wm_mdidestory message,
Instead of using destroywindow to close an MDI subwindow.
Example:
. 386
. Model flat, stdcall
Option Casemap: None
Include/masm32/include/Windows. inc
Include/masm32/include/user32.inc
Include/masm32/include/kernel32.inc
Includelib/masm32/lib/user32.lib
Includelib/masm32/lib/kernel32.lib
Winmain proto: DWORD,: DWORD
. Const
Idr_mainmenu equ 101
Idr_childmenu equ 102
Idm_exit equ 40001
Idm_tilehorz equ 40002
Idm_tilevert equ 40003
Idm_cascade equ 40004
Idm_new equ 40005
Idm_close equ 40006
. Data
Classname DB "mdiasmclass", 0
Mdiclientname DB "mdiclient", 0
Mdichildclassname DB "win32asmmdichild", 0
Mdichildtitle DB "MDI child", 0
Appname DB "win32asm MDI Demo", 0
Closepromptmessage DB "are you sure you want to close this window? ", 0
. Data?
Hinstance dd?
Hmainmenu dd?
Hwndclient dd?
Hchildmenu dd?
Mdicreate mdicreatestruct <>
Hwndframe dd?
. Code
Start:
Invoke getmodulehandle, null
MoV hinstance, eax
Invoke winmain, hinstance, null, null, sw_showdefault
Invoke exitprocess, eax
Winmain proc hinst: hinstance, hprevinst: hinstance, using line: lpstr, cmdshow: DWORD
Local WC: wndclassex
Local MSG: msg
; ========================================================== =====
; Register the framework window class
; ========================================================== =====
MoV WC. cbsize, sizeof wndclassex
MoV WC. style, cs_hredraw or cs_vredraw
MoV WC. lpfnwndproc, offset wndproc
MoV WC. cbclsextra, null
MoV WC. cbwndextra, null
Push hinstance
Pop WC. hinstance
MoV WC. hbrbackground, color_appworkspace
MoV WC. lpszmenuname, idr_mainmenu
MoV WC. lpszclassname, offset classname
Invoke loadicon, null, idi_application
MoV WC. hicon, eax
MoV WC. hiconsm, eax
Invoke loadcursor, null, idc_arrow
MoV WC. hcursor, eax
Invoke registerclassex, ADDR WC
; ========================================================== ==========
; Register the MDI subwindow class
; ========================================================== ==========
MoV WC. lpfnwndproc, offset childproc
MoV WC. hbrbackground, color_window + 1
MoV WC. lpszclassname, offset mdichildclassname
Invoke registerclassex, ADDR WC
Invoke createappswex, null, ADDR classname, ADDR appname ,/
Ws_overlappedwindow or ws_clipchildren, cw_usedefault ,/
Cw_usedefault, null, 0 ,/
Hinst, null
MoV hwndframe, eax
Invoke loadmenu, hinstance, idr_childmenu
MoV hchildmenu, eax
Invoke showwindow, hwndframe, sw_shownormal
Invoke updatewindow, hwndframe
. While true
Invoke getmessage, addr msg, null, 0, 0
. Break. If (! Eax)
Invoke translatemdisysaccel, hwndclient, ADDR msg
. If! Eax
Invoke translatemessage, ADDR msg
Invoke dispatchmessage, ADDR msg
. Endif
. Endw
Invoke destroymenu, hchildmenu
MoV eax, MSG. wparam
RET
Winmain endp
Wndproc proc hwnd: hwnd, umsg: uint, wparam: wparam, lparam: lparam
Local clientstruct: clientcreatestruct
. If umsg = wm_create
Invoke getmenu, hwnd
MoV hmainmenu, eax
Invoke getsubmenu, hmainmenu, 1
MoV clientstruct. hwindowmenu, eax
MoV clientstruct. idfirstchild, 100
Invoke createmediawex, null, ADDR mdiclientname, null ,/
Ws_child or ws_visible or ws_clipchildren, cw_usedefault ,/
Cw_usedefault, hwnd, null ,/
Hinstance, ADDR clientstruct
MoV hwndclient, eax
========================================================
; Initialize the mdicreatestruct Structure
========================================================
MoV mdicreate. szclass, offset mdichildclassname
MoV mdicreate. sztitle, offset mdichildtitle
Push hinstance
Pop mdicreate. howner
MoV mdicreate. X, cw_usedefault
MoV mdicreate. Y, cw_usedefault
MoV mdicreate. lx, cw_usedefault
MoV mdicreate. ly, cw_usedefault
. Elseif umsg = wm_command
. If lparam = 0
MoV eax, wparam
. If AX = idm_exit
Invoke sendmessage, hwnd, wm_close, 0, 0
. Elseif AX = idm_tilehorz
Invoke sendmessage, hwndclient, wm_mditile, mditile_horizontal, 0
. Elseif AX = idm_tilevert
Invoke sendmessage, hwndclient, wm_mditile, mditile_vertical, 0
. Elseif AX = idm_cascade
Invoke sendmessage, hwndclient, wm_mdicascade, mditile_skipdisabled, 0
. Elseif AX = idm_new
Invoke sendmessage, hwndclient, wm_mdicreate, 0, ADDR mdicreate
. Elseif AX = idm_close
Invoke sendmessage, hwndclient, wm_mdigetactive, 0, 0
Invoke sendmessage, eax, wm_close, 0, 0
. Else
Invoke defframeproc, hwnd, hwndclient, umsg, wparam, lparam
RET
. Endif
. Endif
. Elseif umsg = wm_destroy
Invoke postquitmessage, null
. Else
Invoke defframeproc, hwnd, hwndclient, umsg, wparam, lparam
RET
. Endif
XOR eax, eax
RET
Wndproc endp
Childproc proc hchild: DWORD, umsg: DWORD, wparam: DWORD, lparam: DWORD
. If umsg = wm_mdiactivate
MoV eax, lparam
. If eax = hchild
Invoke getsubmenu, hchildmenu, 1
MoV edX, eax
Invoke sendmessage, hwndclient, wm_mdisetmenu, hchildmenu, EDX
. Else
Invoke getsubmenu, hmainmenu, 1
MoV edX, eax
Invoke sendmessage, hwndclient, wm_mdisetmenu, hmainmenu, EDX
. Endif
Invoke drawmenubar, hwndframe
. Elseif umsg = wm_close
Invoke MessageBox, hchild, ADDR closepromptmessage, ADDR appname, mb_yesno
. If eax = idyes
Invoke sendmessage, hwndclient, wm_mdidestroy, hchild, 0
. Endif
. Else
Invoke defmdichildproc, hchild, umsg, wparam, lparam
RET
. Endif
XOR eax, eax
RET
Childproc endp
End start
Analysis:
The first thing the program does is to register the framework window class and the MDI child window class. After this is done, the program calls create‑wex
Create a Framework Window. Use the wm_create handle of the Framework Window to create a customer window:
Local clientstruct: clientcreatestruct
. If umsg = wm_create
Invoke getmenu, hwnd
MoV hmainmenu, eax
Invoke getsubmenu, hmainmenu, 1
MoV clientstruct. hwindowmenu, eax
MoV clientstruct. idfirstchild, 100
Invoke createmediawex, null, ADDR mdiclientname, null ,/
Ws_child or ws_visible or ws_clipchildren, cw_usedefault ,/
Cw_usedefault, hwnd, null ,/
Hinstance, ADDR clientstruct
MoV hwndclient, eax
We call getmenu to obtain the menu handle of the Framework Window. This handle will be used when getsubmenu is called. Note that we set
Pass to getsubmenu, because we want to display the sub-menu in the window list as the second sub-menu.
Assign values to members of the clientcreatestruct structure.
Next, initialize the mdiclientstruct structure. Note that we do not need to do it here. to initialize the mdiclientstruct structure
, Wm_create message is more convenient.
MoV mdicreate. szclass, offset mdichildclassname
MoV mdicreate. sztitle, offset mdichildtitle
Push hinstance
Pop mdicreate. howner
MoV mdicreate. X, cw_usedefault
MoV mdicreate. Y, cw_usedefault
MoV mdicreate. lx, cw_usedefault
MoV mdicreate. ly, cw_usedefault
After the Framework Window is created (including the client window), we call loadmenu to obtain the sub-Window menu from the resource.
Menu handle, so that when an MDI sub-menu appears, we can use this handle to replace the menu of the Framework Window. In this application
Before exiting windows, do not forget to call destroymenu to remove the handle. Normally, when an application exits
Windows Automatically releases window-related menus. However, in this case, the sub-window menus are not associated with any windows,
In this way, even if the application exits from the menu in the last half of the sub-window, it still occupies valuable memory resources.
Invoke loadmenu, hinstance, idr_childmenu
MoV hchildmenu, eax
........
Invoke destroymenu, hchildmenu
In the message loop, we call translatemdisysaccel.
. While true
Invoke getmessage, addr msg, null, 0, 0
. Break. If (! Eax)
Invoke translatemdisysaccel, hwndclient, ADDR msg
. If! Eax
Invoke translatemessage, ADDR msg
Invoke dispatchmessage, ADDR msg
. Endif
. Endw
If translatemdisysaccel returns a non-zero value, it assumes that Windows is already processing this message, so you do not need
This message does everything. If the returned value is zero, this message is not an MDI-related message, so it must follow the General Conditions
Processing.
Wndproc proc hwnd: hwnd, umsg: uint, wparam: wparam, lparam: lparam
.....
. Else
Invoke defframeproc, hwnd, hwndclient, umsg, wparam, lparam
RET
. Endif
XOR eax, eax
RET
Wndproc endp
Note that in the window of the Framework Window, we call defframeproc to process messages we are not interested in.
The important part of the window process is the wm_command handle. When you select "new" from the File menu, we create an MDI sub-Window
Port.
. Elseif AX = idm_new
Invoke sendmessage, hwndclient, wm_mdicreate, 0, ADDR mdicreate
In our example, we send the wm_mdicreate message to the customer window, and at the same time, we must pass the message in the lparam parameter.
The address of the mdicreatestruct structure to create an MDI child window.
Childproc proc hchild: DWORD, umsg: DWORD, wparam: DWORD, lparam: DWORD
. If umsg = wm_mdiactivate
MoV eax, lparam
. If eax = hchild
Invoke getsubmenu, hchildmenu, 1
MoV edX, eax
Invoke sendmessage, hwndclient, wm_mdisetmenu, hchildmenu, EDX
. Else
Invoke getsubmenu, hmainmenu, 1
MoV edX, eax
Invoke sendmessage, hwndclient, wm_mdisetmenu, hmainmenu, EDX
. Endif
Invoke drawmenubar, hwndframe
After an MDI subwindow is created, we can monitor wm_mdiactivate to see if it is an activity window. The specific method is to compare
Compare the handle of an MDI subwindow with the value of the lparam parameter. The parameter lparam contains the handle of the active subwindow.
If the two match, it is proved that the MDI sub-window is the active sub-window. The next step is to replace the menu of the frame window with
Because the original menu will be replaced, you are faster than learning to help the super once again sued which sub-dish the Windows window list will display
Single. This is why we have to call getsubmenu again to retrieve the sub-menu handle. We send the wm_mdisetmenu message
The wparam parameter in the wm_mdisetmenu contains the menu handle you want to replace the original menu.
The lparam parameter contains the sub-menu handle that you want to display the window list. After wm_mdisetmenu is sent, we call
Drawmenubar to refresh the menu. Otherwise, your menu will be messy.
. Else
Invoke defmdichildproc, hchild, umsg, wparam, lparam
RET
. Endif
In the window of the MDI subwindow, you must send all unprocessed messages to defmdichildproc instead of defwindowproc.
. Elseif AX = idm_tilehorz
Invoke sendmessage, hwndclient, wm_mditile, mditile_horizontal, 0
. Elseif AX = idm_tilevert
Invoke sendmessage, hwndclient, wm_mditile, mditile_vertical, 0
. Elseif AX = idm_cascade
Invoke sendmessage, hwndclient, wm_mdicascade, mditile_skipdisabled, 0
When you select a menu item in the window sub-menu, we send the corresponding message to the customer window. If you select a tiled window, I
Wm_mditile is sent to the customer window, which type of tile is specified in the wparam parameter. If overlap is selected, the corresponding
Wm_mdicascade ..
. Elseif AX = idm_close
Invoke sendmessage, hwndclient, wm_mdigetactive, 0, 0
Invoke sendmessage, eax, wm_close, 0, 0
If you select the "close" menu item, you must first send wm_mdigetactive to the customer window to obtain
The handle of the MDI sub-window. The returned value is stored in the eax register. This value is the handle of the active MDI sub-window. After obtaining the handle,
We can send wm_close to that window.
. Elseif umsg = wm_close
Invoke MessageBox, hchild, ADDR closepromptmessage, ADDR appname, mb_yesno
. If eax = idyes
Invoke sendmessage, hwndclient, wm_mdidestroy, hchild, 0
. Endif
In the window of the MDI subwindow, when you receive the message wm_close, a message box is displayed asking whether you really want to close
In this window, if the answer is "yes", we will send wm_mdidestroy to the customer window. wm_mdidestroy to close the MDI subwindow. However
Then restore the title of the Framework Window.