ICZelion Tut32

zhaozj2021-02-11  261

TUTORIAL 32: MULTIPLE Document Interface (MDI)

This Tutorial Shows You How To create MDI Application. It's Actually Not Too Difficult to do.

THEORY:

Multiple Document Interface (MDI) is a specification for applications that handle multple documents at the same time You are familiar with Notepad:. It's an example of Single Document Interface (SDI) Notepad can handle only one document at a time If you want.. to open another document, you have to close the previous one first As you can imagine, it's rather cumbersome Contrast it with Microsoft Word:.. Word can open arbitrary documents at the same time and let the user choose which document to use Microsoft Word. IS AN EXAMPLE OF MULTIPLE Document Interface (MDI).

MDI Application Has Several Characteristics That Are DistINcTive. I'll List Some of Them:

Within the main window, there can be multiple child windows in the client area. All child windows are clipped to the client area. When you minimize a child window, it minimizes to the lower left corner of the client area of ​​the main window. When You Maximize Achild Window, ITS Title Merges with That of the Main WINDOW. You Can Close A Childow By Pressing Ctrl F4 And Switch The Focus Between The Childows By Press Ctrl Tab

The main window that contains the child windows is called a frame window. Its client area is where the child windows live, hence the name "frame". Its job is a little more elaborate than a usual window because it needs to handle some coordination for MDI.

To control an arbitrary number of child windows in your client area, you need a special window called client window. You can think of this client window as a transparent window that covers the whole client area of ​​the frame window. It's this client window that is The Actual Parent of Those Mdi Child Windows. The Client WINDOW Is The Real Supervisor of The MDi Child Windows.Frame Window

|

Client Window

|

|

|

|

|

|

MDI CHILD 1

MDI CHILD 2

MDI CHILD 3

MDI CHILD 4

MDI Child N

Figure 1. THE HIERACHY OF AN MDI Application

Creating the frame window

Now we can turn our attention to the detail First of all you need to create a frame window It's created the same way as the normal window:... By calling CreateWindowEx There are two major differences from a normal window.

The first difference is that you MUST call DefFrameProc instead of DefWindowProc to process the Windows messages your window do not want to handle. This is one way to let Windows do the dirty job of maintaining MDI application for you. If you forget to use DefFrameProc Your Application Won't get the mdi feature. Period. DefframeProc HAS The Following Syntax:

DefframeProc Proc HwndFrame: DWORD,

HWndClient: DWORD,

UMSG: DWORD,

WPARAM: DWORD,

LParam: DWORD

If you compare DefFrameProc with DefWindowProc, you'll notice that the only difference between them is that DefFrameProc has 5 parameters while DefWindowProc has only 4. The extra parameter is the handle to the client window. This handle is necessary so Windows can send MDI- Related Messages to The Client Window.

The second difference is that, you must call TranslateMDISysAccel in the message loop of your frame window. This is necessary if you want Windows to handle MDI-related accelerator key strokes such as Ctrl F4, Ctrl Tab for you. It has the following SYNTAX: TranslateMdisysAccel Proc HWndClient: DWORD,

LPMSG: DWORD

The first parameter is the handle to the client window. This should not come as a surprise to you because it's the client window that is the parent of all MDI child windows. The second parameter is the address of the MSG structure you filled by calling GetMessage . The idea is to pass the MSG structure to the client window so it could examine if the MSG structure contains the MDI-related keypresses. If so, it processes the message itself and returns a non-zero value, otherwise it returns FALSE.

The Steps in Creating The Frame Window Can Be Summarized As Follows:

Fill in the WNDCLASSEX structure as usual Register the frame window class by calling RegisterClassEx Create the frame window by calling CreateWindowEx Within the message loop, call TranslateMDISysAccel. Within the window procedure, pass the unprocessed messages to DefFrameProc instead of DefWindowProc.

Creating the client window

Now that we have the frame window, we can create the client window. The client window class is pre-registered by Windows. The class name is "MDICLIENT". You also need to pass the address of a CLIENTCREATESTRUCT structure to CreateWindowEx. This structure HAS The Following Definition:

