|
-
Jul 22nd, 2003, 09:29 AM
#1
Thread Starter
Frenzied Member
Prototype Elimination!!
I REALLY hate using prototypes. Is it possible to never use them? C# does not use them at all, I don't think they are at all necessary in C++ either.
I have a Form class which is a window. I cannot process the window messages from the class. I have to use a global WndProc function and then pass the variables into a new class.
Here is the problem, the form class needs to know about the global WndProc function and the WndProc function needs to know about the class.
So I had to put a prototype of the WndProc function above the class. I want that nonsense to stop. I did not have to do that in Borland. Is this a compiler issue?
-
Jul 22nd, 2003, 09:50 AM
#2
No, it's not. Not a specific compiler at least.
C compilers basically are top-down compilers. They read and use line by line of the source. C# and Java compilers are lookahead compilers.
The difference is that if a C compiler encounters a symbol it doesn't know, it immediatly fails. A C# compiler first checks the rest of the source file and even some other source files if it can find the symbol being declared somewhere. Only if that too is useless, it fails.
C++ compilers are hybrids. Usually they still show the same behavior as a C compiler, but in some cases they don't.
The reason why C works that way is that C was originally intended as a minimal language. The programs it creates are fast and small. This is to accommodate weak computers with little storage space. And the compiler should do the same. Top-down compilers are easier to implement than the other sort. Thus the requirement of function prototypes.
It's possible to write a C/C++ program completly without prototypes, but only if it's limited to a single source file and you don't have any round-calling functions (a calls b, b calls a, or similar things with more functions).
For your specific problem, I recommend two changes.
First, your class declaration probably doesn't need to know about the global WndProc, so you can simpy define the WndProc above the class implementation.
Second, screw the global function altogether. Declare it as static private member of the class. Makes much more sense that way.
Finally, I have no idea why you don't like prototypes. I think they are a great self-documentation of source code.
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Jul 22nd, 2003, 10:00 AM
#3
Thread Starter
Frenzied Member
They would be ok if I did not make changes the the source code. I just don't like making 2 changes instead of one.
About the static WndProc, the downside to using a static WndProc is that it cannot access the instance members of the class. And I need access to them.
-
Jul 22nd, 2003, 03:06 PM
#4
Neither can the global. Here's how I do it (from a current project of mine):
Code:
// Header File:
class Application
{
int app_main(HINSTANCE instance, tchar_t *cmdline, int showcmd);
static LRESULT CALLBACK WndProcStub(HWND hwnd, UINT msg, WPARAM w, LPARAM l);
protected:
HINSTANCE app_instance;
HWND app_hwnd;
virtual LRESULT WndProc(HWND hwnd, UINT msg, WPARAM w, LPARAM l);
// ...
};
// Implementation
int Application::app_main(HINSTANCE instance, tchar_t *cmdline, int showcmd)
{
app_instance = instance;
// Create a window etc...
::WNDCLASS wc;
// ...
wc.lpszClassName = _T("T3D Game Window Class");
::RegisterClass(&wc);
app_hwnd = CreateWindow(_T("T3D Game Window Class"),
_T("T3D Game"), get_window_flags(), CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL,
NULL, instance, static_cast<void *>(this));
::ShowWindow(hwnd_app, showcmd);
::UpdateWindow(hwnd_app);
// Enter message loop
MSG msg;
while(::GetMessage(&msg, NULL, 0, 0) > 0)
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
return static_cast<int>(msg.wParam);
}
LRESULT CALLBACK Application::WndProcStub(HWND hwnd, UINT msg, WPARAM w, LPARAM l)
{
if(msg == WM_NCCREATE)
{
::CREATESTRUCT *pcs = reinterpret_cast<::CREATESTRUCT *>(l);
::SetWindowLongPtr(hwnd, 0,
reinterpret_cast<LONG_PTR>(pcs->lpCreateParams));
}
Application *pthis = reinterpret_cast<Application *>(
::GetWindowLongPtr(hwnd, 0);
return pthis->WndProc(hwnd, msg, w, l);
}
// etc...
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Jul 22nd, 2003, 03:07 PM
#5
As for code changes - yeah, I don't like that part either, but you could see it as punishment for not planning properly
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Jul 22nd, 2003, 04:38 PM
#6
Thread Starter
Frenzied Member
This will not compile:
::CREATESTRUCT *pcs= reinterpret_cast<::CREATESTRUCT*>(lParam);
Error: Parse error before ;
This will but you know better than I do, CRASH!
::CREATESTRUCT *pcs;
The compiler does not like something here:
= reinterpret_cast<::CREATESTRUCT*>(lParam);
-
Jul 22nd, 2003, 06:15 PM
#7
Thread Starter
Frenzied Member
It did not like the :: before reinterpret_cast<CREATESTRUCT*>.
Code:
static LRESULT CALLBACK WndProcStatic(HWND h, UINT m, WPARAM wParam, LPARAM lParam)
{
switch(m)
{
case WM_NCCREATE:
{
ostringstream oss;
::CREATESTRUCT *pcs= reinterpret_cast<CREATESTRUCT*>(lParam);
oss<< pcs<<" "<< lParam<<" "<<
::SetWindowLongPtr(h, 0, reinterpret_cast<LONG_PTR>(pcs->lpCreateParams));
MessageBox(NULL, oss.str().c_str(), "", MB_OK);
}
default:
{
Form *pthis= reinterpret_cast<Form*>(::GetWindowLongPtr(h, 0));
ostringstream oss;
oss<< pthis<<" "<<" "<<GetWindowLongPtr(h, 0);
if(!pthis)
{
MessageBox(NULL, oss.str().c_str(), "", MB_OK);
return 0;
}
return pthis->WndProc(h, m, wParam, lParam);
}
}
The program produces a fatal error. Is ::SetWindowLongPtr supposed to return 0? Because it does. ::GetWindowLongPtr also returns 0.
First default is called then WM_NCCREATE, and then default again, then the program crashes in default trying to use a pointer that points to nothing. That is if I did not stop it by returning 0 before if got to: return pthis->WndProc(h, m, wParam, lParam);
Last edited by aewarnick; Jul 22nd, 2003 at 06:37 PM.
-
Jul 22nd, 2003, 07:14 PM
#8
Thread Starter
Frenzied Member
I am using the extended window style so I changed the 0's in GetWindow and SetWindow to GWL_EXSTYLE and now none of the messageboxe's show indicating that the variables are initialized but I still get the same error when it tries to return the WndProc.
Or maybe it is because my createparameters are 0:
pcs->lpCreateParams shows 0. If that is it, how do I change it?
Last edited by aewarnick; Jul 22nd, 2003 at 08:52 PM.
-
Jul 22nd, 2003, 09:26 PM
#9
Thread Starter
Frenzied Member
Got it working. Your code confused me. It looks like you wanted the part I have in default not return the DefWindowProc(). So what I tried was putting all that code in WM_NCCREATE and it works.
-
Jul 23rd, 2003, 01:08 AM
#10
I haven't tested the code yet 
And the :: is because my code is in a namespace.
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Jul 23rd, 2003, 01:11 AM
#11
I never use a default: in my WndProcs. I like my way better.
Which works like this:
Code:
WndProc
{
switch(msg)
{
case WM_SOME:
// Handled
return 0;
case WM_OTHER:
// Handled, but we still want default action
break;
}
// Default action
return DefWindowProc();
}
The reason why my code doesn't contain a DefWindowProc call is that this call is in the true WndProc.
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Jul 23rd, 2003, 05:54 AM
#12
Thread Starter
Frenzied Member
Every time the program starts, the pthis pointer is not initialized right away so I always get my messagebox error. I don't think that should be the case. What did I do wrong?
Code:
case WM_NCCREATE:
{
::CREATESTRUCT *pcs= reinterpret_cast<CREATESTRUCT*>(lParam);
::SetWindowLongPtr(h, 0, reinterpret_cast<LONG_PTR>(pcs->lpCreateParams));
Form *pthis= reinterpret_cast<Form*>(::GetWindowLongPtr(h, 0));
if(!pthis)
{
MessageBox(NULL, "create", "Error", MB_OK);
//return -1;
//return 0;
}
else
return pthis->WndProc(h, m, wParam, lParam);
}
Last edited by aewarnick; Jul 23rd, 2003 at 06:02 AM.
-
Jul 23rd, 2003, 08:49 AM
#13
Check if WM_NCCREATE is really the first message the WndProc receives. If not, I need to change my code (and you too )
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Jul 23rd, 2003, 10:45 AM
#14
Thread Starter
Frenzied Member
No it's 36, whatever that is.
-
Jul 23rd, 2003, 10:55 AM
#15
Thread Starter
Frenzied Member
I tried using 36 and also WM_CREATE but both do the same:
Code:
static LRESULT CALLBACK WndProcStatic(HWND h, UINT m, WPARAM wParam, LPARAM lParam)
{
ostringstream oss;
oss<< m;
//MessageBox(NULL, oss.str().c_str(), "Error", MB_OK);
switch(m)
{
case 36:
{
::CREATESTRUCT *pcs= reinterpret_cast<CREATESTRUCT*>(lParam);
::SetWindowLongPtr(h, 0, reinterpret_cast<LONG_PTR>(pcs->lpCreateParams));
Form *pthis= reinterpret_cast<Form*>(::GetWindowLongPtr(h, 0));
if(!pthis)
{
MessageBox(NULL, "create", "Error", MB_OK);
}
else
return pthis->WndProc(h, m, wParam, lParam);
break;
}
}
return DefWindowProc(h, m, wParam, lParam);
}
-
Jul 23rd, 2003, 11:08 AM
#16
Thread Starter
Frenzied Member
It works without most of that code too for some reason:
::CREATESTRUCT *pcs= reinterpret_cast<CREATESTRUCT*>(lParam);
::SetWindowLongPtr(h, 0, reinterpret_cast<LONG_PTR>(pcs->lpCreateParams));
That is all that is in NCCREATE and it works.
Should that be ok?
-
Jul 23rd, 2003, 12:23 PM
#17
Uh... what?
Isn't that what I had all along?
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Jul 23rd, 2003, 12:26 PM
#18
Thread Starter
Frenzied Member
Here is what you had:
Code:
LRESULT CALLBACK Application::WndProcStub(HWND hwnd, UINT msg, WPARAM w, LPARAM l)
{
if(msg == WM_NCCREATE)
{
::CREATESTRUCT *pcs = reinterpret_cast<::CREATESTRUCT *>(l);
::SetWindowLongPtr(hwnd, 0,
reinterpret_cast<LONG_PTR>(pcs->lpCreateParams));
}
Application *pthis = reinterpret_cast<Application *>(
::GetWindowLongPtr(hwnd, 0);
return pthis->WndProc(hwnd, msg, w, l);
}
-
Jul 23rd, 2003, 12:26 PM
#19
36 would be WM_GETMINMAXINFO...
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Jul 23rd, 2003, 01:00 PM
#20
This should never crash. And I missed a closing parenthesis.
Code:
LRESULT CALLBACK Application::WndProcStub(HWND hwnd, UINT msg, WPARAM w, LPARAM l)
{
if(msg == WM_NCCREATE)
{
::CREATESTRUCT *pcs = reinterpret_cast<::CREATESTRUCT *>(l);
::SetWindowLongPtr(hwnd, 0,
reinterpret_cast<LONG_PTR>(pcs->lpCreateParams));
}
Application *pthis = reinterpret_cast<Application *>(
::GetWindowLongPtr(hwnd, 0));
if(pthis)
return pthis->WndProc(hwnd, msg, w, l);
else
return ::DefWindowProc(hwnd, msg, w, l);
}
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Jul 23rd, 2003, 01:06 PM
#21
Thread Starter
Frenzied Member
Guess what? Your not going to like this, it does not work. I did a little experiment and took everything out of WM_NCCREATE and I got the same results- the program seemed to work correctly.
I came to find out that the Window process that the instance form's process was calling was the static one and not the one it should be calling.
Something must not be working right with this:
::CREATESTRUCT *pcs= reinterpret_cast<CREATESTRUCT*>(lParam);
::SetWindowLongPtr(h, 0, reinterpret_cast<LONG_PTR>(pcs->lpCreateParams));
-
Jul 23rd, 2003, 01:21 PM
#22
Thread Starter
Frenzied Member
Here is where I got the idea to use a global WndProc:
http://www.rpi.edu/~pudeyo/articles/wndproc/
He does not mention anything like this. Maybe it can't work?
Look that over and tell me what you think.
-
Jul 23rd, 2003, 01:50 PM
#23
Thread Starter
Frenzied Member
This one is the most like yours, although he still talks about using a global WndProc and not a static. But I think static should work the same way.
"Per-Window Data"
-
Jul 24th, 2003, 01:54 AM
#24
Static and global are binary equivalent.
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Jul 24th, 2003, 03:00 PM
#25
Thread Starter
Frenzied Member
Have you tried your code out yo see if you can get it working? I could not get either to work.
-
Jul 25th, 2003, 05:02 AM
#26
No, not yet. And I will not for some days, I'll not be at home.
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Jul 25th, 2003, 01:21 PM
#27
Thread Starter
Frenzied Member
Ok. If I figure out how to get this working i'll post back, if not i'll just be looking forward to whatever you come up with.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|