Во-первых, я только совсем недавно начал изучать WinAPI. Я уверен, что этот вопрос задавали много раз раньше, но по какой-то причине я нигде не могу найти его в Интернете. Вопрос просто в следующем; зачем возиться с первоначальным вызовом ShowWindow() в теле WinMain() перед выполнением цикла сообщений? Почему бы просто не установить изначально видимое окно с помощью флага WS_VISIBLE?
У меня также есть вопросы по механике работы функции ShowWindow(). Какие сообщения он на самом деле отправляет? В MSDN говорится, что:
If a window has the
WS_VISIBLEstyle when it is created, the window receives this message[WM_SHOWWINDOW]after it is created, but before it is displayed. A window also receives this message when its visibility state is changed by theShowWindoworShowOwnedPopupsfunction.
Означает ли это, что основным средством связи между функцией ShowWindow() и Windows является сообщение WM_SHOWWINDOW? В нем также говорится, что:
The
WM_SHOWWINDOWmessage is not sent under the following circumstances:
When a top-level, overlapped window is created with the
WS_MAXIMIZEorWS_MINIMIZEstyle.When the
SW_SHOWNORMALflag is specified in the call to theShowWindowfunction.
В MSDN также говорится, что:
The first time an application calls
ShowWindow, it should use theWinMainfunction'snCmdShowparameter as itsnCmdShowparameter.
Петцольд заявляет, что аргумент, передаваемый этому параметру nCmdShow, будет либо SW_SHOWNORMAL, либо SW_SHOWMAXIMIZED, либо SW_SHOWMINNOACTIVE. Должен ли я брать из этого, что единственный раз, когда функция ShowWindow() не отправляет сообщение WM_SHOWWINDOW, - это когда мы делаем этот самый первый первоначальный вызов в Winmain()? Если да, то как затем заставить окно отображаться? Кроме того, как все это связано с фактической окраской окна?
Извините, если мой вопрос представляет собой беспорядочный беспорядок, но механика отображения окна сбивает меня с толку, и по какой-то причине трудно найти четкие ответы на эти вопросы в Интернете (в отличие от просто кусочков информации ). Мы будем благодарны за любую помощь в прояснении всего этого!
При первом вызове ShowWindow для главного окна, явно или неявно, и только в первый раз, тогда, если nCmdShow - это SW_SHOW, SW_SHOWNORMAL или SW_SHOWDEFAULT, тогда система вместо этого использует либо значение STARTUPINFOwShowWindow, если установлен флаг STARTF_USESHOWWINDOW, либо в противном случае SW_SHOWNORMAL если флаг не установлен. Значение STARTUPINFO используется только для вызова первый. Последующие вызовы ShowWindow, которые указывают SW_SHOWDEFAULT, фактически будут использовать SW_SHOWNORMAL.
Что касается [w]WinMain - конечно, его значение nCmdShow - это просто значение STARTUPINFOwShowWindow, если установлен флаг STARTF_USESHOWWINDOW, и в противном случае - SW_SHOWDEFAULT.
Кроме того, ответ ниже подразумевает, что у процесса не может быть STARTUPINFO. Это не имеет смысла. WinAPI STARTUPINFO - это сочетание RTL_USER_PROCESS_PARAMETERS NT и атрибутов создания (например, STARTUPINFOEXlpAttributeList). Указатель на ProcessParameters всегда существует в блоке среды процесса. Сюда входит запись WinAPI STARTUPINFO, включая WindowFlags, ShowWindowFlags, WindowTitle, DesktopInfo, ShellInfo, StandardInput и т. д. Это то, что WinAPI GetStartupInfo использует для восстановления записи STARTUPINFO.