ClientCreateStruct Struct

HWindowMenu DD?

IDFirstChild DD?

ClientCreatestruct Ends

hWindowMenu is the handle to the submenu that Windows will append the list of MDI child window names. This feature requires a little explanation. If you ever use an MDI application like Microsoft Word before, you'll notice that there is a submenu named "window "which, on activation, displays various menuitems related to window management and at the bottom, the list of the MDI child window currently opened That list is internally maintained by Windows itself:. you do not have to do anything special for it Just. pass the handle of the submenu you want the list to appear in hWindowMenu and Windows will handle the rest Note that the submenu can be ANY submenu:. it does not have to be the one that is named "window" The bottom line is. ............................... ..

idFirstChild is the ID of the first MDI child window. Windows increments the ID for each new MDI child window the application created. For example, if you pass 100 to this field, the first MDI child window will have the ID of 100, the second one will have the ID of 101 and so on. This ID is sent to via WM_COMMAND the frame window when the MDI child window is selected from the window list. Normally you'll pass this "unhandled" WM_COMMAND messages to DefFrameProc. I use the word "unhandled" because the menuitems in the window list are not created by your application thus your application does not know their IDs and does not have the handler for them This is another special case for the MDI frame window:. if you have The Window List, You MODIFY YOUR WM_COMMAND HANDLER A Bit Like this: .elseif umsg == WM_Command .IF lparam == 0; this message is generated from a menu

Mov Eax, WParam .IF AX == IDM_CASCADE ..... .ELSEIF AX == IDM_TILEVERT .....

.ELSE Invoke DefframeProc, HwndFrame, HwndClient, UMSG, WPARAM, LPARAM RET .Endif

Normally, you would just ignore the messages from unhandled cases. But In the MDI case, if you ignore them, when the user clicks on the name of an MDI child window in the window list, that window will not become active. You need To pass them to defframeproc so the can be handled profr.

A caution on the value of idFirstChild: you should not use 0. Your window list will not behave properly, ie the check mark will not appear in front of the name of the first MDI child even though it's active Choose a safe value such.. AS 100 OR Above.

Having filled in the CLIENTCREATESTRUCT structure, you can create the client window by calling CreateWindowEx with the predefined class name, "MDICLIENT", and passing the address of the CLIENTCREATESTRUCT structure in lParam. You must also specify the handle to the frame window in the hWndParent . parameter so Windows knows the parent-child relationship between the frame window and the client window The window styles you should use are:. WS_CHILD, WS_VISIBLE and WS_CLIPCHILDREN If you forget WS_VISIBLE, you will not see the MDI child windows even if they were Created successfully.the Steps in Creating The Client Window Are As Follows:

Obtain the handle to the submenu that you want to append the window list to. Put the value of the menu handle along with the value you want to use as the ID of the first MDI child window in a CLIENTCREATESTRUCT structure call CreateWindowEx with the class name "Mdiclient", Passing The Address of the ClientCreateStruct Structure You Just Filled in LPARAM.

Creating the MDi Child Window

Now You Have Both The Frame Window and The Client Window. The Stage Is Now Ready for The Creation of The MDi Child Window. Theere Two Ways to do..

You can send WM_mdicreate Message to The Client Window, Passing The Client of A Structure of Type Mdicreatestruct in WParam. This is The Easiest and The Usual Method of MDi Child Window Creation.

.data? mdicreate mdicreatestruct <> ..... Code ..... [Fill the Members of Mdicreate] ......

Invoke SendMessage, HWndClient, WM_mdicreate, Addr Mdicreate, 0

SendMessage will return the handle of the newly created MDI child window if successful. You do not need to save the handle though. You can obtain it by other means if you want to. MDICREATESTRUCT has the following definition.MDICREATESTRUCT STRUCTszClass DWORD? SzTitle DWORD ? HowNer DWORD? X DWORD? Y DWORD? LX DWORD? LY DWORD? STYL DWORD? LPARAM DWORD? MdicreateStruct Ends

