I have setup a hook on WM_SETTEXT message using WH_CALLWNDPROC.
In hook procedure
CWPSTRUCT* info = (CWPSTRUCT*) lParam;
wchar_t *wsz = NULL;
switch(info->message)
{
case WM_SETTEXT:
wsz = (wchar_t *) info->lParam;
//info->lParam = (LPARAM) L"Hello";
//SendMessage(info->hWnd,WM_SETTEXT,0,(LPARAM)L"HEllo");
//SetWindowText(info->hWnd,L"Hello");
break;
}
Is it possible to change the string as done above in the code.
I tried by using APIs like
SendMessage(info->hWnd,WM_SETTEXT,0,(LPARAM)L"HEllo");
SetWindowText(info->hWnd,L"Hello");
But none of them working.Idea here is to hook WM_SETTEXT message and change the string before it reached destination window.
No, the WH_CALLWNDPROC doesn't allow you to modify messages, the documentation for CallWndProc directly states this.
The WH_GETMESSAGE does allow you to modify the message. See the documentation for GetMsgProc. However, this probably won't work for what you want since it only messages that are retrieved with GetMessage() or PeekMessage() and send messages call the WndProc directly rather than using the message queue.
The way to do what you want is to use the WH_CBT hook and listed for HCBT_CREATEWND events. Then subclass the window as it is created and handle the WM_SETTEXT message.
Related
How can I send a double click message to the specified listview element in Windows? I know that i need to use SendMessage function, but I'm not sure about an arguments to this function. Can you give me an example, please?
How to fake a NM_DBLCLK notification:
#include <Commctrl.h>
// ensure those variables are ok
HWND hWndListViewParent;
INT iListViewID;
HWND hWndListView;
[...]
NMITEMACTIVATE nmia;
nmia.hdr.code = NM_DBLCLK;
nmia.hdr.hwndFrom = hWndListView;
nmia.hdr.idFrom = iListViewID;
// set up the rest of NMITEMACTIVATE
[...]
SendMessage( hWndListViewParent, WM_NOTIFY, (WPARAM)iListViewID, (LPARAM)&nmia );
I don't think you can do that cross process, however. Try it. If that indedd doesn't work, you will have to fake mouse action via SendInput, or maybe use UIAutomation.
I am working on writing a simple game engine and I am having trouble handling Windows console events; specifically, I cannot figure out how to pass custom data to the callback handler.
I first call this code to specify my callback function:
SetConsoleCtrlHandler((PHANDLER_ROUTINE)WindowsSystemManager::ConsoleControlHandler, true);
My static-member callback function is defined as:
bool WINAPI WindowsSystemManager::ConsoleControlHandler(DWORD controlType){
if(controlType == CTRL_CLOSE_EVENT){
MessageBox(NULL, L"Close Event Captured", L"Close Event Captured", NULL);
}
return true;
}
Everything works fine - when I click on the close button in the console, this MessageBox pops up. Only problem is, I need to call code that flushes a logging buffer to a log file on this type of shutdown (as well as other clean-up), and the Logger instance is a member in my WindowsSystemManager.
I have dealt with a similar problem of passing custom data to window handles by using SetWindowLongPtr and GetWindowLongPtr successfully, but I can't find any information on how to do this type of thing with console control handlers. Any thoughts?
EDIT: I got this functionality working based on MSalters' suggestions. The final code for the console control handler is here:
bool WINAPI WindowsSystemManager::ConsoleControlHandler(DWORD controlType){
BerserkEngine* engine = (BerserkEngine*)GetWindowLongPtr(GetConsoleWindow(), GWLP_USERDATA);
if(controlType == CTRL_CLOSE_EVENT){
engine->~BerserkEngine();
PostQuitMessage(0);
}
return true;
}
Where I set this custom data pointer in the WindowsSystemManager constructor:
SetWindowLongPtr(GetConsoleWindow(), GWL_USERDATA, (LONG_PTR)this->engine);
I'm not sure why you'd need this. You can have multiple windows, but only one console.
However, GetConsoleWindow will give you the console HWND, on which you might call SetWindowLongPtr. Not very clean (you're not supposed to do this on windows that you don't manage), but it might just work.
Basically i make mousestruct in the hook
MOUSEHOOKSTRUCT* str;
Then make it from lparam,
LRESULT CALLBACK MouseProc( int nCode, WPARAM wParam, LPARAM lParam )
{
str = (MOUSEHOOKSTRUCT *) lParam;
...
Then I catch mousemovements
case WM_MOUSEMOVE:
wParm = AU3_WM_MOUSEMOVE;
fromp = WindowFromPoint(str->pt);
Then validate and try not to send to many messages...
if (fromp != currentwindow)
{
currentwindow= fromp;
PostMessage(m_hHwndMouse, wParm,(WPARAM)( (MOUSEHOOKSTRUCT*) lParam )->hwnd, LPARAM(fromp));
}
break;
This sends the mousemove message along with hwnd to my autoit app which inspects hwnd and if that hwnd is not active it activates it.
Func mouse_func($hWndGUI, $MsgID, $wParam, $lParam)
Select
Case $MsgID = $WM_AUTOITMOUSEMOVE
If GUICtrlRead($activateundermouse) = 1 And $sitting = 0 Then
;Local $starttime = _Timer_Init()
If StringInStr(WinGetTitle($lParam), "ID=") Then
If Not WinActive($lParam) Then
;ConsoleWrite("HOVERING NEW, Activate It: " & WinGetTitle($lParam) & #LF)
WinActivate($lParam)
EndIf
;ConsoleWrite("diff is > " & _Timer_Diff($starttime) & #LF)
EndIf
EndIf
This is how I am activating window that is hovered by the mouse but the problem is that rarely autoit wont read the message that should signal new window being hovered(or the dll with hook didnt send it, I dont know)
Also if the window is overlapping another window and both of them are valid windows that should be activate once hovered I get flickering as autoit is constantly trying to activate the current window and the overlapped one, in a loop
Is there something that perhaps I missed or could be doing wrong here?
It's easiest just to use the facility built into Windows. For example on Windows 7 it looks like this:
This capability is present in older versions of Windows too but is not exposed in such a simple interface. Instead you have to set it with a PowerToy or through SystemParametersInfo.
As Raymond Chen explains, this is a user preference which should not be changed without the user's consent.
You can use the blocking SendMessage instead depending on surrounding implementation. PostMessage will send to the window message queue but may not have the priority you expect as it returns without waiting for the processing of the message.
Also check out SetCapture and ReleaseCapture to change which window is capturing mouse events based on a hit test in mouse move as an alternative to forwarding. Only one window at a time can capture mouse events using these functions so that will solve your flicker issue of the windows forwarding messages to each other most likely.
Why does Windows SendMessage() always return ZERO, even the message delivery is success? Is there anyway to check the message delivery failure with SendMessage() ?
EDIT
Forgot to mention that I'm using SendMessage() inside a c++ DLL
LRESULT result = ::SendMessage(hwndOtherWindow,WM_COPYDATA, NULL/*(WPARAM)this->GetSafeHwnd()*/,(LPARAM)&structCDS);
"result" is always zero :(, but message delivers to other window successfully
EDIT
BOOL CDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
{
return /*CDialog::OnCopyData(pWnd, pCopyDataStruct)*/ true; //true is the trick
}
A zero return from SendMessage for WM_COPYDATA means the target application didn't process the message (FALSE = 0).
The message might deliver successfully, but if the target application doesn't handle the message properly (ie, wrong return value, or passing it to the default window procedure) then your SendMessage call will appear to come back with the wrong result.
It might be worth your time to see what the target application's handling of the WM_COPYDATA message is, if possible.
I have setup a hook on WM_SETTEXT message using WH_CALLWNDPROC.
In hook procedure
CWPSTRUCT* info = (CWPSTRUCT*) lParam;
switch(info->message)
{
case WM_SETTEXT:
break;
}
Now in the above code how can I get the string that is passed along WM_SETTEXT message?
I am not able to get this information anywher..
The lParam passed to WM_SETTEXT contains the string, so info->lParam should have the info you want.
According to http://msdn.microsoft.com/en-us/library/ms632644(VS.85).aspx
You should be able to get that with info->lParam.