Идея, лежащая в основе параметра nCmdShow для WinMain, заключается в том, что он дает Windows возможность сообщить вашему приложению, как Windows хочет, чтобы оно отображало окно. Этот механизм, вероятно, больше не полезен, но, возможно, есть крайние случаи. В любом случае вы должны передать его во все, что вы считаете своим главным окном, после того, как вы его создали. Его скрытие позволяет создавать любые дочерние окна без мерцания, что и делает большинство людей.
Я думаю, что логика, лежащая в основе того, когда WM_SHOWWINDOW отправляется и не отправляется, заключается в том, чтобы позволить вам использовать его для перехвата вызовов ShowWindow (hWnd, SW_HIDE) и ShowWindow (hWnd, SW_SHOW) в вашем оконном процессе, поскольку вполне вероятно, что вы, возможно, захотите предпринять какие-то действия в это время (например, прекратить воспроизведение аудио, например). И, возможно, также SW_MINIMIZE, SW_MAXIMIZE и SW_RESTORE, я думаю, все зависит от этого.
Это вообще помогает?
Редактировать
Что ж, в этой теме было опубликовано довольно много информации, поэтому я подумал, что постараюсь резюмировать ее так, как я понимаю. Поехали.
Параметр nCmdShow для WinMain кажется историческим. Вместо этого первый вызов ShowWindow действует так, как если бы вы передали ему это значение, нравится вам это или нет, так что этот вызов должен быть в вашем главном окне. Тем не менее, при этом, вы могли бы также сыграть в игру и передать ее, как знать.
Прочтите и поймите комментарий Ханса Пассанта к этому сообщению. Это скажет вам, откуда в пользовательском интерфейсе Windows чаще всего берется это значение.
К вашему сведению, нормально создавать окна ребенок с установленным WS_VISIBLE. Вы не увидите их, пока не откроете главное окно.
Ладно, я готов. Иногда лучше меньше, да лучше.
Он по-прежнему полезен, устанавливается свойством Run ярлыка на рабочем столе. Хотя SW_HIDE намеренно опущен, это вариант вредоносной программы :)
@HansPassant О да, он все еще там, как в старые добрые времена.
Спасибо, помогло. Таким образом, идея вызова ShowWindow() состоит в том, чтобы иметь возможность фактически определять дополнительные элементы клиентской области (например, дочерние окна) до фактического отображения главного окна, чтобы предотвратить возможное возникновение определенной «задержки», когда главное окно уже открыто. отображается, но некоторые элементы его клиентской области все еще создаются? Кроме того, вы, вероятно, правы насчет использования WS_SHOWWINDOW (хотя я обнаружил, что он отправляется только при изменении видимости окна, для минимизации / максимизации / восстановления вместо этого отправляется сообщение WM_SIZE).
О, хорошо, в этом [WM_SIZE] есть смысл. Я также вижу, перечитывая документация, что есть другие обстоятельства, при которых отправляется WM_SHOWWINDOW. А по поводу ShowWindow (), в основном, да.
Если вы не используете WS_VISIBLE и, следовательно, явно вызываете ShowWindow, вам не нужно использовать значение nCmdShow, которое передается WinMain реальной точкой входа C / C++. Это избыточность устаревшего программирования для Windows. nCmdShow поступает от ProcessParameters, если установлен флаг STARTF_USESHOWWINDOW, в противном случае - от SW_SHOWDEFAULT. Диспетчер окон уже по умолчанию использует это значение при первом вызове ShowWindow для главного окна с помощью SW_SHOW, SW_SHOWNORMAL или SW_SHOWDEFAULT. Все, что касается WinMain, можно игнорировать. Это просто чушь.
why bother with the initial call to ShowWindow() in the body of WinMain() before the execution of the message loop?
Ответ находится в документации ShowWindow():
nCmdShow
Controls how the window is to be shown. This parameter is ignored the first time an application calls
ShowWindow, if the program that launched the application provides aSTARTUPINFOstructure. Otherwise, the first timeShowWindowis called, the value should be the value obtained by theWinMainfunction in itsnCmdShowparameter.
Если приложение запускается пользователем, STARTUPINFO отсутствует, и следует использовать nCmdShow из WinMain(), чтобы определить, как должен отображаться ваш основной пользовательский интерфейс (или нет).
Если приложение запускается системой или другим приложением, скорее всего, это STARTUPINFO, поэтому вам следует игнорировать nCmdShow из WinMain() и использовать вместо него nCmdShow из STARTUPINFO.
Вызов ShowWindow() обрабатывает оба условия за вас. Но если вы заставляете окно отображаться с помощью VS_VISIBLE, вы не уважаете то, как вызывающий абонент хочет, чтобы ваше приложение отображалось (или нет) при запуске.
Спасибо за Ваш ответ. По словам Петцольда, использование аргумента nCmdShow из WinMain() действительно относится только к «предпочтениям, которые пользователь устанавливает при добавлении программы в меню« Пуск »». Я даже не уверен, возможно ли это. Мне кажется, что либо по умолчанию используется SW_SHOWNORMAL (в зависимости от спецификации программы), либо SW_SHOWDEFAULT (когда задействован родительский процесс). Я думаю, что отсутствие флага WS_VISIBLE гораздо больше связано с ответом Пола Сандерса, который дал выше.
@PvtWitt "Я даже не уверен, возможно ли это." - конечно все еще возможно. Ярлыки можно создавать в любом месте файловой системы, а не только в меню «Пуск».
@PvtWitt, ОС не вызывает [w]WinMain. Он вызывает исполняемую точку входа с указателем на его блок среды процесса (PEB), который сам по себе является избыточным параметром, поскольку поток может легко получить TEB и PEB. Для приложения Microsoft C / C++ реальная точка входа вызывает GetStartupInfo для восстановления записи STARTUPINFO из ProcessParameters PEB, каждый из которых обрабатывает должны быть. Если флаг STARTF_USESHOWWINDOW не установлен, точка входа C / C++ по умолчанию принимает значение SW_SHOWDEFAULT при вызове вашей функции [w]WinMain.
@RemyLebeau Мои извинения, вы абсолютно правы. Спасибо за ответы!
Если вы используете стиль
WS_VISIBLEв главном окне, тогда система неявно вызываетShowWindow(конечно, функцию win32k в ядре). По умолчанию используетсяSW_SHOW, если толькоxне являетсяCW_USEDEFAULT, аyне являетсяCW_USEDEFAULT, то естьyявляется некоторым значениемnCmdShow.