Как да принудя приложението си да излезе отпред и да постави фокус?

Работя върху приложение, което случайно е началната програма за инсталатор, върху който също работя. Приложението прави няколко MSI извиквания, за да получи информацията, от която се нуждая, за да сглобя съветника, който е главният прозорец на моето приложение, което води до отваряне на прозорец за напредък, докато информацията се събира, и след това изчезва, след като това приключи. След това съветникът се настройва и стартира. Проблемът ми е, че съветникът (извлечен от CPropertySheet) не иска да излезе отпред и да бъде активното приложение, без да добавя някои извиквания за това.

Реших проблема с извеждането му отпред със следния код в моя метод OnInitDialog():

SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); // force window to top
SetWindowPos(&wndNoTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); // lose the topmost status that the previous line gave us

Проблемът ми е, че все още не съм разбрал как да накарам прозореца да се самоактивира (т.е. да направи себе си този, който има фокус). SetFocus() няма да работи в този контекст. Имам нужда от нещо, което ще принуди прозореца да стигне до върха на Z-реда и ще го активира, за предпочитане при възможно най-малко обаждания.

Предполагам, че прозорецът за напредък, отворен в началото от MSI извикванията, причинява прецакване на главния прозорец, но нямам начин да попреча на този прозорец да се появи. Освен това не би имало смисъл да го скривате, защото позволява на потребителя да разбере какво се случва, преди да пристигне основният прозорец.


person RobH    schedule 27.03.2009    source източник


Отговори (5)


Андрей не е напълно прав. Windows наистина се опитва да ви попречи да откраднете фокуса, но е възможно с помощта на следния метод.

  1. Прикрепете към нишката на прозореца, който в момента има фокус.
  2. Поставете прозореца си на фокус.
  3. Откачете се от конеца.

И кодът за това ще изглежда нещо подобно:

DWORD dwCurrentThread = GetCurrentThreadId();
DWORD dwFGThread      = GetWindowThreadProcessId(GetForegroundWindow(), NULL);


AttachThreadInput(dwCurrentThread, dwFGThread, TRUE);

// Possible actions you may wan to bring the window into focus.
SetForegroundWindow(hwnd);
SetCapture(hwnd);
SetFocus(hwnd);
SetActiveWindow(hwnd);
EnableWindow(hwnd, TRUE);

AttachThreadInput(dwCurrentThread, dwFGThread, FALSE);

Може или не може да се наложи да стартирате програмата си с администраторски привилегии, за да работи това, но аз съм използвал този код лично и той свърши работата.

person Caleb Bartholomew    schedule 19.12.2013
comment
Това не работи в Windows 10 1703 (актуализация на Creators) - person Robin Andersson; 13.10.2017

Не можете да откраднете фокуса. Месечен цикъл.

Вижте тази статия за старото ново нещо:

https://web.archive.org/web/20190209213353/https://blogs.msdn.microsoft.com/oldnewthing/20090220-00/?p=19083

person nobody    schedule 27.03.2009
comment
Благодаря ви, търсих тази статия като отговор на този въпрос. Моля, всички, които четат това, да го интернализират и да поправят вирусния мем, който се опитва да открадне активирането на преден план. Но моето приложение е специално! Вашето приложение е враждебно към потребителя. Не го прави! - person 1800 INFORMATION; 27.03.2009
comment
Съгласен съм и въпреки че по всяка вероятност това се отнася за автора, той (или някой друг) може да има основателна причина да се нуждае от тази функционалност (затворена система, само частен или домашен компютър). Направете препоръка за употреба, но не крийте информацията. - person Arnold Spence; 27.03.2009
comment
Надявам се, че някой ден Microsoft най-накрая ще коригира кражбата на фокус веднъж завинаги. Програмистите, които се занимават с кражба на фокус, трябва да бъдат изпратени в Сибир. гол. - person snemarch; 27.03.2009
comment
Моята причина да открадна фокуса е, че потребителят току-що е стартирал приложението, то стартира прозорец, който получава фокус, този прозорец изчезва и приложението стартира друг прозорец, който не получава фокус. Това кара потребителя да се чеше по главата, ако не го поправя. - person RobH; 27.03.2009
comment
Тази статия не ми е полезна, защото не изпълнявам втори екземпляр на същото приложение. Моето приложение (или по-скоро MSI извикванията, които моето приложение извиква) стартира прозорец и след това го затваря, а приложението ми след това стартира главния си прозорец. Не се фокусира, но трябва. - person RobH; 27.03.2009
comment
Изглежда, че се отнася точно за вашата ситуация. Имате процес A, който стартира процес B и искате процес B да получи фокус. Решението, както се обяснява в статията, е, че процес A трябва да даде фокус на процес B - процес B не може да постави фокуса сам. - person nobody; 28.03.2009
comment
Не, моята програма извиква MSI функции, които в крайна сметка отварят прозорец за напредък (който получава фокус). Последното извикване на MSI функция затваря прозореца и след това моето приложение отваря основния си прозорец (който не получава фокус). Всичко се случва в един и същи процес. - person RobH; 30.03.2009
comment
За тези, които следват: ситуацията на RobH е ТОЧНО защо не трябва да крадете фокуса. Ако стартирам приложение, което стартира някакъв процес, можете да се обзаложите, че пиша имейл, докато чакам да се зареди. Сега идва вашето приложение за кражба на фокуса, което най-вероятно пита дали е добре да направите нещо в същото време, когато натискам enter.. Просто не го правете. - person NotMe; 10.05.2011

ShowWindow(youwindow,SW_SHOWNORMAL) не работи? -дон

person Don Dickinson    schedule 27.03.2009
comment
Не съм го пробвал, но предполагам, че не е по-ефективен от BringWindowToTop(). (Вижте коментара ми за отговора на Мич Уит.) - person RobH; 27.03.2009

Ще откриете, че BringWindowToTop или SetForegroundWindow имат изисквания, които трябва да бъдат изпълнени, преди прозорецът действително да бъде поставен отпред над всички други прозорци (приложения). Ако те не са изпълнени, Windows ще мига само иконата на приложението в лентата на задачите. Тази статия представя начин за заобикаляне на това, но както посочва 1800 ИНФОРМАЦИЯ, не се препоръчва. Предполагам, че просто ще трябва да го приемеш.

person Arnold Spence    schedule 27.03.2009
comment
не прави това Реймънд Чен обяснява защо това често кара приложението ви да виси: блогове. msdn.com/oldnewthing/archive/2008/08/01/8795860.aspx - person 1800 INFORMATION; 27.03.2009

ИМА добри причини едно приложение да „открадне“ фокуса. Моето приложение е сървър, зареждащ много DLL файлове на драйвери. Друго приложение, свързващо се със сървъра, има бутон, който изпраща съобщение до сървъра, за да покаже подробна информация в един от тези DLL (притежавани от сървъра, а не от клиентското приложение) за удобство. За съжаление, този отворен прозорец обикновено е заровен под няколко прозореца.

person Lee Davis    schedule 19.02.2021