Диалог, созданный после первого, перестает отвечать, если не создан первым? - PullRequest
1 голос
/ 29 апреля 2010

После создания начального диалогового окна, которое работает отлично, я создаю другое диалоговое окно, когда нажата кнопка «Присоединиться к игре». Диалоговое окно создано и отображается успешно, однако я не могу набрать в поле для редактирования или даже нажать или выйти из диалогового окна. Кто-нибудь понимает, как это исправить или почему это происходит? Я удостоверился, что само диалоговое окно не было проблемой, создав и отобразив его из основного цикла в приложении. Он работал нормально, когда я создал его таким образом. Так почему же это ошибка при создании из другого диалога? Мой код ниже.

Этот код предназначен для функции DLGPROC, которую использует каждый диалог.

#define WIN32_LEAN_AND_MEAN
#include "Windows.h"
#include ".\Controllers\Menu\MenuSystem.h"
#include ".\Controllers\Game Controller\GameManager.h"
#include ".\Controllers\Network\Network.h"
#include "resource.h"
#include "main.h"
using namespace std;
extern GameManager g;
extern bool men;
NET_Socket server;
extern HWND d;
HWND joinDlg;
char ip[64];

void JoinMenu(){
 joinDlg = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_GETADDRESSINFO), NULL, (DLGPROC)GameJoinDialogPrompt);
 SetFocus(joinDlg);
// ShowWindow(joinDlg, SW_SHOW);
 ShowWindow(d, SW_HIDE);
}
LRESULT CALLBACK GameJoinDialogPrompt(HWND Dialogwindow, UINT Message, WPARAM wParam, LPARAM lParam){
 switch(Message){
  case WM_COMMAND:{ 
   switch(LOWORD(wParam)){
    case IDCONNECT:{
      GetDlgItemText(joinDlg, IDC_IP, ip, 63);
      if(server.ConnectToServer(ip, 7890, NET_UDP) == NET_INVALID_SOCKET){
       LogString("Failed to connect to server! IP: %s", ip);
       MessageBox(NULL, "Failed to connect!", "Error", MB_OK);
       ShowWindow(joinDlg, SW_SHOW);
       break;
      }
       }
     LogString("Connected!");
     break;
    case IDCANCEL:
     ShowWindow(d, SW_SHOW);
     ShowWindow(joinDlg, SW_HIDE);
     break;
   }
   break;
  }
  case WM_CLOSE:
   PostQuitMessage(0);
   break;
 }
 return 0;
}
LRESULT CALLBACK GameMainDialogPrompt(HWND Dialogwindow, UINT Message, WPARAM wParam, LPARAM lParam){
 switch(Message){
 case WM_PAINT:{
   PAINTSTRUCT ps;
   RECT rect;
   HDC hdc = GetDC(Dialogwindow);
      hdc = BeginPaint(Dialogwindow, &ps);
   GetClientRect (Dialogwindow, &rect);
   FillRect(hdc, &rect, CreateSolidBrush(RGB(0, 0, 0)));
      EndPaint(Dialogwindow, &ps);
      break;
      }
  case WM_COMMAND:{
   switch(LOWORD(wParam)){
    case IDC_HOST:
     if(!NET_Initialize()){
      break;
     }
     if(server.CreateServer(7890, NET_UDP) != 0){
      MessageBox(NULL, "Failed to create server.", "Error!", MB_OK);
      PostQuitMessage(0);
      return -1;
     }
     ShowWindow(d, SW_HIDE);
     break;
    case IDC_JOIN:{
     JoinMenu();
     }
     break;
    case IDC_EXIT:
     PostQuitMessage(0);
     break;
    default:
     break;
   }
   break;
  }
 return 0;
 }
}

Я вызываю первый диалог, используя код ниже

void EnterMenu(){
// joinDlg = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_GETADDRESSINFO), g_hWnd, (DLGPROC)GameJoinDialogPrompt);//
 d = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_SELECTMENU), g_hWnd, (DLGPROC)GameMainDialogPrompt);

}

Диалоговые окна по умолчанию не отключены и по умолчанию они видимы. Все настроено на создание при создании, и ни один код не деактивирует элементы в диалоговом окне или в самом диалоговом окне.

Ответы [ 3 ]

2 голосов
/ 29 апреля 2010

Сначала убедитесь, что вы написали правильную подпись для процедур диалога:

INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, 
                            WPARAM wParam, LPARAM lParam);

(см. http://msdn.microsoft.com/en-us/library/ms645469(v=VS.85).aspx)

Поэтому ваши диалоговые процедуры должны выглядеть так:

INT_PTR CALLBACK GameJoinDialogPrompt(HWND Dialogwindow, UINT Message,
                                      WPARAM wParam, LPARAM lParam)
    { /* ... */ }
INT_PTR CALLBACK GameMainDialogPrompt(HWND Dialogwindow, UINT Message,
                                      WPARAM wParam, LPARAM lParam)
    { /* ... */ }

Тогда вы сможете сделать это без предупреждений или ошибок:

void EnterMenu()
{     
    d = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_SELECTMENU),
                     g_hWnd, &GameMainDialogPrompt);
    // Note the ampersand. Also note that no cast is needed. You should
    // not need to use a cast to pass in the address of the function.
}     

См. http://blogs.msdn.com/oldnewthing/archive/2004/01/15/58973.aspx, почему крайне важно правильно выбрать сигнатуру функции.

При этом ваш joinDlg должен быть модальным диалоговым окном, поскольку он запрашивает информацию у пользователя:

