; #########################################################################

      .486                      ; create 32 bit code
      .model flat, stdcall      ; 32 bit memory model
      option casemap :none      ; case sensitive

      include MDI.inc       ; local includes for this file

.code

; #########################################################################

start:

    ; ------------------
    ; set global values
    ; ------------------
      mov hInstance, $invoke (GetModuleHandle, NULL)
      mov hIcon, $invoke (LoadIcon,NULL,IDI_APPLICATION)      
      mov hCursor, $invoke (LoadCursor,NULL,IDC_ARROW)
      call Main
      invoke ExitProcess,eax

; #########################################################################

Main proc

    STRING szClassMain,"MDI_XXMENU"
    STRING szClassChild,"MDI_CHILD"

  ; --------------------------------------------
  ; Register the main application window class.
  ; --------------------------------------------
    invoke RegisterWinClass,ADDR WndProc,ADDR szClassMain,
                       hIcon,hCursor,COLOR_APPWORKSPACE+1

  ; --------------------------------------------
  ; Register the window class for the MDI child windows.
  ; --------------------------------------------  
 
    invoke RegisterWinClass,ADDR ChildWndProc,ADDR szClassChild,
                       hIcon,hCursor,COLOR_WINDOW+1                       
 
  ; -------------------------------------------------
    mov hMenu, $invoke ( LoadMenuA, hInstance, MAINMENU)
    mov hContextMenu, $invoke (GetSubMenu, hMenu, 1)   ; выберем дескриптор конекстного меню
    
  ; Create the main application window.
    invoke CreateWindowEx, NULL, ADDR szClassMain,
                          ADDR szDisplayName,
                          WS_OVERLAPPEDWINDOW or WS_CLIPCHILDREN,
                          CW_USEDEFAULT,0,CW_USEDEFAULT,0,
                          NULL,hMenu,
                          hInstance,NULL
    mov hWnd,eax

    invoke ShowWindow,hWnd, SW_SHOWNORMAL 
    invoke UpdateWindow,hWnd

    mov h_Accel, $invoke (LoadAccelerators, hInstance, ACC)

    call MsgLoop
    ret

Main endp

; #########################################################################

RegisterWinClass proc lpWndProc:DWORD, lpClassName:DWORD,
                      Icon:DWORD, Cursor:DWORD, bColor:DWORD

    LOCAL wc:WNDCLASSEX

    mov wc.cbSize,         sizeof WNDCLASSEX
    mov wc.style,          CS_HREDRAW or \
                           CS_VREDRAW
    m2m wc.lpfnWndProc,    lpWndProc
    mov wc.cbClsExtra,     NULL
    mov wc.cbWndExtra,     NULL
    m2m wc.hInstance,      hInstance
    m2m wc.hbrBackground,  bColor
    mov wc.lpszMenuName,   NULL
    m2m wc.lpszClassName,  lpClassName
    m2m wc.hIcon,          Icon
    m2m wc.hCursor,        Cursor
    m2m wc.hIconSm,        Icon

    invoke RegisterClassEx, ADDR wc

    ret

RegisterWinClass endp

; ########################################################################

MsgLoop proc

  ; ------------------------------------------
  ; The following 4 equates are available for
  ; processing messages directly in the loop.
  ; m_hWnd - m_Msg - m_wParam - m_lParam
  ; ------------------------------------------

    LOCAL msg:MSG

    StartLoop:
      invoke GetMessage,ADDR msg,NULL,0,0
      cmp eax, 0
      je ExitLoop
      .if hWndClient
      	invoke TranslateMDISysAccel,hWndClient,addr msg
      	cmp eax, 0
      	ja short StartLoop
      .endif      
      invoke TranslateAccelerator, hWnd, h_Accel, ADDR msg
      cmp eax, 0
      jne StartLoop      
      invoke TranslateMessage, ADDR msg
      invoke DispatchMessage,  ADDR msg
      jmp short StartLoop
    ExitLoop:

    mov eax, msg.wParam
    ret

MsgLoop endp

; #########################################################################

