DS_CONTROL | Комбинация WS_CHILD вызывает бесконечный цикл - PullRequest
0 голосов
/ 02 ноября 2018

Привет.

Я пытаюсь создать пример "диалогового окна в диалоге" с использованием WinAPI и C. Этот пример состоит из дочернего диалогового окна с автоматической галочкой и основного диалогового окна, содержащего статический черный прямоугольник, который является родительским для дочернего диалога, и кнопка, отображающая в окне сообщения текст со статусом флажка.

Когда я устанавливаю флаги DS_CONTROL | WS_CHILD для дочернего диалога, всякий раз, когда я пытаюсь изменить Статус флажка, приложение входит в бесконечный цикл, и я вынужден закрыть его. Когда я удаляю флаг DS_CONTROL, он работает как положено, но я не могу переключаться между элементами управления с помощью клавиши табуляции.

Что я могу сделать, чтобы заставить его работать, как предполагалось, с использованием флага DS_CONTROL?

Вот содержимое моего main.c файла:

#include <windows.h>

#pragma comment (lib, "user32")


HINSTANCE hInst;
BOOL isChecked;
const unsigned char checkedStr[] = "Checkbox is checked";
const unsigned char notCheckedStr[] = "Checkbox is not checked";


BOOL CALLBACK ChildDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  switch (uMsg)
  {
    case WM_COMMAND:
      switch (LOWORD(wParam))
      {
        case 21:
          isChecked = IsDlgButtonChecked(hwndDlg, 21);
          return TRUE;
      }

      return FALSE;
  }

  return FALSE;
}


BOOL CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  switch (uMsg)
  {
    case WM_INITDIALOG:
    {
      HWND hContainer, hChilddDlg;

      hContainer = GetDlgItem(hwndDlg, 11);
      hChilddDlg = CreateDialogParam(hInst, MAKEINTRESOURCE(20), hContainer, ChildDlgProc, 0);
      ShowWindow(hChilddDlg, SW_SHOW);

      return TRUE;
    }

    case WM_COMMAND:
      switch (LOWORD(wParam))
      {
        case 12:
        {
          const unsigned char *ptr;

          if (isChecked)
          {
            ptr = checkedStr;
          }
          else
          {
            ptr = notCheckedStr;
          }

          MessageBox(hwndDlg, ptr, TEXT("Checkbox status"), MB_OK | MB_ICONINFORMATION);

          return TRUE;
        }
      }

      return FALSE;

    case WM_CLOSE:
      EndDialog(hwndDlg, 0);
      return TRUE;
  }


  return FALSE;
}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
  hInst = hInstance;
  isChecked = FALSE;

  return DialogBoxParam(hInstance, MAKEINTRESOURCE(10), NULL, DialogProc, 0);
}

А вот содержимое моего rsrc.rc файла:

#include <windows.h>

10 DIALOGEX 0, 0, 130, 47
STYLE DS_CENTER | DS_SETFONT | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU
CAPTION "Checkbox status"
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
FONT 9, "Segoe UI"
{
  CONTROL "", 11, STATIC, SS_BLACKRECT | WS_CHILD | WS_VISIBLE, 5, 5, 120, 20
  CONTROL "&Status", 12, BUTTON, BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 75, 30, 50, 12
}


20 DIALOGEX 0, 0, 120, 20
STYLE DS_SETFONT | DS_CONTROL | WS_CHILD
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
FONT 9, "Segoe UI"
{
  CONTROL "Checkbox", 21, BUTTON, BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0, 5, 50, 10
}

Я компилирую его в командной строке Visual C ++ с помощью: cl /c main.c && rc rsrc.rc && link /SUBSYSTEM:WINDOWS /OUT:test.exe main.obj rsrc.res.

Заранее благодарен за помощь.

1 Ответ

0 голосов
/ 03 ноября 2018

Нашел решение в исходном коде NSIS. Проблема заключалась в том, что я помещал дочерний диалог как дочерний элемент blackrect, чтобы он был вне цикла событий основного диалога, вызывая зависание. Чтобы решить эту проблему, я должен был поставить его как дочерний элемент основного диалога и переместить его поверх черного.

Вот обновленный код случая WM_INITDIALOG в процедуре основного диалога:

// ...
case WM_INITDIALOG:
{
  HWND hChilddDlg;

  hChilddDlg = CreateDialogParam(hInst, MAKEINTRESOURCE(20), hwndDlg, ChildDlgProc, 0);

  if (hChilddDlg)
  {
    RECT rect;

    GetWindowRect(GetDlgItem(hwndDlg, 11), &rect);
    ScreenToClient(hwndDlg, (LPPOINT)&rect);
    SetWindowPos(hChilddDlg, 0, rect.left, rect.top, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
    ShowWindow(hChilddDlg, SW_SHOWNA);
  }

  return TRUE;
}
// ...

Благодаря этому я смог использовать флаг DS_CONTROL и цикл табуляции между элементами управления.

...