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.
Related
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)();
}
I'm trying to bind a non-static class member to a standard WNDPROC function. I know I can simply do this by making the class member static. But, as a C++11 STL learner, I'm very interested in doing it by using the tools under the <functional> header.
My code is as follows.
class MainWindow
{
public:
void Create()
{
WNDCLASSEXW WindowClass;
WindowClass.cbSize = sizeof(WNDCLASSEX);
WindowClass.style = m_ClassStyles;
WindowClass.lpfnWndProc = std::function<LRESULT(HWND, UINT, WPARAM, LPARAM)>
( std::bind(&MainWindow::WindowProc,
*this,
std::placeholders::_1,
std::placeholders::_2,
std::placeholders::_3,
std::placeholders::_4));
WindowClass.cbClsExtra = 0;
WindowClass.cbWndExtra = 0;
WindowClass.hInstance = m_hInstance;
WindowClass.hIcon = LoadIconW(m_hInstance, MAKEINTRESOURCEW(IDI_WINDOW));
WindowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WindowClass.hbrBackground = (HBRUSH) COLOR_WINDOW;
WindowClass.lpszMenuName = MAKEINTRESOURCEW(IDR_MENU);
WindowClass.lpszClassName = m_ClassName.c_str();
WindowClass.hIconSm = LoadIconW(m_hInstance, MAKEINTRESOURCEW(IDI_WINDOW_SMALL));
RegisterClassExW(&WindowClass);
m_hWnd = CreateWindowEx(/*_In_ DWORD*/ ExtendedStyles,
/*_In_opt_ LPCTSTR*/ m_ClassName.c_str(),
/*_In_opt_ LPCTSTR*/ m_WindowTitle.c_str(),
/*_In_ DWORD*/ m_Styles,
/*_In_ int*/ m_x,
/*_In_ int*/ m_y,
/*_In_ int*/ m_Width,
/*_In_ int*/ m_Height,
/*_In_opt_ HWND*/ HWND_DESKTOP,
/*_In_opt_ HMENU*/ NULL,
/*_In_opt_ HINSTANCE*/ WindowClass.hInstance,
/*_In_opt_ LPVOID*/ NULL);
}
private:
LRESULT CALLBACK WindowProc(_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam)
{
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
};
When I run it as is, it gives the error message:
Error: no suitable conversion function from "std::function<LRESULT(HWND, UINT, WPARAM, LPARAM)>" to "WNDPROC".
While JohnB already explained the details why this is not possible, here is a common solution to the problem you are trying to solve: Granting class instance access to a static class member.
The guiding principle to the solution is that an instance pointer must be stored in a way that is accessible to the static class member. When dealing with windows the extra window memory is a good place to store this information. The requested space of extra window memory is specified through WNDCLASSEXW::cbWndExtra while data access is provided through SetWindowLongPtr and GetWindowLongPtr.
Store an instance pointer in the window extra data area after construction:
void Create()
{
WNDCLASSEXW WindowClass;
// ...
// Assign the static WindowProc
WindowClass.lpfnWndProc = &MainWindow::StaticWindowProc;
// Reserve space to store the instance pointer
WindowClass.cbWndExtra = sizeof(MainWindow*);
// ...
RegisterClassExW(&WindowClass);
m_hWnd = CreateWindowEx( /* ... */ );
// Store instance pointer
SetWindowLongPtrW(m_hWnd, 0, reinterpret_cast<LONG_PTR>(this));
}
Retrieve the instance pointer from the static window procedure and call into the window procedure member function:
static LRESULT CALLBACK StaticWindowProc( _In_ HWND hwnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam )
{
// Retrieve instance pointer
MainWindow* pWnd = reinterpret_cast<MainWindow*>(GetWindowLongPtrW(hwnd, 0));
if ( pWnd != NULL ) // See Note 1 below
// Call member function if instance is available
return pWnd->WindowProc(hwnd, uMsg, wParam, lParam);
else
// Otherwise perform default message handling
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
The signature of the class member WindowProc is the same as in the code you provided.
This is one way to implement the desired behavior. Remy Lebeau suggested a variation to this which has the benefit of getting all messages routed through the class member WindowProc:
Allocate space in the window extra data (same as above):
void Create()
{
WNDCLASSEXW WindowClass;
// ...
// Assign the static WindowProc
WindowClass.lpfnWndProc = &MainWindow::StaticWindowProc;
// Reserve space to store the instance pointer
WindowClass.cbWndExtra = sizeof(MainWindow*);
// ...
Pass instance pointer to CreateWindowExW:
m_hWnd = CreateWindowEx( /* ... */,
static_cast<LPVOID>(this) );
// SetWindowLongPtrW is called from the message handler
}
Extract instance pointer and store it in the window extra data area when the first message (WM_NCCREATE) is sent to the window:
static LRESULT CALLBACK StaticWindowProc( _In_ HWND hwnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam )
{
// Store instance pointer while handling the first message
if ( uMsg == WM_NCCREATE )
{
CREATESTRUCT* pCS = reinterpret_cast<CREATESTRUCT*>(lParam);
LPVOID pThis = pCS->lpCreateParams;
SetWindowLongPtrW(hwnd, 0, reinterpret_cast<LONG_PTR>(pThis));
}
// At this point the instance pointer will always be available
MainWindow* pWnd = reinterpret_cast<MainWindow*>(GetWindowLongPtrW(hwnd, 0));
// see Note 1a below
return pWnd->WindowProc(hwnd, uMsg, wParam, lParam);
}
Note 1: The instance pointer is stored into the window extra data area after the window has been created while the lpfnWndProc is set prior to creation. This means that StaticWindowProc will be called while the instance pointer is not yet available. As a consequence the if-statement inside StaticWindowProc is required so that messages during creation (like WM_CREATE) do get properly handled.
Note 1a: The restrictions stated under Note 1 do not apply to the alternative implementation. The instance pointer will be available going forward from the first message and the class member WindowProc will consequently be called for all messages.
Note 2: If you want to destroy the C++ class instance when the underlying HWND is destroyed, WM_NCDESTROY is the place to do so; it is the final message sent to any window.
Guess you cannot do that, since WNDPROC stands for a function pointer. Every function pointer can be converted to a std::function, yet not every std::function represents a function pointer.
Proof of impossibility of your plan: Technically, WNDPROC represents only the address of the function in memory which is to be called. Hence a variable of type WNDPROC does not contain "space" to store information about bound parameters.
Its the same problem as in the following example:
typedef void (* callbackFn) ();
struct CallingObject {
callbackFn _callback;
CallingObject (callbackFn theCallback) : _callback (theCallback) {
}
void Do () {
_callback ();
}
};
void f () { std::cout << "f called"; }
void g () { std::cout << "g called"; }
void h (int i) { std::cout << "h called with parameter " << i; }
int main () {
CallingObject objF (f); objF.Do (); // ok
CallingObject objG (g); objG.Do (); // ok
}
Yet in order to call h from a CallingObject with some parameter value determined at runtime, you must store the parameter value in a static variable and then write a wrapper function calling h with this value as argument.
That's the reason callback functions usually take an argument of type void *, where you can pass arbitrary data needed for the calculation.
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.
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.
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.