Может ли WM_NEXTDLGCTL использоваться без диалоговых окон?

В документации для WM_NEXTDLGCTL указано, что это сообщение должно использоваться с диалогами:

Отправлено в процедуру диалогового окна, чтобы настроить фокус клавиатуры на другой элемент управления в диалоговом окне.

Если это сообщение не может использоваться с родителями без диалога, было бы очень утомительно подклассифицировать элементы управления общим образом (как показано на этом вопросе) поскольку оконная процедура должна была бы вызвать SetFocus или отправить сообщение WM_NEXTDLGCTL, основанное на не совсем тривиальном определении контекста.

Так как другие диалоговые API-интерфейсы могут использоваться с не-диалоговыми окнами (например, IsDialogMessage), было бы естественно, что можно используйте WM_NEXTDLGCTL в этой настройке.

Вопрос: Может ли WM_NEXTDLGCTL использоваться с родителями без диалога?

Ответ 1

Может ли WM_NEXTDLGCTL использоваться с родителями без диалога?

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

Это цитата, которую я нашел в "Старой новой вещи: практическое развитие на всей эволюции Windows: что происходит внутри DefDlgProc?

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

Другой причиной, по которой это сообщение является только диалоговое, является тот факт, что он (цитата из msdn для WM_NEXTDLGCTL):

задает идентификатор элемента управления по умолчанию

для этого он должен отправить DM_SETDEFID, который определяется как:

#define DM_SETDEFID         (WM_USER+1)

так что это WM_USER, и как таковой он может использоваться для какой-либо другой цели в недиалоговом окне (этот факт также упоминается в книге Раймонда Ченна). Интересно то, что согласно этой книге IsDialogMessage также отправляет DM_SETDEFID/DM_GETDEFID в ваше окно. Поэтому, если вы хотите использовать TAB как навигацию внутри вашего диалогового окна (используя код диалога), вы должны придерживаться некоторых правил, вы можете прочитать их внутри: What happens inside IsDialogMessage? выше книги. Это означает, среди прочего, использование следующего цикла сообщений:

while (GetMessage(&msg, NULL, 0, 0)) {
    if (IsDialogMessage(hwnd, &msg)) {
        /* Already handled by dialog manager */
    } else {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

поэтому, если вы не хотите делать серьезные изменения в своем родительском коде Windows, я боюсь, что вам не повезло.