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: 80
Rept. Given: 4
Rept. Rcvd 14 Times in 6 Posts
Thanks Given: 12
Thanks Rcvd at 48 Times in 21 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: 80
Rept. Given: 4
Rept. Rcvd 14 Times in 6 Posts
Thanks Given: 12
Thanks Rcvd at 48 Times in 21 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: 80
Rept. Given: 4
Rept. Rcvd 14 Times in 6 Posts
Thanks Given: 12
Thanks Rcvd at 48 Times in 21 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: 80
Rept. Given: 4
Rept. Rcvd 14 Times in 6 Posts
Thanks Given: 12
Thanks Rcvd at 48 Times in 21 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, 15:54
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
I now see your problem: you must not intercept the first WM_NOTIFY which arrives, with notify code NM_CLICK (0xFFFFFFFE), but the following WM_NOTIFY, with notify code TVN_SELCHANGED (0xFFFFFE6E in ascii version, 0xFFFFFE3D in Unicode version)!

Best regards
bilbo
Reply With Quote
  #8  
Old 02-12-2015, 22:24
BlackWhite BlackWhite is offline
Friend
 
Join Date: Apr 2013
Posts: 80
Rept. Given: 4
Rept. Rcvd 14 Times in 6 Posts
Thanks Given: 12
Thanks Rcvd at 48 Times in 21 Posts
BlackWhite Reputation: 14
Quote:
Originally Posted by bilbo View Post
I now see your problem: you must not intercept the first WM_NOTIFY which arrives, with notify code NM_CLICK (0xFFFFFFFE), but the following WM_NOTIFY, with notify code TVN_SELCHANGED (0xFFFFFE6E in ascii version, 0xFFFFFE3D in Unicode version)!

Best regards
bilbo
Yes, I wish I could intercept WM_NOTIFY with code TVN_SELCHANGED
instead of NM_CLICK, but that program was not written by myself. It
stubbornly sticks to NM_CLICK.

I have done several experiments to defy GetMessagePos(), but got
no success:

Experiment1: It did not trigger the WM_NOTIFY event processing.
And if I change hWnd to hTreeView itself instead of its father,
the result is the same.
Code:
   POINT ap={0x0027, 0x0289}, cp={0x0025, 0x00AE};
   SetFocus(GetParent((HWND)hTreeView));
   SetCursorPos(ap.x, ap.y);
   ScreenToClient(GetParent((HWND)hTreeView), &ap);
   cp = ap;
   PostMessage(GetParent((HWND)hTreeView), WM_LBUTTONDOWN, MK_LBUTTON, cp.y<<16 | cp.x);
Experiment2: It triggered the WM_NOTIFY event processing,
but GetMessagePos() got the wrong coordinates.
Code:
   POINT ap={0x0027, 0x0289}, cp={0x0025, 0x00AE};
   SetFocus(GetParent((HWND)hTreeView));
   SetCursorPos(ap.x, ap.y);
   ScreenToClient(GetParent((HWND)hTreeView), &ap);
   cp = ap;
   PostMessage(GetParent((HWND)hTreeView), WM_LBUTTONDOWN, MK_LBUTTON, cp.y<<16 | cp.x);
   NMHDR notify;
   notify.hwndFrom = (HWND)hTreeView;
   notify.idFrom = 0xE901; 
   notify.code = NM_CLICK; // 0xFFFFFFFE
   SendMessage(GetParent((HWND)hTreeView), WM_NOTIFY, 0xE901, (long)&notify);
Experiment3: It did not triggered the WM_NOTIFY event processing.
Code:
   TV_ITEM ti;
   POINT ap={0x0027, 0x0289}, cp={0x0025, 0x00AE};
   ti.hItem = (HTREEITEM)hLstRetract;     
   ti.mask = TVIF_HANDLE | TVIF_STATE | TVIF_PARAM;   
   ti.stateMask = TVIF_HANDLE | TVIF_STATE | TVIF_PARAM;
   SendMessage((HWND)hTreeView, TVM_GETITEM, 0, (long)&ti);
   NM_TREEVIEW tvnm;
   memset(&tvnm, 0, sizeof(tvnm));
   tvnm.itemNew = ti;          
   tvnm.action = TVC_BYMOUSE; // by mouse click
   tvnm.ptDrag.x = cp.x; // client 
   tvnm.ptDrag.y = cp.y; // coordinates
   tvnm.hdr.hwndFrom = (HWND)hTreeView;
   tvnm.hdr.idFrom = 0xE901;
   tvnm.hdr.code = TVN_SELCHANGED;
   SendMessage(GetParent((HWND)hTreeView), WM_NOTIFY, 0xE901, (long)&tvnm);
