Exetools  

Go Back   Exetools > General > General Discussion

Notices

Reply
 
Thread Tools Display Modes
  #1  
Old 02-09-2015, 12:13
BlackWhite BlackWhite is offline
Friend
 
Join Date: Apr 2013
Posts: 85
Rept. Given: 4
Rept. Rcvd 14 Times in 6 Posts
Thanks Given: 14
Thanks Rcvd at 56 Times in 25 Posts
BlackWhite Reputation: 14
Does simulating click affect GetMessagePos()?

I want to select one item of CTreeCtrl by sending message
WM_LBUTTONDOWN to it, but the CTreeCtrl's message processing
function uses API GetMessagePos() to fetch the last message's
position which is always not the one corresponding to my simulating
WM_LBUTTONDOWN. The CTreeCtrl's message processing function
further uses CTreeCtrl::HitTest() to check whether that item was clicked,
and inevitably HitTest() returns NULL.

My code is as follows:
Code:
   POINT ap={0x0027, 0x0289}, cp={0x0025, 0x00AE};
   ScreenToClient((HWND)hTreeView, &ap);
   cp = ap;
   SendMessage((HWND)hTreeView, WM_LBUTTONDOWN, MK_LBUTTON, cp.y<<16|cp.x);
The screen coordinates (0x0027, 0x0289) are absolutly correct, because
I have used SetCursorPos() to check them. And I have also tried the
following code to activate the tree item, yet it was selected but not
activated(its corresponding code was not executed):
Code:
   SendMessage((HWND)hTreeView, TVM_SELECTITEM, TVGN_CARET, hLstRetract);
So the problem lies in GetMessagePos(). I guess this API ignores any
simulating message, it only returns the position of the last physical
message say one actual click. Does anyone have an idea to defeat
GetMessagePos()? Thank you.
Reply With Quote
  #2  
Old 02-10-2015, 15:42
BlackWhite BlackWhite is offline
Friend
 
Join Date: Apr 2013
Posts: 85
Rept. Given: 4
Rept. Rcvd 14 Times in 6 Posts
Thanks Given: 14
Thanks Rcvd at 56 Times in 25 Posts
BlackWhite Reputation: 14
It seems that no one has encountered such a problem.
Yesterday, I resorted to patch the message processing
function so that it can accept the item selected by my
simulating message:
Code:
extern "C" __declspec(naked) void hook_tc(void)
{
   __asm
   {
      test edi, edi // EDI=hMenuItem
      jz is_it_treeview
   do_nothing:
      ret
   is_it_treeview:
      mov eax, [esi+20h] // EAX=current hWnd processing message
      cmp eax, hTreeView
      je is_it_retract
   it_is_not_retract:
      add dword ptr [esp], (0x2D57D - 0x2D4CE)
      ret
   is_it_retract:
      call is_retract_selected
      test eax, eax
      jz it_is_not_retract
      mov edi, hLstRetract        // patch EDI
      mov dword ptr [esp+0x24], 4 // patch flag=4=TVHT_ONITEMLABEL
      ret
   }
}
Though the problem is solved temporarily, but it's still a pity that
I cannot defeat that damn GetMessagePos().
Reply With Quote
  #3  
Old 02-10-2015, 21:17
bilbo bilbo is offline
Friend
 
Join Date: Jul 2004
Posts: 103
Rept. Given: 36
Rept. Rcvd 15 Times in 12 Posts
Thanks Given: 15
Thanks Rcvd at 17 Times in 11 Posts
bilbo Reputation: 15
Hi BlackWhite,
I found your question rather interesting so I decided to spend some time on it.

First of all, do not forget to set the focus to the tree control, before sending the message, else no selection is performed!

Next, you can have 4 cases (note that in all 4 cases the simulated selection works, in the sense that the wanted item is highlighted):

(1) send message without setting the cursor:
Code:
hTreeView.SetFocus();
::SendMessage((HWND)hTreeView, WM_LBUTTONDOWN, MK_LBUTTON, cp.y<<16 | cp.x);
GetMessagePos() KO, GetCursorPos() KO, HitTest() KO

(2) send message preceeded by set cursor:
Code:
hTreeView.SetFocus();
SetCursorPos(screen.x, screen.y);
::SendMessage((HWND)hTreeView, WM_LBUTTONDOWN, MK_LBUTTON, cp.y<<16 | cp.x);
GetMessagePos() KO, GetCursorPos() OK, HitTest() KO

(3) post message without setting the cursor
Code:
hTreeView.SetFocus();
::PostMessage((HWND)hTreeView, WM_LBUTTONDOWN, MK_LBUTTON, cp.y<<16 | cp.x);
GetMessagePos() OK, GetCursorPos() KO, HitTest() OK

