If so, what if I want to keep some information when one message is processed. Obviously I need to save such information in a global or static data. As the result, it makes window procedure non-reentrant.
Printable View
If so, what if I want to keep some information when one message is processed. Obviously I need to save such information in a global or static data. As the result, it makes window procedure non-reentrant.
I am not for sure what you're implying. You usually parse these message asap since they are only active during the procedure. If you feel the need to collect them for later, you can create a vector of messages.
What you say about global or static data is correct, but why not keep them in local variables? They would be located in the stack frame and each "call instance" of the window procedure would get its own set of them. ;)
If I save them in local variables then next time I enter the window procedure again, I will lose them. So that is why I need to keep them in static or global variables. But that would make window procedure non-reentrant. I wonder if there is any requirement that Window procedure must be reentrant? Thanks.
Maybe a way to make that issue less severe is to limit static/global storage to certain message handlers rather than the entire window procedure. If you still got reentrance issues then, you might implement some syncronization stuff and/or something like the vector approach suggested by Joeman.
On the sidenote: That vector approach somehow resembles something like your own local message queue. Interesting picture... :cool:
Absolutely not obvious. You may allocate a structure/object/memory and pass the pointer to CreateWindow. There in WM_CREATE handler you store it in window properties and use whenever you want that later.Quote:
If so, what if I want to keep some information when one message is processed. Obviously I need to save such information in a global or static data.
What You do is this
In your procedure addCode:CreateWindowEx
(
0,
"class name here",
"window name here",
WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
x,
y,
Width,
Height,
HWND_DESKTOP,
NULL,
Instance_Here,
(void*)this
);
This is code I use, but I removed the error checking and it is incomplete as you can see. This is just an example and not a how to guide.Code:
if( message == WM_NCCREATE )
{
cWindow* Window = (cWindow*)(LPCREATESTRUCT(lParam))->lpCreateParams;
if( Window == 0 ) do error code here;
else
{
if( SetProp( hwnd, "C++_Pointer", (void*)Window ) == 0 ) do error code here;
else
{
// call init setup
Window_Count++;
}
}
return DefWindowProc( hwnd, message, wParam, lParam );
}
if( message == WM_NCDESTROY )
{
if( RemoveProp( hwnd, "C++_Pointer" ) == 0) do error code here;
else
{
Window_Count--;
if( Window_Count == 0 ) PostQuitMessage( 0 );
}
return DefWindowProc( hwnd, message, wParam, lParam );
}
void* Handle = GetProp( hwnd, "C++_Pointer" );
if( Handle == 0 && message != WM_GETMINMAXINFO ) do error code here;
else if( Handle == 0 ) return DefWindowProc( hwnd, message, wParam, lParam );
return Window->Parse( message, wParam, lParam );
hi,
I enter the window procedure again, I will lose them. So that is why I need to keep them in static or global variables. But that would make window procedure non-reentrant. I wonder if there is any requirement that Window procedure must be reentran
thanks
regards,
phe9oxis,
http://www.guidebuddha.com
Then the problem is somewhere in your "get" code. :)Quote:
If I save the time when processing WM_CREATE, then the time I get is always current time.
I think it is a design issue not coding issue. Whenever I open the window, the time saved to a struct is always current time when processing WM_CREATE. Basically I want to get last time when the window was opened. But unfortunately the last time is always overwritten by current time.
You mean, some miracle happens in your program? Or silicon chips made a plot against you? :)Quote:
But unfortunately the last time is always overwritten by current time.
I hardly see the difference. Design issue? Is that your design? Then just fix it.Quote:
I think it is a design issue not coding issue.
Okey, here is my code. Basically I want to show last time when the window is opened. But current time is always shown instead. Would you please point out what mistake I made. Thanks.
Code:LRESULT CALLBACK windowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
TCHAR szName[] = _T("Hello window");
struct time_tag
{
char* time;
};
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
WNDCLASS wndClass;
MSG msg;
wndClass.lpszClassName = szName;
wndClass.lpfnWndProc = windowProc;
wndClass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
wndClass.hCursor = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_CURSOR1));
wndClass.lpszMenuName = NULL;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndClass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wndClass.hInstance = hInstance;
if(!RegisterClass(&wndClass))
{
return 1;
}
time_t t = time(NULL);
char* s = ctime(&t);
time_tag _time;
_time.time = s;
HWND hwnd = CreateWindow(szName, _T("hello"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,CW_USEDEFAULT, NULL, NULL, hInstance, (void*)&_time);
ShowWindow(hwnd, nCmdShow);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT _stdcall windowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
switch(msg)
{
case WM_CREATE:
{
time_tag* pTimeTag;
pTimeTag = (time_tag*)((LPCREATESTRUCT)lParam)->lpCreateParams;
if(pTimeTag)
{
if(!SetProp(hwnd, _T("Last Time"), (void*)pTimeTag))
MessageBox(hwnd, _T("Failed setting time"), NULL, MB_OK);
}
return 0;
}
case WM_PAINT:
{
hdc = BeginPaint(hwnd, &ps);
RECT rect;
GetClientRect(hwnd, &rect);
time_tag* _time = (time_tag*)GetProp(hwnd, _T("Last Time"));
TCHAR* t_s = A2T(_time->time);
if(_time)
TextOut(hdc, (rect.right - rect.left)/2, (rect.bottom - rect.top)/2, t_s, lstrlen(t_s)-1);
EndPaint(hwnd, &ps);
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
It just does what you told it to do: display the time of window creation. Everything else would be some kind of miracle or at least a bug. ;)
If you want it do display the time of the last window creation before this time (and I think that's what you intend to do), you would need some kind of persistant storage for your time tag, as closing the window also shuts down your app.
You are going to have to collect this info and store it. You can't expect a pointer to stay valid after the execution of the function.
What you have is a severely flawed ideal. You should not have to pass the time through the lparam. You should have a static local map that registers a hwnd to a time struct which is generated when a WM_CREATE message is receive and destroyed when WM_NCDESTROY is received
Well, persistant storage is a wide field. And especially when it's about raw Win32, I'm short of "simple examples" for that. Maybe you could use some file or a registry key?
But if it finally is meant to display saved window creation times during a single app session, Joeman's suggestion looks really promising too.
If you do need it longer than the programs life span, you will need to dump this info to a file.
Your questions are very misleading. You aren't getting the right answers because you aren't asking the right questions. You can't effectively use the hwnd to identify your window from the previous run. It can be different in the next run.
The same way window properties are destroyed when you destroy the window. Even if your program is still running and able to create another window instance, it is absolutely different window with its own properties. So you just cannot store something there in props after window death. And your case is definitely a design issue. :)Quote:
Static variable won't work because after the program exits, the static variable will be destroyed.
PS. There was no need in such a complex schema of passing pointer to time_tag in this case. That time_t fits in DWORD and could be just stored in property as it is. Besides, there's no need to snap it before CreateWindow, and it might be inside WM_CREATE handler alright.
Just to give you an ideal how simple this should be
This was generated with code::blocks and I only added a little code. This is just an example on how to accomplish this. It is by no means the best approach.Code:#include <windows.h>
#include <fstream>
#include <ctime>
#include <string>
#include <iostream>
using namespace std;
/* Declare Windows procedure */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
/* Make the class name into a global variable */
char szClassName[ ] = "CodeBlocksWindowsApp";
void StoreTime( const string& Name )
{
ofstream OutFile( (Name + "_Last_Run.txt").c_str(), ios::out);
if( OutFile.is_open() )
{
time_t t = time(NULL);
char* s = ctime(&t);
OutFile << s;
}
else
{
throw( "can't open file to write" );
}
}
string GetLastLoadTime( const string& Name )
{
string Time;
ifstream InFile;
InFile.open( (Name + "_Last_Run.txt").c_str(), ios::in );
if( !InFile.is_open() )
{
InFile.close();
StoreTime( Name );
InFile.open( (Name + "_Last_Run.txt").c_str(), ios::in );
if( !InFile.is_open() ) throw( "can't open file to receive last load time" );
}
getline( InFile, Time );
StoreTime( Name );
return Time;
}
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nCmdShow)
{
HWND hwnd; /* This is the handle for our window */
MSG messages; /* Here messages to the application are saved */
WNDCLASSEX wincl; /* Data structure for the windowclass */
/* The Window structure */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
wincl.style = CS_DBLCLKS; /* Catch double-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);
/* Use default icon and mouse-pointer */
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL; /* No menu */
wincl.cbClsExtra = 0; /* No extra bytes after the window class */
wincl.cbWndExtra = 0; /* structure or the window instance */
/* Use Windows's default colour as the background of the window */
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
/* Register the window class, and if it fails quit the program */
if (!RegisterClassEx (&wincl))
return 0;
/* The class is registered, let's create the program*/
hwnd = CreateWindowEx (
0, /* Extended possibilites for variation */
szClassName, /* Classname */
"Window1", /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
544, /* The programs width */
375, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);
string Time = GetLastLoadTime( "Window1" );
cout << "Last load time was " << Time << endl;
/* Make the window visible on the screen */
ShowWindow (hwnd, nCmdShow);
/* Run the message loop. It will run until GetMessage() returns 0 */
while (GetMessage (&messages, NULL, 0, 0))
{
/* Translate virtual-key messages into character messages */
TranslateMessage(&messages);
/* Send message to WindowProcedure */
DispatchMessage(&messages);
}
/* The program return-value is 0 - The value that PostQuitMessage() gave */
return messages.wParam;
}
/* This function is called by the Windows function DispatchMessage() */
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) /* handle the messages */
{
case WM_DESTROY:
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
break;
default: /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
I have a question here. After I call SetProp and GetProp, why'd I need to call RemoveProp since when the program exits the property will be destroyed anyway. What if I don't call RemoveProp? Thanks.
Because msdn says so. http://msdn.microsoft.com/en-us/libr...8VS.85%29.aspx
Quote:
Remarks
Before a window is destroyed (that is, before it returns from processing the WM_NCDESTROY message), an application must remove all entries it has added to the property list. The application must use the RemoveProp function to remove the entries.
I am guessing it has to do with properly destroying what these properties containQuote:
Originally Posted by LarryChen
Just be a good citizen and always call cleanup operations.
Why? You might as well get in the habit of always cleaning up resources properly. Sure it doesn't necessarily matter in this case, but one day sloppy habits will come back to bite you and you spend hours tracking down some problem related to not properly cleaning up resources.