szClassthe address of the window class you want to use as the template for the MDI child window.szTitlethe address of the text you want to appear in the title bar of the child windowhOwnerthe instance handle of the applicationx, y, lx, lythe upper left coordinate and the width and height of the child windowstylechild window style. If you create the client window with MDIS_ALLCHILDSTYLES, you can use any window style. lParaman application-defined 32-bit value. This is a way of sharing values ​​among MDI windows. If you Don't Need to Use IT, Set It To Null

You can Call CreatemdiWindow. This function has the folloading 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 look closely at the parameters, you'll find that they are identical to the members of MDICREATESTRUCT structure, except for the hWndParent. Essentially it's the same number of parameters you pass with WM_MDICREATE. MDICREATESTRUCT does not have the hWndParent field because you must pass the whole structure to the correct client window with SendMessage anyway.At this point, you may have some questions: which method should I use What is the difference between the two Here is the answer??:

The WM_MDICREATE method creates the MDI child window in the same thread as the calling code. That means if the application only has the primary thread, all MDI child windows run in the primary thread context. This is not a big issue until one or more of Your MDI Childs Perform Some Length Operation. That Could Be A Problem! Think About IT, Suddenly Your Application Will Seem to Freeze, Won't respond to anything unsage

This problem is exactly what CreateMDIWindow is designed to solved. CreateMDIWindow creates a separate thread for each MDI child window. Thus if one MDI child is busy, it will not drag the whole application down with it.

A little more detail needs to be covered about the window procedure of the MDI child. As with the frame window case, you must not call DefWindowProc to handle the unprocessed messages. Instead, you must use DefMDIChildProc. This function has exactly the same parameters as DEFWINDOWPROC.

In addition to wm_mdicreate, There Are Other MDI-Related Window Messages. I'll List Them Below:

WM_MDIACTIVATEThis message can be sent by the application to the client window to instruct the client window to activate the selected MDI child. When the client window receives the message, it activates the selected MDI child window and sends WM_MDIACTIVATE to the child being deactivated and activated. The use of this message is two-fold: it can be used by the application to activate the desired child window And it can be used by the MDI child window itself as the indicator that it's being activated / deactivated For example, if each.. MDI CHILD WINDOW HAS DIFFERENT MENU, IT CAN Use this Opportunity To change the menu of the frame window means'

s activated / deactivated.WM_MDICASCADEWM_MDITILEWM_MDIICONARRANGE These messages handle the arrangement of the MDI child windows. For example, if you want the MDI child windows to arrange themselves in cascading style, send WM_MDICASCADE to the client window. WM_MDIDESTROYSend this message to the client window to destroy an MDI child window. you should use this message instead of calling DestroyWindow because if the MDI child window is maxmized, this message will restore the tile of the frame window. If you use DestroyWindow, the title of the frame window will not be restored. WM_MDIGETACTIVESend this message to retrieve the handle of the currently active MDI child window.WM_MDIMAXIMIZEWM_MDIRESTORE Send WM_MDIMAXIMIZE to maximize the MDI child window and WM_MDIRESTORE to restore it to previous state. Always use these messages for the operations. If you use ShowWindow with SW_MAXIMIZE, the MDI Child Window Will Maximize Fine But It Will Have The Problem When You Try To Restore It To Prev ious size. You can minimize the MDI child window with ShowWindow without problem, however.WM_MDINEXTSend this message to the client window to activate the next or the previous MDI child window according to the values ​​in wParam and lParam.WM_MDIREFRESHMENUSend this message to the client window to refresh the menu of the frame window. Note that you must call DrawMenuBar to update the menu bar after sending this message.WM_MDISETMENUSend this message to the client window to replace the whole menu of the frame window or just the window submenu. you must use .....................

Normally you will use this message when the active MDI child window has its own menu and you want it to replace the menu of the frame window while the MDI child window is active.I'll review the steps in creating an MDI application for you again Below.

