SendMessageCallback usage example - c++

http://msdn.microsoft.com/en-us/library/ms644951%28v=VS.85%29.aspx
I v been searching everywhere but cant find a single working thing in c on how this could be done. There seems to be several calls which totally confused me. Perhaps someone can put just a small example on how to declare this callback then post message to it?
Thank you

I assume that you are perfectly comfortable with plain ol' SendMessage. The step from there to SendMessageCallback is not that long.
First, look at
LRESULT WINAPI SendMessage(__in HWND hWnd,
__in UINT Msg,
__in WPARAM wParam,
__in LPARAM lParam);
Then look at
BOOL WINAPI SendMessageCallback(__in HWND hWnd,
__in UINT Msg,
__in WPARAM wParam,
__in LPARAM lParam,
__in SENDASYNCPROC lpCallBack,
__in ULONG_PTR dwData);
It's glaringly obvious that the differing parts are the SENDASYNCPROC and ULONG_PTR parameters of SendMessageCallback.
The lpCallBack up there is the name of a callback of yours that will be called by the OS when the hWnd window procedure returns after handling the message Msg you sent to it.
The type of lpCallBack is SENDASYNCPROC, which is declared as
VOID CALLBACK SendAsyncProc(__in HWND hwnd,
__in UINT uMsg,
__in ULONG_PTR dwData,
__in LRESULT lResult);
The dwData up there is any kind of data you want to use inside your callback, whenever it gets called. This is usually a pointer to complex data, like a struct or C++ class. In that case the lifetime of the memory must be considered carefully, so that it's valid when the callback is called. The dwData can also be just the simple integer data it looks like.
Bringing it all together, then. In your code you call SendMessageCallback like this (error checking omitted for readability):
SendMessageCallback(hWnd, WM_FOO, 0, 0, MySendAsyncProc, (ULONG_PTR)myData);
But, hmmm, since this is an exercise, let's assume that myData is just 0:
SendMessageCallback(hWnd, WM_FOO, 0, 0, MySendAsyncProc, 0);
That means you have declared a callback MySendAsyncProc:
VOID CALLBACK MySendAsyncProc(__in HWND hwnd,
__in UINT uMsg,
__in ULONG_PTR dwData, // This is *the* 0
__in LRESULT lResult) // The result from the callee
{
// Whohoo! It called me back!
}
And that callback will be called when your WM_FOO message has been handled.
That pretty much sums it up.

Related

Passing class' member address correctly with the ability of invoking it

I'm struggling with passing member's address to another function.
Here's what im trying to do:
I've the following defention:
bool MyClass::FunctionName();
and then somewhere in my program i execute the following command:
::SendMessage(hWnd, WM_NULL, (WPARAM)this, (LPARAM)&MyFunction);
where this stands for MyClass
Once my WndProc is executed, i try this:
LRESULT CALLBACK MyClass::WndProc(_In_ HWND hWnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam)
{
Myclass* pClass= (Myclass*)wParam;
std::function<bool()> pFunc = std::bind(bool(&Myclass::MyFunction)&lParam, pClass);
pFunc();
}
Errors im receving:
warning C4554: '&' : check operator precedence for possible error; use
parentheses to clarify precedence
Error 3 error C2064: term does not evaluate to a function taking 1
arguments c:\program files (x86)\microsoft visual studio
12.0\vc\include\xrefwrap 58
Well this should compile:
LRESULT CALLBACK MyClass::WndProc(_In_ HWND hWnd, _In_ UINT uMsg,
_In_ WPARAM wParam, _In_ LPARAM lParam)
{
switch (uMsg)
{
case WM_METHOD_CALL:
Myclass* pClass= static_cast<Myclass*>(wParam);
typedef bool Myclass::pmf();
const auto pointer_to_member_function = static_cast<pmf>(lParam);
(pClass->*pointer_to_member_function)();
break;
}
}
Your problem is that while it is perfectly safe to expect a WPARAM to be a class pointer, a "pointer to member function" is a surprisingly complex beast (consider a virtual function in a second base class), and is typically larger than a single pointer - so it won't fit in an LPARAM.
Given you want to use SendMessage, you can do the following:
Move the typedef into Myclass:
typedef bool Myclass::pmf(); // Inside the definition of Myclass.
Somewhere in your program:
Myclass::pmf ptr = &MyFunction;
::SendMessage(hWnd, WM_METHOD_CALL, (WPARAM)this, (LPARAM)&ptr);
Then in your message handler:
LRESULT CALLBACK MyClass::WndProc(_In_ HWND hWnd, _In_ UINT uMsg,
_In_ WPARAM wParam, _In_ LPARAM lParam)
{
Myclass* pClass= static_cast<Myclass*>(wParam);
switch(uMsg)
{
case WM_METHOD_CALL:
do_method_call(wParam, lParam);
break;
}
return 0; // Or whatever.
}
void do_method_call(_In_ WPARAM wParam, _In_ LPARAM lParam)
{
const auto pointer_to_member_function = *static_cast<Myclass::pmf*>(lParam);
(pClass->*pointer_to_member_function)();
}

