предотвращение кражи приложений

<p>есть ли какие-нибудь решения для предотвращения кражи приложений из активного окна?</p><p>это особенно раздражает, когда я запускаю приложение, переключаюсь на что-то еще, и новое приложение начинает получать половину предложения текста.</p>

<p>это невозможно без <em>обширного</em> манипулирования внутренними компонентами windows, и вам нужно преодолеть это.</p><p>в повседневном использовании компьютера бывают моменты, когда очень важно выполнить одно действие, прежде чем операционная система позволит вам выполнить другое. для этого нужно заблокировать фокус на определенных окнах. в windows контроль над этим поведением в основном остается за разработчиками отдельных программ, которые вы используете.</p><p>не каждый разработчик принимает правильные решения, когда речь заходит об этой теме.</p><p>я знаю, что это очень расстраивает и раздражает, но вы не можете съесть свой пирог и съесть его тоже. вероятно, в вашей повседневной жизни есть много случаев, когда вы совершенно в порядке с переносом фокуса на определенный элемент пользовательского интерфейса или с приложением, запрашивающим его фиксацию. но большинство приложений примерно одинаковы, когда речь заходит о том, кто сейчас является лидером, и система никогда не может быть идеальной.</p><p>некоторое время назад я провел обширные исследования по решению этой проблемы раз и навсегда (и не смог). результат моего исследования можно найти на странице проекта <a href="http://code.google.com/p/annoyance/">annoyance</a> .</p><p>проект также включает в себя приложение, которое неоднократно пытается захватить фокус, вызывая:</p><pre><code>switch( message ) { case wm\_timer: if( hwnd != null ) { // start off easy // setforegroundwindow will not move the window to the foreground, // but it will invoke flashwindow internally and, thus, show the // taskbar. setforegroundwindow( hwnd ); // our application is awesome! it must have your focus! setactivewindow( hwnd ); // flash that button! flashwindow( hwnd, true ); } break; </code></pre><p>как видно из этого фрагмента, мои исследования были также сосредоточены на других аспектах поведения пользовательского интерфейса, которые мне не нравятся.</p><p>я пытался решить эту проблему, загружая dll в каждый новый процесс и перехватывая вызовы api, которые вызывают активацию других окон.<br> последняя часть проста благодаря потрясающим api-интерфейсам для подключения библиотек. я использовал очень большую библиотеку <a href="http://codefromthe70s.org/mhook23.aspx">mhook</a> :</p><pre><code>#include "stdafx.h" #include "mhook-2.2/mhook-lib/mhook.h" typedef ntstatus( winapi* pnt\_query\_system\_information ) ( \_\_in system\_information\_class systeminformationclass, \_\_inout pvoid systeminformation, \_\_in ulong systeminformationlength, \_\_out\_opt pulong returnlength ); // originals pnt\_query\_system\_information originalflashwindow = (pnt\_query\_system\_information)::getprocaddress( ::getmodulehandle( l"user32" ), "flashwindow" ); pnt\_query\_system\_information originalflashwindowex = (pnt\_query\_system\_information)::getprocaddress( ::getmodulehandle( l"user32" ), "flashwindowex" ); pnt\_query\_system\_information originalsetforegroundwindow = (pnt\_query\_system\_information)::getprocaddress( ::getmodulehandle( l"user32" ), "setforegroundwindow" ); // hooks bool winapi hookedflashwindow( \_\_in hwnd hwnd, \_\_in bool binvert ) { return 0; } bool winapi hookedflashwindowex( \_\_in pflashwinfo pfwi ) { return 0; } bool winapi hookedsetforegroundwindow( \_\_in hwnd hwnd ) { // pretend window was brought to foreground return 1; } bool apientry dllmain( hmodule hmodule, dword ul\_reason\_for\_call, lpvoid lpreserved ) { switch( ul\_reason\_for\_call ) { case dll\_process\_attach: mhook\_sethook( (pvoid*)&originalflashwindow, hookedflashwindow ); mhook\_sethook( (pvoid*)&originalflashwindowex, hookedflashwindowex ); mhook\_sethook( (pvoid*)&originalsetforegroundwindow, hookedsetforegroundwindow ); break; case dll\_process\_detach: mhook\_unhook( (pvoid*)&originalflashwindow ); mhook\_unhook( (pvoid*)&originalflashwindowex ); mhook\_unhook( (pvoid*)&originalsetforegroundwindow ); break; } return true; } </code></pre><p>из моих тестов тогда это работало отлично. за исключением части загрузки dll в каждый новый процесс. как можно себе представить, это не слишком легко. тогда я использовал <a href="http://support.microsoft.com/kb/197571">appinit\_dlls</a> подход (которого просто недостаточно).</p><p>в принципе, это прекрасно работает. но я так и не нашел время написать что-то, что<strong> правильно </strong>внедряет мою dll в новые процессы. и время, потраченное на это, в значительной степени омрачает раздражение, которое вызывает кража фокуса.</p><p>помимо проблемы с инъекцией dll, существует также метод кражи фокуса, который я не рассматривал при реализации в google code. сотрудник действительно провел дополнительное исследование и рассказал об этом методе. проблема обсуждалась на so: <a href="https://stackoverflow.com/questions/7430864/windows-7-prevent-application-from-losing-focus">https://stackoverflow.com/questions/7430864/windows-7-prevent-application-from-losing-focus</a> </p>

<p>в windows 7 запись реестра <code>foregroundlocktimeout</code> больше не проверяется, это можно проверить с помощью process monitor. фактически, в windows 7 они запрещают вам изменять окно переднего плана. пойдите и прочитайте <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms633539(v=vs.85).aspx">о его деталях</a> , это было там даже с windows 2000.</p><p>тем не менее,<em> документация отстой, и они преследуют друг друга и находят способы обойти это </em>.</p><p>итак, с <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms633539(v=vs.85).aspx"><code>setforegroundwindow</code></a> происходит что-то глючное или подобные api-функции ...</p><p>единственный способ действительно сделать это правильно - создать небольшое приложение, которое периодически вызывает <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms633532(v=vs.85).aspx"><code>locksetforegroundwindow</code></a> , фактически отключая любые вызовы нашей глючной функции api.</p><p>если этого недостаточно (еще один ошибочный вызов api?), вы можете пойти еще дальше и сделать несколько <a href="https://www.rohitab.com/apimonitor">мониторинг api</a> , чтобы увидеть, что происходит, а затем просто <a href="http://easyhook.codeplex.com/">перехватывать вызовы api для каждого процесса</a> после чего вы можете избавиться от<em> любых </em>вызовов, которые портят передний план. однако, по иронии судьбы, это не одобряется microsoft ...</p>

<p>в <a href="http://www.microsoft.com/windowsxp/downloads/powertoys/xppowertoys.mspx">tweakui</a> есть опция, которая делает это. это предотвращает большинство обычных уловок, которые сомнительные разработчики программного обеспечения используют, чтобы сосредоточиться на своем приложении.</p><p>это война вооружений, поэтому я не знаю, работает ли она на все.</p><p><sub><strong> обновить </strong>: согласно <a href="https://superuser.com/users/865/endangeredmassa">endangeredmassa</a> , tweakui не работает на windows 7.</sub></p>

<p>я полагаю, что некоторая путаница может существовать, так как есть два способа «украсть фокус»: (1) окно, выходящее на передний план, и (2) окно, принимающее нажатия клавиш.</p><p>проблема, о которой здесь говорится, является, вероятно, второй, когда окна требуют фокусировки, выдвигая себя на передний план - без запроса или разрешения пользователя.</p><p>обсуждение должно быть разделено здесь между xp и 7.</p><h1>windows xp</h1><p>в xp есть взлом реестра, который заставляет xp работать так же, как windows 7, в предотвращении кражи приложений:</p><ol> <li>используйте regedit, чтобы перейти к: <code>hkey\_current\_user\control panel\desktop</code>.</li> <li>дважды щелкните <code>foregroundlocktimeout</code> и установите его значение в шестнадцатеричном формате на <code>30d40</code>.</li> <li>нажмите ok и выйдите из программы regedit.</li> <li>перезагрузите компьютер, чтобы изменения вступили в силу.</li> </ol><h1>windows 7</h1><p><sub>(обсуждение ниже в основном относится и к xp.)</sub></p><p>пожалуйста, поймите, что никоим образом windows не может полностью блокировать приложения от кражи фокуса и оставаться функциональной. например, если во время копирования файла антивирус обнаружил возможную угрозу и хотел бы открыть окно с просьбой предпринять действия, если это окно заблокировано, вы никогда не поймете, почему копирование никогда не прекращается.</p><p>в windows 7 возможна только одна модификация поведения самой windows, которая заключается в использовании взломов реестра <a href="http://sinewalker.wordpress.com/2010/03/10/ms-windows-focus-follows-mouse-registry-hacks/">ms-windows focus-follow-mouse</a> , где фокус и/или активация всегда идут к окнам под курсор. можно добавить задержку, чтобы приложения не появлялись по всему рабочему столу.<br> см. эту статью: <a href="http://www.sevenforums.com/tutorials/9000-mouse-hover-makes-window-active-enable.html">windows 7 - при наведении курсора мыши окно становится активным - включить</a> .</p><p>в противном случае необходимо обнаружить и нейтрализовать виновную программу: если это всегда одно и то же приложение, которое получает фокус, то это приложение запрограммировано на получение фокуса, и предотвратить это можно, либо отключив его запуск с компьютера, либо используйте некоторые настройки, предоставляемые этим приложением, чтобы избежать такого поведения.</p><p>вы можете использовать сценарий vbs, включенный в <a href="http://archive.msdn.microsoft.com/templeofvb/release/projectreleases.aspx?releaseid=18">vb код, который определяет, кто ворует фокус</a> , который автор использовал для определения виновника как средства обновления «call home» для программного обеспечения принтера.</p><p>отчаянная мера, когда все остальное терпит неудачу, и если вы определили это плохо запрограммированное приложение, состоит в том, чтобы свести его к минимуму и надеяться, что тогда он не выйдет на передний план. более сильная форма минимизации - использование лотка с помощью одного из бесплатных продуктов, перечисленных в <a href="http://www.techsupportalert.com/best-free-app-minimizer.htm">best free application minimizer</a> .</p><p>последняя идея в порядке отчаяния состоит в том, чтобы виртуально сломать ваш рабочий стол, используя такой продукт, как <a href="http://technet.microsoft.com/en-us/sysinternals/cc817881">desktops</a> или <a href="http://dexpot.de/">dexpot</a> , и выполнять свою работу на другом рабочем столе, чем по умолчанию.</p><p>[правка]</p><p>поскольку microsoft удалила галерею архивов, приведен приведенный выше vb код:</p><pre><code>declare auto function getforegroundwindow lib "user32.dll" () as integer declare auto function getwindowthreadprocessid lib "user32.dll" (byval hwnd as integer, byref procid as integer) as uinteger private sub form1\_load(byval sender as system.object, byval e as system.eventargs) handles mybase.load me.richtextbox1.appendtext("starting up at " & now & vbcrlf) end sub private sub goingaway(byval sender as object, byval e as system.eventargs) handles me.deactivate, me.lostfocus dim hwnd as integer = getforegroundwindow() ' note that process\_id will be used as a byref argument ' and will be changed by getwindowthreadprocessid dim process\_id as integer = 1 getwindowthreadprocessid(hwnd, process\_id) if (process\_id <> 1) then dim appexepath as string = process.getprocessbyid(process\_id).mainmodule.filename() me.richtextbox1.appendtext("lost focus at " & now & " due to " & appexepath & vbcrlf) else me.richtextbox1.appendtext("lost focus due to unknown cause.") end if end sub </code></pre>

<p>вдохновленный <a href="https://superuser.com/a/404246/111821">ответом der hochstapler</a> , я решил написать инжектор dll, который работает как с 64, так и с 32-разрядными процессами и предотвращает кражу фокуса в windows 7 или новее: <a href="https://blade.sk/stay-focused/">https: // blade.sk/stay-focused/</a> </p><p>это работает так, как будто он наблюдает за вновь созданными окнами (используя <code>setwineventhook</code>) и внедряет dll, очень похожий на тот, который был у der hochstapler, в процесс окна, если он еще не представлен. он выгружает библиотеки dll и восстанавливает исходную функциональность при выходе.</p><p>судя по моим тестам, пока все работает очень хорошо. однако проблема, похоже, заключается не только в приложениях, вызывающих <code>setforegroundwindow</code>. например, когда создается новое окно, оно автоматически выводится на передний план, что также мешает пользователю печатать в другом окне.</p><p>чтобы иметь дело с другими методами кражи фокуса, требуется дополнительное тестирование, и я буду признателен за любые отзывы о сценариях, где это происходит.</p>

<p>ghacks имеет <a href="http://www.ghacks.net/2008/04/04/prevent-applications-from-stealing-focus/">возможное решение:</a> </p><blockquote> <p>несколько раз в день некоторые приложения крадут фокус активного окна, всплывая. это может произойти по ряду причин, например, когда я извлекаю файлы или передача завершается. в большинстве случаев это не имеет значения, но иногда я пишу статью, и это означает не только то, что мне нужно снова набирать некоторые слова, но и то, что я потерял концентрацию и должен нажать, чтобы восстановить фокус.</p> <p>на <a href="http://proreviewer.com/2008/04/04/tip-stop-applications-in-windows-stealing-focus/">pro reviewer</a> есть совет, как этого избежать. самый простой способ предотвратить кражу фокуса - использовать tweak ui с настройкой, которая называется «запретить краже приложений». установка этой опции предотвращает внезапное появление других приложений и захватывает фокус окна, в котором вы сейчас работаете.</p> <p><strong> это работает только тогда, когда приложение было свернуто ранее. </strong>вместо кражи фокуса он будет мигать несколько раз, что можно определить в том же меню в <a href="http://www.microsoft.com/windowsxp/downloads/powertoys/xppowertoys.mspx">tweak ui</a> . если вы не хотите использовать tweak ui, вы можете изменить настройки в реестре windows.</p> <p>перейдите к разделу реестра hkey\_current\_user> панель управления> рабочий стол и измените значение foregroundlocktimeout на 30d40 (шестнадцатеричное) или 200000 (десятичное). ключ foregroundflashcount определяет количество вспышек окна, чтобы предупредить пользователя, где 0 означает неограниченный.</p> </blockquote>