WndProc proc hWin :HWND, uMsg :UINT, wParam :WPARAM, lParam :LPARAM

    LOCAL var         :DWORD
    LOCAL buffer1[128]:BYTE  ; these are two spare buffers
    LOCAL buffer2[128]:BYTE  ; for text manipulation etc..
    LOCAL ccs	  :CLIENTCREATESTRUCT

    LOCAL hBmpImgList :HBITMAP
 
   .if uMsg == WM_CREATE

    ; создадим список изображений
    mov hImageList, $invoke (ImageList_Create, 16, 16, ILC_COLOR or ILC_MASK, 18,0)
    mov hBmpImgList, $invoke (LoadBitmap, hInstance, IDB_BITMAP1)
    RGB 192, 192, 192
    invoke ImageList_AddMasked, hImageList, hBmpImgList, eax
    invoke DeleteObject, hBmpImgList

    invoke RedrawMenu, hWin, hMenu, StyleMenu     ; Перерисуем меню
    invoke SetMenuItemIcon, hMenu, IDM_FILE_NEW, $invoke (ImageList_GetIcon, hImageList, 0, ILD_NORMAL)
    invoke SetMenuItemIcon, hMenu, IDM_FILE_OPEN, $invoke (ImageList_GetIcon, hImageList, 1, ILD_NORMAL)
    invoke SetMenuItemIcon, hMenu, IDM_FILE_SAVE, $invoke (ImageList_GetIcon, hImageList, 2, ILD_NORMAL)
    invoke SetMenuItemIcon, hMenu, IDM_FILE_PRINT, $invoke (ImageList_GetIcon, hImageList, 3, ILD_NORMAL)
    invoke SetMenuItemIcon, hMenu, IDM_FILE_PRINT_PREVIEW,  $invoke (ImageList_GetIcon, hImageList, 4, ILD_NORMAL)
    invoke SetMenuItemIcon, hMenu, IDM_FILE_PRINT_SETUP, $invoke (ImageList_GetIcon, hImageList, 5, ILD_NORMAL) 

    invoke SetMenuItemIcon, hMenu, IDM_EDIT_UNDO, $invoke (ImageList_GetIcon, hImageList, 6, ILD_NORMAL)
    invoke SetMenuItemIcon, hMenu, IDM_EDIT_CUT, $invoke (ImageList_GetIcon, hImageList, 7, ILD_NORMAL)
    invoke SetMenuItemIcon, hMenu, IDM_EDIT_COPY, $invoke (ImageList_GetIcon, hImageList, 8, ILD_NORMAL)
    invoke SetMenuItemIcon, hMenu, IDM_EDIT_PASTE, $invoke (ImageList_GetIcon,  hImageList, 9, ILD_NORMAL)
    invoke SetMenuItemIcon, hMenu, IDM_EDIT_DELETE, $invoke (ImageList_GetIcon, hImageList, 10, ILD_NORMAL)
    invoke SetMenuItemIcon, hMenu, IDM_VIEW_TOOLBARS_CUSTOMIZE, $invoke (ImageList_GetIcon, hImageList, 11, ILD_NORMAL) 
    invoke SetMenuItemIcon, hMenu, IDM_HELP_ABOUT_XX,  $invoke (ImageList_GetIcon, hImageList, 12, ILD_NORMAL)

    invoke SetMenuItemIcon, hMenu, IDM_WINDOW_CASCADE, $invoke (ImageList_GetIcon,  hImageList, 13, ILD_NORMAL)
    invoke SetMenuItemIcon, hMenu, IDM_WINDOW_TILEHORZ, $invoke (ImageList_GetIcon, hImageList, 14, ILD_NORMAL)
    invoke SetMenuItemIcon, hMenu, IDM_WINDOW_TILEVERT, $invoke (ImageList_GetIcon, hImageList, 15, ILD_NORMAL) 
    invoke SetMenuItemIcon, hMenu, IDM_WINDOW_ARRANGE, $invoke (ImageList_GetIcon, hImageList, 16, ILD_NORMAL)
    invoke SetMenuItemIcon, hMenu, IDM_NOT_STANDART_CHECK_ITEM, $invoke (ImageList_GetIcon, hImageList, 17, ILD_NORMAL)	; Check item with icon

    ; установим переключатели стилей в меню
    invoke CheckMenuRadioItem, hMenu, IDM_VIEW_STYLE_DEFAULT, IDM_VIEW_STYLE_XNET, IDM_VIEW_STYLE_OFFICE_2000, MF_BYCOMMAND

    ; ИЗМЕНИМ СИСТЕМНОЕ МЕНЮ
    mov hSysMenu, $invoke ( GetSystemMenu, hWin, FALSE )   ; выбрем дескриптор системного меню   
    invoke AppendMenu, hSysMenu, MF_SEPARATOR, 0, 0        ; Добавим к системному меню пункт меню сепартор
    ; Добавим к системному меню пункт меню "О программе"
    invoke GetMenuString, hMenu, IDM_HELP_ABOUT_XX, ADDR buffer1, 128, MF_BYCOMMAND    ; получим строку
    invoke AppendMenu, hSysMenu, MF_STRING, IDM_HELP_ABOUT_XX, ADDR buffer1    
    invoke RedrawMenu, hWin, hSysMenu, StyleMenu     ; Перерисуем добавленные в меню пунты
    ; Установим иконку на добавленом пункте меню.
    invoke SetMenuItemIcon, hSysMenu, IDM_HELP_ABOUT_XX, $invoke (ImageList_GetIcon, hImageList, 12, ILD_NORMAL)   
    
    ; MDI ==>
    invoke GetSubMenu, hMenu, 3   ; Assign the 'Window' menu.
    mov hMenu_AddDocNumber, eax
    mov ccs.hWindowMenu, eax
    mov ccs.idFirstChild, ID_CHILDWINDOW    
    
    ; Create the client window.
    invoke CreateWindowEx,WS_EX_CLIENTEDGE,
                          ADDR szClassMDI,NULL,
                          WS_CHILD or WS_CLIPCHILDREN or WS_VISIBLE,
                          0, 0, 0, 0,
                          hWin,0,
                          hInstance,ADDR ccs
    mov hWndClient,eax    
    
   .elseif uMsg == WM_COMMAND

    ;======== menu commands ========
    mov eax, wParam
    
        .if ax == IDM_FILE_NEW
        
        	  ; Create a new child window.
        	  invoke CreateMDIWindow,ADDR szClassChild,ADDR Document, 0,
                                  CW_USEDEFAULT, CW_USEDEFAULT, 
                                  CW_USEDEFAULT, CW_USEDEFAULT,
                                  hWndClient, hInstance, 0
                                
            invoke ShowWindow, eax, SW_SHOW
            invoke RedrawMenu, hWin, hMenu_AddDocNumber, StyleMenu     ; Перерисуем меню (в него добавился пункт, номер документа)
        
        .elseif ax == IDM_FILE_CLOSE
        
        	  ; Close the active child window.
            invoke SendMessage, hWndClient, WM_MDIGETACTIVE, 0, 0
            .if eax
            	invoke SendMessage, hWndClient, WM_MDIDESTROY, eax, 0
            .endif
        
        .elseif ax == IDM_WINDOW_CASCADE
        	  
            invoke SendMessage,hWndClient,WM_MDICASCADE,MDITILE_SKIPDISABLED,0
        
        .elseif ax == IDM_WINDOW_TILEHORZ
        
        	  invoke SendMessage,hWndClient,WM_MDITILE,MDITILE_HORIZONTAL,0
        
        .elseif ax == IDM_WINDOW_TILEVERT
        
        	  invoke SendMessage,hWndClient,WM_MDITILE,MDITILE_VERTICAL,0
        
        .elseif ax == IDM_WINDOW_ARRANGE
        
        	  invoke ArrangeIconicWindows, hWndClient
        
        .elseif ax == IDM_FILE_APP_EXIT
        
            invoke	SendMessage,hWin,WM_SYSCOMMAND,SC_CLOSE,NULL
        
        .elseif ax == IDM_VIEW_TOOLBARS_STANDARD
              
            jmp reverse            
        .elseif ax == IDM_VIEW_SATATUSBAR
        
