Skip to content

Commit e80a06c

Browse files
author
Dave Bartolomeo
committed
Try grabbing screenshot
1 parent c70ec71 commit e80a06c

File tree

3 files changed

+302
-1
lines changed

3 files changed

+302
-1
lines changed

.github/workflows/main.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,3 +273,10 @@ jobs:
273273
if: matrix.os == 'windows-latest'
274274
run: |
275275
npm run test:cli-integration
276+
277+
- name: Upload screenshots (Windows)
278+
if: true
279+
uses: actions/upload-artifact@v2
280+
with:
281+
name: screenshots
282+
path: extensions/ql-vscode/*.png
Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
// 2>nul||@goto :batch
2+
/*
3+
:batch
4+
@echo off
5+
setlocal
6+
7+
:: find csc.exe
8+
set "csc="
9+
for /r "%SystemRoot%\Microsoft.NET\Framework\" %%# in ("*csc.exe") do set "csc=%%#"
10+
11+
if not exist "%csc%" (
12+
echo no .net framework installed
13+
exit /b 10
14+
)
15+
16+
if not exist "%~n0.exe" (
17+
call %csc% /nologo /r:"Microsoft.VisualBasic.dll" /out:"%~n0.exe" "%~dpsfnx0" || (
18+
exit /b %errorlevel%
19+
)
20+
)
21+
%~n0.exe %*
22+
endlocal & exit /b %errorlevel%
23+
24+
*/
25+
26+
// reference
27+
// https://gallery.technet.microsoft.com/scriptcenter/eeff544a-f690-4f6b-a586-11eea6fc5eb8
28+
29+
using System;
30+
using System.Runtime.InteropServices;
31+
using System.Drawing;
32+
using System.Drawing.Imaging;
33+
using System.Collections.Generic;
34+
using Microsoft.VisualBasic;
35+
36+
37+
/// Provides functions to capture the entire screen, or a particular window, and save it to a file.
38+
39+
public class ScreenCapture
40+
{
41+
42+
/// Creates an Image object containing a screen shot the active window
43+
44+
public Image CaptureActiveWindow()
45+
{
46+
return CaptureWindow(User32.GetForegroundWindow());
47+
}
48+
49+
/// Creates an Image object containing a screen shot of the entire desktop
50+
51+
public Image CaptureScreen()
52+
{
53+
return CaptureWindow(User32.GetDesktopWindow());
54+
}
55+
56+
/// Creates an Image object containing a screen shot of a specific window
57+
58+
private Image CaptureWindow(IntPtr handle)
59+
{
60+
// get te hDC of the target window
61+
IntPtr hdcSrc = User32.GetWindowDC(handle);
62+
// get the size
63+
User32.RECT windowRect = new User32.RECT();
64+
User32.GetWindowRect(handle, ref windowRect);
65+
int width = windowRect.right - windowRect.left;
66+
int height = windowRect.bottom - windowRect.top;
67+
// create a device context we can copy to
68+
IntPtr hdcDest = GDI32.CreateCompatibleDC(hdcSrc);
69+
// create a bitmap we can copy it to,
70+
// using GetDeviceCaps to get the width/height
71+
IntPtr hBitmap = GDI32.CreateCompatibleBitmap(hdcSrc, width, height);
72+
// select the bitmap object
73+
IntPtr hOld = GDI32.SelectObject(hdcDest, hBitmap);
74+
// bitblt over
75+
GDI32.BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, GDI32.SRCCOPY);
76+
// restore selection
77+
GDI32.SelectObject(hdcDest, hOld);
78+
// clean up
79+
GDI32.DeleteDC(hdcDest);
80+
User32.ReleaseDC(handle, hdcSrc);
81+
// get a .NET image object for it
82+
Image img = Image.FromHbitmap(hBitmap);
83+
// free up the Bitmap object
84+
GDI32.DeleteObject(hBitmap);
85+
return img;
86+
}
87+
88+
public void CaptureActiveWindowToFile(string filename, ImageFormat format)
89+
{
90+
Image img = CaptureActiveWindow();
91+
img.Save(filename, format);
92+
}
93+
94+
public void CaptureScreenToFile(string filename, ImageFormat format)
95+
{
96+
Image img = CaptureScreen();
97+
img.Save(filename, format);
98+
}
99+
100+
static bool fullscreen = true;
101+
static String file = "screenshot.bmp";
102+
static System.Drawing.Imaging.ImageFormat format = System.Drawing.Imaging.ImageFormat.Bmp;
103+
static String windowTitle = "";
104+
105+
static void parseArguments()
106+
{
107+
String[] arguments = Environment.GetCommandLineArgs();
108+
if (arguments.Length == 1)
109+
{
110+
printHelp();
111+
Environment.Exit(0);
112+
}
113+
if (arguments[1].ToLower().Equals("/h") || arguments[1].ToLower().Equals("/help"))
114+
{
115+
printHelp();
116+
Environment.Exit(0);
117+
}
118+
119+
file = arguments[1];
120+
Dictionary<String, System.Drawing.Imaging.ImageFormat> formats =
121+
new Dictionary<String, System.Drawing.Imaging.ImageFormat>();
122+
123+
formats.Add("bmp", System.Drawing.Imaging.ImageFormat.Bmp);
124+
formats.Add("emf", System.Drawing.Imaging.ImageFormat.Emf);
125+
formats.Add("exif", System.Drawing.Imaging.ImageFormat.Exif);
126+
formats.Add("jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
127+
formats.Add("jpeg", System.Drawing.Imaging.ImageFormat.Jpeg);
128+
formats.Add("gif", System.Drawing.Imaging.ImageFormat.Gif);
129+
formats.Add("png", System.Drawing.Imaging.ImageFormat.Png);
130+
formats.Add("tiff", System.Drawing.Imaging.ImageFormat.Tiff);
131+
formats.Add("wmf", System.Drawing.Imaging.ImageFormat.Wmf);
132+
133+
134+
String ext = "";
135+
if (file.LastIndexOf('.') > -1)
136+
{
137+
ext = file.ToLower().Substring(file.LastIndexOf('.') + 1, file.Length - file.LastIndexOf('.') - 1);
138+
}
139+
else
140+
{
141+
Console.WriteLine("Invalid file name - no extension");
142+
Environment.Exit(7);
143+
}
144+
145+
try
146+
{
147+
format = formats[ext];
148+
}
149+
catch (Exception e)
150+
{
151+
Console.WriteLine("Probably wrong file format:" + ext);
152+
Console.WriteLine(e.ToString());
153+
Environment.Exit(8);
154+
}
155+
156+
157+
if (arguments.Length > 2)
158+
{
159+
windowTitle = arguments[2];
160+
fullscreen = false;
161+
}
162+
163+
}
164+
165+
static void printHelp()
166+
{
167+
//clears the extension from the script name
168+
String scriptName = Environment.GetCommandLineArgs()[0];
169+
scriptName = scriptName.Substring(0, scriptName.Length);
170+
Console.WriteLine(scriptName + " captures the screen or the active window and saves it to a file.");
171+
Console.WriteLine("");
172+
Console.WriteLine("Usage:");
173+
Console.WriteLine(" " + scriptName + " filename [WindowTitle]");
174+
Console.WriteLine("");
175+
Console.WriteLine("filename - the file where the screen capture will be saved");
176+
Console.WriteLine(" allowed file extensions are - Bmp,Emf,Exif,Gif,Icon,Jpeg,Png,Tiff,Wmf.");
177+
Console.WriteLine("WindowTitle - instead of capture whole screen you can point to a window ");
178+
Console.WriteLine(" with a title which will put on focus and captuted.");
179+
Console.WriteLine(" For WindowTitle you can pass only the first few characters.");
180+
Console.WriteLine(" If don't want to change the current active window pass only \"\"");
181+
}
182+
183+
public static void Main()
184+
{
185+
User32.SetProcessDPIAware();
186+
187+
parseArguments();
188+
ScreenCapture sc = new ScreenCapture();
189+
if (!fullscreen && !windowTitle.Equals(""))
190+
{
191+
try
192+
{
193+
194+
Interaction.AppActivate(windowTitle);
195+
Console.WriteLine("setting " + windowTitle + " on focus");
196+
}
197+
catch (Exception e)
198+
{
199+
Console.WriteLine("Probably there's no window like " + windowTitle);
200+
Console.WriteLine(e.ToString());
201+
Environment.Exit(9);
202+
}
203+
204+
205+
}
206+
try
207+
{
208+
if (fullscreen)
209+
{
210+
Console.WriteLine("Taking a capture of the whole screen to " + file);
211+
sc.CaptureScreenToFile(file, format);
212+
}
213+
else
214+
{
215+
Console.WriteLine("Taking a capture of the active window to " + file);
216+
sc.CaptureActiveWindowToFile(file, format);
217+
}
218+
}
219+
catch (Exception e)
220+
{
221+
Console.WriteLine("Check if file path is valid " + file);
222+
Console.WriteLine(e.ToString());
223+
}
224+
}
225+
226+
/// Helper class containing Gdi32 API functions
227+
228+
private class GDI32
229+
{
230+
231+
public const int SRCCOPY = 0x00CC0020; // BitBlt dwRop parameter
232+
[DllImport("gdi32.dll")]
233+
public static extern bool BitBlt(IntPtr hObject, int nXDest, int nYDest,
234+
int nWidth, int nHeight, IntPtr hObjectSource,
235+
int nXSrc, int nYSrc, int dwRop);
236+
[DllImport("gdi32.dll")]
237+
public static extern IntPtr CreateCompatibleBitmap(IntPtr hDC, int nWidth,
238+
int nHeight);
239+
[DllImport("gdi32.dll")]
240+
public static extern IntPtr CreateCompatibleDC(IntPtr hDC);
241+
[DllImport("gdi32.dll")]
242+
public static extern bool DeleteDC(IntPtr hDC);
243+
[DllImport("gdi32.dll")]
244+
public static extern bool DeleteObject(IntPtr hObject);
245+
[DllImport("gdi32.dll")]
246+
public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
247+
}
248+
249+
250+
/// Helper class containing User32 API functions
251+
252+
private class User32
253+
{
254+
[StructLayout(LayoutKind.Sequential)]
255+
public struct RECT
256+
{
257+
public int left;
258+
public int top;
259+
public int right;
260+
public int bottom;
261+
}
262+
[DllImport("user32.dll")]
263+
public static extern IntPtr GetDesktopWindow();
264+
[DllImport("user32.dll")]
265+
public static extern IntPtr GetWindowDC(IntPtr hWnd);
266+
[DllImport("user32.dll")]
267+
public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC);
268+
[DllImport("user32.dll")]
269+
public static extern IntPtr GetWindowRect(IntPtr hWnd, ref RECT rect);
270+
[DllImport("user32.dll")]
271+
public static extern IntPtr GetForegroundWindow();
272+
[DllImport("user32.dll")]
273+
public static extern int SetProcessDPIAware();
274+
}
275+
}

