Sign in to follow this  
psae0001

WNDPROC in a class... no idea--PART 2

Recommended Posts

Ok folks, thank you for those suggestions yesterday. I know there're lots of ways to get round this problem, but I'm very interested in to make it the simplest the possible, so let me explain here. I did some sorta to put the address of my WNDPROC to the WNDCLASSEX.lpfnWndProc. However, this time it gets an error message from CreateWindowEx which I use the GetLastError function that tell me it's an invalid window handle. I know sprintf and sscanf probably just some stupid idea since the window doesn't get the class pointer at all. But this time, any idea that why it's giving me the 1400 Error? http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/system_error_codes__1300-1699_.asp --------------- The class code below -------------------- #include "WinClzCtrl.h" const DWORD // Normal window extened style WIN_MODE_EX_SYL = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE, // Full screen windwow extened sytle WIN_FULL_EX_SYL = WS_EX_APPWINDOW, // Normal window style WIN_MODE_SYL = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, // Full screen style during active WIN_FULL_SYL_ACTIVE = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, // Full screen style when inactive WIN_FULL_SYL_MIN = WIN_FULL_SYL_ACTIVE | WS_SYSMENU; WinClzCtrl::WinClzCtrl () { mySC.ReadCfgIniFile (); hInstance = NULL; lpCmdLine = NULL; nShowCmd = 0; wcEX.cbSize = sizeof (wcEX); wcEX.style = wcEX.cbClsExtra = wcEX.cbWndExtra = 0; wcEX.lpfnWndProc = NULL; wcEX.hInstance = NULL; wcEX.hIcon = wcEX.hIconSm = wcEX.hCursor = NULL; wcEX.hbrBackground = NULL; wcEX.lpszMenuName = wcEX.lpszClassName = NULL; hWnd = NULL; wndMsg.hwnd = NULL; wndMsg.message = wndMsg.wParam = wndMsg.lParam = wndMsg.time = wndMsg.pt.x = wndMsg.pt.y = 0; clzName = winName = NULL; bigIcon = smallIcon = NULL; thisWinRect.bottom = thisWinRect.left = thisWinRect.right = thisWinRect.top = 0; currentstyle = currentstyleEX = 0; currentstyle = WIN_MODE_SYL; currentstyleEX = WIN_MODE_EX_SYL; } // MessageBox (NULL, buf, ERROR, MB_OK); // sprintf (buf, "%d", wcEX.lpfnWndProc); // MessageBox (NULL, buf, ERROR, MB_OK); bool WinClzCtrl::OnlyReg (HINSTANCE deInst, HICON hBig, HICON hSmall, char* className) { char buf[12]; int i = 0; // Trying to obtain the physically address of the WndProc function. sprintf (buf, "%d", WndProc); sscanf (buf, "%d", &i); wcEX.cbSize = sizeof (wcEX); wcEX.style = CS_HREDRAW | CS_VREDRAW; wcEX.lpfnWndProc = (WNDPROC) i; wcEX.cbClsExtra = 0; wcEX.cbWndExtra = 0; wcEX.hInstance = deInst; wcEX.hIcon = hBig; wcEX.hCursor = LoadCursor (hInstance, IDC_ARROW); wcEX.hbrBackground = (HBRUSH) GetStockObject (GRAY_BRUSH); wcEX.lpszMenuName = NULL; wcEX.lpszClassName = className; wcEX.hIconSm = hSmall; if (RegisterClassEx (&wcEX) == false) { MessageBox (NULL, "reg has problem", ERROR, MB_OK); UnregisterClass (clzName, hInstance); return false; } else { return true; } } bool WinClzCtrl::RegNCreate (HINSTANCE deInst, LPSTR cmdLine, int showCmd, char* className, char* titleName, HICON hBig, HICON hSmall) { char buf[12]; OnlyReg (deInst, hBig, hSmall, className); if (mySC.GetDisplayMode()) { currentstyle = WIN_FULL_SYL_ACTIVE; currentstyleEX = WIN_FULL_EX_SYL; } else { currentstyle = WIN_MODE_SYL; currentstyleEX = WIN_MODE_EX_SYL; } hInstance = deInst; lpCmdLine = cmdLine; nShowCmd = showCmd; hWnd = NULL; wndMsg.hwnd = NULL; wndMsg.message = wndMsg.wParam = wndMsg.lParam = wndMsg.time = wndMsg.pt.x = wndMsg.pt.y = 0; winName = titleName; clzName = className; bigIcon = hBig; smallIcon = hSmall; thisWinRect.left = thisWinRect.top = 0; thisWinRect.right = thisWinRect.left + mySC.GetResolutionWidth (); thisWinRect.bottom = thisWinRect.top + mySC.GetResolutionHeight (); if ((AdjustWindowRectEx (&thisWinRect, currentstyle, FALSE, currentstyleEX) == FALSE) || (hWnd = CreateWindowEx (currentstyleEX, clzName, winName, currentstyle, 0 /* thisWinRect.left */, 0 /* thisWinRect.top */, thisWinRect.right - thisWinRect.left, thisWinRect.bottom - thisWinRect.top, NULL, NULL, hInstance, this)) == NULL) { int j = (int) GetLastError(); sprintf (buf, "%d", j); MessageBox (NULL, "create has problem", ERROR, MB_OK); sprintf (buf, "%d", j); MessageBox (NULL, buf, ERROR, MB_OK); return false; } else { // Show The Window, see the following URL for more info. ShowWindow (hWnd, nShowCmd); // Sets Keyboard Focus To The Window SetFocus (hWnd); // Draw and update the window UpdateWindow (hWnd); // This should be true for window mode, in full screen probably false. // It's optional anyway. ShowCursor (TRUE); return true; } } WPARAM WinClzCtrl::Run() { while (GetMessage (&wndMsg, NULL, 0, 0)) { TranslateMessage (&wndMsg); DispatchMessage (&wndMsg); } return (wndMsg.wParam); } void WinClzCtrl::ChangePstNSz (RECT deWinSz) { thisWinRect = deWinSz; // call functions to change it // if (!SetWindowPos(hWnd, HWND_TOP, thisWinRect.left, thisWinRect.top, // thisWinRect.right, thisWinRect.bottom, SWP_SHOWWINDOW)) // { /* do something */ } } bool WinClzCtrl::Changestyle (DWORD style, DWORD styleX) { if ((SetWindowLong(hWnd, GWL_EXstyle, style) == false) || (SetWindowLong(hWnd, GWL_style, styleX) == false)) { return false; } else { currentstyle = style; currentstyleEX = styleX; mySC.SetDisplayMode (!mySC.GetDisplayMode ()); return true; } } WinClzCtrl::~WinClzCtrl() { UnregisterClass (clzName, hInstance); wcEX.hInstance = hInstance = NULL; lpCmdLine = NULL; nShowCmd = 0; wcEX.cbSize = wcEX.style = wcEX.cbClsExtra = wcEX.cbWndExtra = 0; wcEX.lpfnWndProc = NULL; wcEX.hIcon = wcEX.hIconSm = wcEX.hCursor = NULL; wcEX.hbrBackground = NULL; wcEX.lpszMenuName = NULL; wcEX.lpszClassName = NULL; hWnd = NULL; wndMsg.hwnd = NULL; wndMsg.message = wndMsg.wParam = wndMsg.lParam = wndMsg.time = wndMsg.pt.x = wndMsg.pt.y = 0; winName = clzName = NULL; bigIcon = smallIcon = NULL; thisWinRect.bottom = thisWinRect.left = thisWinRect.right = thisWinRect.top = 0; mySC.~SysCtrl (); } void WinClzCtrl::Testing () { MessageBox (NULL, "Testing", ERROR, MB_OK); } LRESULT CALLBACK WinClzCtrl::WndProc (HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { switch (msg) { case WM_CREATE: Testing (); return 0; case WM_DESTROY: // After that we need to destroy the window handle PostQuitMessage(0); return 0; default: return DefWindowProc (hWnd, msg, wp, lp); } }

Share this post


Link to post
Share on other sites
LRESULT CALLBACK WinClzCtrl::WndProc (HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)

thjis isn't declared static.

Did you read that article about wrapping a window in a class?

Share this post


Link to post
Share on other sites
There are few syntax errors in the article, one being on the line you're getting an error with. He forgets a pair of parenthesis, it should be:

wnd = reinterpret_cast<Window*>(((LPCREATESTRUCT)lparam)->lpCreateParams);

Share this post


Link to post
Share on other sites
Ok, I can't even get my WM_NCCREATE message passed to the CALLBACK function since I did it very differently!

----- in my WinClzCtrl::OnlyReg function ------------

char buf[12];
int i = 0;

sprintf (buf, "%d", WndProc);
sscanf (buf, "%d", i);
...
...

wcEX.lpfnWndProc = (WNDPROC) i; // <---- I can obtain the address of the function--EVEN it's inside a class--please read my codes if you have time.

------ in my WinClzCtrl::RegNCreate function -----------

....

if ((AdjustWindowRectEx (&thisWinRect, currentstyle, FALSE,
currentstyleEX) == FALSE) || (hWnd = CreateWindowEx (currentstyleEX,
clzName, winName, currentstyle, 0 , 0,
thisWinRect.right - thisWinRect.left, thisWinRect.bottom - thisWinRect.top,
NULL, NULL, hInstance, this)) == NULL)
{
int j = (int) GetLastError();
sprintf (buf, "%d", j);
MessageBox (NULL, "create has problem", ERROR, MB_OK);
sprintf (buf, "%d", j);
MessageBox (NULL, buf, ERROR, MB_OK);
return false;
}
....

----- then I try to test my WinClzCtrl::WndProc function with WM_NCCREATE ----------

case WM_NCCREATE:

MessageBox (NULL, "WM_NCCREATE", ERROR, MB_OK);

return TRUE;

----------------------- end -----------------------------------

To a working window the MessageBox message in WM_NCCREATE should show up before any other messages show up... but it did NOT. Which I believe is the WM_NCCREATE was even passed to the WndProc function; in other words, the WndProc wasn't even called! There's no way I can store the pointer thing if it wasn't even called.

I guess that's probably I try to use the sprintf and sscanf functions to obtain the address of the WndProc--which works if it's not a class function. Yet, I'm pretty sure the both sprintf and sscanf works completely fine to get the address of the WndProc, but I'm not sure if the

wcEX.lpfnWndProc = (WNDPROC) i;

points to the correct WndProc address since it's inside a class. I've tested non-class function and it works fine to me. So, I'm trying to figure out WTH is going on here. Any ideas?

Share this post


Link to post
Share on other sites
C++ member functions used a different calling convention than regular functions, known as thiscall. What you're doing is a terribly hack that is guaranteed to cause you more problems that it's worth, since you don't even emulate the full behavior of the thiscall convention, which is a bad idea and probably compiler-specific anyway.

Just accept the fact you can't use a member function as a WindowProc, and follow Oluseyi's article completely.

Share this post


Link to post
Share on other sites
Whenever i get "Invalid Window Handle" from CreateWindowEx, its because in the WndProc, i've been using the m_hWnd variable.
When you call CreateWindowEx, windows sends a few messages to the WndProc, then returns from the call. If you write "m_hWnd = CreateWindowEx(...), then m_hWnd isn't filled in until the call returns. So, if you use the m_hWnd variable in the WndProc during those few calls (I think you get WM_NCCREATE, WM_CREATE, WM_SIZE, and possible one or 2 others), then you'll end up calling DefWindowProc with a NULL hWnd parameter. Windows doesn't like that, and takes it as meaning your WndProc returned failure for the WM_NCCREATE message (the first one the WndProc gets), so CreateWindowEx fails with the Invalid Window Handle error.

My reply in the previous thread shows a way around this problem.

Share this post


Link to post
Share on other sites
Very simple question: even if you can get the address to the WndProc, what do you intend to do with it? Call it yourself?

You DO realize that means generating all the messages that Windows generates... and dispatching those yourself, to everything with a handle. That means interfacing with hardware like the kernel does... so you may as well rewrite that, too.

To some people, the words "you can't breathe water" is just an annoying challenge, so good luck.

Share this post


Link to post
Share on other sites
Reply to Evil Steve:

Why do you put "this" on the last paramter to CreateWindowEx? I mean what do it do in order to create the static WNDPROC? Or for other purposes? Could you explain that?

Share this post


Link to post
Share on other sites
When Evil Steve passes the "this" pointer as the last parameter in CreateWindowEx(), it becomes data accessible by the window. You can access it in the struct passed in one of the parameters with the WM_(NC?)CREATE message, and later on you can access it with GetWindowLong( GWL_USERDATA, ... ). So even thought the WndProc is a static function, it can now look up the class instance associated with the window. So now the window is "properly" tied to the WinClzCtrl class you wrote. :)

