comment $
//-----------------------------------------------------------------------------------//
//  Source code                                                                      //
//                                                                                   //
//  Written      by  Chib, amdtm                     http://www.xxcontrols.com       //
//                                                                                   //
//  FileName   : Hook.inc				                                             //
//  Description: libraries of functions for work with menu                           //
//  Version    : 1.00.000, January 1, 2004                                           //
//-----------------------------------------------------------------------------------//
$

InstallHook proc
    .if !hHook
        call GetCurrentThreadId
        invoke SetWindowsHookEx, WH_CALLWNDPROC, ADDR HookProc, NULL, eax
        mov hHook, eax
    .endif  
    
    ret
InstallHook endp

UnInstallHook proc
    .if hHook
        invoke UnhookWindowsHookEx, hHook   
        mov hHook, 0
    .endif
    ret
UnInstallHook endp

;--------------------------------------------------------------------------------

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

HookProc proc uses ebx nCode:DWORD, wParam:DWORD, lParam:DWORD

    LOCAL class_name[128]:BYTE

mov ebx, lParam
assume ebx: ptr CWPSTRUCT   

    .if nCode == HC_ACTION

;      .if [ebx].hwnd == 90
;       jmp TheMenu
;      .endif
    
        invoke GetClassName, [ebx].hwnd, ADDR class_name, 127  

        ; Check for the menu-class
        
        .if eax == 6
            invoke lstrcmp, ADDR class_name, ADDR ClassWndMenu
            
            .if !eax
;TheMenu:
                   ; Изменим адрес оконной процедуры для меню
                   ; Перед изменением проверим не изменён ли уже адрес оконной процедуры
                   invoke GetWindowLong, [ebx].hwnd, GWL_WNDPROC
                   cmp eax,offset WndProc_WindowMenu
                   je @f                   
                  
                   invoke SetWindowLong, [ebx].hwnd, GWL_WNDPROC, ADDR WndProc_WindowMenu
                   invoke SetProp, [ebx].hwnd, ADDR szProp_XX, eax                   
@@:                    
                  
;               mov eax, [ebx].hwnd
;               PrintHex eax
        
            .endif
        
        .endif

    .endif
    
assume ebx: nothing
    invoke CallNextHookEx, hHook, nCode, wParam, lParam 
    xor eax, eax
    ret
HookProc endp

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

WndProc_WindowMenu proc uses ebx edx hWin :DWORD, uMsg :DWORD, wParam :DWORD, lParam :DWORD

    LOCAL hDC   :HDC
    LOCAL hDCDsk:HDC
    LOCAL rect  :RECT
    LOCAL cwrect:RECT
    LOCAL OldWndProc :DWORD
    LOCAL default_call :BYTE
    LOCAL Ps    :PAINTSTRUCT
    LOCAL crect :RECT
    LOCAL wrect :RECT
    LOCAL hMemDC:HDC
    LOCAL hBmp  :HBITMAP
    LOCAL hOldBmp:HBITMAP
    LOCAL hBmpWnd:HBITMAP
    LOCAL sz    :SIZEL
    LOCAL nWidth:DWORD
    LOCAL nHeight:DWORD
    LOCAL ps    :PAINTSTRUCT
    LOCAL fPrpNc:DWORD
     
LOCAL hNCRgn    :HRGN
LOCAL hCRgn     :HRGN
LOCAL hCombineRgn :HRGN

LOCAL wndOffset :POINT
     
;    PrintHex uMsg 
     
    invoke GetProp, hWin, ADDR szProp_XX
    mov OldWndProc, eax
    
    mov default_call, TRUE
  
    .if uMsg == WM_ERASEBKGND

       mov no_nc_paint, TRUE
       invoke SendMessage, hWin, WM_NCPAINT, 1, 0
       
;       invoke CallWindowProc,OldWndProc, hWin, uMsg, wParam, lParam
        
