I'm working on a program that needs to work with an imported DLL. I can load the DLL, and execute functions within it fine.
The problem comes up when I need to extract data it has sent with Send/PostMessage.
The documentation says:
MSG_PSKCHARRDY
Numeric Value is WM_USER+1001 or 0x400+0x3E9 or 0x7E9 or 2025.
This message is sent from the DLL to the Window whose handle is passed when the fnStartSoundCard is called. It is sent whenever there is an ASCII character available from the receiver or if in the Transmit mode, when a character has been sent out the soundcard.
The following parameters are sent along with this message:
wParam = The ASCII character(0 to 255)
lParam = -1 if is a transmitted character, or the Receive channel number(0-49) that is sending the message.
I've added this as a case under my WindProc as case: WM_USER + 1001: and any code underneath is executed when the fnStartSoundCard function is called, so I know it's receiving the message.
But when I try to print the wParam as a char string, I always get an exception thrown at the end of my DispatchMessage(&msg) function here:
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
Exception thrown at 0x76524463 (ucrtbase.dll) in PSK31.exe:
0xC0000005: Access violation reading location 0x0000004D.
My message handler looks like this:
case WM_USER + 1001:
if (hWnd == GetActiveWindow()) {
char textChar;
SOMETHING = (char*)wParam;
printf(SOMETHING);
Sleep(1000);
}
break;
How can I get the char extracted from the message?
There are two mistakes in your code.
The documentation you quote clearly says that the MSG_DATARDY message is defined as WM_USER+1000 but you are using WM_USER+1001 instead.
The documentation you quote does not say anything about the message's wParam and lParam values being pointers to strings, but you are trying to treat the wParam as if it were, and it is clearly not. Your code is crashing trying to read from address 0x0000004D, which is a memory address reserved by the OS, so wParam can't be a pointer to data in application-accessible memory. 0x4D (77) is a small number, certainly small enough to look like the actual frequency number, so the numeric values of wParam and lParam should be used as-is, not casted to string pointers.
Try this instead:
#define MSG_DATARDY (WM_USER + 1000)
case MSG_DATARDY:
if (hWnd == GetActiveWindow()) {
int freq = (int) wParam;
int strength = (int) lParam;
printf("RX frequency: %d Hz, signal strength: %d", freq, strength);
Sleep(1000);
}
break;
UPDATE: in leau of the updated documentation you quoted, you are still making the same mistake regarding the wParam. It is NOT a pointer to an ASCII character. It is the actual character instead, so use the value as-is:
#define MSG_PSKCHARRDY (WM_USER + 1001)
case MSG_PSKCHARRDY:
if (hWnd == GetActiveWindow()) {
char textChar = (char) wParam;
int channel = (int) lParam;
if (channel == - 1) {
printf("TX character: %c", textChar);
}
else {
printf("RX channel: %d, character: %c, ", channel, textChar);
}
Sleep(1000);
}
break;
Related
LRESULT CALLBACK LowLevelMouseProc(_In_ int nCode, _In_ WPARAM wParam, _In_ LPARAM lParam)
{
BOOL fpassmove = FALSE;
if (nCode == HC_ACTION)
{
switch (wParam)
{
case WM_MOUSEMOVE: // how do i catch a dx instead of a cursor points?
PMOUSEHOOKSTRUCT me = (PMOUSEHOOKSTRUCT)lParam;
printf("x:%d\ny:%d\nextrainfo:%04X\n", me->pt.x,me->pt.y, me->dwExtraInfo );
break;
}
}
return(fpassmove ? 1 : CallNextHookEx(NULL, nCode, wParam, lParam));
}
int main()
{
// Install the low-level keyboard & mouse hooks
HHOOK hhkLowLevelMouse = SetWindowsHookEx(WH_MOUSE_LL, LowLevelMouseProc, 0, 0);
// Keep this app running until we're told to stop
MSG msg;
while (!GetMessage(&msg, NULL, NULL, NULL)) { //this while loop keeps the hook
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(hhkLowLevelMouse);
return(0);
}
I am looking at all mouse moment from a global hook, and I'm trying to find the dx and dy of the mouse event, And I was hoping to find it in "dwExtraInfo". However, I have no idea how to make sense of the data inside "dwExtraInfo".
the windows documentation is not helpful in telling me what the data in dwExtraInfo means
dwExtraInfo
Type: ULONG_PTR
Additional information associated with the message.
Could not find any documentation on dwExtraInfo directly, but found something related: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getmessageextrainfo:
Return value
Type: LPARAM
The return value specifies the extra information. The meaning of the
extra information is device specific.
One example of such device specific extra information is Pen gestures: https://learn.microsoft.com/en-us/windows/win32/tablet/system-events-and-mouse-messages
Distinguishing Pen Input from Mouse and Touch
When your application receives a mouse message (such as
WM_LBUTTONDOWN), it may call the GetMessageExtraInfo function to
evaluate whether the message originated from a pen or a mouse device.
The value returned from GetMessageExtraInfo needs to be mask-checked
against 0xFFFFFF00, and then compared with 0xFF515700. The following
definitions may make this clearer:
#define MI_WP_SIGNATURE 0xFF515700
#define SIGNATURE_MASK 0xFFFFFF00
#define IsPenEvent(dw) (((dw) & SIGNATURE_MASK) == MI_WP_SIGNATURE
If the comparison is true, then this mouse message was generated by a
Tablet PC pen or touch screen. In all other cases, you can assume that
this message was generated by a mouse device.
The lower 8 bits returned from GetMessageExtraInfo are variable. Of
those bits, 7 (the lower 7, masked by 0x7F) are used to represent the
cursor ID, zero for the mouse or a variable value for the pen ID.
Additionally, in Windows Vista, the eighth bit, masked by 0x80, is
used to differentiate touch input from pen input (0 = pen, 1 = touch).
I'm working on ToUnicodeEx function and it requires keyboard state as the input parameter. So, I used the GetKeyboardState function to do that. But I noticed when I'm typing key combinations with modifier keys like SHIFT+A there is one character delay. Here is the example.
aaa (holding SHIFT now) aAAAAAAA (release SHIFT) Aaaa
While I was debugging this I noticed GetKeyboardState is causing this delay. How can I handle or prevent this delay?
Here is my whole keyboard hook proc.
void proc(KBDLLHOOKSTRUCT kbdStruct) {
fdebug = fopen("debug.txt", "a");
foutput= fopen("output.txt", "a");
WCHAR pwszBuff[9];
WCHAR key[9];
char str[8];
BOOL isDead = FALSE;
BYTE lpKeyState[256];
HWND currentHwnd = GetForegroundWindow();
LPDWORD currentProcessID = 0;
DWORD currentWindowThreadID = GetWindowThreadProcessId(currentHwnd, currentProcessID);
DWORD thisProgramThreadId = GetCurrentThreadId();
hkl = GetKeyboardLayout(thisProgramThreadId);
if (AttachThreadInput(thisProgramThreadId, currentWindowThreadID, TRUE))
{
GetKeyboardState(lpKeyState);
AttachThreadInput(thisProgramThreadId, currentWindowThreadID, FALSE);
}
else
{
GetKeyboardState(lpKeyState);
}
int ret = ToUnicodeEx(kbdStruct.vkCode, kbdStruct.scanCode, lpKeyState, pwszBuff, 8, 0, hkl);
fprintf(fdebug, "vkCode: %d\n", (int)kbdStruct.vkCode);
fprintf(fdebug, "ret: %d\n", (int)ret);
fprintf(fdebug, "lastIsDead: %d\n", (int)lastIsDead);
fprintf(fdebug, "lastIsMod: %d\n", (int)lastIsMod);
fprintf(fdebug, "lastVKCode: %d\n", (int)lastVKCode);
if (ret == -1) {
isDead = TRUE;
ClearKeyboardBuffer(kbdStruct.vkCode, kbdStruct.scanCode, hkl);
}
else if (ret == 0) {
}
else {
memcpy(&key, &pwszBuff, sizeof(pwszBuff));
WideCharToMultiByte(CP_UTF8, 0, key, -1, str, sizeof(str), NULL, NULL);
fprintf(fdebug, "str: %s\n", str);
}
if (lastVKCode != 0 && lastIsDead == TRUE) {
ToUnicodeEx(lastVKCode, lastScanCode, lastKeyState, pwszBuff, 4, 0, hkl);
memcpy(&key, &pwszBuff, sizeof(pwszBuff));
WideCharToMultiByte(CP_UTF8, 0, key, -1, str, sizeof(str), NULL, NULL);
fprintf(fdebug, "str: %s\n", str);
lastVKCode = 0;
}
fprintf(fdebug, "%s", "---------------------------------------------------\n");
fprintf(foutput, "LSHIFT: %d\n", (int)lpKeyState[160]);
fprintf(foutput, "RSHIFT: %d\n", (int)lpKeyState[161]);
fprintf(foutput, "%s", "---------------------------------------------------\n\n");
lastVKCode = kbdStruct.vkCode;
lastScanCode = kbdStruct.scanCode;
lastIsDead = isDead;
fclose(fdebug);
fclose(foutput);
}
Here is updated version of hookcallback thanks for Ton Plooij. But still, I have the same problem.
LRESULT __stdcall HookCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
LRESULT ret = CallNextHookEx(_hook, nCode, wParam, lParam);
if (nCode >= 0)
{
if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)
{
hookStruct = *((KBDLLHOOKSTRUCT*)lParam);
proc(hookStruct);
}
}
return ret;
}
AttachThreadInput(thisProgramThreadId, currentWindowThreadID, FALSE);
This does not do what you hope it does. Sometimes. It is a valiant and necessary effort to get the proper values when you call GetKeyboardState(). Took me a while to find the failure mode, it wasn't obvious at all and I could not get the code to fail the same way. It works just fine when a GUI process is in the foreground, try it with Notepad or VS for example.
But not when it is a console mode process.
Explaining that is a bit convoluted, it is actually GetWindowThreadProcessId() that returns misleading information. It tries too hard to keep up the illusion that it is the console process that owns the console window. It doesn't, it is actually the associated conhost.exe process that owns it. It was csrss.exe on old Windows versions, conhost.exe was added in Windows 7 to solve the drag+drop issues caused by UIPI (aka UAC).
But without any decent way to discover the specific conhost.exe process that owns the window, let alone the thread id. The subject of this Q+A. Pretty doubtful it is going to help you.
Only decent advice is the well-known unpleasant one: if you need to reliably translate keystrokes then you need to use a WH_KEYBOARD hook instead of WH_KEYBOARD_LL. So GetKeyboardState() is always accurate, the hook callback runs in-process.
A LowLevelKeyboardProc receives WM_KEYUP and WM_KEYDOWN messages in its wParam. You could simply keep track of pressed modifier keys yourself, in this case to detect shift down and up. Store the key state information in a static variable and use this to test if shift is pressed while processing other keys instead of using GetKeyState.
You can try GetAsyncKeyState().
This function in my keyboard hook module work perfectly.
https://msdn.microsoft.com/en-us/library/windows/desktop/ms646293(v=vs.85).aspx
It seems that this function can catch hardware interrupt when you press keys.
And your GetKeyboardState has something to do with the Windows Registry.
It seems to have something to do with belows:
“HKEY_USERS\DEFAULT\ControlPanel\Keyboard”,Modify “KeyboardDelay” value to 0(default 1)
And change “KeyboardSpeed” value to 48(dafault 31).
According to Hans Passant's answer I searched for how can I get correct value from GetWindowThreadProcessId() and succeeded with instead of getting hWnd and windowThreadID every time in hook callback, I get these values to global variable just after program start and used variables in hook callback.
I'm trying to learn WinAPI programming but now I got stuck with this problem - I want to get pressed key and show it. I have this piece of code
LRESULT CALLBACK WndProc(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam){
switch(Msg){
case WM_CREATE:
break;
case WM_CHAR:
char ascii_code = wParam;
unsigned int key_state = lParam;
SetWindowText(hwndStatic, TEXT("You pressed key "+ascii_code));
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, Msg, wParam, lParam);
}
but the output is weird... It shows random messages(different for each key). What am I doing wrong?
I tried to debug it (step by step) and the ascii_code contains the pressed key but the TEXT() doesn't show it.
You can't add characters together like this:
"You pressed key "+ascii_code;
This will take the address of "You pressed key ", e.g. 1000 and add the ascii code value to it, e.g. 95.
The function will try to print the string at memory address 1095. It will print all the memory until it hits a null character (zero). This could be anything.
You need to either use C functions to build your string, or, as this is tagged C++ use std::string.
std::string message = "You pressed key ";
message += ascii_code;
SetWindowText(hwndStatic, TEXT(message.c_str()))
"You pressed key "+ascii_code
You cannot concatenate strings like that. The real type of "foo bar" is const char[8] - a raw C-like array of characters. When you apply + on it, it decays to a pointer to its first element and the operation is carried on the pointer. This means you end up printing some random data based on where this pointer ends up pointing in the end.
If you want to concatenate a character to a string, you have to use more intelligent string representation, such as std::string:
(std::string("you pressed key ") + ascii_code).c_str();
I have a situation here and i don't know what is wrong.
I have a parent and 2 sunclassed children.Both are edit types.
Now i am using the first control(first child) to get input from the user and it all works fine,
then i send a message to the parent through a custom message and than i want to forward the message to the second control yet when i use
SendMessage();
nothing happends....
my custom message is defined like this :
#define WM_USERMESSAGE 0x0401
Another question i have is how do i send strings? 'cause when i send the message to the father
through lParam it says its value is 72 but i dont see any refrence to my text that i have sent.
these are the code segments:
child 1 sending message to father after getting input:
case WM_KEYUP:
{
switch (wParam) {
case VK_RETURN:
{
length = GetWindowTextLength(hwnd);
GetWindowText(hwnd, buf,length);
SetWindowText(hwnd,NULL);
tempa = SendMessage(GetParent(hwnd), WM_USERMESSAGE,sizeof(buf),*buf);
return 0;
}
}
return 0;
}
Father gets message and trys to forward it:
case WM_USERMESSAGE:
{
int tempb = SendMessage(nhwnd, WM_USERMESSAGE, wParam, (LPARAM)"Hi");
}
and the child number 2 is listening for the message:
case WM_USERMESSAGE:
{
SetWindowText(window, "hi");//(TCHAR*)lParam);
return 0;
}
(now as you see i used static strings to check if the functions work but i want to change them so i could recive information from the messages)
Thanks for the help in advance!
Your initial SendMessage() from the first edit to the parent window is not sending the string data correctly. You are dereferencing your buffer pointer, so you are only sending the first character (72 is the ASCII 'H' character). You need to get rid of that dereference and pass the buffer pointer as-is. And if you are going to send the buffer length (which you don't use), you need to send the length that GetWindowText() returns, not the full size of your buffer, so the receiver knows exactly how many characters are actually in the buffer.
Try this:
case WM_KEYUP:
{
switch (wParam)
{
case VK_RETURN:
{
ZeroMemory(buf, sizeof(buf));
length = GetWindowTextLength(hwnd);
if (length > 0)
length = GetWindowText(hwnd, buf, min(length+1, sizeof(buf)));
SetWindowText(hwnd, NULL);
tempa = SendMessage(GetParent(hwnd), WM_USERMESSAGE, length, (LPARAM)buf);
return 0;
}
}
return 0;
}
.
case WM_USERMESSAGE:
{
int tempb = SendMessage(nhwnd, WM_USERMESSAGE, wParam, lParam);
return 0;
}
.
case WM_USERMESSAGE:
{
SetWindowText(window, (LPTSTR)lParam);
return 0;
}
Assuming all of your HWNDs are valid, then the forwarding should work fine. If the message is not making it all of the way, then one of your HWNDs is not valid.
I have a win 32 application written in c++ which sets the low level keyboard hook. now i want to sendInput to any app like word / notepad. how do i do this?
i have already done enough of using findwindow / sendmessage. for all these, i need to know edit controls. finding the edit control is very difficult.
since SendInput works for any windows application, i want to use it. the problem is i get a call to my callback function with the pressed key.
for e.g i pressed A and i want to send U+0BAF unicode character to the active applciation windows. in this case, assume it is notepad.
the problem is i get two characters U+0BAF and A in the notepad.
A is being sent because i am calling CallNextHookEx( NULL, nCode, wParam, lParam);
if i return 1 after sendInput, then nothing is sent to notepad.
any suggestion?
If I understood your problem correctly, you should ignore "injected" key events in your hook procedure, like this:
LRESULT CALLBACK
hook_proc( int code, WPARAM wParam, LPARAM lParam )
{
KBDLLHOOKSTRUCT* kbd = (KBDLLHOOKSTRUCT*)lParam;
// Ignore injected events
if (code < 0 || (kbd->flags & LLKHF_INJECTED)) {
return CallNextHookEx(kbdhook, code, wParam, lParam);
}
...
Update: additionally, you have to eat characters and notify some other routine for a character press through Windows messages.
Example:
...
// Pseudocode
if (kbd->vkCode is character) {
if (WM_KEYDOWN == wParam) {
PostMessage(mainwnd, WM_MY_KEYDOWN, kbd->vkCode, 0);
return 1; // eat the char, ie 'a'
}
}
return CallNextHookEx(kbdhook, code, wParam, lParam);
And, in some other module, you handle WM_MY_KEYDOWN:
ie, #define WM_MY_KEYDOWN (WM_USER + 1)
and call the appropriate routine that will generate new key events.