DirectX full screen window to windowed by window handle with use Windows API functions

南笙酒味 提交于 2019-12-13 02:38:56

问题


Short story

A game is started fullscreen but is a fullscreen directX window. The game supports windowed but I have to do it manually. I made a program in Delphi that stretch/resize any window to fit the screen (with use of a system-wide hotkey) without border and caption so it looks like a fullscreen but doesn't trigger direct hardware access. This is important because I'm using a DisplayLink adapter that doesn't support the tricks used by direct hardware access but want to play it full screen without ugly borders. I can resize any window except a fullscreen DirectX window, I have to manually change the full screen mode to windowed, this is what I want to automate.

Long story (scroll down if you want to know the question)

I have a DisplayLink adapter with TV-screen 5 Meters away from my computer. I want to use it to run games so I can play games from the couch. The DisplayLink driver however cannot play most games full screen because most games bypass the Desktop Window Manager (DWM) to access the graphics hardware directly when full screen.

This is a common/known problem with DisplayLink. In windowed mode the adapter performs very well so I thought to write a little program in Delphi to maximize a windowed directx screen to full screen without going full screen by maximizing it, stretching the window to full screen instead.

The program I made works pretty well however only when the directx screen is already windowed (the game starts full screen so I have to click once the windowed icon to make it windowed). The game already has an option to make it windowed at launch but with less fixed resolution possibilities. I want to automate this process when launched full screen. I want to change the directx screen to windowed and after this resize/stretch it to full screen without maximizing it.

How the program works

The program defines a system wide keyboard hotkey. When pressing the hotkey the program maximize any active foreground window (windows API getForeGroundWindow()) by stretching it to full screen and makes it a borderless window so it looks like full screen. This enable you also to run the game on any screen you like and not only on the main screen of your system. When pressing the hotkey again, the window returns to it's previous state (toggle). Before applying the 'patch', it also checks the type of window, so it cannot be used on non-resizable windows.

Question

I know the handle of the window that must be stretched/resized to fullscreen. When it is a fullscreen DirectX window I can't do anything with unless it is windowed. How can I change it's state to windowed by sending messages to this window handle (sendMessage()). Is this possible anyway?

Some code (to give you some idea what's happening behind the scenes)

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;

Some screenshots

Notice: In this picture there is a typo, ActiveX must be DirectX ;-)

More info about the DisplayLink problem: http://support.displaylink.com/knowledgebase/articles/543922-games-do-not-work-on-windows-with-displaylink-soft

来源:https://stackoverflow.com/questions/32062929/directx-full-screen-window-to-windowed-by-window-handle-with-use-windows-api-fun

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!