Я изучаю C++
и у меня есть некоторые вопросы. Некоторые исследования в msdn мне не помогли. Я хочу создать два окна в одном приложении. Одно окно - диалог с опциями и другой для графического вывода. Вот код, который я использую. Но у меня есть некоторые проблемы:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR lpCmdLine, int nCmdShow)
{
InitCommonControls();
if(FAILED(DialogWindow_OnCreate(hInstance)))
return 1;
if(FAILED(GraphicWindow_OnCreate(hInstance)))
return 1;
MSG msg;
memset(&msg, 0, sizeof(MSG));
while(msg.message != WM_QUIT)
{
while(PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
OnUpdate();
}
GraphicWindow_OnClose();
return 0;
}
Создание главного окна (Dialog):
HRESULT DialogWindow_OnCreate(HINSTANCE hInst)
{
g_hDialogWindow = CreateDialog(hInst, MAKEINTRESOURCE(IDD_MAIN), NULL, DialogWindow_WndProc);
if(!g_hDialogWindow)
return E_NOTIMPL;
UpdateWindow(g_hDialogWindow);
return S_OK;
}
Главное окно proc (Диалог):
INT_PTR CALLBACK DialogWindow_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
{
g_hDialogWindow = hWnd;
// Some init actions ...
return (INT_PTR)TRUE;
}
case WM_COMMAND:
int wmId, wmEvent;
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch(wmEvent)
{
case NULL: // Menu used
{
switch(wmId)
{
case IDC_BTN_1:
{
DialogWindow_OnBtn1();
MessageBoxA(NULL, "Some message", "Some title", MB_OK);
return (INT_PTR)TRUE;
} break;
case IDC_BTN_2:
{
DialogWindow_OnBtn2();
return (INT_PTR)TRUE;
} break;
// ...
case IDCANCEL:
{
// Close window
DefWindowProc(hWnd, WM_CLOSE, wParam, lParam);
} break;
case IDOK:
{
// Close window
DefWindowProc(hWnd, WM_CLOSE, wParam, lParam);
} break;
}
}
}
case WM_CLOSE:
DefWindowProc(hWnd, message, wParam, lParam);
return (INT_PTR)TRUE;
break;
case WM_DESTROY:
PostQuitMessage(0);
return (INT_PTR)TRUE;
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return (INT_PTR)FALSE;
}
Создание второго окна (графика):
HRESULT GraphicWindow_OnCreate(HINSTANCE hInst)
{
HWND g_hGraphicWindow = NULL;
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = GraphicWindow_WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInst;
wcex.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_APP_ICO));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = 0;
wcex.lpszClassName = _T("MyApp");
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
if(!RegisterClassEx(&wcex))
{
DWORD dwError = GetLastError();
if(dwError != ERROR_CLASS_ALREADY_EXISTS)
{
MessageBoxA(NULL, "GraphicWindow: RegisterClass() failed!", "Error", MB_OK | MB_ICONERROR);
return HRESULT_FROM_WIN32(dwError);
}
}
// Set window initial size, but it might be changed later
int nDefaultWidth = 320;
int nDefaultHeight = 240;
RECT rc;
SetRect(&rc, 0, 0, nDefaultWidth, nDefaultHeight);
AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, false);
// Create the window
g_hGraphicWindow = CreateWindowA("MyApp", "GraphicWindow", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, (rc.right - rc.left), (rc.bottom - rc.top), 0,
0, hInst, 0);
if(!g_hGraphicWindow)
{
DWORD dwError = GetLastError();
MessageBoxA(NULL, "GraphicWindow: CreateWindow() failed!", "Error", MB_OK | MB_ICONERROR);
return HRESULT_FROM_WIN32(dwError);
}
UpdateWindow(g_hGraphicWindow);
return S_OK;
}
Графическое окно proc:
LRESULT CALLBACK GraphicWindow_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_KEYDOWN:
{
switch(wParam)
{
case VK_RETURN:
// Some actions ...
break;
case VK_ESCAPE:
// Some actions ...
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_CLOSE:
ShowWindow(hWnd, SW_HIDE);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Где моя проблема? Помоги мне, пожалуйста.
У меня есть следующие комментарии:
A
Вам нужно будет префикс строковых литералов с L
чтобы указать широкие строки. Например, L"foo"
.hWndParent
когда вы вызываете CreateDialog
. В противном случае модельный dailog будет неактивен, поэтому у него есть собственная кнопка на панели задач и не всегда будет отображаться поверх главного окна.hWnd
при вызове MessageBox
. Более подробно в цикле сообщений вы не следуете правилам, изложенным в документации для CreateDialog
, в котором говорится:
Для поддержки навигации на клавиатуре и других функций диалогового окна цикл сообщения для диалогового окна должен вызвать функцию IsDialogMessage.
Таким образом, ваш цикл сообщений должен быть:
while(GetMessage(&msg, NULL, 0, 0))
{
if(!IsDialogMessage(g_hDialogWindow, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Также обратите внимание, что я переключился на цикл GetMessage
. Я не думаю, что вам нужно запустить горячий цикл для ваших нужд. Использование GetMessage
позволяет основному потоку вашего приложения получать процессор и блокировать, если он неактивен.
В вашей процедуре диалога не используйте DefWindowProc
.