OK, I close the window but the process doesn't go away - it stays there and has to be manually shut down. I am calling DestroyWindow, too.
OK, I close the window but the process doesn't go away - it stays there and has to be manually shut down. I am calling DestroyWindow, too.
Last edited by samGwilliam; 04-12-2005 at 05:42 AM.
Current Setup: Win 10 with Code::Blocks 17.12 (GNU GCC)
Also, what's the WM_ event for when the window gets the focus. I got it so it redraws when you move or resize but if it goes behind another window then goes back in front it won't redraw.
Current Setup: Win 10 with Code::Blocks 17.12 (GNU GCC)
OK now I got another problem: at first, just to test things out I had a message box come up on WM_CREATE. After I got my game of life working I decided to take this message box out. All of a sudden I just get a window full of black. Commenting out a MessageBox statement has altered the entire logic of the program or something.
I swear Windows programming is the most ridiculous, frustrating, arcane and downright stupid thing I have ever come across. I mean you couldn't make it up. What a pile of crap.
Current Setup: Win 10 with Code::Blocks 17.12 (GNU GCC)
WM_ACTIVATE is the message you need to have a look at for window activation, and WM_PAINT is the message you need to handle for redrawing.
To make sure that your process exits when you destroy the window, make sure you call PostQuitMessage(). Providing you have the correct checking in your message pump, your thread should end.
Cheers.
Hrm, sounds quite strange to me. Perhaps you could upload your code for us to check out ?
cheers.
Here's the entire code (with message commented out):
Code:#include <windows.h> #define MAX 300 LRESULT CALLBACK MainWindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASS myWin; MSG msg; myWin.style = CS_VREDRAW | CS_HREDRAW; myWin.lpfnWndProc = MainWindowProc; myWin.cbClsExtra = 0; myWin.cbWndExtra = 0; myWin.hInstance = hInstance; myWin.hIcon = LoadIcon (NULL, IDI_APPLICATION); myWin.hCursor = LoadCursor (NULL, IDC_ARROW); myWin.hbrBackground = (HBRUSH) (COLOR_SCROLLBAR + 1); myWin.lpszMenuName = 0; myWin.lpszClassName = "My First App."; if (!RegisterClass (&myWin)) return 0; HWND hwnd; hwnd = CreateWindow ( "My First App.", "SamLife, v1.0", WS_OVERLAPPEDWINDOW, 20, 20, MAX + 40, MAX + 60, NULL, NULL, hInstance, NULL); if (!hwnd) return 0; SetTimer(hwnd, 1, 1, NULL); ShowWindow (hwnd, nCmdShow); while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg); DispatchMessage (&msg); } } HDC hdc; LRESULT CALLBACK MainWindowProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { static int currentGrid = 0; char s [60]; int sum = 0; int i, j; int temp_i, temp_j; static unsigned char grid [2] [MAX] [MAX]; switch (msg) { case WM_CREATE: //MessageBox (hwnd, "hello", "hi", NULL); for (i = 0; i < MAX; i++) for (j = 0; j < MAX; j++) { grid [0] [i] [j] = 0; grid [1] [i] [i] = 0; } grid [0] [110] [110] = 1; // Init R-pentomino; grid [0] [110] [111] = 1; grid [0] [111] [109] = 1; grid [0] [111] [110] = 1; grid [0] [112] [110] = 1; break; case WM_MOVE: case WM_SIZE: hdc = GetDC (hwnd); if (!hdc) break; for (i = 0; i < MAX; i++) for (j = 0; j < MAX; j++) { if (grid [currentGrid] [i] [j]) SetPixel (hdc, j + 20, i + 20, RGB (255, 0, 0)); else SetPixel (hdc, j + 20, i + 20, RGB (0, 0, 0)); } ReleaseDC(hwnd, hdc); hdc = NULL; break; case WM_CLOSE: case WM_DESTROY: DestroyWindow (hwnd); break; } hdc = GetDC (hwnd); if(hdc) { // Compute: for (i = 0; i < MAX; i++) for (j = 0; j < MAX; j++) { // Check top left: temp_i = i - 1; temp_j = j - 1; if (temp_i < 0) temp_i += MAX; if (temp_j < 0) temp_j += MAX; sum += grid [currentGrid] [temp_i] [temp_j]; // Check top mid: ++temp_j %= MAX; sum += grid [currentGrid] [temp_i] [temp_j]; // Check top right: ++temp_j %= MAX; sum += grid [currentGrid] [temp_i] [temp_j]; // Check mid right: ++temp_i %= MAX; sum += grid [currentGrid] [temp_i] [temp_j]; // Check mid left: temp_j -= 2; if (temp_j < 0) temp_j += MAX; sum += grid [currentGrid] [temp_i] [temp_j]; // Check bottom left: ++temp_i %= MAX; sum += grid [currentGrid] [temp_i] [temp_j]; // Check bottom mid: ++temp_j %= MAX; sum += grid [currentGrid] [temp_i] [temp_j]; // Check bottom right: ++temp_j %= MAX; sum += grid [currentGrid] [temp_i] [temp_j]; grid [1 - currentGrid] [i] [j] = grid [currentGrid] [i] [j]; switch (grid [currentGrid] [i] [j]) { // If this square alive: case 1: if ((sum < 2) || (sum > 3)) { grid [1 - currentGrid] [i] [j] = 0; SetPixel (hdc, j + 20, i + 20, RGB (0, 0, 0)); } break; // If this square is dead: case 0: if (sum == 3) { grid [1 - currentGrid] [i] [j] = 1; SetPixel (hdc, j + 20, i + 20, RGB (255, 0, 0)); } break; } sum = 0; } currentGrid ^= 1; ReleaseDC(hwnd, hdc); hdc = NULL; } return DefWindowProc (hwnd, msg, wParam, lParam); }
Current Setup: Win 10 with Code::Blocks 17.12 (GNU GCC)
Hello,
I've made a few changes here and there, please search for my name in the code below.
Things to note:
1) You were "painting" every time a window message was being received, instead of doing through some other controlled fashion (such as through timers, as my example shows).
2) I think the message box just forced some kind of repaint which is what forced the chain of messages that you were getting in order to update the screen. The example given should be a bit more friendly
Hope that helps!
Code:#include <windows.h> #define MAX 300 LRESULT CALLBACK MainWindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASS myWin; MSG msg; myWin.style = CS_VREDRAW | CS_HREDRAW; myWin.lpfnWndProc = MainWindowProc; myWin.cbClsExtra = 0; myWin.cbWndExtra = 0; myWin.hInstance = hInstance; myWin.hIcon = LoadIcon (NULL, IDI_APPLICATION); myWin.hCursor = LoadCursor (NULL, IDC_ARROW); myWin.hbrBackground = (HBRUSH) (COLOR_SCROLLBAR + 1); myWin.lpszMenuName = 0; myWin.lpszClassName = "My First App."; if (!RegisterClass (&myWin)) return 0; HWND hwnd; hwnd = CreateWindow ( "My First App.", "SamLife, v1.0", WS_OVERLAPPEDWINDOW, 20, 20, MAX + 40, MAX + 60, NULL, NULL, hInstance, NULL); if (!hwnd) return 0; SetTimer(hwnd, 1, 1, NULL); ShowWindow (hwnd, nCmdShow); while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg); DispatchMessage (&msg); } // TheColonial: You need to return a value! return 0; } HDC hdc; LRESULT CALLBACK MainWindowProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { // TheColonial: use a timer, so give it an id. static int timerId = 3000; static int currentGrid = 0; // TheColonial: this variable isn't used. // char s [60]; int sum = 0; int i, j; int temp_i, temp_j; static unsigned char grid [2] [MAX] [MAX]; switch (msg) { case WM_CREATE: //MessageBox (hwnd, "hello", "hi", NULL); for (i = 0; i < MAX; i++) for (j = 0; j < MAX; j++) { grid [0] [i] [j] = 0; grid [1] [i] [i] = 0; } grid [0] [110] [110] = 1; // Init R-pentomino; grid [0] [110] [111] = 1; grid [0] [111] [109] = 1; grid [0] [111] [110] = 1; grid [0] [112] [110] = 1; // TheColonial: create a timer for the updates. fire every half second SetTimer(hwnd, timerId, 500, NULL); break; case WM_MOVE: case WM_SIZE: hdc = GetDC (hwnd); if (!hdc) break; for (i = 0; i < MAX; i++) for (j = 0; j < MAX; j++) { if (grid [currentGrid] [i] [j]) SetPixel (hdc, j + 20, i + 20, RGB (255, 0, 0)); else SetPixel (hdc, j + 20, i + 20, RGB (0, 0, 0)); } ReleaseDC(hwnd, hdc); hdc = NULL; break; // TheColonial: Check out the following changes case WM_CLOSE: // Destroy on WM_CLOSE, NOT on WM_DESTROY DestroyWindow (hwnd); break; case WM_DESTROY: // TheColonial: finish the timer KillTimer(hwnd, timerId); // quit when destroyed PostQuitMessage(0); break; case WM_TIMER: { // handle the painting through the timer. hdc = GetDC (hwnd); if(hdc) { // Compute: for (i = 0; i < MAX; i++) for (j = 0; j < MAX; j++) { // Check top left: temp_i = i - 1; temp_j = j - 1; if (temp_i < 0) temp_i += MAX; if (temp_j < 0) temp_j += MAX; sum += grid [currentGrid] [temp_i] [temp_j]; // Check top mid: ++temp_j %= MAX; sum += grid [currentGrid] [temp_i] [temp_j]; // Check top right: ++temp_j %= MAX; sum += grid [currentGrid] [temp_i] [temp_j]; // Check mid right: ++temp_i %= MAX; sum += grid [currentGrid] [temp_i] [temp_j]; // Check mid left: temp_j -= 2; if (temp_j < 0) temp_j += MAX; sum += grid [currentGrid] [temp_i] [temp_j]; // Check bottom left: ++temp_i %= MAX; sum += grid [currentGrid] [temp_i] [temp_j]; // Check bottom mid: ++temp_j %= MAX; sum += grid [currentGrid] [temp_i] [temp_j]; // Check bottom right: ++temp_j %= MAX; sum += grid [currentGrid] [temp_i] [temp_j]; grid [1 - currentGrid] [i] [j] = grid [currentGrid] [i] [j]; switch (grid [currentGrid] [i] [j]) { // If this square alive: case 1: if ((sum < 2) || (sum > 3)) { grid [1 - currentGrid] [i] [j] = 0; SetPixel (hdc, j + 20, i + 20, RGB (0, 0, 0)); } break; // If this square is dead: case 0: if (sum == 3) { grid [1 - currentGrid] [i] [j] = 1; SetPixel (hdc, j + 20, i + 20, RGB (255, 0, 0)); } break; } sum = 0; } currentGrid ^= 1; ReleaseDC(hwnd, hdc); hdc = NULL; } break; } } return DefWindowProc (hwnd, msg, wParam, lParam); }
That's great! Thanks! I apologise for my abrasiveness. I have a very bad temper with computers (I broke a cup while trying to sort this problem out ).
Last edited by samGwilliam; 04-12-2005 at 07:10 AM.
Current Setup: Win 10 with Code::Blocks 17.12 (GNU GCC)
No need for apologise.. we've all been there, and there's no doubt we'll all go there again
You should paint when you receive a WM_PAINT message. A WM_PAINT will be posted when Windows needs the window repainted. For example, when it is exposed from behind another window. You can paint while handling another message but the typical procedure is to call InvalidateRect (and optionally UpdateWindow) to trigger a WM_PAINT and keep the painting code inside the WM_PAINT handler.
Here is what a WM_PAINT handler looks like:
>> Commenting out a MessageBox statement has altered the entire logic of the program or something. <<Code:case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); /* Do your drawing here using hdc. */ EndPaint(hwnd, &ps); return 0; }
Yes calling MessageBox will interact and alter how a window works.
- MessageBox has its own inbuilt message pump.
- When the message box is shown, your window will lose focus,
- When the message box is dismissed, your window will regain focus and if your window was behind the message box it will be posted a WM_PAINT message to repaint the affected area.
- Because MessageBox runs its own message loop, it is re-entrant. For example, if you call MessageBox in your WM_PAINT handler, you may get dozens of message boxes on the screen.