I'm building a Sudoku Win32 Application in C. I have some issues with GetWindowText(), I guess, that works correctly for an undefined number of times but then the application freezes, without hanging (the state of the process is normal, no "app.exe stopped working"), no more values can be inserted in Edit Boxes, Menus are unclickable, only the minimize and close buttons respond. I've already inserted some MessageBoxes but it all seems to work fine until the issue comes unexpectedly. I've already tried to debug with multiple debuggers, the CLion (the IDE I'm using), the Codeblocks one, and even the Windows integrated one (Visual Studio) but nothing relevant came up. I'm freaking out. Please help me, and ask me for more details if necessary, but I think that's all. Thanks!
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>
#include <windows.h>
#include <winuser.h>
#include <windowsx.h>
#include <scrnsave.h>
#define N 9
#define SRN 3
#define K 64 //Celle nascoste all'inizio
#define ID_STUFF_GO 9000
#define ID_MODE_NOHINT 4200
#define ID_MODE_HINT 4201
typedef struct{
int correctVal;
int insertedVal;
bool visible;
}cell;
cell puzzle[N][N];
HWND grid[N][N];
bool hint=true;
bool ready=false;
int count=0;
int CDECL MessageBoxPrintf(unsigned int , const char *, const char *, ...);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void sudokuInit(void);
void diagonalInit(void);
void boxInit(int, int);
bool fillMissing(int, int);
bool notInBox(int, int, int);
bool notInRow(int, int);
bool notInColumn(int, int);
bool isLegalValue(int, int, int);
void setVisibleValues(void);
void createFile(void);
bool checkValue(int, int);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){
static char appName[]= TEXT("Sudoku");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
//------------------- Definizione finestra -------------------//
wndclass.style = CS_HREDRAW | CS_VREDRAW; //Definizione stili della finestra, in questo caso il contenuto viene centrato sia verticalmente che orizontalmente all'interno della finestra
wndclass.lpfnWndProc = WndProc; //Collega la procedura che gestira i messaggi provenienti dalla finestra
wndclass.cbClsExtra = 0; //Spazio extra per specifici scopi del programma
wndclass.cbWndExtra = 0; //Spazio extra per specifici scopi del programma
wndclass.hInstance = hInstance; //Imposta l'istanza che gestisce la finestra
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION); //Carica l'icona del programma
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); //Carica il cursore del mouse da usare nel programma
wndclass.hbrBackground = CreateSolidBrush(RGB(63,81,181)); //Recupera un oggetto grafico, in questo caso un pennelo che colora lo sfondo
wndclass.lpszMenuName = appName; //Configura il menu della finestra
wndclass.lpszClassName = appName; //Definisce il nome della classe della finestra
//------------------------------------------------------------//
if(!RegisterClass (&wndclass)){
MessageBoxPrintf(MB_OK|MB_ICONERROR,appName,"Questo programma richiede Windows NT!");
return 0;
}
//------------------ Creazione finestra ----------------------//
hwnd = CreateWindow (appName, //nome della classe della finestra
TEXT("Sudoku Game"), //Titolo della finestra
WS_OVERLAPPED|WS_MINIMIZEBOX|WS_SYSMENU, //Stile della finestra
CW_USEDEFAULT, //Posizione orizontale iniziale
CW_USEDEFAULT, //Posizione verticale iniziale
525, //Larghezza iniziale
565, //ALtezza iniziale
NULL, //Gestore della finestra madre
NULL, //Gestore del menu della finestra
hInstance, //Gestore dell'istanza del programma
NULL); //Parametri di creazione
//------------------------------------------------------------//
ShowWindow(hwnd, nCmdShow); //Mostra la finestra sullo schermo
sudokuInit();
UpdateWindow(hwnd); //Ordina alla finestra di riempire(dipingere) se stessa
while(GetMessage(&msg, NULL, 0, 0)){ //Recupera i messaggi dalla coda dei messaggi
/*if(count==K){
MessageBoxPrintf(MB_ICONINFORMATION,appName,"Gioco terminato!");
SendMessage(hwnd, WM_DESTROY, MAKEWPARAM(FALSE, 0), MAKELPARAM(FALSE,0));
}*/
TranslateMessage(&msg); //Traduce gli eventi di input (tastiera/mouse) in messaggi
DispatchMessage(&msg); //Invia i messaggi alla procedura della finestra
}
return msg.wParam;
}
int CDECL MessageBoxPrintf(unsigned int type, const char *title, const char *content, ...){
char buffer[1024];
va_list pArgList;
va_start(pArgList, content);
_vsnprintf(buffer, sizeof(buffer)/ sizeof(char), content, pArgList);
va_end(pArgList);
return MessageBox(NULL, buffer, title, type);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
HFONT hfont = CreateFont(50,0,0,0,FW_SEMIBOLD,0,0,0,0,0,0,0,0,"Century Gothic");
HMENU hSubMenu, hMenu;
int i, j, k=10, m=10, n, id;
char out[2];
switch(message){
case WM_CREATE:
hMenu = CreateMenu();
hSubMenu = CreatePopupMenu();
AppendMenu(hSubMenu, MF_STRING, ID_MODE_NOHINT, "Senza suggerimenti");
AppendMenu(hSubMenu, MF_STRING, ID_MODE_HINT, "Con suggerimenti");
AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "Modalita'");
ModifyMenu(hMenu, ID_MODE_HINT, MF_BYCOMMAND | MF_CHECKED, ID_MODE_HINT, "Con suggerimenti");
hSubMenu = CreatePopupMenu();
AppendMenu(hSubMenu, MF_STRING, ID_STUFF_GO, "Nope");
AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "Difficolta'");
SetMenu(hwnd, hMenu);
for (i=0; i<N ; i++){
for (j=0; j<N; j++) {
id=i*10+j+1;
grid[i][j]= CreateWindow("EDIT",
"",
ES_CENTER | ES_NUMBER | WS_BORDER | WS_CHILD | WS_VISIBLE,
k, m, 50, 50,
hwnd, (HMENU)id, NULL, NULL);
SendMessage(grid[i][j], WM_SETFONT, (WPARAM)hfont, MAKELPARAM(FALSE, 0));
if((j+1)%3==0)
k+=60;
else
k+=55;
}
k=10;
if((i+1)%3==0)
m+=60;
else
m+=55;
}
return 0;
case WM_CTLCOLOREDIT:
hdc = (HDC) wParam;
return SetTextColor(hdc, RGB(63,81,181));
case WM_COMMAND:
switch(LOWORD(wParam)){
case ID_MODE_HINT:
hint=true;
ModifyMenu(hMenu, ID_MODE_HINT, MF_BYCOMMAND | MF_CHECKED, ID_MODE_HINT, "Con suggerimenti");
ModifyMenu(hMenu, ID_MODE_NOHINT, MF_BYCOMMAND | MF_UNCHECKED, ID_MODE_NOHINT, "Senza suggerimenti");
break;
case ID_MODE_NOHINT:
hint=false;
ModifyMenu(hMenu, ID_MODE_HINT, MF_BYCOMMAND | MF_UNCHECKED, ID_MODE_HINT, "Con suggerimenti");
ModifyMenu(hMenu, ID_MODE_NOHINT, MF_BYCOMMAND | MF_CHECKED, ID_MODE_NOHINT, "Senza suggerimenti");
break;
case ID_STUFF_GO:
MessageBoxPrintf(MB_ICONINFORMATION,"Test", "NOPE!");
break;
}
switch(HIWORD(wParam)){
case EN_CHANGE:
if(ready){
MessageBoxPrintf(MB_ICONEXCLAMATION,"Test", "Acquiring");
GetWindowText((HWND)lParam, out, 2);
UINT err= GetLastError();
n=atoi(out);
id=(int)GetMenu((HWND)lParam);
MessageBoxPrintf(MB_ICONEXCLAMATION,"Test", "Ready");
if(checkValue(n,id)){
if(hint)
MessageBoxPrintf(MB_ICONINFORMATION,"Test", "Giusto");
//SetTextColor(hdc, RGB(76,175,80));
count++;
}else
if(hint)
MessageBoxPrintf(MB_ICONSTOP,"Test", "Sbagliato");
//SetTextColor(hdc,RGB(244,67,54));
}
break;
}
return 0;
case WM_PAINT:
BeginPaint(hwnd, &ps); //Inizia a riempire(dipingere) la finestra
GetClientRect(hwnd, &rect); //Ottiene le dimensioni sullo schermo della finestra
for (i=0; i<N; i++){
for (j=0; j<N; j++){
if(puzzle[i][j].visible){
itoa(puzzle[i][j].correctVal, out,10);
Edit_SetText(grid[i][j], out);
SendMessage(grid[i][j],EM_SETREADONLY,(WPARAM)TRUE, MAKELPARAM(FALSE, 0));
}
SetTextColor(GetDC(hwnd), RGB(63,81,181));
}
}
ready=true;
EndPaint(hwnd, &ps); //Finisce di riempire(dipingere) la finestra
return 0;
case WM_DESTROY:
PostQuitMessage(0); //Inserisce un messaggio di uscita alla coda dei messaggi
return 0;
default:
return DefWindowProc (hwnd, message, wParam, lParam); //Esegue il processo predefinito per i messaggi
}
}
void sudokuInit(void){
srand(time(NULL));
diagonalInit();
fillMissing(0, SRN);
setVisibleValues();
createFile();
}
void diagonalInit(void){
int i;
for (i=0; i<N; i+=SRN)
boxInit(i, i);
}
void boxInit(int r, int c){
int i, j, num;
for (i=0; i<SRN; i++) {
for (j=0; j<SRN; j++) {
do{
num=rand()%N+1;
}while(!notInBox(r, c, num));
puzzle[r+i][c+j].correctVal=num;
puzzle[r+i][c+j].visible=true;
}
}
}
bool fillMissing(int i, int j){
int num;
if (j>=N && i<N-1){
i++;
j=0;
}
if (i>=N && j>=N)
return true;
if (i<SRN){
if (j<SRN)
j=SRN;
}
else if (i<N-SRN){
if (j==(i/SRN)*SRN)
j+=SRN;
}
else{
if (j==N-SRN){
i++;
j=0;
if (i>=N)
return true;
}
}
for (num=1; num<=N; num++){
if (isLegalValue(i, j, num)){
puzzle[i][j].correctVal=num;
puzzle[i][j].visible=true;
if (fillMissing(i, j+1))
return true;
puzzle[i][j].correctVal=0;
puzzle[i][j].visible=true;
}
}
return false;
}
bool isLegalValue(int i, int j, int num){
return notInRow(i, num) && notInColumn(j, num) && notInBox(i-i%SRN, j-j%SRN, num);
}
bool notInRow(int i, int num){
int j;
for (j=0; j<N; j++)
if (puzzle[i][j].correctVal==num)
return false;
return true;
}
bool notInColumn(int j, int num){
int i;
for (i=0; i<N; i++)
if (puzzle[i][j].correctVal==num)
return false;
return true;
}
bool notInBox(int rS, int cS, int num){
int i, j;
for (i=0; i<SRN; i++)
for (j=0; j<SRN; j++)
if (puzzle[rS+i][cS+j].correctVal==num)
return false;
return true;
}
void setVisibleValues(void){
int i, j, cellId, count=K;
while(count!=0){
cellId=rand()%(N*N)+1;
i=cellId/N;
j=cellId%N;
j=j-1;
if(puzzle[i][j].visible){
count--;
puzzle[i][j].visible=false;
}
}
}
void createFile(void){
FILE *file;
char fileName[MAX_PATH], prefix[]="sudoku";
time_t id = time(NULL);
int i, j;
sprintf(fileName, "%s-%ld.txt", prefix, id);
file=fopen(fileName,"w");
for (i=0; i<N; i++)
for (j=0; j<N; j++){
if(i!=0 || j!=0)
fprintf(file,",");
fprintf(file,"%d", puzzle[i][j].correctVal);
}
fclose(file);
}
bool checkValue(int n, int cell){
MessageBoxPrintf(MB_APPLMODAL,"Checking value", "Hey there!");
int i=0, j=0, op=0;
op=(int)cell/10;
switch(op){
case 0:
i=0;
break;
case 1:
i=1;
break;
case 2:
i=2;
break;
case 3:
i=3;
break;
case 4:
i=4;
break;
case 5:
i=5;
break;
case 6:
i=6;
break;
case 7:
i=7;
break;
case 8:
i=8;
break;
default:
MessageBoxPrintf(MB_ICONERROR, "Errore", "Impossibile determinare la riga");
break;
}
op=(int)(cell-1)%10;
switch(op){
case 0:
j=0;
break;
case 1:
j=1;
break;
case 2:
j=2;
break;
case 3:
j=3;
break;
case 4:
j=4;
break;
case 5:
j=5;
break;
case 6:
j=6;
break;
case 7:
j=7;
break;
case 8:
j=8;
break;
default:
MessageBoxPrintf(MB_ICONERROR, "Errore", "Impossibile determinare la colonna");
break;
}
puzzle[i][j].insertedVal=n;
MessageBoxPrintf(MB_APPLMODAL,"Checking value", "Detected!");
if(puzzle[i][j].insertedVal == puzzle[i][j].correctVal)
return true;
else
return false;
}
This is what it looks like when started:
Your program eats all available resources. This line gets new DC
but never releases it to the system.
SetTextColor(GetDC(hwnd), RGB(63,81,181));
You should delete this line. Setting color and immediately forgetting HDC does not make any sense.
I would also think about moving code witch reads or modifies edit controls form WM_PAINT
to better place. WM_PAINT
should only paint main window contents. In your case (background is painted ny class brush) it could be left out altogether.