Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Problematyczny WM_COMMAND (WINAPI Windows.h)

Ostatnio zmodyfikowano 2018-12-02 19:00
Autor Wiadomość
tirurir
Temat założony przez niniejszego użytkownika
Problematyczny WM_COMMAND (WINAPI Windows.h)
» 2018-12-02 17:35:32
Cześć, piszę w związku z problemem z WINAPI którego nie jestem w stanie rozwiązać. Chciałbym dodać obsługę kliknięcia przycisku, a co za tym idzie muszę dodać WM_COMMAND i odpowiedni warunek do kodu jednak wtedy kompilator twierdzi, że istniejący przycisk nie został zadeklarowany (linijka 84, 'g_hButton' was not declared in this scope) choć bez tej linijki kod działa jak należy.
Piszę w C, nie korzystam z C++ choć na tym etapie to bez znaczenia dla tego ćwiczenia. Kompiluję w Devie wspomagając się wygodniejszym Visual Studio. Kod poniżej jest oparty na tym co dev nam sam generuje oraz tym co znalazłem w kursie. Komentarze wybaczcie ale będą po angielsku - staram się trzymać ten nawyk już teraz.
Problematyczny fragment zakomentowałem abyście mogli szybko skompilować kod i zobaczyć, że poza nim nie występują błędy kompilacji.


case WM_COMMAND:
if ((HWND)lParam == g_hButton) //show msgbox if g_hButton is pressed
MessageBox(hwnd, "You pressed it! Hurray!", "It works!", MB_ICONINFORMATION);
===========================

#include <windows.h>

LPSTR WindowClass = "WindowClass";
MSG msg;

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{

// Structure Parameters
WNDCLASSEX wc;

wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = WindowClass;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

//Is Registering Window Accomplished
if (!RegisterClassEx(&wc)) {
MessageBox(NULL, "Window Registration Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
return 0;
}


// Creating Window
HWND hwnd;
HWND g_hButton; //button declaration
HWND g_hCheckbox; //checkbox button declaration
HWND g_hRadioButton; //radiobutton declaration

hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, WindowClass, "Window Exercise", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, /* x */
CW_USEDEFAULT, /* y */
200, /* width */
280, /* height */
NULL, NULL, hInstance, NULL);




g_hButton = CreateWindowEx(0, "BUTTON", "My Button Text", WS_CHILD | WS_VISIBLE,
15, 10, 150, 30, hwnd, NULL, hInstance, NULL);
g_hCheckbox = CreateWindowEx(0, "BUTTON", "Checkbox", WS_CHILD | WS_VISIBLE | BS_CHECKBOX,
15, 40, 150, 30, hwnd, NULL, hInstance, NULL);
g_hRadioButton = CreateWindowEx(0, "BUTTON", "Radio Button", WS_CHILD | WS_VISIBLE | BS_RADIOBUTTON,
15, 70, 150, 30, hwnd, NULL, hInstance, NULL);




if (hwnd == NULL) {
MessageBox(NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
return 0;
}

ShowWindow(hwnd, nCmdShow); // Show window...
UpdateWindow(hwnd);

//Message Loop
while (GetMessage(&msg, NULL, 0, 0)) /* If no error is received... */
{
TranslateMessage(&msg); /* Translate key codes to chars if present */
DispatchMessage(&msg);  /* Send it to WndProc */
}
return msg.wParam;
}

// Event Handling
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
/*WADLIWY FRAGMENT
//WADLIWY FRAGMENT
//WADLIWY FRAGMENT
case WM_COMMAND:
if ((HWND)lParam == g_hButton) //show msgbox if g_hButton is pressed
MessageBox(hwnd, "You pressed it! Hurray!", "It works!", MB_ICONINFORMATION);

break;
//WADLIWY FRAGMENT
//WADLIWY FRAGMENT
*/WADLIWY FRAGMENT
case WM_CLOSE:
DestroyWindow(hwnd);
break;

case WM_DESTROY:
PostQuitMessage(0);
break;




default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}