I have traced that program by using OllyDbg & Soft-ICE to figure out
why Experiment3 failed:
Code:
73D322C3    FF75 08         push    dword ptr [ebp+8]
73D322C6    FF75 0C         push    dword ptr [ebp+C]
73D322C9    53              push    ebx
73D322CA    FF76 04         push    dword ptr [esi+4]
73D322CD    E8 DDFEFFFF     call    #AfxFindMessageEntry_1145;[!]=>*73D321AF
73D322D2    85C0            test    eax, eax; in simulating case, EAX=0
73D322D4    75 0F           jnz     short 73D322E5; in physical click case, EAX=4471860h
this_is_bad:
...
that_is_good:
73D322E5    FF75 14         push    dword ptr [ebp+14]
73D322E8    FF70 10         push    dword ptr [eax+10]; 0x26
73D322EB    FF75 10         push    dword ptr [ebp+10]
73D322EE    FF70 14         push    dword ptr [eax+14]; 0x442D470=message_processing_function_ptr
73D322F1    FF75 0C         push    dword ptr [ebp+C]
73D322F4    FF75 08         push    dword ptr [ebp+8]
73D322F7    57              push    edi
73D322F8    E8 6E000000     call    73D3236B; [!]
73D322FD  ^ EB DF           jmp     short 73D322DE
   || 
  \||/
   \/
;[!]*73D3236B
73D3236B    55              push    ebp
73D3236C    8BEC            mov     ebp, esp
73D3236E    8B45 20         mov     eax, [ebp+20]
73D32371    53              push    ebx
73D32372    33DB            xor     ebx, ebx
73D32374    43              inc     ebx
73D32375    85C0            test    eax, eax
73D32377    74 12           je      short 73D3238B
...
73D323C2    8B45 18         mov     eax, [ebp+18]
73D323C5    FF30            push    dword ptr [eax]
73D323C7    8B4D 08         mov     ecx, [ebp+8]
73D323CA    FF70 04         push    dword ptr [eax+4]
73D323CD    FF55 14         call    [ebp+14]; [!]=>*0x442D470=message_processing_function_ptr
73D323D0    E9 97000000     jmp     73D3246C
   || 
  \||/
   \/
;[!]73D321AF;#AfxFindMessageEntry_1145
73D321AF >  55              push    ebp
73D321B0    8BEC            mov     ebp, esp
73D321B2    53              push    ebx
73D321B3    8B5D 08         mov     ebx, [ebp+8]; EBX=4471848h->MessageMap
73D321B6    8B45 0C         mov     eax, [ebp+C]; EAX=EventCodePrefix=0xBC4E
73D321B9    8B55 10         mov     edx, [ebp+10]; EDX=EventCode=TVN_SELCHANGED=0xFE6E
73D321BC    8B4D 14         mov     ecx, [ebp+14]
73D321BF    837B 10 00      cmp     dword ptr [ebx+10], 0; is_it_null_message_map_item
73D321C3    74 1D           je      short 73D321E2; has reached the end of message map
73D321C5    3B03            cmp     eax, [ebx]; check EventCodePrefix
73D321C7    74 05           je      short 73D321CE
73D321C9    83C3 18         add     ebx, 18; EBX->next_message_map_item
73D321CC  ^ EB F1           jmp     short 73D321BF
73D321CE    3B53 04         cmp     edx, [ebx+4]; check EventCode
73D321D1  ^ 75 F6           jnz     short 73D321C9
73D321D3    3B4B 08         cmp     ecx, [ebx+8]
73D321D6  ^ 72 F1           jb      short 73D321C9
73D321D8    3B4B 0C         cmp     ecx, [ebx+C]
73D321DB  ^ 77 EC           ja      short 73D321C9
73D321DD    895D 08         mov     [ebp+8], ebx; save message_map_item_ptr
73D321E0    EB 05           jmp     short 73D321E7
73D321E2    33C0            xor     eax, eax
73D321E4    8945 08         mov     [ebp+8], eax
73D321E7    8B45 08         mov     eax, [ebp+8]; EAX=message_map_item_ptr
73D321EA    5B              pop     ebx         ; [EAX+14h]=message_processing_function_ptr
73D321EB    5D              pop     ebp
73D321EC    C2 1000         retn    10

;This is the message map. It contains 3 items. Every item holds 18h bytes.
04471848  64 03 00 00 00 00 00 00  00 00 00 00 00 00 00 00
04471858  0C 00 00 00 40 D4 42 04  4E BC 00 00 FE FF 00 00
04471868  00 00 00 00 00 00 00 00  26 00 00 00 70 D4 42 04
04471878  0F 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
04471888  0C 00 00 00 90 D5 42 04  00 00 00 00 00 00 00 00
04471898  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
According to the above analysis, that program's message map does not
contain an item related to TVN_SELCHANGED.

So I have fallen into a dilemma. If I PostMessage(WM_LBUTTON), that
will not trigger WM_NOTIFY's processing; If I SendMessage(WM_NOTIFY),
that program gets the wrong coordinates.

Do you have any good idea to defeat that damn program?
Reply With Quote
  #9  
Old 02-12-2015, 23:31
BlackWhite BlackWhite is offline
Friend
 
Join Date: Apr 2013
Posts: 80
Rept. Given: 4
Rept. Rcvd 14 Times in 6 Posts
Thanks Given: 12
Thanks Rcvd at 48 Times in 21 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
  #10  
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
  #11  
Old 02-14-2015, 02:54
mr.exodia mr.exodia is offline
Retired Moderator
 
Join Date: Nov 2011
Posts: 784
Rept. Given: 492
Rept. Rcvd 1,122 Times in 305 Posts
Thanks Given: 90
Thanks Rcvd at 711 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


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 09:04.


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