Win32 (C) приложение зависает после некоторого GetWindowText? - PullRequest
0 голосов
/ 09 сентября 2018

Я создаю приложение Sudoku Win32 на C. У меня есть некоторые проблемы с GetWindowText (), я думаю, что он работает правильно неопределенное количество раз, но затем приложение зависает, не зависая (состояние процесса нормальный, нет «app.exe перестал работать»), больше нельзя вставлять значения в поля ввода, меню не щелкаются, реагируют только кнопки сворачивания и закрытия. Я уже вставил несколько MessageBoxes, но, кажется, все работает нормально, пока проблема не возникнет неожиданно. Я уже пытался отлаживать с помощью нескольких отладчиков, CLion (IDE, который я использую), Codeblocks и даже интегрированного с Windows (Visual Studio), но ничего не вышло. Я волнуюсь. Пожалуйста, помогите мне и попросите более подробную информацию, если это необходимо, но я думаю, что это все. Спасибо!

#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;

}

Вот как это выглядит при запуске:

1 Ответ

0 голосов
/ 09 сентября 2018

Ваша программа съедает все доступные ресурсы. Эта строка получает новый DC, но никогда не выпускает ее в систему.

SetTextColor(GetDC(hwnd), RGB(63,81,181));

Вы должны удалить эту строку. Установка цвета и немедленное забывание HDC не имеет никакого смысла.

Я бы также подумал о перемещении кода, который читает или изменяет форму редактирования элементов управления WM_PAINT, в лучшее место. WM_PAINT следует рисовать только содержимое основного окна. В вашем случае (фон нарисован кистью ny класса) он может быть полностью исключен.

...