3
#include <iostream>
#include <fstream>
#define _WIN32_WINNT 0x501
#include <windows.h>

using namespace std;

HHOOK hKeyboardHook = 0;
LRESULT CALLBACK KeyboardCallback(int code,WPARAM wParam,LPARAM lParam) {  
  cout << "a key was pressed" << endl;
  ofstream myfile;
  myfile.open ("hookcheck.txt", ios::ate | ios::app);
  myfile << "a key was pressed\n";
  myfile.close();
  return CallNextHookEx(hKeyboardHook,code,wParam,lParam);
}

int main() {

  HWND consoleWindow = GetConsoleWindow();
  HINSTANCE hInstCons = (HINSTANCE)GetWindowLong( consoleWindow, GWL_HINSTANCE );
  hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD, (HOOKPROC)KeyboardCallback, (HINSTANCE)consoleWindow, GetCurrentThreadId());

  MessageBox(NULL, "It is keyboard time!", "Let's Go", MB_OK);

}

This code on every key press while the loop is going should print message on console and create a file, but nothing is happening. What do I wrong ?

rsk82
  • 28,217
  • 50
  • 150
  • 240
  • SetWindowsHookEx hooks Windows messages. A console app doesn't use messages. You'll have to write a native windows app that pumps a message loop. – Hans Passant Jun 24 '12 at 11:23
  • 1
    By the way, Windows console does provide low-level input APIs, you should use them instead of using hooks. – Matteo Italia Jun 24 '12 at 12:45
  • @MatteoItalia: That's interesting, could you give me link to manual, im not quite sure about which api are you talking and I was searching for this many days. – rsk82 Jun 24 '12 at 12:55
  • 2
    Start from [here](http://msdn.microsoft.com/en-us/library/windows/desktop/ms682010.aspx). – Matteo Italia Jun 24 '12 at 13:03
  • 1
    [This](http://msdn.microsoft.com/en-us/library/windows/desktop/ms685035.aspx) page in particular should be relevant to your aim. – Matteo Italia Jun 24 '12 at 13:08

4 Answers4

8

I will quote from another topic:

Console windows are handled entirely by CSRSS, which is a system process. Installing a hook into a process means injecting your DLL into it. Since CSRSS is so important (it's vital for running of the system, and code within runs as LocalSystem, which is the local super-admin user), you're not allowed to inject code into it. So you can't hook any of its windows.

There are no real window messages taking place in your simple console application, so your hook does not have to be called, and in your case you are not even injecting your hook but using thread mode hook only. Per MSDN documentation it is called when messages are about to be processed:

An application-defined or library-defined callback function used with the SetWindowsHookEx function. The system calls this function whenever an application calls the GetMessage or PeekMessage function and there is a keyboard message (WM_KEYUP or WM_KEYDOWN) to be processed.

Now let me show you what you can do to start receiving calls on your hook:

MessageBox(NULL, _T("It is keyboard time!"), _T("Let's Go"), MB_OK);

//for(int i=0; i<=10; i++) {
//  cout << i << endl;
//  Sleep(1000);
//}

Do MessageBox and before closing it start typing - you will start getting hook calls.

Roman R.
  • 68,205
  • 6
  • 94
  • 158
  • If I understand what text that you cited means, `SetWindowsHookEx` doesn't work with console apps, right ? I updated my code in question and it still doesn't work. – rsk82 Jun 24 '12 at 12:45
  • 1
    Works for me. Make sure your message box window is in foreground, but don't press button to close it. Type something there. This generates keyboard messages in the thread where you installed the hook. Your hook will be called. – Roman R. Jun 24 '12 at 12:53
  • Sorry, I do not what I'm doing wrong here but no events are showing for me. (I use gcc 4.7.0 mingw) – rsk82 Jun 24 '12 at 18:58
  • Most likely you are typing with no message box window in foreground, and keyboard input is not routed to the window and thread of interest. – Roman R. Jun 24 '12 at 19:09
  • No, I tried to do it both ways, that is with window in foreground and background mode. When message box in is in foreground I god sound on every keypress but nothing is shown on the console. – rsk82 Jun 24 '12 at 20:45
  • 1
    I am not quite sure if this is going to be helpful, but this is my source and binary http://www.alax.info/trac/public/browser/trunk/Utilities/ConsoleKeyboardHook Also, you might want to use `Spy++` tool to check what messages occur within your process. – Roman R. Jun 24 '12 at 21:43
  • Your binary also doesn't work as expected. That is it runs without any error but it also doesn't react on keypresses just identically as code compiled by me. Maybe this is a windows issue, I use XP SP3. – rsk82 Jun 25 '12 at 03:54
  • 1
    This is because you don't do checking per Scott Langham's suggestion. You don't have the hook installed in XP, because in XP `GetWindowLong` returns non-NULL result and you have to have NULL there (see updated code). – Roman R. Jun 25 '12 at 05:42
  • I am doing C programming, I have used `ShowWindow(hwnd, FALSE)` for my console window, and `SetWindowsHookEx()` does not work when I do that. Is it because my program becomes a background process? – Ahmed Can Unbay Oct 18 '17 at 23:16
  • I put `ShowWindow()` function right before my `GetMessage()` function loop for the program to keep going – Ahmed Can Unbay Oct 18 '17 at 23:17
1

Read the documentation for SetWindowsHookEx. Is it working, it will return NULL if it fails and GetLastError() can be called to get an error code to help diagnose what is wrong.

http://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx

Scott Langham
  • 58,735
  • 39
  • 131
  • 204
  • `GetLastError()` returns `0`. - Where can I find what it means ? – rsk82 Jun 24 '12 at 10:28
  • That means it succeeded :) http://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx – Scott Langham Jun 24 '12 at 22:09
  • And that is true. There something strange going on, code compiles without error and there is no error showing anywhere in the code, just callback doesn't initialize. – rsk82 Jun 25 '12 at 03:59
1

Sleep(1000) suspends the execution of the current thread until the time-out interval elapses. It means that your program is not actually running (ie. processing messages) during this sleep.

You need to use a different kind of command, that will keep the message loop running. The simplest thing would be to wait for user input

while(true)
   std::cin.get(); 
Chris Bednarski
  • 3,364
  • 25
  • 33
0

I have created a dll that hooked the keyboard and in there I used the DllMainfunction to retrieve a HINSTANCE that can be used in SetWindowsHookEx.

Next to that I also used 0 as the threadid so all threads get hooked.

Perhaps you could try a similar tactic as well.

giriel
  • 93
  • 12