![]() |
|
|
|
#1
|
|||
|
|||
|
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);
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); 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. |
|
#2
|
|||
|
|||
|
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
}
}
I cannot defeat that damn GetMessagePos(). |
|
#3
|
|||
|
|||
|
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); (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); (3) post message without setting the cursor Code:
hTreeView.SetFocus(); ::PostMessage((HWND)hTreeView, WM_LBUTTONDOWN, MK_LBUTTON, cp.y<<16 | cp.x); (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); Best regards bilbo |
|
#4
|
|||
|
|||
|
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)¬ify);
*/
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 Last edited by BlackWhite; 02-11-2015 at 12:04. |
|
#5
|
|||
|
|||
|
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 |
|
#6
|
|||
|
|||
|
Quote:
Will you please try intercepting WM_NOTIFY in message processing instead of WM_LBUTTON ? Thank you. |
|
#7
|
|||
|
|||
|
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 substitute SendMessage() for PostMessage(), the above code will not work. So, I'm much indebted to bilbo. |
|
#8
|
|||
|
|||
|
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 |
|
#9
|
|||
|
|||
|
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));
}
|
![]() |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Simulating a Button Push | lilmeanman | General Discussion | 16 | 02-18-2005 09:24 |