reverse:        
            invoke GetMenuState, hMenu, wParam, MF_BYCOMMAND            
            and eax, MF_CHECKED
            
            .if eax == MF_CHECKED
                invoke CheckMenuItem,hMenu, wParam, MF_BYCOMMAND or MF_UNCHECKED                        
            .else                           
                invoke CheckMenuItem,hMenu, wParam, MF_BYCOMMAND or MF_CHECKED             
            .endif
            
        .elseif ax == IDM_NOT_STANDART_CHECK_ITEM
            
                jmp reverse            
        .elseif ax == IDM_VIEW_STYLE_DEFAULT
            mov StyleMenu, STYLE_DEFAULT                        
            jmp radio_check
            
        .elseif ax == IDM_VIEW_STYLE_OFFICE_2000
            mov StyleMenu, STYLE_OFFICE_2000
            jmp radio_check
             
        .elseif ax == IDM_VIEW_STYLE_OFFICE_XP
            mov StyleMenu, STYLE_OFFICE_XP
            jmp radio_check
            
        .elseif ax == IDM_VIEW_STYLE_XNET
            mov StyleMenu, STYLE_XNET
     
radio_check:
	  invoke RedrawMenu, hWin, hMenu, StyleMenu
            invoke RedrawMenu, hWin, hSysMenu, StyleMenu
            invoke CheckMenuRadioItem, hMenu, IDM_VIEW_STYLE_DEFAULT, IDM_VIEW_STYLE_XNET, wParam, MF_BYCOMMAND
            
            invoke SendMessage, hWndClient, WM_MDIGETACTIVE, 0, 0 ; перерисуем меню текущего активного окна 
            .if eax
            	mov ebx, eax
            	push ebx
            	invoke GetSystemMenu, eax, FALSE	     ; выбрем дескриптор системного меню
            	pop ebx
    		invoke RedrawMenu, ebx, eax, StyleMenu      ; Перерисуем добавленные в меню пунты
            .endif                                       

        .elseif ax == IDM_HELP_ABOUT_XX        ; О ПРОГРАММЕ

            invoke CreateXXAboutDlg, hWin
            
        .else
            invoke DefFrameProc,hWin,hWndClient,uMsg,wParam,lParam		
	  ret
        .endif
        
    ;====== end menu commands ======
   .elseif uMsg == WM_SYSCOMMAND       

        mov eax, wParam    
        .if ax == IDM_HELP_ABOUT_XX        ; О ПРОГРАММЕ
            invoke CreateXXAboutDlg, hWin
        .endif
        
   .elseif uMsg == WM_SIZE

        ; Size the client window to the size of the client
        ; area of the main application window.
        push TRUE        
        HIWORD lParam
        push eax
        LOWORD lParam
        push eax
        push 0
        push 0
        push hWndClient
        call MoveWindow
        
   .elseif uMsg == WM_DESTROY    
        invoke ImageList_Destroy, hImageList
        invoke PostQuitMessage,NULL

   .else
        invoke DefFrameProc,hWin,hWndClient,uMsg,wParam,lParam		
        ret
   .endif
   invoke DefFrameProc,hWin,hWndClient,uMsg,wParam,lParam   
   xor eax,eax
   ret