;       mov eax, TRUE
       mov default_call, FALSE
    .elseif uMsg == WM_SHOWWINDOW        
        
        .if wParam == 0 ; Hide the window ? Test for 98 and 2000 
               
            invoke UnSubClassMenu, hWin
            ;mov default_call, FALSE
        .endif               

    .elseif uMsg == WM_NCDESTROY
            
        invoke UnSubClassMenu, hWin
 
    .elseif uMsg == WM_NCCALCSIZE 

;        PrintDec hWin, "NCCALCSIZE"
 
        .if wParam
        
            invoke CallWindowProc,OldWndProc,hWin,uMsg,wParam,lParam
        
mov ebx, lParam    
assume ebx: ptr NCCALCSIZE_PARAMS
            
;            add [ebx].rgrc.left, 6      ; !
;            add [ebx].rgrc.right, 6     ; !
       
            mov default_call, FALSE

assume ebx: nothing        
        
        .endif        
         
    .elseif uMsg == WM_NCPAINT
    
;    PrintDec hWin, "WM_NCPAINT"
      
       .if no_nc_paint
                  
        invoke GetProp, hWin, ADDR szProp_NC
        mov fPrpNc, eax        

        .if eax == 1       
        
            invoke GetWindowRect, hWin, ADDR wrect
            
            call IsShadowEnabled           
            .if !eax 
                sub wrect.right, 4        ; ширина тени
                sub wrect.bottom, 4              
            .endif
            
            invoke InflateRect, ADDR wrect, -2, -2
            invoke CreateRectRgnIndirect, ADDR wrect
            mov hNCRgn, eax
            invoke InflateRect, ADDR wrect, 2, 2
            invoke CallWindowProc,OldWndProc,hWin,WM_NCPAINT,hNCRgn,lParam        
            invoke DeleteObject, hNCRgn         
        
            invoke GetWindowDC, hWin     
            mov hDC, eax
            invoke OnDrawBorder, hWin, hDC
            invoke ReleaseDC, hWin, hDC
            
            inc fPrpNc
            invoke SetProp, hWin, ADDR szProp_NC, fPrpNc
        .else
            inc fPrpNc
            invoke SetProp, hWin, ADDR szProp_NC, fPrpNc
            call IsShellType            
            .if eax == WIN_XP || eax == WIN_2000
                invoke CallWindowProc,OldWndProc,hWin,WM_NCPAINT,0,0
            .endif       
        .endif
        
      .endif

        mov default_call, FALSE
        
    .elseif uMsg == WM_WINDOWPOSCHANGING ;|| uMsg == WM_WINDOWPOSCHANGED

        mov edx, lParam
        mov eax, [edx].WINDOWPOS.flags
        
;        PrintDec eax, "WINDOWPOSCHANGING"
               
        .if eax == 97h
            invoke UnSubClassMenu, hWin
            mov no_nc_paint, FALSE
            
        .elseif eax == 15h
            invoke UnSubClassMenu, hWin
            mov no_nc_paint, TRUE       ; для 98 - й, убирает баг тени 
            
        .else        
            mov no_nc_paint, TRUE
            
            call IsShadowEnabled            
            .if !eax
                add [edx].WINDOWPOS.lx, 4
                add [edx].WINDOWPOS.cy, 4
            .endif
            
            m2m XCor, [edx].WINDOWPOS.x ; для востановления "фона" при обработке WM_PRINT (для тени)
            m2m YCor, [edx].WINDOWPOS.y 
            
        .endif

;        mov default_call, FALSE         

     .elseif uMsg == WM_PRINT

;        PrintDec eax, "WM_PRINT"

; ------------------Скопируем и отобразим неклиентскую область окна-----------------
        ; востановим фон
        invoke GetWindowDC, NULL
        mov hDCDsk, eax 

        invoke GetWindowRect, hWin, ADDR wrect        
        mov eax, wrect.right
        sub eax, wrect.left
        mov edx, wrect.bottom
        sub edx, wrect.top        

        invoke BitBlt, wParam, 0, 0, eax, edx, hDCDsk, XCor, YCor, SRCCOPY  

        invoke ReleaseDC, hWin, hDCDsk

        invoke GetWindowRect, hWin, ADDR wrect
        invoke CopyRect, ADDR cwrect, ADDR wrect 

        mov wrect.left, 0
        mov wrect.top, 0
        mov eax, cwrect.right
        sub eax, cwrect.left
        mov wrect.right, eax
        mov eax, cwrect.bottom
        sub eax, cwrect.top
        mov wrect.bottom, eax