(4) post message preceeded by set cursor:
Code:
hTreeView.SetFocus();
SetCursorPos(screen.x, screen.y);
::PostMessage((HWND)hTreeView, WM_LBUTTONDOWN, MK_LBUTTON, cp.y<<16 | cp.x);
GetMessagePos() OK, GetCursorPos() OK, HitTest() OK

Best regards
bilbo
Reply With Quote
  #4  
Old 02-11-2015, 11:08
BlackWhite BlackWhite is offline
Friend
 
Join Date: Apr 2013
Posts: 85
Rept. Given: 4
Rept. Rcvd 14 Times in 6 Posts
Thanks Given: 14
Thanks Rcvd at 56 Times in 25 Posts
BlackWhite Reputation: 14
Hi, bilbo. Thank you for your experiments.
But I found that SetFocus() did not work in my case,
GetMessagePos() still returned the wrong value.
Code:
   SetFocus((HWND)hTreeView);
   SetCursorPos(0x0027, 0x0289);
   POINT ap={0x0027, 0x0289}, cp={0x0025, 0x00AE};
   ScreenToClient((HWND)hTreeView, &ap);
   cp = ap;
   SendMessage((HWND)hTreeView, WM_LBUTTONDOWN, MK_LBUTTON, cp.y<<16|cp.x); // It does not work.
/* Whether or not the following WM_NOTIFY is sent, GetMessagePos() returns the wrong value.
   NMHDR notify;
   notify.hwndFrom = (HWND)hTreeView;
   notify.idFrom = 0x9E01; 
   notify.code = 0xFFFFFFFE; // NM_CLICK;  
   SendMessage(GetParent((HWND)hTreeView), 0x4E, 0x9E01, (long)&notify);
*/
In my case, the message processing function is bound to
hTreeView, and the message being processed is WM_NOTIFY,
here is the code for processing WM_NOTIFY:
Code:
0442D470    83EC 08         sub     esp, 8
0442D473    8B4424 10       mov     eax, [esp+10]
0442D477    53              push    ebx
0442D478    55              push    ebp
0442D479    56              push    esi
0442D47A    57              push    edi
0442D47B    8BF1            mov     esi, ecx; ESI=pTreeView
0442D47D    C700 00000000   mov     dword ptr [eax], 0
0442D483    C74424 20 00000>mov     dword ptr [esp+20], 0
0442D48B    E8 D8670200     call    <jmp.&MFC4.#CWnd::GetCurrentMessage_3021>; GetCurrentMessage() further calls GetMessagePos()
;[!] GetCurrentMessage() returns a MSG pointer in EAX
;EAX->hwnd=hTreeViewFather
;EAX->message=4Eh=WM_NOTIFY
;EAX->wParam=0xE901=hTreeView's ID
;EAX->lParam=pNMHDR
;       pNMHDR->hwndFrom=hTreeView, pNMHDR->idFrom=0xE901, pNMHDR->code=0xFFFFFFFE=NM_CLICK
;EAX->pt.x = screen coordinate x  \ They are not the same as those corresponding to my simulating 
;EAX->pt.y = screen coordinate y  / WM_LBUTTON message.

0442D490    8BC8            mov     ecx, eax
0442D492    8D5424 10       lea     edx, [esp+10]
0442D496    52              push    edx
0442D497    8B41 14         mov     eax, [ecx+14]; EAX=pt.x
0442D49A    8B49 18         mov     ecx, [ecx+18]; ECX=pt.y
0442D49D    894424 14       mov     [esp+14], eax
0442D4A1    8B46 20         mov     eax, [esi+20]; EAX=hTreeView
0442D4A4    894C24 18       mov     [esp+18], ecx
0442D4A8    50              push    eax
0442D4A9    FF15 F4E24604   call    [<&USER32.ScreenToClient>]                  ; user32.ScreenToClient
;[!]
;EDX->x=client coordinate x
;EDX->y=client coordinate y
0442D4AF    8B5424 14       mov     edx, [esp+14]
0442D4B3    8B4424 10       mov     eax, [esp+10]
0442D4B7    8D4C24 20       lea     ecx, [esp+20]
0442D4BB    51              push    ecx
0442D4BC    52              push    edx
0442D4BD    50              push    eax
0442D4BE    8BCE            mov     ecx, esi
0442D4C0    E8 9D670200     call    <jmp.&MFC42.#CTreeCtrl::HitTest_3914>
;[!] EAX=NULL, that's bad!
0442D4C5    8BF8            mov     edi, eax                                    ; EDI=hMenuItem
0442D4C7    85FF            test    edi, edi
0442D4C9    0F84 AE000000   je      0442D57D
......
0442D57D    5F              pop     edi                                         ; 05B0D428
0442D57E    5E              pop     esi
0442D57F    5D              pop     ebp
0442D580    5B              pop     ebx
0442D581    83C4 08         add     esp, 8
0442D584    C2 0800         retn    8
So, is there any difference between WM_LBUTTON and WM_NOTIFY?

