-- illustrates use of WH_MSGFILTER, and WH_CBT message hooks.
-- this program *sometimes* creates a GPF on closing.
-- I've yet to find out why !,
-- so I've left it out of the 'tuts'.

include win32lib.ew
without warning

atom jk,flag
  flag=0

constant
  HCBT_DESTROYWND=4,
  HCBT_ACTIVATE=5,
  zSetWindowsHookEx=registerw32Function(user32,"SetWindowsHookExA",
  { C_INT,C_INT,C_INT,C_INT},C_INT ),
  zUnhookWindowsHookEx=registerw32Function(user32,"UnhookWindowsHookEx",
  { C_INT },C_INT ),
  zGetCurrentThreadId=registerw32Function(kernel32,"GetCurrentThreadId",
  {},C_INT ),
  zCallNextHookEx=registerw32Function(user32,"CallNextHookEx",
  { C_INT,C_INT,C_INT,C_INT},C_INT ),


  MSGF_DIALOGBOX=0,
  WM_KEYFIRST=256,
  WM_KEYLAST=264,
  MSG=acquire_mem(0,16)


sequence mystyle
  mystyle={WS_CAPTION,WS_SYSMENU,WS_THICKFRAME}

constant
  win=create(Window,"'hooking' threads",0,5,5,300,300,mystyle),
  menu1=create(Menu,"About",win,0,0,0,0,0),
  menu2=create(MenuItem,"This !",menu1,0,0,0,0,0),
  dat=create(LText,"",win,5,5,140,20,0),
  dat2=create(LText,"",win,5,25,140,20,0),
  dat3=create(LText,"",win,150,5,140,20,0),
  dat4=create(LText,"",win,150,25,140,20,0),
  dat5=create(LText,"",win,5,45,140,20,0),
  button=create(PushButton,"Start",win,10,150,60,30,0),
  pix = create(Pixmap,"",0,0,0,34,34,0),
  pix2=create(Pixmap,"",0,0,0,34,34,0),
  mytimer=1

  setPenColor(pix2,getSysColor( COLOR_BTNFACE ))
  drawRectangle(pix2,1,0,0,34,34)

  setFont(button,"System",10,0)
  showWindow(win,SW_NORMAL)
  setPixmap( pix, loadBitmapFromFile("smile.bmp") )

atom threadid

  threadid=w32Func(zGetCurrentThreadId,{} )
  setText(dat,sprintf("thread_id = %x",{threadid}))

atom left,top,right,bottom,new_x,new_y,msg_handle,msg_pos,mem
  msg_pos=0

sequence main_pos
  main_pos={}

atom hook, hook2


  -- the call_back routine for our WH_MSGFILTER message hook.
function MessageProc(atom message,atom wParam,atom lParam)
  atom result, keyvalue, ret
    ret=0

  if flag=1 then --**

    if message=MSGF_DIALOGBOX then
      result=peek4u(lParam+4)
      keyvalue=peek4u(lParam+8)
      if result = WM_LBUTTONUP or keyvalue=VK_SPACE or keyvalue=VK_RETURN then
        mem=acquire_mem(0,16)
        msg_pos=w32Func(xGetWindowRect,{msg_handle,mem})
        left=peek4s(mem)
        top=peek4s(mem+4)
        right=peek4s(mem+8)
        bottom=peek4s(mem+12)
        release_mem(mem)
        copyBlt(Screen,left+15,top+85,pix)  -- smily location
        sleep(1)
      end if
      ret=1
    end if
    if message < 0 then
      -- this is probably not -really- necessary ?
      jk=w32Func(zCallNextHookEx,{hook2,message,wParam,lParam})
      ret=jk
    else
      ret=0
    end if

  end if --**

  return ret
end function
constant fake2=call_back(routine_id("MessageProc"))

hook2=w32Func(zSetWindowsHookEx,{ WH_MSGFILTER, fake2, NULL, threadid } )


-- the call_back routine for our WH_CBT message hook.
function CBTProc(atom message,atom wParam,atom lParam)
  msg_handle=wParam
  if flag=0 then
    if message = HCBT_ACTIVATE then 
      setText(dat3,"call_back ...got here !")
      setText(dat4,sprintf("message-box_id = %x",{wParam}))
      main_pos=getWindowRect(win)
      mem=acquire_mem(0,16)
      msg_pos=w32Func(xGetWindowRect,{wParam,mem})
      left=peek4s(mem)
      top=peek4s(mem+4)
      right=peek4s(mem+8)
      bottom=peek4s(mem+12)
      release_mem(mem)
      new_x=floor(((main_pos[3]+main_pos[1])/2)-((right-left)/2))
      new_y=floor(((main_pos[4]+main_pos[2])/2)-((bottom-top)/2))
      jk=w32Func(xMoveWindow,{wParam,new_x,new_y,right-left,bottom-top,1})
      flag=1
    end if
  end if
  return NULL
end function
constant fake=call_back(routine_id("CBTProc"))


hook=w32Func(zSetWindowsHookEx,{ WH_CBT, fake, NULL, threadid } )
setText(dat2,sprintf("hook_id = %x",{hook}))


procedure go_away()
  atom jk2
    jk=w32Func(zUnhookWindowsHookEx, {hook} )
    jk2=w32Func(zUnhookWindowsHookEx, {hook2} )
    setText(dat5,sprintf("unhook_success %x,%x",{jk,jk2}))
    sleep(2)
  end procedure
  --
  onClose[win]=routine_id("go_away")

procedure message()
  flag=0
  setEnable(button,False)
  jk = message_box( "This message box should open\n" &
  "< centered >  over the application\n ", -- give smily extra space
  "... a thread 'hook' demo.",#2000)
  if jk = IDOK then
    setText(dat3,"")
    setText(dat4,"")
    main_pos=getWindowRect(win)
    new_x=floor((main_pos[3]+main_pos[1])/2 -17)
    new_y=floor((main_pos[4]+main_pos[2])/2 -17)
    copyBlt(Screen,new_x,new_y,pix)
    setTimer(win, mytimer, 1250)
  end if
end procedure
--
onClick[button]=routine_id("message")

procedure on_timer(integer id)
  if flag=1 then --**
    main_pos=getWindowRect(win)
    new_x=floor((main_pos[3]+main_pos[1])/2 -17)
    new_y=floor((main_pos[4]+main_pos[2])/2 -17)
    copyBlt(Screen,new_x,new_y,pix2)
    killTimer(win,mytimer)
    setEnable(button,True)
    setFocus(button)
  end if --**
end procedure
--
onTimer[win]=routine_id("on_timer")

procedure on_key(integer key,integer shift)
  if key=VK_RETURN then
    jk=w32Func(xGetMessage,{MSG,getHandle(button),WM_KEYFIRST,WM_KEYLAST})
    message()
  end if
end procedure
--
onKeyPress[button]=routine_id("on_key")

WinMain(win,Normal)