;------------------Скопируем клиентскую область окна-------------------------------
 
        invoke GetClientRect, hWin, ADDR crect       
        call IsShadowEnabled            
        .if !eax                                          
            sub wrect.right, 4        ; ширина тени
            sub wrect.bottom, 4
            sub crect.right, 4        ; ширина тени
            sub crect.bottom, 4                     
        .endif        
        
        invoke CreateCompatibleDC, wParam
        mov hMemDC, eax
        invoke CreateCompatibleBitmap, wParam, wrect.right, wrect.bottom
        mov hBmp, eax 
        invoke SelectObject, hMemDC, eax
        mov hOldBmp, eax
;       
;        invoke SendMessage, hWin, WM_ERASEBKGND, hMemDC, 0  ; создаёт эффект 2 - развёртывания
        invoke FillRect, hMemDC, ADDR wrect, COLOR_MENU+1 
       
        xor lParam, PRF_CLIENT
        invoke CallWindowProc,OldWndProc,hWin,uMsg,hMemDC,lParam
        or  lParam, PRF_CLIENT        
        
        invoke BitBlt, wParam, 0, 0, wrect.right, wrect.bottom, hMemDC, 0,0,SRCCOPY        
       
        invoke OnDrawBorder, hWin, wParam ; прорисуем не клиентскую область       
       
        ; Отрисуем клиентскую область
       
        invoke SelectClipRgn, hMemDC, NULL  ; может и не надо
       
        xor lParam, PRF_NONCLIENT ; не клиентскую область не прорисовываем      
        invoke SendMessage, hWin, WM_PRINTCLIENT, hMemDC, lParam
        or lParam, PRF_NONCLIENT
        
        mov wndOffset.x, 0
        mov wndOffset.y, 0
        invoke ClientToScreen, hWin, ADDR wndOffset
        
        mov eax,cwrect.top          ; для всплывающих меню (context) и системного
        sub wndOffset.y, eax
        mov eax,cwrect.left
        sub wndOffset.x, eax        
        
        .if wndOffset.x > 3         ; меню прокручиваеться
           add crect.right, 4
        .endif
        .if wndOffset.y > 3
           add crect.bottom, 4           
           invoke SetProp, hWin, ADDR szProp_NC, 2           
        .endif     

        invoke BitBlt, wParam, wndOffset.x, wndOffset.y, crect.right, crect.bottom, hMemDC, 0, 0,SRCCOPY
        
;-------------------Освободим ресурсы--------------------------------------------        

        invoke SelectObject, hMemDC, hOldBmp
        invoke DeleteObject, eax
        invoke DeleteDC, hMemDC
       
        mov default_call, FALSE   

    .endif
    
    
    .if default_call == TRUE
        invoke CallWindowProc,OldWndProc,hWin,uMsg,wParam,lParam    ; call original wndproc for default handling
        ret    
    .endif    

    xor eax,eax
    ret
WndProc_WindowMenu endp

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

OnDrawBorder proc uses ebx edx ecx hWin :HWND, hDC :HDC

LOCAL crect    :RECT
LOCAL wrect     :RECT
LOCAL cwrect    :RECT
LOCAL Rct       :RECT

LOCAL xX        :DWORD
LOCAL yY        :DWORD

LOCAL hPenLeft      :HPEN
LOCAL hPenRight     :HPEN
LOCAL OldPen        :HPEN
LOCAL colorMenuBar  :COLORREF
LOCAL colorBorder   :COLORREF
LOCAL colorWindow   :COLORREF
LOCAL tmp       :DWORD

