@@ -91,6 +91,22 @@ public static class ScreenshotManager
9191 private static extern IntPtr SetThreadDpiAwarenessContext ( IntPtr dpiContext ) ;
9292 private static readonly IntPtr DPI_PER_MONITOR_AWARE_V2 = new IntPtr ( - 4 ) ;
9393
94+ [ DllImport ( "user32.dll" , CharSet = CharSet . Auto ) ]
95+ private static extern IntPtr FindWindow ( string lpClassName , string lpWindowName ) ;
96+
97+ [ DllImport ( "user32.dll" ) ]
98+ [ return : MarshalAs ( UnmanagedType . Bool ) ]
99+ private static extern bool GetWindowRect ( IntPtr hWnd , out RECT lpRect ) ;
100+
101+ [ StructLayout ( LayoutKind . Sequential ) ]
102+ private struct RECT
103+ {
104+ public int Left ;
105+ public int Top ;
106+ public int Right ;
107+ public int Bottom ;
108+ }
109+
94110 [ DllImport ( "user32.dll" ) ]
95111 private static extern bool GetCursorInfo ( out CURSORINFO pci ) ;
96112
@@ -198,6 +214,62 @@ public static void TakeCustom(Settings settings, Action finishCallback)
198214 Application . Run ( new CustomScreenshotForm ( settings , finishCallback ) ) ;
199215 }
200216
217+ public static void TakeWindowScreenshot ( Settings settings , string windowTitle )
218+ {
219+ Logger . Log ( $ "TakeWindowScreenshot() called. WindowTitle='{ windowTitle } '") ;
220+ if ( string . IsNullOrEmpty ( settings . SavePath ) )
221+ {
222+ Logger . Log ( "TakeWindowScreenshot: SavePath is empty, aborting." ) ;
223+ return ;
224+ }
225+
226+ if ( string . IsNullOrWhiteSpace ( windowTitle ) )
227+ {
228+ Logger . Log ( "TakeWindowScreenshot: WindowTitle is empty, aborting." ) ;
229+ return ;
230+ }
231+
232+ WithHighDpiContext ( ( ) =>
233+ {
234+ IntPtr hWnd = FindWindow ( null , windowTitle ) ;
235+ if ( hWnd == IntPtr . Zero )
236+ {
237+ Logger . Log ( $ "TakeWindowScreenshot: Window '{ windowTitle } ' not found.") ;
238+ return ;
239+ }
240+
241+ if ( GetWindowRect ( hWnd , out RECT rect ) )
242+ {
243+ int width = rect . Right - rect . Left ;
244+ int height = rect . Bottom - rect . Top ;
245+
246+ if ( width <= 0 || height <= 0 )
247+ {
248+ Logger . Log ( $ "TakeWindowScreenshot: Invalid window dimensions { width } x{ height } ") ;
249+ return ;
250+ }
251+
252+ Rectangle bounds = new Rectangle ( rect . Left , rect . Top , width , height ) ;
253+ Logger . Log ( $ "TakeWindowScreenshot: Capturing window at { bounds } ") ;
254+
255+ using ( var bmp = new Bitmap ( width , height ) )
256+ using ( var g = Graphics . FromImage ( bmp ) )
257+ {
258+ g . CopyFromScreen ( bounds . Location , Point . Empty , bounds . Size ) ;
259+ if ( settings . ShowCursor )
260+ DrawCursor ( g , bounds ) ;
261+ SaveImageSafely ( bmp , settings ) ;
262+ }
263+ }
264+ else
265+ {
266+ Logger . Log ( $ "TakeWindowScreenshot: Failed to get window rect for '{ windowTitle } '") ;
267+ }
268+ } ) ;
269+
270+ ExecuteFinishAction ( settings ) ;
271+ }
272+
201273
202274 public static void CompositeCapture ( Rectangle rect , Settings settings )
203275 {
@@ -450,6 +522,12 @@ public static void ExecuteBang(IntPtr data, IntPtr args)
450522 ScreenshotManager . ExecuteFinishAction ( settings ) ;
451523 } ) ;
452524 }
525+ else if ( cmd . StartsWith ( "-ws|" , StringComparison . OrdinalIgnoreCase ) )
526+ {
527+ string windowTitle = cmd . Substring ( 4 ) ; // Extract everything after "-ws|"
528+ Logger . Log ( $ "ExecuteBang: Window screenshot requested for '{ windowTitle } '") ;
529+ ScreenshotManager . TakeWindowScreenshot ( settings , windowTitle ) ;
530+ }
453531 else if ( cmd . StartsWith ( "ExecuteBatch " , StringComparison . OrdinalIgnoreCase ) )
454532 {
455533 if ( int . TryParse ( cmd . Split ( ' ' ) [ 1 ] , out int code ) )
0 commit comments