Pass object's pointer as parameter to DialogBoxParam()

I would like to pass an object's pointer as the fifth parameter of DialogBoxParam().
INT_PTR WINAPI DialogBoxParam(
_In_opt_ HINSTANCE hInstance,
_In_ LPCTSTR lpTemplateName,
_In_opt_ HWND hWndParent,
_In_opt_ DLGPROC lpDialogFunc,
_In_ LPARAM dwInitParam
);
Here is my call to DialogBoxParam() :
MyClass *myObject = new MyClass();
DialogBoxParam(
GetModuleHandle(NULL),
MAKEINTRESOURCE(IDD_SELECT_ETC),
hwnd,
CallbackDlgProc,
(LPARAM)&myObject
);
And here is one of my tries in CallbackDlgProc() (knowing myFile is a public char* member of myObject) :
BOOL CALLBACK CallbackDlgProc(HWND hwndDlg, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch(Message)
{
case WM_INITDIALOG:
{
MessageBox(NULL, (CHAR*)((*(MyClass*)lParam).myFile), "Title", MB_OK);
return TRUE;
}
case [...]
}
}
Any idea how I could access and edit myObject from CallbackDlgProc() ?
When you pass it to DialogBoxParam, you use the address-of operator & to get a pointer. However, it's already a pointer so you actually pass a pointer to a pointer (type MyClass**).
Either adjust the code in your callback function for it, or do not use the address-of operator.
A more detailed explanation for someone that will not understand the above answer, in the OP's example code you must remove "&" to make it work:
DialogBoxParam(
GetModuleHandle(NULL),
MAKEINTRESOURCE(IDD_SELECT_ETC),
hwnd,
CallbackDlgProc,
(LPARAM)myObject
);
Enjoy.

Function does not work inside a class - function call missing argument list

I've built a working keylogger and now I want to move it to class so I can re-use it whenever I want and even on different languages like c# however I encountered error because same code does not work inside a class.
main.cpp (working)
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
void main()
{
HINSTANCE h_instance = GetModuleHandle(NULL);
SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, h_instance, 0); // Works here
}
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
// Populate typedChars
return NULL;
}
KeyboardHook.cpp (not working)
class KeyboardHook
{
stringstream typedChars;
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
// Populate typedChars
return NULL;
}
KeyboardHook()
{
HINSTANCE h_instance = GetModuleHandle(NULL);
SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, h_instance, 0); // Does not work
}
public:
std::string Get()
{
return typedChars.str();
}
void Clear()
{
typedChars.str(std::string());
typedChars.clear();
}
};
Error
C3867: 'KeyboardHook::KeyboardProc': function call missing argument list; use '&KeyboardHook::KeyboardProc' to create a pointer to member
So I modify it to SetWindowsHookEx(WH_KEYBOARD_LL, &KeyboardProc, h_instance, 0); and now different error occurs
C2276: '&' : illegal operation on bound member function expression
I've also tried but no success:
SetWindowsHookEx(WH_KEYBOARD_LL, (LRESULT)&KeyboardProc, h_instance, 0);
SetWindowsHookEx(WH_KEYBOARD_LL, (LRESULT)KeyboardProc, h_instance, 0);
SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHook::KeyboardProc, h_instance, 0);
SetWindowsHookEx(WH_KEYBOARD_LL, &KeyboardHook::KeyboardProc, h_instance, 0);
Assuming SetWindowsHookEx is supposed to take a function pointer (I can never understand the horrible Windows API documentation), you need to bind your pointer to member function to an object on which it should be called. If you want to bind it to the object pointed to by this (i.e. the KeyboardHook object you're creating at the time), try this:
using std::placeholders;
SetWindowsHookEx(WH_KEYBOARD_LL,
std::bind(&KeyboardHook::KeyboardProc, this, _1, _2, _3),
h_instance, 0);
Alternatively, KeyboardProc can be declared as a static member function, but that means it won't be able to use the typedChars member.
You must define KeyboardProc as a static member
static LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
...
}
if it must and can be called without an object.

sending lparam as a pointer to class, and use it in WndProc()

