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.
Related
About
I am trying to build a custom mouse input for Unity that gets the data directly from the HID. I do this because I want to try if there is any difference (when using my own custom mouse input) to the Unity API that gives me raw mouse input.
Also I need to say that everything I am doing right now does not happen within Unity. I want to build an C++ application and then pass the data to Unity (that's not a part of this question).
This link (MSDN High-Definition Mouse Movement) shows that there are three different types of messages I can use. Due to I need so called "High-Definition Mouse Movement" I need to go with WM_INPUT.
This message can be caught with the WinProc handler as the documentation says. Within that callback the raw mouse data can be accessed. This is what I want to achieve and where I need help.
My current approach
The documentation (link above) gives me this example to register the mouse:
RAWINPUTDEVICE Rid[1];
Rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC;
Rid[0].usUsage = HID_USAGE_GENERIC_MOUSE;
Rid[0].dwFlags = RIDEV_INPUTSINK;
Rid[0].hwndTarget = gameWindowHandle;
regDeviceDone = RegisterRawInputDevices(Rid, 1, sizeof(Rid[0]));
The following two lines were modified by me:
Rid[0].hwndTarget = gameWindowHandle;
There I define the Unity window as target. gameWindowHandle is set by EnumWindows.
The other line I changed is the last one due to there is a syntax error (missing parenthesis).
As far as I understood the documentation right this should be it. Now the following callback should be called when there are WM_INPUT messages sent to the Unity window.
LRESULT CALLBACK WindowProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
) {
printf("%d", uMsg);
switch (uMsg) {
case WM_INPUT:
UINT dwSize = 40;
static BYTE lpb[40];
GetRawInputData((HRAWINPUT)lParam, RID_INPUT,
lpb, &dwSize, sizeof(RAWINPUTHEADER));
RAWINPUT* raw = (RAWINPUT*)lpb;
if (raw->header.dwType == RIM_TYPEMOUSE)
{
int xPosRelative = raw->data.mouse.lLastX;
int yPosRelative = raw->data.mouse.lLastY;
printf("X: %d, Y: %d", xPosRelative, yPosRelative);
}
break;
}
return NULL;
}
My problems
The first problem I have is that calling this
regDeviceDone = RegisterRawInputDevices(Rid, 1, sizeof(Rid[0]));
does not return true as it should. Instead it returns false and GetLastError gives me error 87 (after googling this I found out it has to do with wrong parameters).
The documentation says to do so but unfortunately it does not work the way I do it.
Another problem is how to keep the application alive. After registering the device I need to wait for the callbacks to trigger (if they would work). How can I achieve that the application does nothing than waiting for the callbacks?
Is my approach even reasonable or am I doing completely wrong and have to use different APIs?
Your approach is wrong. First, RawInput requires Window. A Window under your control with your own WndProc. Hence in your C++ library, you should define a window procedure. Start a thread. In this thread register window class with that procedure. After you succeed in registering your class, create HWND_MESSAGE window, register your devices and enter a while GetMessage... DispatchMessage loop. This should be done in a separate thread. In your window procedure you must now catch WM_INPUT messages. Enjoy.
We can use this as the last argument to CreateWindow and get a pointer to the app object in the WndProc like this:
if(message == WM_CREATE)
{
CREATESTRUCT* cs = (CREATESTRUCT*)lParam;
pApp = (DemoApp*)cs->lpCreateParams;
return 0;
}
What is the best way to access this pointer in a Dialog Message Proc? Is the solution to make a global pointer?
You get additional initialization data with WM_INITDIALOG, see WM_INITDIALOG message :
lParam
Additional initialization data. This data is passed to the system
as the lParam parameter in a call to the CreateDialogIndirectParam,
CreateDialogParam, DialogBoxIndirectParam, or DialogBoxParam function
used to create the dialog box. For property sheets, this parameter is
a pointer to the PROPSHEETPAGE structure used to create the page. This
parameter is zero if any other dialog box creation function is used.
That is, you can pass lParam as an argument with CreateDialogParam and the dialog proc will receive it with WM_INITDIALOG message.
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.
When do you use ON_COMMAND and when do we use ON_MESSAGE. What are the differences between them.
ON_COMMAND is specifically used to handle a command message (i.e. WM_COMMAND) like the click of a button/menu item/toolbar button.
ON_MESSAGE is more generic and can be used for any windows message. It is usually used for less frequently handled messages for which specific message map macros have not been provided. You can use ON_MESSAGE to handle ON_COMMAND messages as well but you will have to extract message information (i.e. command ID) yourself.
Example:
See here:
http://msdn.microsoft.com/en-us/library/k35k2bfs(VS.80).aspx
http://msdn.microsoft.com/en-us/library/ms647591(VS.85).aspx
In the message map:
ON_MESSAGE( WM_COMMAND, OnMyCommand )
The handler:
LRESULT CMyWnd::OnMyCommand( WPARAM wParam, LPARAM lParam )
{
// ... Handle message here
int commandId = LOWORD(wParam);
switch(commandId){
case ID_HELLOCOMMAND:
MessageBox(0, "Hello there!", "ID_HELLO_COMMAND", MB_OK);
break;
// ... other commands here
}
return 0L;
}
Disclaimer: Owing to MFC's message pump mechanism, you may have to do a bit more than what's shown above. The best man to ask: Jeff Prosise
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.