return 0;
}
EDIT:
Teoretycznie wystarczy, że wyciągnę declaracje okienka i przycisków na górę kodu poza int WinMain i jest to logiczne ale nie wiem czy powinno tak być, czy lepiej deklarować to w mniej 'globalny sposób'. Chyba potrzebuję wyjaśnienia gdzie dokładnie należy to deklarować, a gdzie lepiej nie.
Sprawny kod:

#include <windows.h>

LPSTR WindowClass = "WindowClass";
MSG msg;

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
// Creating Window
HWND hwnd;
HWND g_hButton; //button declaration
HWND g_hCheckbox; //checkbox button declaration
HWND g_hRadioButton; //radiobutton declaration
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{

// Structure Parameters
WNDCLASSEX wc;

wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = WindowClass;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

//Is Registering Window Accomplished
if (!RegisterClassEx(&wc)) {
MessageBox(NULL, "Window Registration Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
return 0;
}




hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, WindowClass, "Window Exercise", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, /* x */
CW_USEDEFAULT, /* y */
200, /* width */
280, /* height */
NULL, NULL, hInstance, NULL);




g_hButton = CreateWindowEx(0, "BUTTON", "My Button Text", WS_CHILD | WS_VISIBLE,
15, 10, 150, 30, hwnd, NULL, hInstance, NULL);
g_hCheckbox = CreateWindowEx(0, "BUTTON", "Checkbox", WS_CHILD | WS_VISIBLE | BS_CHECKBOX,
15, 40, 150, 30, hwnd, NULL, hInstance, NULL);
g_hRadioButton = CreateWindowEx(0, "BUTTON", "Radio Button", WS_CHILD | WS_VISIBLE | BS_RADIOBUTTON,
15, 70, 150, 30, hwnd, NULL, hInstance, NULL);




if (hwnd == NULL) {
MessageBox(NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
return 0;
}

ShowWindow(hwnd, nCmdShow); // Show window...
UpdateWindow(hwnd);

//Message Loop
while (GetMessage(&msg, NULL, 0, 0)) /* If no error is received... */
{
TranslateMessage(&msg); /* Translate key codes to chars if present */
DispatchMessage(&msg);  /* Send it to WndProc */
}
return msg.wParam;
}

// Event Handling
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{

case WM_COMMAND:
if ((HWND)lParam == g_hButton) //show msgbox if g_hButton is pressed
MessageBox(hwnd, "You pressed it! Hurray!", "It works!", MB_ICONINFORMATION);

break;

case WM_CLOSE:
DestroyWindow(hwnd);
break;

case WM_DESTROY:
PostQuitMessage(0);
break;




default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}

return 0;
}
Nie usuwam wątku mimo samodzielnego niekoniecznie rozwiązania problemu ale sprawienia, że kod działa. Może dowiem się jeszcze czegoś bądź ktoś napotka podobny problem i go znajdzie.
P-173072
pekfos
» 2018-12-02 18:44:10
Zmienne globalne to najprostsze możliwe rozwiązanie problemu. Jeśli z jakiegoś powodu nie chcesz zmiennych globalnych, innym sposobem byłoby użycie SetWindowLongPtr(), lub identyfikowanie kontrolki w inny sposób, niż przez porównywanie uchwytów.
» Kurs WinAPI, C++ » PodstawyKontrolki lekcja, "Identyfikowanie kontrolek w komunikatach".

choć bez tej linijki kod działa jak należy.
Bez tego warunku, przycisk nie będzie jedyną rzeczą, która wywoła ten komunikat.
P-173073
tirurir
Temat założony przez niniejszego użytkownika
» 2018-12-02 19:00:26
Dzięki za rozjaśnienie. Właśnie trochę się tych globalnych obawiałem, staram się ich unikać jeśli nie są niezbędne i nie zaśmiecać nimi pamięci.
Poczytam o funkcji którą podesłałeś jak poczuję się bardziej obeznany z tym co do tej pory przerobiłem.
P-173074
« 1 »
  Strona 1 z 1