Полноэкранное окно DirectX для оконного дескриптора с использованием функций Windows API
Короткий рассказ
Игра запускается в полноэкранном режиме, но является полноэкранным окном DirectX. Игра поддерживает оконный режим, но я должен сделать это вручную. Я создал программу на Delphi, которая растягивает / изменяет размеры любого окна, чтобы соответствовать экрану (с использованием общесистемной горячей клавиши) без рамки и заголовка, чтобы она выглядела как полноэкранная, но не запускала прямой аппаратный доступ. Это важно, потому что я использую адаптер DisplayLink, который не поддерживает приемы, используемые прямым доступом к оборудованию, но хочет воспроизвести его на весь экран без безобразных границ. Я могу изменить размер любого окна, кроме полноэкранного окна DirectX, я должен вручную изменить полноэкранный режим на оконный, это то, что я хочу автоматизировать.
Длинная история (прокрутите вниз, если хотите узнать вопрос)
У меня есть адаптер DisplayLink с экраном в 5 метрах от компьютера. Я хочу использовать его для запуска игр, чтобы я мог играть в игры с дивана. Однако драйвер DisplayLink не может воспроизводить большинство игр в полноэкранном режиме, поскольку большинство игр не используют Диспетчер окон рабочего стола (DWM) для прямого доступа к графическому оборудованию в полноэкранном режиме.
Это распространенная / известная проблема с DisplayLink. В оконном режиме адаптер работает очень хорошо, поэтому я подумал написать небольшую программу на Delphi, чтобы максимизировать оконный экран DirectX до полного экрана, не переходя в полноэкранный режим путем его максимизации, вместо этого растягивая окно до полного экрана.
Созданная мною программа работает довольно хорошо, но только тогда, когда на экране DirectX уже есть окно (игра запускается в полноэкранном режиме, поэтому мне нужно один раз щелкнуть значок окна, чтобы сделать его оконным). В игре уже есть возможность сделать ее оконной при запуске, но с меньшими возможностями фиксированного разрешения. Я хочу автоматизировать этот процесс при запуске в полноэкранном режиме. Я хочу изменить экран DirectX на оконный, и после этого изменить его размер / растянуть на весь экран, не увеличивая его.
Как работает программа
Программа определяет общесистемную горячую клавишу клавиатуры. При нажатии горячей клавиши программа максимизирует любое активное окно переднего плана (Windows API getForeGroundWindow()
), растягивая его на весь экран и делая его окном без границ, чтобы оно выглядело как полный экран. Это позволяет вам также запускать игру на любом экране, который вам нравится, а не только на главном экране вашей системы. При повторном нажатии горячей клавиши окно возвращается в предыдущее состояние (переключение). Перед применением "патча" он также проверяет тип окна, поэтому его нельзя использовать в окнах без изменения размера.
Вопрос
Я знаю дескриптор окна, которое должно быть растянуто / изменено до полного экрана. Когда это полноэкранное окно DirectX, я ничего не могу сделать, если оно не оконное. Как я могу изменить его состояние на оконное, отправив сообщения на этот дескриптор окна (sendMessage()
). Это возможно в любом случае?
Некоторый код (чтобы дать вам некоторое представление о том, что происходит за кулисами)
function TWinSpread.setWindowStyleBounds( h : hWnd; lStyle : LongInt = 0; pR : PRect = nil ) : LongInt;
var
bRestore : Boolean;
r : TRect;
pMouse : TPoint;
rStyle : TStyleStruct;
begin
Result:=0;
if( h <= 0 ) then
Exit;
bRestore:=( lStyle > 0 );
if( NOT bRestore ) then
begin
lStyle:=getWindowLong( h, GWL_STYLE );
Result:=lStyle;
lStyle:=lStyle and not WS_BORDER and not WS_SIZEBOX and not WS_DLGFRAME;
if( Assigned( pR )) then
begin
r:=pR^;
end
else begin
getWindowRect( h, r );
r:=getDisplayRect( getDisplayNumFromPoint( Point( r.left+2, r.top+2 ) ) );
end;
end
else begin
Result:=lStyle;
end;
rStyle.styleOld:=Result;
rStyle.styleNew:=lStyle;
if( Result = lStyle ) then
begin
rStyle.styleOld:=getWindowLong( h, GWL_STYLE );
end;
sendMessage( h, WM_ENTERSIZEMOVE, 0, 0 );
__restoreWindow( h );
setWindowLong( h, GWL_STYLE, lStyle );
if( NOT bRestore ) then
begin
setWindowPos( h, HWND_TOP, r.left,r.top,r.right-r.left,r.bottom-r.top, SWP_FRAMECHANGED and WS_SIZEBOX );
moveWindow( h, r.left,r.top,r.right-r.left,r.bottom-r.top, TRUE );
sendMessage( h, WM_SIZE, SIZE_RESTORED, makeLong( r.right-r.left,r.bottom-r.top ));
end
else begin
// updateWindowFrame( h );
setWindowPos( h, 0, 0,0,0,0, SWP_FRAMECHANGED or SWP_NOMOVE or SWP_NOSIZE or SWP_NOZORDER or SWP_NOOWNERZORDER );
getWindowRect( h, r );
end;
sendMessage( h, WM_EXITSIZEMOVE, 0, 0 );
sendMessage( h, WM_STYLECHANGED, GWL_STYLE, longInt( Pointer( @rStyle )));
activateWindow( h );
windows.setFocus( h );
if( __mousePresent() ) then
begin
pMouse:=__getMousePos();
// Simulate click to focus window
__setMousePos( Point( r.left+2, r.top+2 ));
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
// restore mouse
__setMousePos( pMouse );
end;
end;
procedure TWinSpread.shHotKeyHotKey(Sender: TObject; Index: Integer);
var
h : hWnd;
sHandle : string;
lStyle : LongInt;
bNoBorder : Boolean;
begin
h:=getForeGroundWindow();
if( h <= 0 ) then
exit;
if( h = handle ) then
begin
showMessage( 'It works!' );
exit;
end;
sHandle:=ItoA( h );
if( scWinStyles.Count > 0 ) then
begin
lStyle:=AtoI( scWinStyles.list.Values[sHandle] );
if( lStyle > 0 ) then
begin
scWinStyles.list.delete( scWinStyles.list.IndexOfName(sHandle));
setWindowStyleBounds( h, lStyle );
Exit;
end;
end;
bNoBorder:=windowIsBorderless( h );
if( isMaximized( h ) or bNoBorder ) then
begin
// does not work for ActiveX fullscreen window :-(
//if( bNoBorder ) then
// setWindowSizeable( h, TRUE );
__maximizeWindow( h );
__restoreWindow( h );
showWindow( h, SW_SHOWNORMAL );
end;
if( windowIsSizeable( h ) ) then
begin
lStyle:=setWindowStyleBounds( h );
scWinStyles.list.Values[sHandle]:=ItoA( lStyle );
end
else Windows.Beep( 600, 200 );
end;
Некоторые скриншоты
Обратите внимание: на этом рисунке изображена опечатка, ActiveX должен быть DirectX;-)
Дополнительная информация о проблеме DisplayLink: http://support.displaylink.com/knowledgebase/articles/543922-games-do-not-work-on-windows-with-displaylink-soft