WndProc endp

; ########################################################################

ChildWndProc proc hWin :HWND, uMsg :UINT, wParam :WPARAM, lParam :LPARAM

   .if uMsg == WM_MDIACTIVATE
   
    ; ИЗМЕНИМ СИСТЕМНОЕ МЕНЮ
    invoke GetSystemMenu, hWin, FALSE	         ; выбрем дескриптор системного меню
    invoke RedrawMenu, hWin, eax, StyleMenu      ; Перерисуем

    ; нужно хотя бы один раз вызвать перерисовку меню, так как 
    ; у hContextMenu новый владелец меню, новое окно
    ; другой хендл. 
        
    invoke RedrawMenu, hWin, hContextMenu, StyleMenu      ; Перерисуем
  
   .elseif uMsg == WM_CONTEXTMENU
   
        push 0
        push hWin       ; ВАЖНО!!! Здесь должен стоять хендл окна которое обрабатывает
                        ; сообщения от меню, WM_COMMAND и т.п.
        push 0        
        HIWORD lParam   ; вертикальное расположение всплывающего меню
        push eax
        LOWORD lParam   ; горизонтальное расположение всплывающего меню
        push eax
        push 0
        push hContextMenu
        call TrackPopupMenu
        
   .elseif uMsg == WM_DESTROY
   
    invoke RedrawMenu, hWnd, hMenu_AddDocNumber, StyleMenu     ; Перерисуем меню (из него удалился пункт, номер документа)
                    
   .else
   
      invoke DefMDIChildProc, hWin, uMsg, wParam, lParam
      ret
   .endif
   
    xor eax, eax    
    ret
ChildWndProc endp

end start