void JoinMenu()
{
    // DialogBox() creates a modal dialog box. It "blocks" its owner until
    // it closes. On the other hand, CreateDialog() creates a non-modal
    // dialog box.
    joinDlg = DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_GETADDRESSINFO),
        d, &GameJoinDialogPrompt);
    // Again, note the ampersand and the lack of a cast when passing in
    // the address of the dialog procedure. Also, the main dialog box is
    // serving as the owner of this dialog box.
} 

Также обратите внимание, что процедуры диалогового окна отличаются от процедур Windows тем, что они возвращают либо TRUE, либо FALSE: TRUE, если ваша диалоговая процедура обработала сообщение, FALSE в противном случае. (Есть некоторые «странные» сообщения, которые нарушают это правило, но вы не обрабатываете эти сообщения)

Итак, ваши диалоговые процедуры должны выглядеть примерно так:

INT_PTR CALLBACK GameMainDialogPrompt(HWND Dialogwindow, UINT Message,
                                      WPARAM wParam, LPARAM lParam)
{ 
    switch(Message)
    { 
    case WM_PAINT:
        /* Do painting */
        return TRUE; // We handled the paint message
    case WM_COMMAND:
        switch(LOWORD(wParam))
        {
        case IDC_HOST:
            /* Do command */
            return TRUE; // We handled this particular command.
        case IDC_JOIN:
            /* Do command */
            return TRUE; // We handled this particular command.
        case IDC_EXIT:
            /* Do command */
            return TRUE; // We handled this particular command.
        }
        return FALSE; // The command wasn't handled.
    }
    return FALSE; // The message wasn't handled.
} 

Процедуры диалога не звонить DefWindowProc() и не возвращать 0!

0 голосов
/ 29 апреля 2010

Если ничего не помогает, начните заново с этого:

В resource.h:

#define IDD_DIALOG1                     101
#define IDD_DIALOG2                     102
#define ID_OPEN                         1001
#define ID_MESSAGE                      1002

В файле ресурсов:

#include <winres.h>
#include "resource.h"

IDD_DIALOG1 DIALOGEX 0, 0, 300, 200
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER |
    WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Main Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
    DEFPUSHBUTTON "Open Secondary Dialog", ID_OPEN, 73 ,49, 133, 64
END

IDD_DIALOG2 DIALOGEX 0, 0, 200, 150
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER |
    WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Secondary Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
    DEFPUSHBUTTON "Message Box", ID_MESSAGE, 50, 49, 88, 50
END

В исходном файле:

#include <windows.h>
#include "resource.h"

INT_PTR CALLBACK SecondaryDialogProc(HWND hwnd, UINT msg,
                                     WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
    case WM_INITDIALOG:
        return TRUE;
    case WM_COMMAND:
        switch(LOWORD(wParam))
        {
        case ID_MESSAGE:
            // Show a message box. Note that we're passing in our own HWND into
            // the function, so we "block" this dialog box until the user
            // dismisses this message box.
            ::MessageBox(hwnd, "Hello World!", "Greetings", MB_OK);
            return TRUE;
        }
        return FALSE;
    case WM_CLOSE:
        // Because this is a modal dialog box (we used ::DialogBox()), we
        // use ::EndDialog() instead of ::DestroyWindow() to destroy this
        // dialog box.
        ::EndDialog(hwnd, 0);
        return TRUE;
    }
    return FALSE;
}

INT_PTR CALLBACK MainDialogProc(HWND hwnd, UINT msg,
                                WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
    case WM_INITDIALOG:
        return TRUE;
    case WM_COMMAND:
        switch(LOWORD(wParam))
        {
        case ID_OPEN:
            // Open a modal dialog box. This will block the main dialog box
            // until the secondary dialog box is closed.
            ::DialogBox(::GetModuleHandle(NULL),
                MAKEINTRESOURCE(IDD_DIALOG2), hwnd, &SecondaryDialogProc);
            return TRUE;
        }
        return FALSE;
    case WM_CLOSE:
        // We close this dialog box with ::DestroyWindow(). This causes the
        // WM_DESTROY message to be sent.
        ::DestroyWindow(hwnd);
        return TRUE;
    case WM_DESTROY:
        // Since the main dialog box is being destroyed, we quit
        // the application.
        ::PostQuitMessage(0);
        return TRUE;
    }
    return FALSE;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine, int nShowCmd)
{
    // Open a non-modal dialog box using ::CreateDialog().
    HWND mainDlg = ::CreateDialog(::GetModuleHandle(NULL),
        MAKEINTRESOURCE(IDD_DIALOG1), NULL, &MainDialogProc);
    // The first ::ShowWindow() call should use nShowCmd.
    ::ShowWindow(mainDlg, nShowCmd);

    MSG msg;
    while (::GetMessage(&msg, NULL, 0, 0) > 0)
    {
        // So our main dialog behaves properly.
        if(!::IsDialogMessage(mainDlg, &msg))
        {
            ::TranslateMessage( & msg );
            ::DispatchMessage( & msg );
        }
    }
    return msg.wParam;
}

Здесь это просто простой код для открытия главного диалога с кнопкой для открытия другого диалога. Посмотрите, работает ли это сначала, а затем добавьте свою бизнес-логику.

0 голосов
/ 29 апреля 2010

В дополнение к другому отличному сообщению вы также делаете глупости, такие как:

if(server.CreateServer(7890, NET_UDP) != 0){
  MessageBox(NULL, "Failed to create server.", "Error!", MB_OK);
  PostQuitMessage(0);

в обработчике WM_COMMAND. Это ужасный кусок кода, так как он останавливает модальный цикл диалогов, не отключая его или не выводя всплывающее окно с сообщением.

Если вы вызываете модальное окно из другого окна (или диалогов), вы ДОЛЖНЫ отключить остановленное окно. Фактически, передайте Windows HWND вызову MessageBox.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...