extensions/ql-vscode/test/vscode-tests/cli-integration/queries.test.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,14 @@ import {
4545
import { ProgressCallback } from "../../../src/common/vscode/progress";
4646
import { withDebugController } from "./debugger/debug-controller";
4747
import { getDataFolderFilePath } from "./utils";
48+
import { spawn } from "child-process-promise";
4849

4950
const simpleQueryPath = getDataFolderFilePath("debugger/simple-query.ql");
5051

5152
type DebugMode = "localQueries" | "debug";
5253

54+
let screenshotCount = 0;
55+
5356
async function compileAndRunQuery(
5457
mode: DebugMode,
5558
appCommands: AppCommandManager,
@@ -98,12 +101,28 @@ async function compileAndRunQuery(
98101
console.log(`QL config: ${qlConfig}`);
99102
console.log(`CodeQL config: ${codeqlConfig}`);
100103
console.log("Starting debugging");
101-
await controller.startDebugging(
104+
const start = controller.startDebugging(
102105
{
103106
query: queryUri.fsPath,
104107
},
105108
true,
106109
);
110+
let timedOut = false;
111+
const timeout = new Promise<void>((resolve) =>
112+
setTimeout(() => {
113+
timedOut = true;
114+
resolve();
115+
}, 10000),
116+
);
117+
await Promise.race([start, timeout]);
118+
if (timedOut) {
119+
const screenshotPath = `screenshot-${screenshotCount++}.png`;
120+
console.log("Timed out waiting for debug session to start");
121+
await spawn(".\\screenshot.bat", [screenshotPath], {
122+
shell: true,
123+
});
124+
}
125+
107126
console.log("Waiting for launch");
108127
await controller.expectLaunched();
109128
console.log("Checking success");

0 commit comments

Comments
 (0)