Thread: Compiler Error with Classes

  1. #1
    Registered User
    Join Date
    Mar 2006
    Location
    USA::Colorado
    Posts
    155

    Compiler Error with Classes

    Hey,

    I get this error when I compile the following code:
    Code:
    1>c:\users\******\desktop\macrokeys 4\macrokeys 4\keyboardhook.cpp(12) : error C2440: 'type cast' : cannot convert from 'overloaded-function' to 'HOOKPROC'
    Here's the keyboardhook.h source:
    Code:
    #ifndef GUARD_KEYBOARDHOOK_H
    #define GUARD_KEYBOARDHOOK_H
    
    #include <windows.h>
    #include <vector>
    
    using std::vector;
    
    class CKeyboardHook
    {
    public:
    	(LRESULT CALLBACK) HookProc ( int nCode, WPARAM wParam, LPARAM lParam );
    
    	vector<int> keysDown;
    	vector<int> keysToStop;
    
    	HINSTANCE hExe;
    	HHOOK hHook;
    
    	bool keyIsDown ( int vkey );
    	void stopKey ( int vkey );
    	void resumeKey ( int vkey );
    
    	void initHook();
    	void killHook();
    } kbHook;
    
    #endif
    Here is the code for keyboardhook.cpp
    Code:
    #include "stdafx.h"
    #include "keyboardhook.h"
    
    LRESULT CALLBACK CKeyboardHook::HookProc ( int nCode, WPARAM wParam, LPARAM lParam )
    {
    	return CallNextHookEx(kbHook.hHook, nCode, wParam, lParam);
    }
    
    void CKeyboardHook::initHook()
    {
    	hExe = GetModuleHandle ( NULL );
    	hHook = SetWindowsHookEx ( WH_KEYBOARD_LL, (HOOKPROC)HookProc, hExe, NULL ); //This line gives the error
    }
    
    void CKeyboardHook::killHook()
    {
    	UnhookWindowsHookEx(hHook);
    }
    
    bool CKeyboardHook::keyIsDown(int vkey)
    {
    	for ( vector<int>::iterator i = keysDown.begin(); i != keysDown.end(); ++i )
    	{
    		if ( vkey == *i )
    			return true;
    	}
    
    	return false;
    }
    
    void CKeyboardHook::stopKey ( int vkey )
    {
    	for ( vector<int>::iterator i = keysToStop.begin(); i != keysToStop.end(); ++i )
    	{
    		if ( vkey == *i )
    			return;
    	}
    
    	keysToStop.push_back ( vkey );
    }
    
    void CKeyboardHook::resumeKey ( int vkey )
    {
    	for ( vector<int>::iterator i = keysToStop.begin(); i != keysToStop.end(); ++i )
    	{
    		if ( vkey == *i )
    		{
    			keysToStop.erase ( i );
    			return;
    		}
    	}
    }
    Any help towards this problem would be greatly appreciated.

    Thanks in advance,

    Matt
    ~guitarist809~

  2. #2
    The larch
    Join Date
    May 2006
    Posts
    3,573
    You are trying to pass a member function, which has a hidden parameter of type CKeyboardHook*.

    You might try a static or a free function, but that wouldn't allow it to access non-static members of CKeyboardHook...
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  3. #3
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    You are trying to cast a class member function into a non-member function. That is not allowed in C++. A class member function takes a hidden parameter "this", which normal functions don't. [The hidden "this" points to the current instance of the class, and it is what allows you to do *this or this->x inside your member functions]

    Since code that is non-C++ [such as the Windows kernel code] don't even understand the hidden parameter, you can't do that with the best will in the world.

    It is a bit tricky to solve this sort of problem generically, but one solution that would work in this particular case, as I presume you are not going to log keys several times in the same macro recorder. So we can use a global variable that is the instance of CKeyboardHook.

    Then you can have a static member function that knows about the global variable, something like this:
    Code:
    class CKeyboardHook
    {
    public:
    	static (LRESULT CALLBACK) HookProc ( int nCode, WPARAM wParam, LPARAM lParam );
            int DoHookProcessing( int nCode, WPARAM wParam, LPARAM lParam )
    ...
    CKeyboardHook hook;
    LRESULT CALLBACK CKeyboardHook::HookProc ( int nCode, WPARAM wParam, LPARAM lParam )
    {
            if (hook.DoHookProcessing( nCode, wParam, lParam ) > 0)
                ... do some stuff 
    
    	return CallNextHookEx(kbHook.hHook, nCode, wParam, lParam);
    }
    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  4. #4
    Registered User
    Join Date
    Mar 2006
    Location
    USA::Colorado
    Posts
    155
    Thanks for the replies, guies.

    That last bit of code looks like it should work just fine for me.

    Thanks!
    ~guitarist809~

  5. #5
    Registered User
    Join Date
    Mar 2006
    Location
    USA::Colorado
    Posts
    155
    Actually, is there any possible of doing this without using globals? (I'm getting linker errors with this)

    Is the only way to make everything in the class static?

    Err:
    Code:
    error C2352: 'CKeyboardHook::hookProcess' : illegal call of non-static member function
    Updated Code

    keyboardhook.h
    Code:
    #ifndef GUARD_KEYBOARDHOOK_H
    #define GUARD_KEYBOARDHOOK_H
    
    #define CALL_NEXT_HOOK 1
    #define DROP_NEXT_HOOK 2
    
    #include <windows.h>
    #include <vector>
    
    using std::vector;
    
    class CKeyboardHook
    {
    public:
    	int hookProcess ( int nCode, WPARAM wParam, LPARAM lParam );
    
    	static LRESULT CALLBACK LLKeyboardHook ( int nCode, WPARAM wParam, LPARAM lParam );
    
    	vector<DWORD> keysDown;
    	vector<DWORD> keysToStop;
    
    	HINSTANCE hExe;
    	static HHOOK hHook;
    
    	bool keyIsDown ( int vkey );
    	void stopKey ( int vkey );
    	void resumeKey ( int vkey );
    
    	void initHook();
    	void killHook();
    };
    
    #endif
    keyboardhook.cpp
    Code:
    #include "stdafx.h"
    #include "keyboardhook.h"
    
    LRESULT CALLBACK CKeyboardHook::LLKeyboardHook ( int nCode, WPARAM wParam, LPARAM lParam )
    {
    	if ( hookProcess ( nCode, wParam, lParam ) == CALL_NEXT_HOOK )
    	{
    		return CallNextHookEx( hHook, nCode, wParam, lParam);
    	}
    	else
    	{
    		return TRUE;
    	}
    }
    
    void CKeyboardHook::initHook()
    {
    	hExe = GetModuleHandle ( NULL );
    	hHook = SetWindowsHookEx ( WH_KEYBOARD_LL, (HOOKPROC)LLKeyboardHook, hExe, NULL );
    }
    
    void CKeyboardHook::killHook()
    {
    	UnhookWindowsHookEx(hHook);
    }
    
    bool CKeyboardHook::keyIsDown(int vkey)
    {
    	return false;
    }
    
    void CKeyboardHook::stopKey ( int vkey )
    {
    }
    
    void CKeyboardHook::resumeKey ( int vkey )
    {
    }
    Last edited by guitarist809; 12-02-2008 at 01:07 AM.
    ~guitarist809~

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by guitarist809
    Actually, is there any possible of doing this without using globals?
    It does sound like the singleton pattern is applicable here.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by laserlight View Post
    It does sound like the singleton pattern is applicable here.
    Yes, I agree - however, a global is also a possible solution. Yes, I know, globals are not good and all that. But a singleton is really just a global with a interface to get to it...

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  8. #8
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    I will add another advice:
    Never, ever cast a function pointer to something else unless you are really, really, really, REALLY sure you must do that.
    And even then, it is possible to define functions that are much safer at implementing such a cast than an old-style C-cast.
    The problem is that these casts usually hides errors. If the function address you're passing is compatible with what the function expects, then it will compile without the need of a cast.
    And if it does not match and you cast, then... well, it might just compile and crash later!
    The compiler is your friend, and probably knows better than you, too! Don't shut it out!
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. College Classes
    By nubby in forum C Programming
    Replies: 2
    Last Post: 10-07-2007, 12:32 AM
  2. added start menu crashes game
    By avgprogamerjoe in forum Game Programming
    Replies: 6
    Last Post: 08-29-2007, 01:30 PM
  3. C++ Classes: Use, Misuse...Confusion.
    By Snorpy_Py in forum C++ Programming
    Replies: 4
    Last Post: 10-23-2006, 01:46 AM
  4. C Compiler and stuff
    By pal1ndr0me in forum C Programming
    Replies: 10
    Last Post: 07-21-2006, 11:07 AM
  5. include question
    By Wanted420 in forum C++ Programming
    Replies: 8
    Last Post: 10-17-2003, 03:49 AM