Register the window classes, both the frame window class and the MDI child window class Create the frame window with CreateWindowEx. Within the message loop, call TranslateMDISysAccel to process the MDI-related accelerator keys Within the window procedure of the frame window, call DefFrameProc to handle ALL messages unhandled by your code. Create the client window by calling CreateWindowEx using the name of the predefined window class, "MDICLIENT", passing the address of a CLIENTCREATESTRUCT structure in lParam. Normally, you would create the client window within the WM_CREATE handler of the frame window proc You can create an MDI child window by sending WM_MDICREATE to the client window or, alternatively, by calling CreateMDIWindow. Within the window proc of the MDI child window, pass all unhandled messages to DefMDIChildProc. Use MDI version of the messages If IT EXISTS. for EXAMPLE, USE WM_MDIDESTROY INSTEAD OF CALLING DESTROYWINDOW

EXAMPLE:

.386 .Model flat, stdcall option/Include/windows.inc include /masm32/include/user32.inc

INCLUDE /MASM32/INCLUDE / WANEL32.INC

INCLUDELIB /MASM32/LIB/USER32.LIB

INCLUDELIB /MASM32/LIB/kernel32.lib

Winmain Proto: DWORD,: DWORD,: 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", 0mdichildclassname DB "Win32ASmmdichild", 0

MdichildTitle DB "MDI Child", 0

Appname DB "Win32ASM MDI DEMO", 0

ClosePromptMessage DB "Are you have 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, Cmdline: lpstr, cmdshow: DWORD

Local WC: WNDCLASSEX

Local MSG: MSG

; =============================================

; Register The Frame 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 Child Window Class

; ================================================

Mov wc.lpfnwndproc, Offset ChildProc

Mov wc.hbrbackground, Color_Window 1

Mov wc.lpszclassname, Offset mdichildclassname

Invoke RegisterClassex, Addr WC

Invoke CreateWindowex, Null, AddR ClassName, Addr Appname, /

WS_OVERLAPPEDWINDOW OR WS_CLIPCHILDEN, CW_USEDEFAULT, /

CW_USEDEFAULT, 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 CreateWindowex, Null, Addr MdiclientName, NULL, /

WS_CHILD or WS_VISIBLE or WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND, NULL, /

Hinstance, Addr ClientstructMov HWndClient, EAX

; ========================================

; Initialize the Mdicreatestruct

; ========================================

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_VERTILAL, 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

.lse

Invoke DefframeProc, Hwnd, HwndClient, UMSG, WPARAM, LPARAM

RET

.endif

.endif

.ELSEIF uMSG == WM_DESTROY

Invoke PostquitMessage, NULL

.lse

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 == hchildinvoke getSubmenu, Hchildmenu, 1

Mov Edx, EAX

Invoke SendMessage, HWndClient, WM_MDisetMenu, Hchildmenu, EDX

.lse

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 ClosePromptMPTMESSAGE, AddR Appname, MB_YESNO

.IF eax == iDYES

Invoke SendMessage, HWndClient, WM_MDIDESTROY, HCHILD, 0

.endif

.lse

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 window classes of the frame window and the MDI child window After that, it calls CreateWindowEx to create the frame window Within the WM_CREATE handler of the frame window, we create the client 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 CreateWindowex, Null, Addr MdiclientName, NULL, /

WS_CHILD or WS_VISIBLE or WS_CLIPCHILDREN, CW_USEDEFAULT, /

CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND, NULL, /

Hinstance, AddR Clientstruct

Mov HWndClient, EAX

It calls GetMenu to obtain the handle to the menu of the frame window, to be used in the GetSubMenu call. Note that we pass the value 1 to GetSubMenu because the submenu we want the window list to appear is the second submenu. Then we fill The Members of The Clientcreatestruct Structure.next, We Initialize The Mdiclientstruct Structure. Note That We don't need to do it here. it's only convegnient to do it in wm_create.

Mov mdicreate.szclass, offset mdichildclassnamemov 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 frame window is created (and also the client window), we call LoadMenu to load the child window menu from the resource. We need to get this menu handle so we can replace the menu of the frame window with it when an MDI child window is present. Do not forget to call DestroyMenu on the handle before the application exits to Windows. Normally Windows will free the menu associated with a window automatically when the application exits but in this case, the child window menu is not associated with any Window Thus It Will Still Occupy Valuable Memory Even After the Application EXITS.