P.S., please use [ source ] tags around your code.

Share this post


Link to post
Share on other sites
Now I got another question.

I believe many people, like me, who try to put the WNDPROC inside a class is mostly for officence (didn't spell right) and security (I believe).

If we put the WNDPROC as a static function how safe is that? And of course we have to do some tricks to asscess our class memeber functions.

Anyway, my question is the advantage and disadvantage (or it's not perferred) of having ONLY 1 static WNDPROC in the class--just like a normal WNDPROC function.


To thedevdan:

Well, I guess C# probably makes it easier, but I'm not just trying to get the job done. I'm looking for more advanced understanding about window programmings.



Thank you

Share this post


Link to post
Share on other sites
Quote:
Original post by psae0001
Now I got another question.

I believe many people, like me, who try to put the WNDPROC inside a class is mostly for officence (didn't spell right) and security (I believe).

If we put the WNDPROC as a static function how safe is that?


As in... other object can see/access it? That's not too big of a deal in this case. What's the harm? Actually, you can set the access specifier for WndProc to private.

Quote:
Anyway, my question is the advantage and disadvantage (or it's not perferred) of having ONLY 1 static WNDPROC in the class--just like a normal WNDPROC function.


Biggest advantage is that you only have to code it once. Now, there are hundreds (probably thousands) of messages that Windows generates; all you have to do is pass the values you care about
to another object and process them there.

Those tutorials (esp. the one on www.relisoft.com) show how to add a user parameter to CreateWindowEx... that's where you put the pointer to the object that will retrieve your messages in the WndProc. Simply get the parameter (using GetWindowLong) and do a static_cast... then you can pass all messages in the WndProc to the object.

[Edited by - Verg on July 10, 2004 5:03:08 PM]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this