Related
I tried to call a function-pointer from a dll that hooks the WM_LBUTONDOWN or WM_TOUCH message on all windows displayed at screen.
I have the following dll source code:
typedef void (*PtrFonct)(int nCode, WPARAM wParam, LPARAM lParam);
PtrFonct pf;
HHOOK global;
extern "C" __declspec(dllexport) LRESULT WINAPI procedure(int nCode, WPARAM wParam,LPARAM lParam)
{
if (nCode == HC_ACTION){
MSG* pMSG = (MSG*)lParam;
if (pMSG->message == WM_LBUTTONDOWN){
pf(nCode, wParam, lParam);
}
}
return CallNextHookEx(global, nCode, wParam, lParam);
}
extern "C" __declspec(dllexport) BOOL setCallback(void ((*callbackFunc)(int, WPARAM, LPARAM))){
pf = callbackFunc;
if (pf)
return TRUE;
return FALSE;
}
and my listener source code is the following one:
MSG message;
HMODULE lib = LoadLibrary(L"C:/HookTouch.dll");
if (lib) {
HOOKPROC procedure = (HOOKPROC)GetProcAddress(lib, "_procedure#12");
dllFunct fonctionCallback = (dllFunct)GetProcAddress(lib, "setCallback");
if (fonctionCallback)
fonctionCallback(MyCallback);
if (procedure)
hook = SetWindowsHookEx(WH_GETMESSAGE, procedure, lib, 0);
}
else
printf("Can't find dll!\n");
while (GetMessage(&message, NULL, 0, 0))
{
TranslateMessage(&message);
DispatchMessage(&message);
}
FreeLibrary(lib);
UnhookWindowsHookEx(hook);
My own callback to display "Hello click" is this one:
void MyCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
printf("Hello Click\n");
}
I know my hook is working because I can display a message on click by using a message box instead of pf(nCode, wParam, lParam) but when I use this function-pointer, MyCallback is not triggered.
I checked if my function was well affected to the pf function-pointer and all seems to be ok.
Do you know why the call of pf(nCode, wParam, lParam) don't trigger the MyCallback function of the listener?
You are calling setCallback only for the dll that's loaded in your process. The dll's that will be injected by SetWindowsHookEx in all the other process will not have the callback set. On top of that, MyCallback is only defined in your own process; the Dll's injected in other processes have no trivial way of accessing it.
Since you cannot know which processes Windows has injected for you, you will need the Dll to broadcast its 'location' to you, via Inter-Process communcation, eg. Named Pipes. Once you have the process ID of each of the DLL's that were injected, you can use CreateRemoteThread to call a function inside the Dll, like setCallback.. there's still some work to be done so that the Dll can directly call you callback: You will need to give the Dll the exact offset of your callback from the module base, and the Dll will then need to use CreateRemoteThread itself to issue the call.
This all quickly becomes too tedious, and you would be wise to just use Named Pipe communication instead of issuing direct function calls.
Tip: An easy way to log things from other processes is using OutputDebugString. Alternatively, write to a file.
This approach will not work.
A message hook runs in the context of each thread that is being hooked. Each hooked process will get its own copy of your DLL injected into it. As such, only the copy that originally installed the hook will have a valid function pointer set. Besides, you can't call your callback function across process boundaries anyway.
You need to use a different IPC mechanism to let your injected hooks communicate back to your main app process.
For instance, you could create a hidden HWND and store it in a block of global shared memory and then each injected hook can send window messages to it, like WM_COPYDATA. Or, your main app can open a named pipe that each injected hook can then connect to and send data to.
Recently, I've started to learn DX11 and I was trying to create message loops in WinAPI. I saw a LRESULT CALLBACK function from the tutorial that I haven't seen before. It is called in Window Procedure function. Here is the WndProc function and the MessageHandler function(the function that I'm talking about).
WndProc:
LRESULT CALLBACK WndProc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
{
switch(umessage)
{
// Check if the window is being destroyed.
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
// Check if the window is being closed.
case WM_CLOSE:
{
PostQuitMessage(0);
return 0;
}
// All other messages pass to the message handler in the system class.
default:
{
return ApplicationHandle->MessageHandler(hwnd, umessage, wparam, lparam);
}
}
}
MessageHandler:
LRESULT CALLBACK SystemClass::MessageHandler(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam)
{
switch(umsg)
{
// Check if a key has been pressed on the keyboard.
case WM_KEYDOWN:
{
// If a key is pressed send it to the input object so it can record that state.
m_Input->KeyDown((unsigned int)wparam);
return 0;
}
// Check if a key has been released on the keyboard.
case WM_KEYUP:
{
// If a key is released then send it to the input object so it can unset the state for that key.
m_Input->KeyUp((unsigned int)wparam);
return 0;
}
// Any other messages send to the default message handler as our application won't make use of them.
default:
{
return DefWindowProc(hwnd, umsg, wparam, lparam);
}
}
}
What I don't understand is, why we added the "LRESULT CALLBACK" part to the MessageHandler function? I know, we must add it to WndProc function, but I don't get the point of creating a new function and adding it a calling convention. What if we don't add any calling convention to the MessageHandler function? What if we didn't create the MessageHandler funciton and write the KEY_DOWN listeners to WndProc's switch-case statement?
These codes are in one class and ApplicationHandler pointer points to "this".
There is no obvious reason for SystemClass::MessageHandler to be declared as CALLBACK because it cannot be used as a message handler for Windows since it is not static. There is no reason for SystemClass::MessageHandler to be declared as CALLBACK in the code you showed.
About the CALLBACK (__stdcall):
Functions called from "within Windows" just have to be stdcall because Windows developers decided to write/compile Windows that it calls stdcall functions. In theory, any CC could be used, but Windows and your code must have the same.
Your own function won´t need it if you´re using it only in your own code in your program.
LRESULT (some int/pointer-like thing) is just the return type.
The reason for not just writing int (or something like that) is that LRESULT is a int with a certain length etc., and if MS decides to change it for some reason, they only need to change the definition of LRESULT, but not every function which has a LRESULT return type.
I think I've fallen in the same trap as many before me where I try to impose a nice OO methodology on win32 API programming. No MFC, no AFX, I'm not even using VC++, I'm using C::B with gcc.
I think what I'm trying to do is impossible, but since MFC exists (although I'm not using it) there must be some way.
I've created a class to contain several window controls. It implements handlers for WM_CREATE and WM_COMMAND, and keeps track of all the associated data around my small group of controls (ID codes and HWNDs).
It works great for buttons, static controls, even light GDI methods, but it all breaks down when I try to subclass an edit control.
Really, I just want to capture the "enter" key, but as anybody who's been down that road before will attest, when an edit control has focus, the parent window doesn't receive WM_KEYDOWN or WM_COMMAND, we are left to implement our own proc. Super lame.
OK, so subclassing an edit control is fine, if the editProc is global or static. I know that is because SetWindowLongPtr needs a function address, and that concept is nebulous for a member function.
So the object of my class is declared as "static" inside the parent WndProc. But the function is not "static" because then I wouldn't have access to non-static data members (completely defeating the purpose of this exercise). I'm hoping that because the objest is itself static, I should be able to properly define the address of one of its member functions.
Readers that have tried this before will either have given up and used MFC or something else, or perhaps have found a clever work-around.
I'll let this sample code do the rest of the talking: (simplified - will not compile as such)
/**** myprogram.c ****/
#include "MyControlGroup.h"
int winMain(){ // etc... }
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// object is static becuse it only needs to be initialized once
static MyControlGroup myControl;
if (msg == WM_CREATE)
myControl.onWMCreate(hWnd);
else if (msg == WM_COMMAND)
myControl.onWMCommand( wParam, lParam );
else if (msg == WM_DESTROY)
PostQuitMessage(0);
return DefWindowProcW(l_hWnd, l_msg, l_wParam, l_lParam);
}
The header file for my class:
/**** MyControlGroup.h ****/
class MyControlGroup
{
private:
HWND m_hWndParent;
HWND m_hWndEditBox;
int m_editBoxID;
public:
MyControlGroup();
void onWMCreate(HWND);
void onWMCommand(WPARAM, LPARAM);
// want to find a way to pass the address of this function to SetWindowLongPtr
LRESULT myEditProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
};
...and the implementation:
/**** MyControlGroup.cpp ****/
static int staticID = 1;
MyControlGroup::MyControlGroup()
{
m_editBoxID = staticID++;
}
void MyControlGroup::onWMCreate(HWND hWnd)
{
// My control group has buttons, static controls, and other stuff which are created here with CreateWindowW. It also has an edit control:
m_hWndEditBox = CreateWindowW(L"EDIT", L"initial text", WS_CHILD | WS_VISIBLE | WS_BORDER, 10, 10, 150, 20, hWnd, (HMENU)m_editBoxID, NULL, NULL);
/*
To subclass the edit control, I need a pointer to my customized proc. That means I
need a pointer-to-member-function, but SetWindowLongPtr needs a pointer to global or
static function (__stdcall or CALLBACK, but not __thiscall).
*/
// I'd like to do something like this, adapted from a great write-up at
// http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible
LERSULT (MyControlGroup::*myEditProcPtr)(HWND, UINT, WPARAM, LPARAM);
myEditProcPtr = &MyControlGroup::myEditProc;
// Up to now it compiles ok, but then when I try to pass it to SetWindowLongPtr, I get
// an "invalid cast" error. Any ideas?
SetWindowLongPtr(m_hWndEditBox, GWLP_WNDPROC, (LPARAM)myEditProcPtr);
}
void MyControlGroup::onWMCommand(WPARAM wParam, LPARAM lParam){ /* process parent window messages. Editboxes don't generate WM_COMMAND or WM_KEYDOWN in the parent :''( */}
LRESULT MyControlGroup::myEditProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// process messages like IDOK, WM_KEYDOWN and so on in the edit control
}
Even once I get this done, I'll still need to figure out a way to pass the address of the parent WndProc to myEditProc for the return value, but until I get past this there is no point in worrying about that.
Thanks in advance for reading!
myEditProc needs to be a static function.
Once you've done that you can pass the address of the function directly without going through the intermediate variable:
static LRESULT myEditProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
...
SetWindowLongPtr(m_hWndEditBox, GWLP_WNDPROC, (LPARAM)myEditProc);
To access your class data from the static function, you can save it in the userdata field of the edit control, e.g.:
// before sub-classing the control
SetWindowLongPtr(m_hWndEditBox, GWLP_USERDATA, (LPARAM)this);
// in the sub-class procedure
MyControlGroup* pThis = (MyControlGroup*)GetWindowLongPtr(m_hWndEditBox, GWLP_USERDATA);
But as #K-ballo suggested, SetWindowSubclass is definitely the way to do this unless you want compatibility with pre-XP. It handles the sub-classing procedure for you automatically, lets you associate a userdata pointer (e.g. this) that is automatically passed to the sub-class procedure, and safely handles removing the sub-class at the end.
I have a pre-made template resource dialog, and I want to use DialogBoxParam to display it, but I can't find any good examples over the internet. The dialog is a simple login dialog, so can someone explain how to build my lpDialogFunc and what to put in dwInitParam?
You've tagged this question as C++, but havn't specified any particular framework (such as ATL or MFC).
So, in the spirit of providing a c++ / OOP answer to the question, without using a framework, the first thing to do is to create a class to wrap the dialog box, as well as provide a way for the dialog proc to reliably retrieve the pointer to the class. The windows API is a C API and cannot call class members directly so it is necessary to create static methods that can then retrieve the classes this pointer from somewhere.
class MyDialog {
HWND _dlg;
public:
int RunModal(HINSTANCE resModule, UINT resId,HWND parent){
return DialogBoxParam(resModule,MAKEINTRESOURCE(resId),parent,&StaticDialogProc,(LPARAM)this);
}
protected:
static INT_PTR CALLBACK StaticDialogProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam){
MyDialog* self;
if(uMsg == WM_INITDIALOG){
self = (MyDialog*)lParam;
self->_dlg = hwndDlg;
SetWindowLongPtr(hwndDlg,DWLP_USER,lParam);
}
else
self = (MyDialog*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA);
if(self)
return self->DialogProc(uMsg,wParam,lParam);
return FALSE;
}
virtual UINT_PTR DialogProc(UINT uMsg,WPARAM wParam,LPARAM lParam){
switch(uMsg){
case WM_INITDIALOG:
OnInitDialog();
break;
case WM_COMMAND:
OnCommand(LOWORD(wParam),HIWORD(wParam),(HWND)lParam);
break;
default:
return FALSE;
}
return TRUE;
}
virtual void OnInitDialog(){
}
virtual void OnCommand(int id, USHORT notifyCode,HWND control){
EndDialog(_hdlg,id);
}
};
Now, there are hundreds of window messages that Windows can send to a dialog. Add handlers for each message to DialogProc and call a specific virtual function so derived classes can handle the message differently by overriding the virtual.
The critical messages to handle are usually WM_INITDIALOG which is sent as soon as the dialog is created, so is an ideal time to initialize any controls on the dialog - to populate drop down controls, or SetWindowText to initielize text boxes with default values.
and WM_COMMAND, which is sent by controls like buttons, when they are clicked, passing in their id, and this is where you would handle the OK and CANCEL buttons.
Once DialogBoxParam returns, the dialog and all its child controls has been destroyed, so you would typically extract all the input fields in the OnCommand handler and store them in class members before calling EndDialog.
Another use case for the second part of the question: "what to put in dwInitParam"?
If you prefer OO programming and do not want to use the global scope for your dialog box, you can pass this to the formal parameter dwInitParam.
Obtaining a pointer to the caller:
template< typename CallerT >
inline CallerT *GetDialogCaller(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
if (WM_INITDIALOG != uMsg) {
// Retrieves information about the specified window.
// 1. A handle to the window and, indirectly, the class to which the window belongs.
// 2. Retrieves the user data associated with the window.
return reinterpret_cast< CallerT * >(GetWindowLongPtr(hwndDlg, GWLP_USERDATA));
}
CallerT * const caller = reinterpret_cast< CallerT * >(lParam);
// Changes an attribute of the specified window.
// 1. A handle to the window and, indirectly, the class to which the window belongs.
// 2. Sets the user data associated with the window.
// 3. The replacement value.
SetWindowLongPtr(hwndDlg, GWLP_USERDATA, reinterpret_cast< LONG_PTR >(caller));
return caller;
}
Delegating the message to the caller:
class Widget {
public:
static INT_PTR CALLBACK DialogProcDelegate(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
// Retrieve a pointer to the instance of Widget
// that called DialogBoxParam.
Widget * const widget = GetDialogCaller< Widget>(hwndDlg, uMsg, wParam, lParam);
// Delegate the message handling.
return widget->DialogProc(hwndDlg, uMsg, wParam, lParam);
}
INT_PTR Show() const {
return DialogBoxParam(nullptr, MAKEINTRESOURCE(IDD_WIDGET_SETTINGS), nullptr, DialogProcDelegate, reinterpret_cast< LPARAM >(this));
}
private:
INT_PTR DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
// Note that this method is not affected by our approach,
// i.e. this method will still receive a WM_INITDIALOG.
switch (uMsg) {
...
}
return FALSE;
}
};
The alternative puts the caller in global scope and is restricted to a single caller for all dialog boxes.
you can do something like this. The dwInitParam Specifies the value to pass to the dialog box in the lParam parameter of the WM_INITDIALOG message. You can pass any value or simply pass NULL
INT_PTR CALLBACK editDlg(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) {
switch (msg) {
case WM_INITDIALOG:
return 1;
break;
}
return 0;
}
if(DialogBoxParam(hInst,MAKEINTRESOURCE(IDD_EDIT),hwndMain,editDlg,NULL)==IDOK)
{
}
I am trying to handle wm_mousewheel for my application.
Code:
BEGIN_MSG_MAP(DxWindow)
MESSAGE_HANDLER(WM_MOUSEWHEEL, KeyHandler)
END_MSG_MAP()
.
.
.
LRESULT DxWindow::KeyHandler( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled )
{
if(uMsg==wm_mousewheel)
{
//Perform task.
}
return 0;
}
But this code doesn't work.KeyHandler doesn't receive wm_mousewheel message.
I am testing this application on vista.
If my approach is wrong how to handle wm_mousewheel properly?
Do vista is responsible for failure in handling wm_mousewheel message?
From the doc:
The WM_MOUSEWHEEL message is sent to the focus window when the mouse wheel is rotated. The DefWindowProc function propagates the message to the window's parent. There should be no internal forwarding of the message, since DefWindowProc propagates it up the parent chain until it finds a window that processes it.
Change your test to if(uMsg == WM_MOUSEWHEEL).
Check that your window or one of it's children has focus.
If this is related to your previous wtl-child-window-event-handling question, I edited my answer to not forward WM_MOUSEWHEEL.
Well, first, you don't have to somehow check uMsg in message handler, because in this situation every message handler is bound to one concrete message.
Second, these atl macroses usually mean to write something like CHAIN_MSG_MAP(CMyBaseClass)
at the end of your map.
Anyway, what you've posted here looks ok, except this part:
if(uMsg==wm_mousewheel)
{
//Perform task.
}
Try erasing it, adding a breakpoint to the handler and debugging. Also you could try adding another neutral message handler (such as WM_CLICK) and tracing it's behavior.
This is the example from MSDN, and the code block that you've posted actually follows it.
class CMyWindow : ...
{
public:
...
BEGIN_MSG_MAP(CMyWindow)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
CHAIN_MSG_MAP(CMyBaseWindow)
END_MSG_MAP()
LRESULT OnPaint(UINT uMsg, WPARAM wParam,
LPARAM lParam, BOOL& bHandled)
{ ... }
LRESULT OnSetFocus(UINT uMsg, WPARAM wParam,
LPARAM lParam, BOOL& bHandled)
{ ... }
};