Invoke loadmenu, Hinstance, IDR_Childmenu

Mov Hchildmenu, EAX

........

Invoke Destroymenu, HChildmenu

WITHIN THE Message Loop, We Call TranslatemdiSaccel.

.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 means the message was already handled by Windows itself so you do not need to do anything to the message. If it returns 0, the message is not MDI-related and thus should be handled as UsuAL.

WNDPROC PROC HWND: HWND, UMSG: UINT, WPARAM: WPARAM, LPARAM: LPARAM

.....

.lse

Invoke DefframeProc, Hwnd, HwndClient, UMSG, WPARAM, LPARAM

RET

.endif

XOR EAX, EAX

RET

WNDPROC ENDP

Note that within the window procedure of the frame window, we call DefFrameProc to handle the messages we are not interested in.The bulk of the window procedure is the WM_COMMAND handler. When the user selects "New" from the File menu, we create a New MDI Child WinDow.

.ELSEIF AX == IDM_NEW

Invoke SendMessage, HWndClient, WM_MDicreate, 0, Addr Mdicreate

In Our Example, We create the mdi child window by sending wm_mdicreate to the client window, passing the address of the mdicreatestruct structure in lparam.

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

.lse

Invoke GetSubmenu, HmainMenu, 1

Mov Edx, EAX

Invoke SendMessage, HWndClient, WM_MDisetMenu, HmainMenu, EDX

.endif

Invoke Drawmenubar, HWNDFrame

When the MDI child window is created, it monitors WM_MDIACTIVATE to see if it's the active window. It does this by comparing the value of the lParam which contains the handle of the active child window with its own handle. If they match, it's the active window and the next step is to replace the menu of the frame window to its own. Since the original menu will be replaced, you have to tell Windows again in which submenu the window list should appear. That's why we must call GetSubMenu again to retrieve the handle to the submenu. We send WM_MDISETMENU message to the client window to achieve the desired result. wParam of WM_MDISETMENU contains the handle of the menu you would like to replace the original menu. lParam contains the handle of the submenu you want the window list To APPEAR. RightAfter Sending WM_MDisetmenu

Invoke DefmdichildProc, Hchild, UMSG, WPARAM, LPARAM

RET

.endif

.....................

.ELSEIF AX == IDM_TILEHORZ

Invoke SendMessage, HWndClient, WM_MDITILE, MDITILE_HORIZONTAL, 0

.ELSEIF AX == IDM_TILEVERT

Invoke SendMessage, HWndClient, WM_MDITILE, MDITILE_VERTILAL, 0

.ELSEIF AX == IDM_CASCADE

Invoke SendMessage, HWndClient, WM_MDicascade, Mditile_skipdisabled, 0

When the user selects one of the menuitems in the window submenu, we send the corresponding message to the client window. If the user chooses to tile the windows, we send WM_MDITILE to the client window, specifying in wParam what kind of tiling we want. WM_CASCADE IS SIMILAR.

.ELSEIF AX == IDM_Close

Invoke SendMessage, HWndClient, WM_MDiGetActive, 0,0invoke SendMessage, Eax, WM_Close, 0,0

If the user chooses "Close" menuitem, we must obtain the handle of the currently active MDI child window first by sending WM_MDIGETACTIVE to the client window. The return value in eax is the handle of the currently active MDI child window. After that, we Send WM_Close to That Window.

.ELSEIF uMSG == WM_Close

Invoke Messagebox, Hchild, Addr ClosePromptMPTMESSAGE, AddR Appname, MB_YESNO

.IF eax == iDYES

Invoke SendMessage, HWndClient, WM_MDIDESTROY, HCHILD, 0

.endif

Within the window procedure of the MDI child, when WM_CLOSE is received, it displays a message box asking the user if he really wants to close the window. If the answer is yes, we send WM_MDIDESTROY to the client window. WM_MDIDESTROY closes the MDI child Window and restores the title of the frame window.

转载请注明原文地址:https://www.9cbs.com/read-4652.html

New Post(0)