LOCAL hNCRgn    :HRGN
LOCAL hCRgn     :HRGN
LOCAL hCombineRgn :HRGN     


    ; Get the size of the menu...
    
    invoke GetWindowRect, hWin, ADDR wrect
    invoke GetClientRect, hWin, ADDR crect
    invoke CopyRect, ADDR cwrect, ADDR wrect 

    mov Rct.left, 0
    mov Rct.top, 0
    mov eax, cwrect.right
    sub eax, cwrect.left
    mov Rct.right, eax
    mov eax, cwrect.bottom
    sub eax, cwrect.top
    mov Rct.bottom, eax
    
    call IsShadowEnabled           
    .if !eax 
        sub Rct.right, 4        ; ширина тени
        sub Rct.bottom, 4              
    .endif   
    
;    invoke InflateRect, ADDR Rct, -2, -2 
;    invoke CreateRectRgnIndirect, ADDR Rct
;    mov hNCRgn, eax
;    
;    invoke FillRect, hDC, ADDR crect, COLOR_MENU+1 
;   
;    invoke InflateRect, ADDR Rct, 2, 2
;    
;    invoke CreateRectRgnIndirect, ADDR crect
;    mov hCRgn, eax
;    
;    invoke CreateRectRgn, 0, 0, 0, 0
;    mov hCombineRgn, eax
;    
;    invoke CombineRgn, hCombineRgn, hCRgn, hNCRgn, RGN_XOR
;    
;    invoke GetSysColorBrush,COLOR_BTNSHADOW
;    invoke FillRgn, hDC, hCombineRgn, eax
    
    
    invoke GetSysColorBrush,COLOR_BTNSHADOW
    invoke FrameRect, hDC, ADDR Rct, eax

;;--------------------------------------------------------------------------------

    mov colorBorder, $invoke ( GetSysColor, COLOR_HIGHLIGHT )
    mov colorMenuBar, $invoke ( GetSysColor, COLOR_MENU )
    mov colorWindow, $invoke ( GetSysColor, COLOR_WINDOW )

    ; создадим перо
    
    invoke GrayColor, colorMenuBar
    mov edx, 255
    sub edx, eax
    
    .if eax > 215
        invoke MixedColor, colorMenuBar, colorBorder            
    .else   
        invoke LightenColor, edx, colorMenuBar  
    .endif
    
    invoke CreatePen, PS_SOLID, 1, eax 
    mov hPenLeft, eax
    

    invoke GrayColor, colorWindow
    mov edx, 255
    sub edx, eax
    
    .if eax > 215
        invoke MixedColor, colorWindow, colorMenuBar        
    .else   
        invoke LightenColor, edx, colorWindow   
    .endif  
    
    invoke CreatePen,PS_SOLID, 1, eax
    mov hPenRight, eax

;-------------------------1 граница слева-----------------------------------
    invoke InflateRect, ADDR Rct, -1, -1    

    invoke SelectObject, hDC, hPenLeft
    mov OldPen, eax
    
    invoke MoveToEx, hDC, Rct.left, Rct.top, NULL
    m2m tmp, Rct.left
    mov eax, WidthBorder
    add eax, 2
    add tmp, eax
    
    invoke LineTo, hDC, tmp, Rct.top
    invoke MoveToEx, hDC, Rct.left, Rct.top, NULL
    mov ebx, Rct.bottom
    dec ebx
    invoke LineTo, hDC, Rct.left, ebx
    invoke LineTo, hDC, tmp, ebx
;   
;-------------------------1 граница справа-------------------------------
    
    invoke SelectObject, hDC, hPenRight
    mov ecx, Rct.right
    dec ecx
    invoke LineTo, hDC, ecx, ebx
    mov ecx, Rct.right
    dec ecx
    invoke LineTo, hDC, ecx, Rct.top
    dec tmp
    invoke LineTo, hDC, tmp, Rct.top
    