Last edited by BlackWhite; 02-11-2015 at 12:04.
Reply With Quote
  #5  
Old 02-11-2015, 20:35
bilbo bilbo is offline
Friend
 
Join Date: Jul 2004
Posts: 103
Rept. Given: 36
Rept. Rcvd 15 Times in 12 Posts
Thanks Given: 15
Thanks Rcvd at 17 Times in 11 Posts
bilbo Reputation: 15
As I showed you, GetMessagePos does not work with SendMessage, but only with PostMessage.
In fact the GetMessagePos function retrieves the cursor position for the last message retrieved by the message queue, but SendMessage does not put the message on the queue.

Best regards
bilbo
Reply With Quote
  #6  
Old 02-11-2015, 21:40
BlackWhite BlackWhite is offline
Friend
 
Join Date: Apr 2013
Posts: 85
Rept. Given: 4
Rept. Rcvd 14 Times in 6 Posts
Thanks Given: 14
Thanks Rcvd at 56 Times in 25 Posts
BlackWhite Reputation: 14
Quote:
Originally Posted by bilbo View Post
As I showed you, GetMessagePos does not work with SendMessage, but only with PostMessage.
In fact the GetMessagePos function retrieves the cursor position for the last message retrieved by the message queue, but SendMessage does not put the message on the queue.

Best regards
bilbo
I have tried PostMessage(), but got failure.
Will you please try intercepting WM_NOTIFY in
message processing instead of WM_LBUTTON ?
Thank you.
Reply With Quote
  #7  
Old 02-12-2015, 23:31
BlackWhite BlackWhite is offline
Friend
 
Join Date: Apr 2013
Posts: 85
Rept. Given: 4
Rept. Rcvd 14 Times in 6 Posts
Thanks Given: 14
Thanks Rcvd at 56 Times in 25 Posts
BlackWhite Reputation: 14
I finally figure out why WM_LBUTTON does not trigger message processing of WM_NOTIFY. WM_NOTIFY should be simulated by posting two messages:
WM_LBUTTONDOWN
WM_LBUTTONUP
Here is the code:
Code:
   POINT ap={0x0027, 0x0289}, cp={0x0025, 0x00AE};
   SetFocus((HWND)hTreeView);
   SetCursorPos(ap.x, ap.y);
   ScreenToClient((HWND)hTreeView, &ap);
   cp = ap;
   PostMessage((HWND)hTreeView, WM_LBUTTONDOWN, MK_LBUTTON, cp.y<<16 | cp.x);
   PostMessage((HWND)hTreeView, WM_LBUTTONUP, 0, cp.y<<16 | cp.x);
If I delete SetFocus() or SetCursorPos(), the above code will not work;
If I substitute SendMessage() for PostMessage(), the above code will not work.
So, I'm much indebted to bilbo.
Reply With Quote
  #8  
Old 02-13-2015, 22:04
bilbo bilbo is offline
Friend
 
Join Date: Jul 2004
Posts: 103
Rept. Given: 36
Rept. Rcvd 15 Times in 12 Posts
Thanks Given: 15
Thanks Rcvd at 17 Times in 11 Posts
bilbo Reputation: 15
Nice trick, BlackWhite, to put a WM_LBUTTONUP message in the message queue too!
This way both notifications (TVN_SELCHANGED and NM_CLICK) now work!

Best regards
bilbo
Reply With Quote
  #9  
Old 02-14-2015, 02:54
mr.exodia mr.exodia is offline
Retired Moderator
 
Join Date: Nov 2011
Posts: 783
Rept. Given: 490
Rept. Rcvd 1,123 Times in 305 Posts
Thanks Given: 89
Thanks Rcvd at 716 Times in 333 Posts
mr.exodia Reputation: 1100-1299 mr.exodia Reputation: 1100-1299 mr.exodia Reputation: 1100-1299 mr.exodia Reputation: 1100-1299 mr.exodia Reputation: 1100-1299 mr.exodia Reputation: 1100-1299 mr.exodia Reputation: 1100-1299 mr.exodia Reputation: 1100-1299 mr.exodia Reputation: 1100-1299
Try this one, it simulates an actual click, in combination with SetMousePos you can click anywhere:

Code:
void LeftClick()
{
    INPUT Input = {0};
    Input.type = INPUT_MOUSE;
    Input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
    SendInput(1, &Input, sizeof(INPUT));
    ZeroMemory(&Input, sizeof(INPUT));
    Input.type = INPUT_MOUSE;
    Input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
    SendInput(1, &Input, sizeof(INPUT));
}
Greetings
Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Simulating a Button Push lilmeanman General Discussion 16 02-18-2005 09:24


All times are GMT +8. The time now is 21:36.


Always Your Best Friend: Aaron, JMI, ahmadmansoor, ZeNiX, chessgod101
( Since 1998 )