Я работаю над оверлейным компонентом проекта в C # / DirectX .
Этот проект не использует WinForms или WPF
Это наложение является гибридным, в котором я хочу визуализировать компоненты пользовательского интерфейса через DirectX в мое окно и пройти через весь ввод, который не имеет отношения к базовому окну / приложению (которое яне владею).Я в основном хочу прозрачное полноэкранное окно, которое действует как интерактивный слой поверх другого приложения, где я определяю, какие входные события я использую, и какие события я пропускаю.
Это наложение создает HWND через RegisterClassEx / CreateWindowEx WIN API-вызовы.Главным образом для целей тестирования, я передаю логическую переменную, чтобы определить, хочу ли я включить «passthrough» (в основном добавляя WS_EX_TRANSPARENT к флагам создания).Мой DX-код отображается в окне с помощью CreateSwapChainForHwnd.
Фрагмент справочного кода:
// prepare WNDPROC-equivalent code for processing WM_* messages
wndProc = windowProcedure;
RuntimeHelpers.PrepareDelegate(wndProc);
wndProcPointer = Marshal.GetFunctionPointerForDelegate(wndProc);
// prepare window class registration structure
PInvoke.WNDCLASSEX wndClassEx = new PInvoke.WNDCLASSEX()
{
cbSize = PInvoke.WNDCLASSEX.Size(),
style = 0,
lpfnWndProc = wndProcPointer,
cbClsExtra = 0,
cbWndExtra = 0,
hInstance = IntPtr.Zero,
hIcon = IntPtr.Zero,
hCursor = PInvoke.LoadCursor(IntPtr.Zero, (int)PInvoke.IDC_STANDARD_CURSORS.IDC_ARROW),
hbrBackground = IntPtr.Zero,
lpszMenuName = randomMenuName,
lpszClassName = randomClassName,
hIconSm = IntPtr.Zero
};
// Register window class via WINAPI
PInvoke.RegisterClassEx(ref wndClassEx);
// Prepare window basic style flags (WS_*)
WS style = (WS.WS_POPUP | WS.WS_VISIBLE);
// Prepare window extended style flags (WS_EX_*)
WSEx exStyle;
if (_Topmost)
{
if (_AllowPassthrough)
exStyle = (WSEx.WS_EX_TOPMOST | WSEx.WS_EX_TRANSPARENT | WSEx.WS_EX_LAYERED | WSEx.WS_EX_TOOLWINDOW | WSEx.WS_EX_NOACTIVATE);
else
exStyle = (WSEx.WS_EX_TOPMOST | WSEx.WS_EX_LAYERED | WSEx.WS_EX_TOOLWINDOW | WSEx.WS_EX_NOACTIVATE);
}
else
{
if (_AllowPassthrough)
exStyle = (WSEx.WS_EX_TRANSPARENT | WSEx.WS_EX_LAYERED | WSEx.WS_EX_TOOLWINDOW | WSEx.WS_EX_NOACTIVATE);
else
exStyle = (WSEx.WS_EX_LAYERED | WSEx.WS_EX_TOOLWINDOW | WSEx.WS_EX_NOACTIVATE);
}
// Create window via WINAPI
_WindowHandle = PInvoke.CreateWindowEx(
(uint)exStyle,
randomClassName,
randomWindowName,
(uint)style,
_Position.X, _Position.Y,
_Size.X, _Size.Y,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero
);
// SetLayeredWindowAttributes is required to define transparency
// BOOL SetLayeredWindowAttributes( HWND hwnd, COLORREF crKey, BYTE bAlpha, DWORD dwFlags);
// Flag: LWA_ALPHA 0x00000002 Use bAlpha to determine the opacity of the layered window.
// Flag: LWA_COLORKEY 0x00000001 Use crKey as the transparency color.
PInvoke.SetLayeredWindowAttributes(_WindowHandle, 0, 255, 0x2);
PInvoke.UpdateWindow(_WindowHandle);
Прозрачное самое верхнее окно DirectX 11 хорошо отрисовывается и ведет себя должным образом извизуальная перспектива.
Если я установлю _AllowPassthrough
на ИСТИНА, все входные данные будут переданы в основное окно.
Если я установлю _AllowPassthrough
на ЛОЖЬ, никакой ввод не будет передан внизв основное окно.
Я использую API-функцию SetWindowsHookEx () для получения низкоуровневой информации о мышке и клавиатуре, но кажется, что когда я вызываю CallNextHookEx () после определения того, что ввод не относится ко мне, он никогда не попадает в основное окно для обработки (если _AllowPassthrough
false) или никогда не блокируется / не используется (если _AllowPassthrough
true).
Внутри процедуры Hook я либо возвращаю (IntPtr) 1; , чтобы заблокировать дальнейшую обработку, либо возвращаю PInvoke.CallNextHookEx (hookHandle, nCode, wParam, lParam); , чтобы позволить кому-то другомусправитьсяit.
Большинство моих исследований привели меня только к дискуссиям или статьям о полностью оверлейных окнах с «кликом»;не окна, которые частично просматриваются в определенных регионах.
Я предполагаю, что это связано с моей реализацией стиля окна "WS_EX_LAYERED".
Должен ли яискать вариант стиля «WS_EX_NOREDIRECTIONBITMAP» (для использования с механизмом композиции Windows) вместо «WS_EX_LAYERED» (выполнение тестов попадания пикселей на основе SetLayeredWindowAttributes)?
Если это имеет какое-либо значение, я использую sharpDX как моя DirectX библиотека-оболочка.Мой проект построен с использованием VS2017 и с использованием последних спецификаций языка C # в .NET Framework 4.7.1.
РЕДАКТИРОВАНИЕ 19.03.2009:
Так что яЯ сделал несколько обширных проб и ошибок по этому вопросу, и я пришел к выводу, что ....
без WS_LAYERED, тестов ввода / нажатия мыши и т. д. никогда не провалится в основное окно, несмотря ни на что.
с WS_LAYERED, мое окно перестает получать сообщения WM_NCHITTEST или другие сообщения, связанные с курсором.Я могу получить их, используя хук WH_MOUSE_LL (и связанный с ним обработчик сообщений LowLevelMouseProc ()), но используя событие и возвращая ненулевое значение (чтобы «предотвратить передачу системой остальной части цепочки хуков или цели»оконная процедура ") все еще позволяет другим" не связанным с мышью "сообщениям проходить через, так что даже попытка подавить MOUSE_MOVE, потребляя его и используя SetCursorPos () для перемещения курсора, все еще заставляет окно внизу получать уведомление о наведении курсора или мышиболее (я вижу подсветку кнопок и всплывающие подсказки).
Если я не использую SetCursorPos (), мышь заблокируется на месте, поскольку необходимый код для перемещения курсора не видит движения мыши.Я не уверен, что SetCursorPos () вызывает событие MOUSE_MOVE, но я предполагаю, что это не так, поскольку я в любом случае потребляю эти события (и предотвращаю блокировку с помощью проверки "last == current".) Я понятия не имею, чтогенерируются другие системные события.Информация о низкоуровневой природе входной очереди сообщений крайне отсутствует в сети.
Что касается «не-альфа» цветов, то, похоже, это не имеет никакого значения;все окрашенные цвета, независимо от непрозрачности, все еще проходят через ввод мыши.
Я попробовал вышеупомянутый WS_EX_NOREDIRECTIONBITMAP и реорганизовал мой код рендеринга DX, чтобы вместо него использовать Composition Engine, используя хорошо цитируемую статью MSDNКенни Керр в качестве ссылки, и это не имело никакого значения.
Я действительно озадачен этим.