i have this abstract code :
i want to use lParam (last parameter) in CreateWindowEx() to save a pointer to a class thats declared in the begining of main - SaveArr. then, i want to use it in the function WndProc.
in the begining i did a global array, and then i could use it anywhere, but its not so "clever" as far as c++ concern, so im trying to upgrade it a bit.
class Samples
{
int arr[ITERATIONS+1];
int index;
...
}
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
Samples * SaveArr;
...
hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
ClsName,
WindowCaption,
WS_OVERLAPPEDWINDOW,
INITIAL_WIN_LOCAT_X,
INITIAL_WIN_LOCAT_Y,
WIN_WIDTH,
WIN_HIGHT,
NULL,
NULL,
hInstance,
NULL); //here i want to pass SaveArr, so that i can use it in the WndProc(...) function
...
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
... //here i would like to use lParam as the class pointer, meaning using the
SaveArr declared in the main function.
}
}
Adding caller information to the window:
m_window = CreateWindow(..., this);
Similar for the extended CreateWindowEx.
Obtaining a pointer to the caller:
template< typename CallerT >
[[nodiscard]]
CallerT* WindowCaller(HWND window, UINT message, LPARAM lParam) noexcept
{
if (message == WM_NCCREATE) [[unlikely]]
{
const auto caller = reinterpret_cast< CallerT* >(
reinterpret_cast< CREATESTRUCT* >(lParam)->lpCreateParams);
// Change the user data of the window for subsequent messages.
::SetWindowLongPtr(window, GWLP_USERDATA,
reinterpret_cast< LONG_PTR >(caller));
return caller;
}
else
{
// Retrieve the user data of the window.
return reinterpret_cast< CallerT* >(
::GetWindowLongPtr(window, GWLP_USERDATA));
}
}
This method needs to be called in your message callback.
Best way would be
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
Samples *savearr = (Samples*)GetWindowLong(hWnd,GWL_USERDATA)
switch(Msg)
{
case WM_CREATE:
SetWindowLong(hWnd, GWL_USERDATA, (LONG)lParam);
break;
}
}
The next time the WndProc is called the value would be in savearr, and can be used.
From the reference:
lpParam [in, optional]
Type: LPVOID
Pointer to a value to be passed to the window through the
CREATESTRUCT structure (lpCreateParams member) pointed to by the
lParam param of the WM_CREATE message. This message is sent to the
created window by this function before it returns.
If an application calls CreateWindow to create a MDI client
window, lpParam should point to a CLIENTCREATESTRUCT structure. If an
MDI client window calls CreateWindow to create an MDI child window,
lpParam should point to a MDICREATESTRUCT structure. lpParam may be
NULL if no additional data is needed.
You're expecting the lParam to be always passed to WndProc, but it is only passed with WM_CREATE.
Note, that even then it's not passed directly, but rather through a structure which is the actual lParam for WM_CREATE.
Your only chance to read the lParam is during WM_CREATE. If you want to keep using the value later then you must store it somewhere. Maybe as a static of the WndProc or otherwise assign it to something else which is going to be scoped.
Why all the insistence on using that last, lpParam value set to X, then catching it on WM_CREATE (through all that indirect struct stuff, no less!) and then setting GWL_USERDATA?!
Why not cut to the chase and do this:
HWND H=CreateWindow(.....)
SetWindowLong(H,GWL_USERDATA,X)
In other words, just put X there directly, yourself, right after the window creation statement.
In my tests it works, and so long as you test the window handle against some list of known handles, you can prevent some errant message picked up by your program, and prevent inappropriate use of something else's userdata.

Function as a type?

I am learning Windows programming in C++. I created my first Windows, but there's one thing I don't really understand: WNDPROC in WNDCLASS. The structure was documented like this:
typedef struct tagWNDCLASS {
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
} WNDCLASS, *PWNDCLASS;
Now in order to assign to lpfnWndProc, I must have a callback function WindowProc like this:
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
And then I have to assign lfpnWndProc like this:
WNDCLASS wc = { };
wc.lpfnWndProc = WindowProc;
As I understand, WindowProc is a function. If I assign like this, it means I am assigning to a function pointer in WNDCLASS. But in the WNDCLASS definition, nothing indicates it is a function pointer. Further more, it looks like a data type to me rather than a function pointer.
Normally I would do get a function pointer like this to pass in as a parameter or used as a variable:
#include <stdio.h>
void my_int_func(int x)
{
printf("%d\n",x);
}
int main(void)
{
void (*foo) (int);
foo = &my_int_func;
foo(2);
(*foo)(2);
}
But the way I have to assign WindowProc just does not make sense to me. Can someone help me understand this?
WNDPROC is a function pointer type. The definition is:
typedef LRESULT (CALLBACK* WNDPROC)(HWND, UINT, WPARAM, LPARAM);
Functions, sort of like arrays, automatically decay into pointers in certain contexts. The & in your example program is optional.
MSDN says,
lpfnWndProc
Type: WNDPROC
A pointer to the window procedure. You must use the CallWindowProc function to call the window procedure.
WinUser.h defines it as,
typedef LRESULT (CALLBACK* WNDPROC)(HWND, UINT, WPARAM, LPARAM);