Один из моих текущих клиентов выполняет цепочку интернет-точек, где клиенты доступ сеть через PC:s, настроенный как "киоски" (сделанное на заказ приложение "блокирует" компьютер, пока пользователь не регистрировался, и репортаж, в большой степени ограничиваются через групповую политику Windows). В настоящее время каждый компьютер выполняет Windows XP и использует Active Desktop для отображения рекламных объявлений в фоновом режиме. Однако, так как у моего клиента есть проблемы с Active Desktop, отказывающим ежедневно (в дополнение к общему замедлению компьютера), меня попросили разработать приложение, которое заменяет его.
Я пытаюсь заняться расследованиями, возможно ли создать приложение форм Windows (использующий C#), который всегда остается в фоновом режиме. Приложение должно лечь выше рабочего стола (так, чтобы это покрыло любые значки, файлы и т.д.), но всегда позади всех других запущенных приложений. Я предполагаю, что действительно ищу a BottomMost
свойство Form
класс (который не существует, конечно).
Любые подсказки или указатели о том, как достигнуть этого, высоко ценились бы.
Пусть значение по умолчанию рассматривается как «никогда»
-121--4648628- Я считаю null
подходящим. Это ясно указывает на «не набор».
В зависимости от того, насколько сложно вы хотите получить, вы можете иметь перечисление и иметь некоторое состояние, как 'NeverExpires' в качестве 'UserState' (или что бы вы ни представляли). Это, вероятно, предпочтительнее, но может быть бесполезно сложным, в зависимости от того, что ваша система.
-121--4648627-Это не поддерживается непосредственно классом .NET Form, поэтому у вас есть два параметра:
1) Используйте функцию Win32 API SetWindowPos
.
pinvoke.net показывает, как объявить это для использования в C #:
[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
static readonly IntPtr HWND_BOTTOM = new IntPtr(1);
const UInt32 SWP_NOSIZE = 0x0001;
const UInt32 SWP_NOMOVE = 0x0002;
const UInt32 SWP_NOACTIVATE = 0x0010;
Так что в вашем коде, вызов:
SetWindowPos(Handle, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
Как вы прокомментировали, это перемещает форму в нижнюю часть z-порядка, но не сохраняет его там. Единственный способ решения этой проблемы - вызвать события SetWindowPos
из Form _ Load
и Form _ Activate
. Если ваше приложение максимизировано, и пользователь не может переместить или минимизировать форму, то вам может сойти с рук такой подход, но это все еще что-то вроде взлома. Кроме того, пользователь может увидеть небольшое «мерцание», если форма будет выведена на передний план z-порядка перед вызовом SetWindowPos
.
2) подкласс формы , переопределить функцию WndProc
и перехватить сообщение WM _ WINDOWPOSCHANGING Windows, установив флаг SWP_NOZORDER (взято с этой страницы ).
Да, функция SetWindowPos с флагом HWND_BOTTOM должна помочь вам. Но, по моему опыту, даже после вызова SetWindowPo в результате некоторых пользовательских операций ваше окно может оказаться перед глазами.
подклассифицируют форму, переопределяют функцию WndProc и перехватывают сообщения Windows, которые отвечают за перемещение их вверх по z-порядку при их активации.
Сделайте ваше окно дочерним окном рабочего стола («Диспетчер программ» или « прогман "процесс). Мне удалось использовать этот метод в Windows XP (x86) и Windows Vista (x64).
Я наткнулся на этот метод, когда искал способ сделать так, чтобы заставка отображалась как обои. Оказывается, это как бы встроено в системный обработчик .scr. Вы используете screensaver.scr / p PID
, где PID - это идентификатор процесса другой программы, к которой нужно подключиться. Итак, напишите программу для поиска дескриптора программы, а затем вызовите.scr с этим аргументом / p, и у вас есть обои для заставки!
Проект, с которым я сейчас играю, - это отображение состояния рабочего стола (показывает время, некоторые задачи, подключенные диски и т. Д.), И он построен на Strawberry Perl и простом Win32 APIS (в основном Win32 :: GUI и Win32 :: Модули API), поэтому код легко переносить на любой динамический язык или понимать его с похожими привязками Win32 API или доступом к хосту сценариев Windows (например, ActivePerl, Python, JScript, VBScript). Вот соответствующая часть класса, который создает окно:
do { Win32::API->Import(@$_) or die "Win32::API can't import @$_ ($^E)" } for
[user32 => 'HWND FindWindow(LPCTSTR lpClassName, LPCTSTR lpWindowName)'],
[user32 => 'HWND SetParent(HWND hWndChild, HWND hWndNewParent)'],
sub __screen_x {
Win32::GUI::GetSystemMetrics(SM_CXSCREEN)
}
sub __screen_y {
Win32::GUI::GetSystemMetrics(SM_CYSCREEN)
}
sub _create_window { # create window that covers desktop
my $self = shift;
my $wnd = $$self{_wnd} = Win32::GUI::Window->new(
-width => __screen_x(), -left => 0,
-height => __screen_y(), -top => 0,
) or die "can't create window ($^E)";
$wnd->SetWindowLong(GWL_STYLE,
WS_VISIBLE
| WS_POPUP # popup: no caption or border
);
$wnd->SetWindowLong(GWL_EXSTYLE,
WS_EX_NOACTIVATE # noactivate: doesn't activate when clicked
| WS_EX_NOPARENTNOTIFY # noparentnotify: doesn't notify parent window when created or destroyed
| WS_EX_TOOLWINDOW # toolwindow: hide from taskbar
);
SetParent($$wnd{-handle}, # pin window to desktop (bottommost)
(FindWindow('Progman', 'Program Manager') or die "can't find desktop window ($^E)")
) or die "can't pin to desktop ($^E)";
Win32::GUI::DoEvents; # allow sizing and styling to take effect (otherwise DC bitmaps are the wrong size)
}
Эта программа буферизует вывод для предотвращения мерцания, что вы, вероятно, тоже захотите сделать. Я создаю DC (контекст устройства) и PaintDesktop для него (вы можете использовать любое растровое изображение только с парой строк - CreateCompatibleBitmap, читать в файле и выбирать дескриптор растрового изображения как кисть), затем создаю буфер хранения, чтобы сохранить чистая копия этого фона и рабочий буфер для сборки частей - в каждом цикле копируйте в фон, затем рисуйте линии и растровые изображения кистью и используйте TextOut - который затем копируется в исходный DC, после чего он появляется на экран.