;-------------------------2 граница слева-----------------------------------
    invoke InflateRect, ADDR Rct, -1, -1    

    invoke SelectObject, hDC, hPenLeft
    mov OldPen, eax
    
    invoke MoveToEx, hDC, Rct.left, Rct.top, NULL
    m2m tmp, Rct.left
    mov eax, WidthBorder
    add eax, 1
    add tmp, eax
    
    invoke LineTo, hDC, tmp, Rct.top
    invoke MoveToEx, hDC, Rct.left, Rct.top, NULL
    mov ebx, Rct.bottom
    dec ebx
    invoke LineTo, hDC, Rct.left, ebx
    invoke LineTo, hDC, tmp, ebx
    
;-------------------------2 граница справа-------------------------------
    
    invoke SelectObject, hDC, hPenRight
    mov ecx, Rct.right
    dec ecx
    invoke LineTo, hDC, ecx, ebx
    mov ecx, Rct.right
    dec ecx
    invoke LineTo, hDC, ecx, Rct.top
    dec tmp
    invoke LineTo, hDC, tmp, Rct.top
            
;-------------------------Освободим ресурсы GDI----------------------------------
    
    invoke SelectObject, hDC, OldPen    
    invoke DeleteObject, hPenLeft
    invoke DeleteObject, hPenRight

    call IsShadowEnabled
            
    .if !eax
        invoke OnDrawShade, hWin, hDC
    .endif

    ret
OnDrawBorder endp

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

OnDrawShade proc hWin :HWND, hDC :HDC

LOCAL wrect     :RECT
LOCAL Rct       :RECT

    ; Get the size of the menu...
    
    invoke GetWindowRect, hWin, ADDR wrect

    mov Rct.top, 4
    mov eax, wrect.right
    sub eax, wrect.left
    mov Rct.right, eax
    mov Rct.left, eax
    sub Rct.left, 4
    mov eax, wrect.bottom
    sub eax, wrect.top
    mov Rct.bottom, 8    
    invoke DrawShade, hDC, ADDR Rct, DARK_LEFT, DARK_DOWN, 5, 5
 
    mov Rct.top, 8
    mov eax, wrect.right
    sub eax, wrect.left
    mov Rct.right, eax
    mov Rct.left, eax
    sub Rct.left, 4
    mov eax, wrect.bottom
    sub eax, wrect.top
    sub eax, 4
    mov Rct.bottom, eax 
    invoke DrawShade, hDC, ADDR Rct, DARK_LEFT, DARK_NONE, 12, NULL
    
    mov eax, wrect.right
    sub eax, wrect.left
    mov Rct.right, eax
    mov Rct.left, eax
    sub Rct.left, 4
    mov eax, wrect.bottom
    sub eax, wrect.top
    mov Rct.bottom, eax
    sub eax, 4
    mov Rct.top, eax     
    invoke DrawShade, hDC, ADDR Rct, DARK_LEFT, DARK_UP, 3, 3
    
    mov Rct.right, 8
    mov Rct.left, 4
    mov eax, wrect.bottom
    sub eax, wrect.top
    mov Rct.bottom, eax
    sub eax, 4
    mov Rct.top, eax
    invoke DrawShade, hDC, ADDR Rct, DARK_RIGHT, DARK_UP, 5, 5
    
    mov eax, wrect.right
    sub eax, wrect.left
    sub eax, 4
    mov Rct.right, eax
    mov Rct.left, 8
    mov eax, wrect.bottom
    sub eax, wrect.top
    mov Rct.bottom, eax
    sub eax, 4
    mov Rct.top, eax
    invoke DrawShade, hDC, ADDR Rct, DARK_NONE, DARK_UP, NULL, 12

    ret
OnDrawShade endp

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

UnSubClassMenu proc hWin :HWND

            invoke GetProp, hWin, ADDR szProp_NC
            .if eax
                ;invoke SetProp, hWin, szProp_NC, NULL
                invoke RemoveProp, hWin, ADDR szProp_NC
            .endif

            invoke GetProp, hWin, ADDR szProp_XX
            .if eax
                invoke SetWindowLong, hWin, GWL_WNDPROC, eax
                invoke RemoveProp, hWin, ADDR szProp_XX
            .endif
    ret
UnSubClassMenu endp