├── screenrecorder
├── ScreenRecorder
│ ├── pch.cpp
│ ├── Client.h
│ ├── packages.config
│ ├── ScreenRecorderProvider.h
│ ├── Server.h
│ ├── CommandLine.h
│ ├── Client.cpp
│ ├── ScreenRecorder.h
│ ├── Response.h
│ ├── CircularFrameBuffer.h
│ ├── Request.h
│ ├── Response.cpp
│ ├── Pipe.h
│ ├── DataStream.h
│ ├── MonitorInfo.h
│ ├── Request.cpp
│ ├── pch.h
│ ├── DataStream.cpp
│ ├── CommandLine.cpp
│ ├── ScreenRecorder.cpp
│ ├── Pipe.cpp
│ ├── SimpleCapture.h
│ ├── Server.cpp
│ ├── ScreenRecorder.vcxproj.filters
│ ├── CircularFrameBuffer.cpp
│ ├── SimpleCapture.cpp
│ ├── ScreenRecorder.vcxproj
│ └── main.cpp
├── LaunchDetectorScript
│ ├── requirements.txt
│ ├── Build-Project.ps1
│ ├── LaunchDetectorScript.spec
│ ├── LaunchDetectorScript.pyproj
│ └── LaunchDetectorScript.py
├── GAUSS
│ ├── Properties
│ │ └── launchSettings.json
│ ├── ICommandFactory.cs
│ ├── Program.cs
│ ├── ICommand.cs
│ ├── HelpCommand.cs
│ ├── HelpCommandFactory.cs
│ ├── GAUSS.csproj
│ ├── GAUSS.cs
│ ├── MeasureCommandFactory.cs
│ ├── Utilities.cs
│ ├── MeasureCommand.cs
│ └── profile.wprp
└── screenrecorder.sln
├── CODE_OF_CONDUCT.md
├── LICENSE
├── SUPPORT.md
├── SECURITY.md
├── README.md
└── .gitignore
/screenrecorder/ScreenRecorder/pch.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 |
--------------------------------------------------------------------------------
/screenrecorder/LaunchDetectorScript/requirements.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/screenrecorder/HEAD/screenrecorder/LaunchDetectorScript/requirements.txt
--------------------------------------------------------------------------------
/screenrecorder/GAUSS/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "GAUSS": {
4 | "commandName": "Project",
5 | "commandLineArgs": "-measure 5 2 -outputpath C:\\"
6 | }
7 | }
8 | }
--------------------------------------------------------------------------------
/screenrecorder/GAUSS/ICommandFactory.cs:
--------------------------------------------------------------------------------
1 | namespace GAUSS
2 | {
3 | public interface ICommandFactory
4 | {
5 | public string CommandName { get; }
6 | public string CommandHelp { get; }
7 | ICommand? Create(string[] args);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/screenrecorder/GAUSS/Program.cs:
--------------------------------------------------------------------------------
1 | namespace GAUSS
2 | {
3 | public class Program
4 | {
5 | public static void Main(string[] args)
6 | {
7 | GAUSS gauss = new GAUSS();
8 | gauss.ProcessCommandLine(args);
9 | }
10 | }
11 | }
--------------------------------------------------------------------------------
/screenrecorder/LaunchDetectorScript/Build-Project.ps1:
--------------------------------------------------------------------------------
1 | Write-Output "Building python project."
2 |
3 | # Get the path of the script
4 | $scriptPath = $PSScriptRoot
5 |
6 | # Construct the path to the spec file
7 | $specFilePath = Join-Path -Path $scriptPath -ChildPath "LaunchDetectorScript.spec"
8 |
9 | pyinstaller $specFilePath
10 |
--------------------------------------------------------------------------------
/screenrecorder/ScreenRecorder/Client.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "pch.h"
4 | #include "Pipe.h"
5 | #include "Request.h"
6 | #include "Response.h"
7 |
8 | class Client {
9 | public:
10 | bool try_connect();
11 | bool try_connect(int retries);
12 |
13 | Response send(Request& request) const;
14 |
15 | private:
16 | Pipe m_pipe;
17 | };
18 |
--------------------------------------------------------------------------------
/screenrecorder/ScreenRecorder/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/screenrecorder/GAUSS/ICommand.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Windows.EventTracing;
2 | using Microsoft.Windows.EventTracing.Cpu;
3 | using Microsoft.Windows.EventTracing.Events;
4 | using Microsoft.Windows.EventTracing.Processes;
5 | using System.ComponentModel;
6 | using System.Diagnostics;
7 |
8 | namespace GAUSS
9 | {
10 | public interface ICommand
11 | {
12 | public bool CanPerform();
13 | public void Perform();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Microsoft Open Source Code of Conduct
2 |
3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
4 |
5 | Resources:
6 |
7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
10 |
--------------------------------------------------------------------------------
/screenrecorder/ScreenRecorder/ScreenRecorderProvider.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "pch.h"
4 |
5 | // Forward-declare the g_hMyComponentProvider variable that will be used in any class that wants to log events for the screen recorder.
6 | TRACELOGGING_DECLARE_PROVIDER(g_hMyComponentProvider);
7 |
8 | #define ReceivedFrameEvent(filename) \
9 | TraceLoggingWrite(g_hMyComponentProvider, \
10 | "ReceivedFrame", \
11 | TraceLoggingString(filename.c_str(), "Filename"))
12 |
13 |
14 |
--------------------------------------------------------------------------------
/screenrecorder/ScreenRecorder/Server.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "pch.h"
4 | #include "Pipe.h"
5 | #include "Request.h"
6 | #include "Response.h"
7 | #include "ScreenRecorder.h"
8 |
9 | // The purpose of this class is to receive screen recording requests from clients and proces them.
10 | class Server {
11 | public:
12 | bool try_init();
13 | void run();
14 |
15 | private:
16 | Response serve_request(Request& request, RequestType requestType);
17 |
18 | Pipe m_pipe;
19 | ScreenRecorder m_screenRecorder;
20 | bool m_isRunning;
21 | bool m_isConnectedToClient;
22 | };
--------------------------------------------------------------------------------
/screenrecorder/ScreenRecorder/CommandLine.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "pch.h"
4 |
5 | enum class CommandType { Start, Stop, Cancel, NewServer, Help, Unknown };
6 |
7 | class CommandLine {
8 | public:
9 | CommandLine(int argc, char* argv[]) : m_argc(argc), m_argv(argv) {}
10 |
11 | CommandType GetCommandType() const;
12 | void GetStartArgs(int& framerate, int& monitor, int& bufferSize, bool& isMegabytes) const;
13 | void GetStopArgs(std::string& folder) const;
14 | void GetHelpArgs(std::string& arg) const;
15 |
16 | private:
17 | int m_argc;
18 | char** m_argv;
19 | };
20 |
--------------------------------------------------------------------------------
/screenrecorder/GAUSS/HelpCommand.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Windows.EventTracing;
2 |
3 | namespace GAUSS
4 | {
5 | public class HelpCommand : ICommand
6 | {
7 | private ICommandFactory commandFactory;
8 |
9 | public HelpCommand(ICommandFactory commandFactory)
10 | {
11 | this.commandFactory = commandFactory;
12 | }
13 |
14 | public bool CanPerform()
15 | {
16 | return true;
17 | }
18 |
19 | public void Perform()
20 | {
21 | Console.WriteLine(commandFactory.CommandHelp);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/screenrecorder/ScreenRecorder/Client.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "Client.h"
3 |
4 | bool Client::try_connect()
5 | {
6 | return m_pipe.try_init(L"myPipe", Pipe::CLIENT);
7 | }
8 |
9 | bool Client::try_connect(int retries)
10 | {
11 | while (!try_connect() && retries >= 0)
12 | {
13 | std::this_thread::sleep_for(std::chrono::seconds(1));
14 |
15 | retries--;
16 | }
17 |
18 | return retries >= 0;
19 | }
20 |
21 | Response Client::send(Request& request) const
22 | {
23 | m_pipe.send(request.ToString());
24 |
25 | return Response::FromString(m_pipe.receive());
26 | }
27 |
--------------------------------------------------------------------------------
/screenrecorder/ScreenRecorder/ScreenRecorder.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "pch.h"
4 | #include "SimpleCapture.h"
5 |
6 | class ScreenRecorder {
7 | public:
8 | ScreenRecorder();
9 | ~ScreenRecorder();
10 |
11 | static const int default_framerate = 1;
12 | static const int default_monitor = 0;
13 | static const int default_bufferCapacity = 10;
14 | static const bool default_asMegabytes = false;
15 |
16 | void start(int framerate, int monitor, int bufferCapacity, bool asMegabytes);
17 | void stop(const std::string& folderPath);
18 | void cancel();
19 |
20 | private:
21 | std::unique_ptr m_simpleCapture;
22 | bool isCapturing;
23 | };
--------------------------------------------------------------------------------
/screenrecorder/ScreenRecorder/Response.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "pch.h"
4 | #include "DataStream.h"
5 |
6 | enum class ResponseType { Success, Exception, Unknown };
7 |
8 | class Response {
9 | public:
10 | Response();
11 |
12 | static Response FromString(const std::string& str);
13 |
14 | static Response BuildSuccessResponse();
15 | static Response BuildExceptionResponse(const std::exception& e);
16 |
17 | void ParseExceptionArgs(std::exception& e);
18 |
19 | ResponseType ParseResponseType();
20 |
21 | std::string ToString() const;
22 |
23 | private:
24 | Response(const DataStream& dataStream) : m_dataStream(dataStream) {}
25 |
26 | DataStream m_dataStream;
27 | };
28 |
--------------------------------------------------------------------------------
/screenrecorder/ScreenRecorder/CircularFrameBuffer.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "pch.h"
4 |
5 | namespace util
6 | {
7 | using namespace robmikh::common::uwp;
8 | }
9 |
10 | class CircularFrameBuffer {
11 | public:
12 | struct Frame {
13 | winrt::com_ptr texture;
14 | std::string filename;
15 | size_t size;
16 | };
17 |
18 | CircularFrameBuffer(size_t capacity, bool asMegabytes);
19 |
20 | void add_frame(winrt::com_ptr texture, const std::string& filename);
21 | void save_frames(winrt::Windows::Storage::StorageFolder storageFolder);
22 |
23 | private:
24 | size_t calculate_frame_size(winrt::com_ptr texture);
25 |
26 | size_t m_capacity;
27 | bool m_asMegabytes;
28 |
29 | size_t m_memoryUsage;
30 | std::deque m_frames;
31 | };
32 |
--------------------------------------------------------------------------------
/screenrecorder/LaunchDetectorScript/LaunchDetectorScript.spec:
--------------------------------------------------------------------------------
1 | # -*- mode: python ; coding: utf-8 -*-
2 |
3 |
4 | a = Analysis(
5 | ['LaunchDetectorScript.py'],
6 | pathex=[],
7 | binaries=[],
8 | datas=[],
9 | hiddenimports=[],
10 | hookspath=[],
11 | hooksconfig={},
12 | runtime_hooks=[],
13 | excludes=[],
14 | noarchive=False,
15 | )
16 | pyz = PYZ(a.pure)
17 |
18 | exe = EXE(
19 | pyz,
20 | a.scripts,
21 | a.binaries,
22 | a.datas,
23 | [],
24 | name='LaunchDetectorScript',
25 | debug=False,
26 | bootloader_ignore_signals=False,
27 | strip=False,
28 | upx=True,
29 | upx_exclude=[],
30 | runtime_tmpdir=None,
31 | console=True,
32 | disable_windowed_traceback=False,
33 | argv_emulation=False,
34 | target_arch=None,
35 | codesign_identity=None,
36 | entitlements_file=None,
37 | )
38 |
--------------------------------------------------------------------------------
/screenrecorder/ScreenRecorder/Request.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "pch.h"
4 | #include "DataStream.h"
5 |
6 | enum class RequestType { Start, Stop, Cancel, Disconnect, Kill, Unknown };
7 |
8 | class Request {
9 | public:
10 | Request();
11 |
12 | static Request FromString(const std::string& str);
13 |
14 | static Request BuildStartRequest(int arg1, int arg2, int arg3, bool arg4);
15 | static Request BuildStopRequest(const std::string& arg1);
16 | static Request BuildCancelRequest();
17 | static Request BuildDisconnectRequest();
18 | static Request BuildKillRequest();
19 |
20 | void ParseStartArgs(int& arg1, int& arg2, int& arg3, bool& arg4);
21 | void ParseStopArgs(std::string& arg1);
22 |
23 | RequestType ParseRequestType();
24 |
25 | std::string ToString() const;
26 |
27 | private:
28 | Request(const DataStream& dataStream) : m_dataStream(dataStream) {}
29 |
30 | DataStream m_dataStream;
31 | };
32 |
--------------------------------------------------------------------------------
/screenrecorder/ScreenRecorder/Response.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "Response.h"
3 |
4 | Response::Response()
5 | {
6 | }
7 |
8 | Response Response::FromString(const std::string& str)
9 | {
10 | return Response(DataStream::FromString(str));
11 | }
12 |
13 | Response Response::BuildSuccessResponse()
14 | {
15 | DataStream stream;
16 |
17 | stream.WriteEnum(ResponseType::Success);
18 |
19 | return Response(stream);
20 | }
21 |
22 | Response Response::BuildExceptionResponse(const std::exception& e)
23 | {
24 | DataStream stream;
25 |
26 | stream.WriteEnum(ResponseType::Exception);
27 | stream.WriteException(e);
28 |
29 | return Response(stream);
30 | }
31 |
32 | void Response::ParseExceptionArgs(std::exception& e)
33 | {
34 | e = m_dataStream.ReadException();
35 | }
36 |
37 | ResponseType Response::ParseResponseType()
38 | {
39 | try
40 | {
41 | return m_dataStream.ReadEnum();
42 | }
43 | catch (const std::runtime_error&)
44 | {
45 | return ResponseType::Unknown;
46 | }
47 | }
48 |
49 | std::string Response::ToString() const
50 | {
51 | return m_dataStream.ToString();
52 | }
53 |
--------------------------------------------------------------------------------
/screenrecorder/ScreenRecorder/Pipe.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "pch.h"
4 |
5 | // The purpose of this class is to wrap communication via a named pipe. It allows a server and client to send messages to each other.
6 | class Pipe {
7 | public:
8 | enum Mode { SERVER, CLIENT };
9 | Pipe();
10 | ~Pipe();
11 | bool try_init(const std::wstring& name, Mode mode);
12 |
13 | /**
14 | * @throws std::ios_base::failure if function fails
15 | */
16 | void send(const std::string& message) const;
17 |
18 | /**
19 | * @throws std::ios_base::failure if function fails
20 | */
21 | std::string receive() const;
22 |
23 | /**
24 | * @throws std::invalid_argument if called on a SERVER pipe
25 | * @throws std::ios_base::failure if attempt to disconnect fails
26 | */
27 | void disconnect() const;
28 |
29 | /**
30 | * @throws std::invalid_argument if called on a SERVER pipe
31 | * @throws std::ios_base::failure if attempt to connect fails
32 | */
33 | void connect() const;
34 |
35 | private:
36 | std::wstring m_name;
37 | HANDLE m_hpipe;
38 | Mode m_mode;
39 | };
--------------------------------------------------------------------------------
/screenrecorder/GAUSS/HelpCommandFactory.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Windows.EventTracing;
2 | using System.ComponentModel.Design;
3 |
4 | namespace GAUSS
5 | {
6 | public class HelpCommandFactory : ICommandFactory
7 | {
8 | public string CommandName => "help";
9 |
10 | public string CommandHelp => @"
11 | Usage: GAUSS options ...
12 |
13 | -help measure - for GAUSS measure command";
14 |
15 | private List commandFactories;
16 |
17 | public HelpCommandFactory(List commandFactories)
18 | {
19 | this.commandFactories = commandFactories;
20 | }
21 |
22 | public ICommand? Create(string[] args)
23 | {
24 | if (args.Length != 1)
25 | {
26 | return null;
27 | }
28 |
29 | List matchingFactories = commandFactories.Where(f => f.CommandName.Equals(args[0])).ToList();
30 |
31 | if (matchingFactories.Count != 1)
32 | {
33 | return null;
34 | }
35 |
36 | return new HelpCommand(matchingFactories[0]);
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Microsoft Corporation.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE
22 |
--------------------------------------------------------------------------------
/screenrecorder/GAUSS/GAUSS.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net8.0
6 | enable
7 | enable
8 | AnyCPU;ARM64;x64
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | PreserveNewest
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/screenrecorder/ScreenRecorder/DataStream.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "pch.h"
4 |
5 | class DataStream {
6 | public:
7 | DataStream();
8 | DataStream(const DataStream& other);
9 | DataStream& operator=(const DataStream& other);
10 |
11 | void WriteInt(int value);
12 | int ReadInt();
13 |
14 | void WriteBool(bool value);
15 | bool ReadBool();
16 |
17 | void WriteString(const std::string& value);
18 | std::string ReadString();
19 |
20 | void WriteException(const std::exception& e);
21 | std::exception ReadException();
22 |
23 | template
24 | typename std::enable_if::value, void>::type
25 | WriteEnum(T value) {
26 | m_stream << static_cast::type>(value) << ' ';
27 | }
28 |
29 | template
30 | typename std::enable_if::value, T>::type
31 | ReadEnum() {
32 | typename std::underlying_type::type intValue;
33 | if (!(m_stream >> intValue))
34 | throw std::runtime_error("Error reading enum from stream");
35 | return static_cast(intValue);
36 | }
37 |
38 | std::string ToString() const;
39 | static DataStream FromString(const std::string& str);
40 |
41 | private:
42 | std::stringstream m_stream;
43 | };
44 |
--------------------------------------------------------------------------------
/SUPPORT.md:
--------------------------------------------------------------------------------
1 | # TODO: The maintainer of this repo has not yet edited this file
2 |
3 | **REPO OWNER**: Do you want Customer Service & Support (CSS) support for this product/project?
4 |
5 | - **No CSS support:** Fill out this template with information about how to file issues and get help.
6 | - **Yes CSS support:** Fill out an intake form at [aka.ms/onboardsupport](https://aka.ms/onboardsupport). CSS will work with/help you to determine next steps.
7 | - **Not sure?** Fill out an intake as though the answer were "Yes". CSS will help you decide.
8 |
9 | *Then remove this first heading from this SUPPORT.MD file before publishing your repo.*
10 |
11 | # Support
12 |
13 | ## How to file issues and get help
14 |
15 | This project uses GitHub Issues to track bugs and feature requests. Please search the existing
16 | issues before filing new issues to avoid duplicates. For new issues, file your bug or
17 | feature request as a new Issue.
18 |
19 | For help and questions about using this project, please **REPO MAINTAINER: INSERT INSTRUCTIONS HERE
20 | FOR HOW TO ENGAGE REPO OWNERS OR COMMUNITY FOR HELP. COULD BE A STACK OVERFLOW TAG OR OTHER
21 | CHANNEL. WHERE WILL YOU HELP PEOPLE?**.
22 |
23 | ## Microsoft Support Policy
24 |
25 | Support for this **PROJECT or PRODUCT** is limited to the resources listed above.
26 |
--------------------------------------------------------------------------------
/screenrecorder/ScreenRecorder/MonitorInfo.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "pch.h"
4 |
5 | // The purpose of this class is to get the handles to available monitors.
6 | struct MonitorInfo
7 | {
8 | MonitorInfo(HMONITOR monitorHandle)
9 | {
10 | MonitorHandle = monitorHandle;
11 | MONITORINFOEX monitorInfo = { sizeof(monitorInfo) };
12 | winrt::check_bool(GetMonitorInfo(MonitorHandle, &monitorInfo));
13 | std::wstring displayName(monitorInfo.szDevice);
14 | DisplayName = displayName;
15 | }
16 | MonitorInfo(HMONITOR monitorHandle, std::wstring const& displayName)
17 | {
18 | MonitorHandle = monitorHandle;
19 | DisplayName = displayName;
20 | }
21 |
22 | HMONITOR MonitorHandle;
23 | std::wstring DisplayName;
24 |
25 | bool operator==(const MonitorInfo& monitor) { return MonitorHandle == monitor.MonitorHandle; }
26 | bool operator!=(const MonitorInfo& monitor) { return !(*this == monitor); }
27 |
28 | static std::vector EnumerateAllMonitors(bool includeAllMonitors)
29 | {
30 | std::vector monitors;
31 | EnumDisplayMonitors(nullptr, nullptr, [](HMONITOR hmon, HDC, LPRECT, LPARAM lparam)
32 | {
33 | auto& monitors = *reinterpret_cast*>(lparam);
34 | monitors.push_back(MonitorInfo(hmon));
35 |
36 | return TRUE;
37 | }, reinterpret_cast(&monitors));
38 | if (monitors.size() > 1 && includeAllMonitors)
39 | {
40 | monitors.push_back(MonitorInfo(nullptr, L"All Displays"));
41 | }
42 | return monitors;
43 | }
44 | };
45 |
46 |
--------------------------------------------------------------------------------
/screenrecorder/GAUSS/GAUSS.cs:
--------------------------------------------------------------------------------
1 | namespace GAUSS
2 | {
3 | public class GAUSS
4 | {
5 | private ICommandFactory helpCommandFactory;
6 | private List commandFactories;
7 |
8 | public GAUSS()
9 | {
10 | commandFactories = new List
11 | {
12 | new MeasureCommandFactory(),
13 | };
14 |
15 | helpCommandFactory = new HelpCommandFactory(commandFactories);
16 | commandFactories.Add(helpCommandFactory);
17 | }
18 |
19 | public void ProcessCommandLine(string[] commandLine)
20 | {
21 | if (commandLine.Length == 0)
22 | {
23 | Console.WriteLine(helpCommandFactory.CommandHelp);
24 |
25 | return;
26 | }
27 |
28 | string commandToken = commandLine[0];
29 |
30 | foreach(ICommandFactory commandFactory in commandFactories)
31 | {
32 | if (commandToken.Equals($"-{commandFactory.CommandName}"))
33 | {
34 | ICommand? command = commandFactory.Create(commandLine.Skip(1).ToArray());
35 |
36 | if (command == null)
37 | {
38 | Console.WriteLine(commandFactory.CommandHelp);
39 | }
40 | else if (command.CanPerform())
41 | {
42 | command.Perform();
43 | }
44 |
45 | return;
46 | }
47 | }
48 |
49 | Console.WriteLine(helpCommandFactory.CommandHelp);
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/screenrecorder/GAUSS/MeasureCommandFactory.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Windows.EventTracing;
2 |
3 | namespace GAUSS
4 | {
5 | public class MeasureCommandFactory : ICommandFactory
6 | {
7 | public string CommandName => "measure";
8 |
9 | public string CommandHelp => @"
10 | GAUSS -measure ... Starts GAUSS measurment of a scenario duration
11 | Usage: GAUSS -measure
12 | [-output ]
13 | Ex> GAUSS -measure 5 2
14 | Ex> GAUSS -measure 20 1 -output C:\gaussoutput
15 |
16 | Duration for which to record the target scenario in seconds.
17 | Framerate at which to record the target scenario in FPS.
18 | -outputpath Specifies the folder to which to save screenshots and trace
19 | of the scenario measured.";
20 |
21 | public ICommand? Create(string[] args)
22 | {
23 | if (args.Length < 2)
24 | {
25 | return null;
26 | }
27 |
28 | if (!int.TryParse(args[0], out int durationParse))
29 | {
30 | return null;
31 | }
32 |
33 | Duration duration = Duration.FromSeconds(durationParse);
34 |
35 | if (!double.TryParse(args[1], out double framerate))
36 | {
37 | return null;
38 | }
39 |
40 | MeasureCommand command = new MeasureCommand(duration, framerate);
41 |
42 | for (int i = 2; i < args.Length; i++)
43 | {
44 | if (args[i].Equals("-outputpath"))
45 | {
46 | command.OutputPath = args[++i];
47 | }
48 | else
49 | {
50 | return null;
51 | }
52 | }
53 |
54 | return command;
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/screenrecorder/LaunchDetectorScript/LaunchDetectorScript.pyproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | Debug
4 | 2.0
5 | 5f5b763c-e633-4089-af35-ca3fc5b23c43
6 | .
7 | LaunchDetectorScript.py
8 |
9 |
10 | .
11 | .
12 | LaunchDetectorScript
13 | LaunchDetectorScript
14 | True
15 |
16 |
17 | true
18 | false
19 |
20 |
21 | true
22 | false
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/screenrecorder/ScreenRecorder/Request.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "Request.h"
3 |
4 | Request::Request()
5 | {
6 | }
7 |
8 | Request Request::FromString(const std::string& str)
9 | {
10 | return Request(DataStream::FromString(str));
11 | }
12 |
13 | Request Request::BuildStartRequest(int framerate, int monitor, int bufferSize, bool isMegabytes)
14 | {
15 | DataStream stream;
16 |
17 | stream.WriteEnum(RequestType::Start);
18 | stream.WriteInt(framerate);
19 | stream.WriteInt(monitor);
20 | stream.WriteInt(bufferSize);
21 | stream.WriteBool(isMegabytes);
22 |
23 | return Request(stream);
24 | }
25 |
26 | Request Request::BuildStopRequest(const std::string& folder)
27 | {
28 | DataStream stream;
29 |
30 | stream.WriteEnum(RequestType::Stop);
31 | stream.WriteString(folder);
32 |
33 | return Request(stream);
34 | }
35 |
36 | Request Request::BuildCancelRequest()
37 | {
38 | DataStream stream;
39 |
40 | stream.WriteEnum(RequestType::Cancel);
41 |
42 | return Request(stream);
43 | }
44 |
45 | Request Request::BuildDisconnectRequest()
46 | {
47 | DataStream stream;
48 |
49 | stream.WriteEnum(RequestType::Disconnect);
50 |
51 | return Request(stream);
52 | }
53 |
54 | Request Request::BuildKillRequest()
55 | {
56 | DataStream stream;
57 |
58 | stream.WriteEnum(RequestType::Kill);
59 |
60 | return Request(stream);
61 | }
62 |
63 | void Request::ParseStartArgs(int& framerate, int& monitor, int& bufferSize, bool& isMegabytes)
64 | {
65 | framerate = m_dataStream.ReadInt();
66 | monitor = m_dataStream.ReadInt();
67 | bufferSize = m_dataStream.ReadInt();
68 | isMegabytes = m_dataStream.ReadBool();
69 | }
70 |
71 | void Request::ParseStopArgs(std::string& folder)
72 | {
73 | folder = m_dataStream.ReadString();
74 | }
75 |
76 | RequestType Request::ParseRequestType()
77 | {
78 | try
79 | {
80 | return m_dataStream.ReadEnum();
81 | }
82 | catch (const std::runtime_error&)
83 | {
84 | return RequestType::Unknown;
85 | }
86 | }
87 |
88 | std::string Request::ToString() const
89 | {
90 | return m_dataStream.ToString();
91 | }
92 |
--------------------------------------------------------------------------------
/screenrecorder/ScreenRecorder/pch.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // Windows SDK support
4 | #include
5 | #include
6 |
7 | // Needs to come before C++/WinRT headers
8 | #include
9 |
10 | // WinRT
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 |
28 | // STL
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 |
38 | // D3D
39 | #include
40 | #include
41 | #include
42 | #include
43 |
44 | // DWM
45 | #include
46 |
47 | // WIL
48 | #include
49 |
50 | // Helpers
51 | #include
52 | #include
53 | #include
54 | #include
55 | #include
56 | #include
57 | #include
58 | #include
59 | #include
60 | #include
61 |
62 | // Other
63 | #include
64 | #include
65 | #include
66 | #include
67 | #include
68 | #include
69 | #include
70 |
71 |
--------------------------------------------------------------------------------
/screenrecorder/ScreenRecorder/DataStream.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "DataStream.h"
3 |
4 | DataStream::DataStream()
5 | {
6 | }
7 |
8 | DataStream::DataStream(const DataStream& other)
9 | {
10 | m_stream << other.m_stream.rdbuf();
11 | }
12 |
13 | DataStream& DataStream::operator=(const DataStream& other)
14 | {
15 | if (this != &other)
16 | {
17 | m_stream.str(other.m_stream.str());
18 | m_stream.clear(other.m_stream.rdstate());
19 | }
20 | return *this;
21 | }
22 |
23 | void DataStream::WriteInt(int value)
24 | {
25 | m_stream << value << ' ';
26 | }
27 |
28 | int DataStream::ReadInt()
29 | {
30 | int value;
31 | if (!(m_stream >> value))
32 | throw std::runtime_error("Error reading int from stream.");
33 | return value;
34 | }
35 |
36 | void DataStream::WriteBool(bool value)
37 | {
38 | m_stream << value << ' ';
39 | }
40 |
41 | bool DataStream::ReadBool()
42 | {
43 | bool value;
44 | if (!(m_stream >> value))
45 | throw std::runtime_error("Error reading bool from stream.");
46 | return value;
47 | }
48 |
49 | void DataStream::WriteString(const std::string& value)
50 | {
51 | m_stream << value.size() << ' ' << value << ' ';
52 | }
53 |
54 | std::string DataStream::ReadString()
55 | {
56 | size_t size;
57 | if (!(m_stream >> size))
58 | throw std::runtime_error("Error reading string size from stream.");
59 |
60 | m_stream.ignore(); // Ignore the space character
61 |
62 | std::string value(size, '\0');
63 | m_stream.read(&value[0], size);
64 | if (!m_stream)
65 | throw std::runtime_error("Error reading string data from stream.");
66 |
67 | m_stream.get();
68 | return value;
69 | }
70 |
71 | void DataStream::WriteException(const std::exception& e)
72 | {
73 | WriteString(e.what());
74 | }
75 |
76 | std::exception DataStream::ReadException()
77 | {
78 | std::string message = ReadString();
79 | return std::runtime_error(message);
80 | }
81 |
82 | std::string DataStream::ToString() const
83 | {
84 | return m_stream.str();
85 | }
86 |
87 | DataStream DataStream::FromString(const std::string& str)
88 | {
89 | DataStream ds;
90 | ds.m_stream.str(str);
91 | return ds;
92 | }
93 |
--------------------------------------------------------------------------------
/screenrecorder/ScreenRecorder/CommandLine.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "CommandLine.h"
3 |
4 | std::map map = { {"-start", CommandType::Start},
5 | {"-stop", CommandType::Stop},
6 | {"-cancel", CommandType::Cancel},
7 | {"-newserver", CommandType::NewServer},
8 | {"-help", CommandType::Help} };
9 |
10 | CommandType CommandLine::GetCommandType() const
11 | {
12 | if (m_argc < 2)
13 | {
14 | return CommandType::Unknown;
15 | }
16 |
17 | auto it = map.find(m_argv[1]);
18 |
19 | if (it != map.end())
20 | {
21 | CommandType type = it->second;
22 | return type;
23 | }
24 | else
25 | {
26 | return CommandType::Unknown;
27 | }
28 | }
29 |
30 | void CommandLine::GetStartArgs(int& framerate, int& monitor, int& bufferSize, bool& isMegabytes) const
31 | {
32 | int i = 2;
33 | framerate = 1;
34 | monitor = 0;
35 | bufferSize = 100;
36 | isMegabytes = true;
37 |
38 | while (i < m_argc)
39 | {
40 | if (strcmp(m_argv[i], "-framerate") == 0)
41 | {
42 | i++;
43 |
44 | if (i == m_argc)
45 | {
46 | throw std::invalid_argument("Syntax error parsing args.");
47 | }
48 |
49 | framerate = std::stoi(m_argv[i]);
50 |
51 | i++;
52 | }
53 | else if (strcmp(m_argv[i], "-monitor") == 0)
54 | {
55 | i++;
56 |
57 | if (i == m_argc)
58 | {
59 | throw std::invalid_argument("Syntax error parsing args.");
60 | }
61 |
62 | monitor = std::stoi(m_argv[i]);
63 |
64 | i++;
65 | }
66 | else if (strcmp(m_argv[i], "-framebuffer") == 0)
67 | {
68 | i++;
69 |
70 | if (i == m_argc)
71 | {
72 | throw std::invalid_argument("Syntax error parsing args.");
73 | }
74 |
75 | isMegabytes = strcmp(m_argv[i], "-mb") == 0;
76 |
77 | if (isMegabytes)
78 | {
79 | i++;
80 | }
81 |
82 | bufferSize = std::stoi(m_argv[i]);
83 |
84 | i++;
85 | }
86 | else
87 | {
88 | throw std::invalid_argument("Syntax error parsing args.");
89 | }
90 | }
91 | }
92 |
93 | void CommandLine::GetStopArgs(std::string& folder) const
94 | {
95 | if (m_argc < 3)
96 | {
97 | throw std::invalid_argument("Syntax error parsing args.");
98 | }
99 |
100 | folder = m_argv[2];
101 | }
102 |
103 | void CommandLine::GetHelpArgs(std::string& arg) const
104 | {
105 | if (m_argc < 3)
106 | {
107 | throw std::invalid_argument("Syntax error parsing args.");
108 | }
109 |
110 | arg = m_argv[2];
111 | }
112 |
--------------------------------------------------------------------------------
/screenrecorder/ScreenRecorder/ScreenRecorder.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "ScreenRecorder.h"
3 | #include "MonitorInfo.h"
4 | #include "SimpleCapture.h"
5 | #include "ScreenRecorderProvider.h"
6 |
7 | ScreenRecorder::ScreenRecorder() : isCapturing(false)
8 | {
9 | TraceLoggingRegister(g_hMyComponentProvider);
10 | }
11 |
12 | ScreenRecorder::~ScreenRecorder()
13 | {
14 | TraceLoggingUnregister(g_hMyComponentProvider);
15 | }
16 |
17 | void ScreenRecorder::start(int framerate, int monitor, int bufferCapacity, bool asMegabytes)
18 | {
19 | if (isCapturing)
20 | {
21 | throw std::logic_error("\b\tRecording already started.\n");
22 | }
23 |
24 | std::vector monitors = MonitorInfo::EnumerateAllMonitors(true);
25 |
26 | if (monitor < 0 || monitors.size() <= monitor)
27 | {
28 | throw std::out_of_range("\b\tMonitor out of range.\n");
29 | }
30 |
31 | CircularFrameBuffer buffer(bufferCapacity, asMegabytes);
32 |
33 | auto d3dDevice = util::CreateD3DDevice();
34 | auto dxgiDevice = d3dDevice.as();
35 | auto device = CreateDirect3DDevice(dxgiDevice.get());
36 |
37 | MonitorInfo monitorInfo = monitors[monitor];
38 | auto item = util::CreateCaptureItemForMonitor(monitorInfo.MonitorHandle);
39 |
40 | m_simpleCapture = std::make_unique(device, item, framerate, buffer);
41 |
42 | m_simpleCapture->StartCapture();
43 | isCapturing = true;
44 | }
45 |
46 | void ScreenRecorder::stop(const std::string& folderPath)
47 | {
48 | if (!isCapturing)
49 | {
50 | throw std::logic_error("\b\tRecording is not started.\n");
51 | }
52 |
53 | StorageFolder storageFolder = NULL;
54 |
55 | try
56 | {
57 | storageFolder = StorageFolder::GetFolderFromPathAsync(winrt::to_hstring(folderPath)).get();
58 | }
59 | catch (const winrt::hresult_invalid_argument&)
60 | {
61 | throw std::invalid_argument("\b\tCould not open folder \"" + folderPath + "\".\n");
62 | }
63 | catch (const winrt::hresult_error&)
64 | {
65 | throw std::invalid_argument("\b\tCould not open folder \"" + folderPath + "\".\n");
66 | }
67 |
68 | m_simpleCapture->CloseAndSave(storageFolder);
69 | isCapturing = false;
70 | }
71 |
72 | void ScreenRecorder::cancel()
73 | {
74 | if (!isCapturing)
75 | {
76 | throw std::logic_error("\b\tRecording is not started.\n");
77 | }
78 |
79 | m_simpleCapture->Close();
80 | isCapturing = false;
81 | }
82 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Security
4 |
5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet) and [Xamarin](https://github.com/xamarin).
6 |
7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/security.md/definition), please report it to us as described below.
8 |
9 | ## Reporting Security Issues
10 |
11 | **Please do not report security vulnerabilities through public GitHub issues.**
12 |
13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/security.md/msrc/create-report).
14 |
15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/security.md/msrc/pgp).
16 |
17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
18 |
19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
20 |
21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
22 | * Full paths of source file(s) related to the manifestation of the issue
23 | * The location of the affected source code (tag/branch/commit or direct URL)
24 | * Any special configuration required to reproduce the issue
25 | * Step-by-step instructions to reproduce the issue
26 | * Proof-of-concept or exploit code (if possible)
27 | * Impact of the issue, including how an attacker might exploit the issue
28 |
29 | This information will help us triage your report more quickly.
30 |
31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/security.md/msrc/bounty) page for more details about our active programs.
32 |
33 | ## Preferred Languages
34 |
35 | We prefer all communications to be in English.
36 |
37 | ## Policy
38 |
39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/security.md/cvd).
40 |
41 |
42 |
--------------------------------------------------------------------------------
/screenrecorder/ScreenRecorder/Pipe.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "Pipe.h"
3 |
4 | Pipe::Pipe() : m_name(L"mypipe"), m_hpipe(INVALID_HANDLE_VALUE), m_mode(SERVER)
5 | {
6 | }
7 |
8 | bool Pipe::try_init(const std::wstring& name, Mode mode)
9 | {
10 | m_name = name;
11 | m_mode = mode;
12 |
13 | if (m_mode == SERVER) {
14 | m_hpipe = CreateNamedPipe(
15 | (L"\\\\.\\pipe\\" + m_name).c_str(),
16 | PIPE_ACCESS_DUPLEX,
17 | PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
18 | 1,
19 | 0,
20 | 0,
21 | 0,
22 | NULL
23 | );
24 |
25 | if (m_hpipe == INVALID_HANDLE_VALUE) {
26 | return false;
27 | }
28 | }
29 | else {
30 | m_hpipe = CreateFile(
31 | (L"\\\\.\\pipe\\" + m_name).c_str(),
32 | GENERIC_READ | GENERIC_WRITE,
33 | 0,
34 | NULL,
35 | OPEN_EXISTING,
36 | 0,
37 | NULL
38 | );
39 |
40 | if (m_hpipe == INVALID_HANDLE_VALUE)
41 | {
42 | return false;
43 | }
44 | }
45 |
46 | return true;
47 | }
48 |
49 | Pipe::~Pipe()
50 | {
51 | if (m_hpipe != INVALID_HANDLE_VALUE) {
52 | CloseHandle(m_hpipe);
53 | }
54 | }
55 |
56 | void Pipe::send(const std::string& message) const
57 | {
58 | DWORD bytesWritten;
59 |
60 | if (!WriteFile(m_hpipe, message.c_str(), (DWORD)message.size(), &bytesWritten, NULL))
61 | {
62 | throw std::ios_base::failure("Failed to write to pipe\nWriteFile failed with error " + std::to_string(GetLastError()));
63 | }
64 | }
65 |
66 | std::string Pipe::receive() const
67 | {
68 | char buffer[1024];
69 | DWORD bytesRead;
70 |
71 | if (!ReadFile(m_hpipe, buffer, sizeof(buffer), &bytesRead, NULL))
72 | {
73 | throw std::ios_base::failure("Failed to read from pipe\nReadFile failed with error " + std::to_string(GetLastError()));
74 | }
75 |
76 | return std::string(buffer, bytesRead);
77 | }
78 |
79 | void Pipe::disconnect() const
80 | {
81 | if (m_mode != SERVER)
82 | {
83 | throw std::invalid_argument("Cannot call disconnect on a client side pipe");
84 | }
85 |
86 | if (!DisconnectNamedPipe(m_hpipe))
87 | {
88 | throw std::ios_base::failure("Failed to disconnect from pipe\nDisconnectNamedPipe failed with error " + std::to_string(GetLastError()));
89 | }
90 | }
91 |
92 | void Pipe::connect() const
93 | {
94 | if (m_mode != SERVER)
95 | {
96 | throw std::invalid_argument("Cannot call connect on a client side pipe");
97 | }
98 |
99 | if (!ConnectNamedPipe(m_hpipe, NULL))
100 | {
101 | throw std::ios_base::failure("Failed to disconnect from pipe\nDisconnectNamedPipe failed with error " + std::to_string(GetLastError()));
102 | }
103 | }
--------------------------------------------------------------------------------
/screenrecorder/ScreenRecorder/SimpleCapture.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "pch.h"
4 | #include "CircularFrameBuffer.h"
5 |
6 | using namespace winrt;
7 | using namespace Windows::Foundation;
8 |
9 | namespace winrt
10 | {
11 | using namespace Windows;
12 | using namespace Windows::Foundation;
13 | using namespace Windows::Foundation::Numerics;
14 | using namespace Windows::Graphics;
15 | using namespace Windows::Graphics::Capture;
16 | using namespace Windows::Graphics::DirectX;
17 | using namespace Windows::Graphics::DirectX::Direct3D11;
18 | using namespace Windows::Graphics::Imaging;
19 | using namespace Windows::Storage;
20 | using namespace Windows::System;
21 | using namespace Windows::UI;
22 | using namespace Windows::UI::Composition;
23 | using namespace Windows::UI::Popups;
24 | }
25 |
26 | namespace util
27 | {
28 | using namespace robmikh::common::desktop;
29 | using namespace robmikh::common::uwp;
30 | }
31 |
32 | // This purpose of this class is to take screenshots and save them to disk.
33 | class SimpleCapture
34 | {
35 | public:
36 | SimpleCapture(
37 | winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice const& device,
38 | winrt::Windows::Graphics::Capture::GraphicsCaptureItem const& item,
39 | int framerate, CircularFrameBuffer frameBuffer);
40 | ~SimpleCapture() { Close(); }
41 |
42 | void StartCapture();
43 |
44 | bool IsCursorEnabled() { CheckClosed(); return m_session.IsCursorCaptureEnabled(); }
45 | void IsCursorEnabled(bool value) { CheckClosed(); m_session.IsCursorCaptureEnabled(value); }
46 | bool IsBorderRequired() { CheckClosed(); return m_session.IsBorderRequired(); }
47 | void IsBorderRequired(bool value) { CheckClosed(); m_session.IsBorderRequired(value); }
48 | winrt::Windows::Graphics::Capture::GraphicsCaptureItem CaptureItem() { return m_item; }
49 |
50 | void Close();
51 | void CloseAndSave(StorageFolder storageFolder);
52 |
53 | private:
54 | void OnFrameArrived(
55 | winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool const& sender,
56 | winrt::Windows::Foundation::IInspectable const& args);
57 |
58 | inline void CheckClosed()
59 | {
60 | if (m_closed.load() == true)
61 | {
62 | throw winrt::hresult_error(RO_E_CLOSED);
63 | }
64 | }
65 |
66 | private:
67 | winrt::Windows::Graphics::Capture::GraphicsCaptureItem m_item{ nullptr };
68 | winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool m_framePool{ nullptr };
69 | winrt::Windows::Graphics::Capture::GraphicsCaptureSession m_session{ nullptr };
70 | winrt::Windows::Graphics::SizeInt32 m_lastSize;
71 |
72 | winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice m_device{ nullptr };
73 | winrt::com_ptr m_d3dDevice{ nullptr };
74 | winrt::com_ptr m_d3dContext{ nullptr };
75 | winrt::guid m_fileFormatGuid;;
76 | winrt::BitmapPixelFormat m_bitmapPixelFormat;
77 |
78 | std::atomic m_closed = false;
79 | std::atomic m_captureNextImage = false;
80 |
81 | CircularFrameBuffer m_frameBuffer;
82 | std::chrono::steady_clock::time_point m_lastFrameTime;
83 | int m_frameInterval;
84 | int m_framesBufferSize;
85 | };
--------------------------------------------------------------------------------
/screenrecorder/GAUSS/Utilities.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using System.Diagnostics;
3 | using System.Security.Principal;
4 |
5 | namespace GAUSS
6 | {
7 | public class Utilities
8 | {
9 | public static bool ExistsOnPath(string fileName)
10 | {
11 | return GetFullPath(fileName) != null;
12 | }
13 |
14 | public static string? GetFullPath(string fileName)
15 | {
16 | if (File.Exists(fileName))
17 | {
18 | return Path.GetFullPath(fileName);
19 | }
20 |
21 | var values = Environment.GetEnvironmentVariable("PATH");
22 |
23 | if (values == null)
24 | {
25 | return null;
26 | }
27 |
28 | foreach (var path in values.Split(Path.PathSeparator))
29 | {
30 | var fullPath = Path.Combine(path, fileName);
31 | if (File.Exists(fullPath))
32 | {
33 | return fullPath;
34 | }
35 | }
36 |
37 | return null;
38 | }
39 |
40 | public static bool IsWindowsAdmin()
41 | {
42 | if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows))
43 | {
44 | WindowsIdentity identity = WindowsIdentity.GetCurrent();
45 | WindowsPrincipal principal = new WindowsPrincipal(identity);
46 | return principal.IsInRole(WindowsBuiltInRole.Administrator);
47 | }
48 | else
49 | {
50 | // For now, assume we are admin on other platforms
51 | return true;
52 | }
53 | }
54 |
55 | public static int RunExecutable(string executablePath, string args)
56 | {
57 | ProcessStartInfo processStartInfo = new ProcessStartInfo
58 | {
59 | FileName = executablePath,
60 | Arguments = args
61 | };
62 |
63 | using Process process = new Process();
64 | process.StartInfo = processStartInfo;
65 | process.Start();
66 | process.WaitForExit();
67 |
68 | return process.ExitCode;
69 | }
70 |
71 | public static int RunExecutable(string executablePath, string args, out string stdout)
72 | {
73 | ProcessStartInfo processStartInfo = new ProcessStartInfo
74 | {
75 | RedirectStandardOutput = true,
76 | FileName = executablePath,
77 | Arguments = args
78 | };
79 |
80 | using Process process = new Process();
81 | process.StartInfo = processStartInfo;
82 |
83 | try
84 | {
85 | process.Start();
86 | }
87 | catch (Win32Exception)
88 | {
89 | stdout = string.Empty;
90 |
91 | return -1;
92 | }
93 |
94 | stdout = process.StandardOutput.ReadToEnd();
95 | process.WaitForExit();
96 |
97 | return process.ExitCode;
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GAUSS
2 |
3 | ## Table of Contents
4 | - [Dev Requirements](#dev-requirements)
5 | - [Screen Recorder](#screen-recorder)
6 | - [Usage](#usage)
7 | - [Capturing ETW Events](#capturing-etw-events)
8 | - [Example Capture](#example-capture)
9 |
10 | ## Dev Requirements
11 | - Install Git
12 | - Install Python 11
13 | - Install modules in requirements.txt
14 | - Visual Studio 2022
15 | - Install Python development, .NET desktop development, and Desktop development with C++ workloads
16 | - Install MSVC v143 - VS 2022 C++ ARM64/ARM64EC build tools (v14.38-17.8) component or newer to compile for ARM
17 |
18 | ## Screen Recorder
19 | ### Usage
20 | The tool allows you to start and stop recording from the command line. When a recording is started, the framerate, monitor, and buffer size can be specified. When a recording is stopped, a folder must be provided in which to store the screenshots.
21 |
22 | screenrecorder.exe -start ... Starts screen recording.
23 | Usage: screenrecorder.exe -start [-framerate ] [-monitor ] [-framebuffer -mb <# of frames>] [-monitor ]
24 | Ex> screenrecorder.exe -start -framerate 10
25 | Ex> screenrecorder.exe -start -framerate 1 -monitor 0 -framebuffer -mb 100
26 |
27 | -framerate Specifies the rate at which screenshots will be taken, in frames per second.
28 | -monitor Specifies the monitor to record, as an index. The highest index will record all monitors.
29 | -framebuffer Specifies the size of the circular memory buffer in which to store screenshots, in number of screenshots. Adding the -mb flag specifies the size of the buffer in megabytes.
30 |
31 | screenrecorder.exe -stop ... Stops screen recording saves all screenshots in buffer to a folder.
32 | Usage: screenrecorder.exe -stop
33 | Ex> screenrecorder.exe -stop "D:\screenrecorder"
34 |
35 | screenrecorder.exe -cancel ... Cancels the screen recording.
36 |
37 | screenrecorder.exe -help ... Prints usage information.
38 |
39 | ### Capturing ETW Events
40 | An ETW event is emitted by the tool every time it receives a frame from DirectX. The event for each frame contains the filename to be used if the frame is saved to disk, allowing for direct correlation between each event and screenshot. The tool does not receive frames from DirectX unless there has been a change in the screen, so desired framerates may not be exact.
41 |
42 | To capture the ETW events, you must use a ETW tracing tool like WPR and watch for events from the following provider guid: fe8fc3d0-1e6a-42f2-be28-9f8a0fcf7b04.
43 |
44 | ### Example Capture
45 |
46 | Create a WPR profile with the following provider and collectors defined:
47 |
48 | ...
49 |
50 |
51 | ...
52 |
53 |
54 |
55 |
56 |
57 | ...
58 |
59 | Take an ETW trace using WPR while you use the tool to capture some scenario.
60 |
61 | wpr -start profile.wprp
62 | ScreenRecorder.exe -start
63 |
64 | ... excercise some scenario of interest ...
65 |
66 | ScreenRecorder.exe -stop "D:\"
67 | wpr -stop trace.etl
68 |
69 | Now opening the trace in WPA, we can see the events produced by the tool in the Generic Events table under the ScreenRecorder provider. Each event contains the filename for the screenshot.
70 |
--------------------------------------------------------------------------------
/screenrecorder/ScreenRecorder/Server.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "Server.h"
3 |
4 | const std::string unknownEnumCaseMessage = "\b\tReceived an unknown request from the main process.\n";
5 | const std::string defaultEnumCaseMessage = "\b\tReceived an unhandled request from the main process.\n";
6 |
7 | bool Server::try_init()
8 | {
9 | return m_pipe.try_init(L"myPipe", Pipe::SERVER);
10 | }
11 |
12 | void Server::run()
13 | {
14 | m_isRunning = true;
15 |
16 | while (m_isRunning)
17 | {
18 | try
19 | {
20 | m_pipe.connect();
21 | }
22 | catch (const std::ios_base::failure&)
23 | {
24 | return;
25 | }
26 |
27 | m_isConnectedToClient = true;
28 |
29 | while (m_isConnectedToClient)
30 | {
31 | Request request;
32 | Response response;
33 |
34 | try
35 | {
36 | request = Request::FromString(m_pipe.receive());
37 | }
38 | catch (const std::ios_base::failure&)
39 | {
40 | m_isConnectedToClient = false;
41 |
42 | break;
43 | }
44 |
45 | RequestType requestType = request.ParseRequestType();
46 |
47 | if (requestType == RequestType::Disconnect)
48 | {
49 | m_isConnectedToClient = false;
50 |
51 | break;
52 | }
53 |
54 | if (requestType == RequestType::Kill)
55 | {
56 | m_isConnectedToClient = false;
57 | m_isRunning = false;
58 |
59 | break;
60 | }
61 |
62 | try
63 | {
64 | response = serve_request(request, requestType);
65 | }
66 | catch (const std::exception& e)
67 | {
68 | response = Response::BuildExceptionResponse(e);
69 | }
70 |
71 | try
72 | {
73 | m_pipe.send(response.ToString());
74 | }
75 | catch (const std::ios_base::failure&)
76 | {
77 | m_isConnectedToClient = false;
78 |
79 | break;
80 | }
81 | }
82 |
83 | try
84 | {
85 | m_pipe.send(Response::BuildSuccessResponse().ToString());
86 | m_pipe.disconnect();
87 | }
88 | catch (std::ios_base::failure)
89 | {
90 | return;
91 | }
92 | }
93 | }
94 |
95 | Response Server::serve_request(Request& request, RequestType requestType)
96 | {
97 | int framerate, monitor, bufferSize;
98 | bool isMegabytes;
99 | std::string folder;
100 |
101 | switch (requestType)
102 | {
103 | case RequestType::Start:
104 | request.ParseStartArgs(framerate, monitor, bufferSize, isMegabytes);
105 |
106 | m_screenRecorder.start(framerate, monitor, bufferSize, isMegabytes);
107 |
108 | return Response::BuildSuccessResponse();
109 | case RequestType::Stop:
110 | request.ParseStopArgs(folder);
111 |
112 | m_screenRecorder.stop(folder);
113 |
114 | return Response::BuildSuccessResponse();
115 | case RequestType::Cancel:
116 | m_screenRecorder.cancel();
117 |
118 | return Response::BuildSuccessResponse();
119 | case RequestType::Unknown:
120 | throw std::invalid_argument(unknownEnumCaseMessage);
121 | default:
122 | throw std::invalid_argument(defaultEnumCaseMessage);
123 | }
124 | }
--------------------------------------------------------------------------------
/screenrecorder/ScreenRecorder/ScreenRecorder.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 | Source Files
23 |
24 |
25 | Source Files
26 |
27 |
28 | Source Files
29 |
30 |
31 | Source Files
32 |
33 |
34 | Source Files
35 |
36 |
37 | Source Files
38 |
39 |
40 | Source Files
41 |
42 |
43 | Source Files
44 |
45 |
46 | Source Files
47 |
48 |
49 | Source Files
50 |
51 |
52 | Source Files
53 |
54 |
55 |
56 |
57 | Header Files
58 |
59 |
60 | Header Files
61 |
62 |
63 | Header Files
64 |
65 |
66 | Header Files
67 |
68 |
69 | Header Files
70 |
71 |
72 | Header Files
73 |
74 |
75 | Header Files
76 |
77 |
78 | Header Files
79 |
80 |
81 | Header Files
82 |
83 |
84 | Header Files
85 |
86 |
87 | Header Files
88 |
89 |
90 | Header Files
91 |
92 |
93 | Header Files
94 |
95 |
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/screenrecorder/screenrecorder.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.8.34330.188
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GAUSS", "GAUSS\GAUSS.csproj", "{26558F0B-6CE0-4A05-B740-775EFD21BF7A}"
7 | ProjectSection(ProjectDependencies) = postProject
8 | {96DF8515-4AB5-4213-ACC0-3CFBEA8FDEE1} = {96DF8515-4AB5-4213-ACC0-3CFBEA8FDEE1}
9 | EndProjectSection
10 | EndProject
11 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ScreenRecorder", "ScreenRecorder\ScreenRecorder.vcxproj", "{96DF8515-4AB5-4213-ACC0-3CFBEA8FDEE1}"
12 | EndProject
13 | Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "LaunchDetectorScript", "LaunchDetectorScript\LaunchDetectorScript.pyproj", "{5F5B763C-E633-4089-AF35-CA3FC5B23C43}"
14 | EndProject
15 | Global
16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
17 | Debug|Any CPU = Debug|Any CPU
18 | Debug|ARM64 = Debug|ARM64
19 | Debug|x64 = Debug|x64
20 | Release|Any CPU = Release|Any CPU
21 | Release|ARM64 = Release|ARM64
22 | Release|x64 = Release|x64
23 | EndGlobalSection
24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
25 | {26558F0B-6CE0-4A05-B740-775EFD21BF7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
26 | {26558F0B-6CE0-4A05-B740-775EFD21BF7A}.Debug|Any CPU.Build.0 = Debug|Any CPU
27 | {26558F0B-6CE0-4A05-B740-775EFD21BF7A}.Debug|ARM64.ActiveCfg = Debug|ARM64
28 | {26558F0B-6CE0-4A05-B740-775EFD21BF7A}.Debug|ARM64.Build.0 = Debug|ARM64
29 | {26558F0B-6CE0-4A05-B740-775EFD21BF7A}.Debug|x64.ActiveCfg = Debug|x64
30 | {26558F0B-6CE0-4A05-B740-775EFD21BF7A}.Debug|x64.Build.0 = Debug|x64
31 | {26558F0B-6CE0-4A05-B740-775EFD21BF7A}.Release|Any CPU.ActiveCfg = Release|Any CPU
32 | {26558F0B-6CE0-4A05-B740-775EFD21BF7A}.Release|Any CPU.Build.0 = Release|Any CPU
33 | {26558F0B-6CE0-4A05-B740-775EFD21BF7A}.Release|ARM64.ActiveCfg = Release|ARM64
34 | {26558F0B-6CE0-4A05-B740-775EFD21BF7A}.Release|ARM64.Build.0 = Release|ARM64
35 | {26558F0B-6CE0-4A05-B740-775EFD21BF7A}.Release|x64.ActiveCfg = Release|x64
36 | {26558F0B-6CE0-4A05-B740-775EFD21BF7A}.Release|x64.Build.0 = Release|x64
37 | {96DF8515-4AB5-4213-ACC0-3CFBEA8FDEE1}.Debug|Any CPU.ActiveCfg = Debug|x64
38 | {96DF8515-4AB5-4213-ACC0-3CFBEA8FDEE1}.Debug|Any CPU.Build.0 = Debug|x64
39 | {96DF8515-4AB5-4213-ACC0-3CFBEA8FDEE1}.Debug|ARM64.ActiveCfg = Debug|ARM64
40 | {96DF8515-4AB5-4213-ACC0-3CFBEA8FDEE1}.Debug|ARM64.Build.0 = Debug|ARM64
41 | {96DF8515-4AB5-4213-ACC0-3CFBEA8FDEE1}.Debug|x64.ActiveCfg = Debug|x64
42 | {96DF8515-4AB5-4213-ACC0-3CFBEA8FDEE1}.Debug|x64.Build.0 = Debug|x64
43 | {96DF8515-4AB5-4213-ACC0-3CFBEA8FDEE1}.Release|Any CPU.ActiveCfg = Release|x64
44 | {96DF8515-4AB5-4213-ACC0-3CFBEA8FDEE1}.Release|Any CPU.Build.0 = Release|x64
45 | {96DF8515-4AB5-4213-ACC0-3CFBEA8FDEE1}.Release|ARM64.ActiveCfg = Release|ARM64
46 | {96DF8515-4AB5-4213-ACC0-3CFBEA8FDEE1}.Release|ARM64.Build.0 = Release|ARM64
47 | {96DF8515-4AB5-4213-ACC0-3CFBEA8FDEE1}.Release|x64.ActiveCfg = Release|x64
48 | {96DF8515-4AB5-4213-ACC0-3CFBEA8FDEE1}.Release|x64.Build.0 = Release|x64
49 | {5F5B763C-E633-4089-AF35-CA3FC5B23C43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
50 | {5F5B763C-E633-4089-AF35-CA3FC5B23C43}.Debug|ARM64.ActiveCfg = Debug|Any CPU
51 | {5F5B763C-E633-4089-AF35-CA3FC5B23C43}.Debug|x64.ActiveCfg = Debug|Any CPU
52 | {5F5B763C-E633-4089-AF35-CA3FC5B23C43}.Release|Any CPU.ActiveCfg = Release|Any CPU
53 | {5F5B763C-E633-4089-AF35-CA3FC5B23C43}.Release|ARM64.ActiveCfg = Release|Any CPU
54 | {5F5B763C-E633-4089-AF35-CA3FC5B23C43}.Release|x64.ActiveCfg = Release|Any CPU
55 | EndGlobalSection
56 | GlobalSection(SolutionProperties) = preSolution
57 | HideSolutionNode = FALSE
58 | EndGlobalSection
59 | GlobalSection(ExtensibilityGlobals) = postSolution
60 | SolutionGuid = {60BC4B44-7896-4470-A734-AE05D53AA5AA}
61 | EndGlobalSection
62 | EndGlobal
63 |
--------------------------------------------------------------------------------
/screenrecorder/ScreenRecorder/CircularFrameBuffer.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "CircularFrameBuffer.h"
3 |
4 | CircularFrameBuffer::CircularFrameBuffer(size_t capacity, bool asMegabytes) : m_capacity(capacity), m_asMegabytes(asMegabytes), m_memoryUsage(0)
5 | {
6 | if (asMegabytes)
7 | {
8 | m_capacity *= 1000000;
9 | }
10 | }
11 |
12 | void CircularFrameBuffer::add_frame(winrt::com_ptr texture, const std::string& filename)
13 | {
14 | size_t frame_size = calculate_frame_size(texture);
15 |
16 | if (m_asMegabytes)
17 | {
18 | while (m_memoryUsage + frame_size > m_capacity && !m_frames.empty())
19 | {
20 | m_memoryUsage -= m_frames.front().size;
21 | m_frames.pop_front();
22 | }
23 | }
24 | else if (m_frames.size() == m_capacity)
25 | {
26 | m_memoryUsage -= m_frames.front().size;
27 | m_frames.pop_front();
28 | }
29 |
30 | m_frames.push_back({ texture, filename, frame_size });
31 | m_memoryUsage += frame_size;
32 | }
33 |
34 | size_t CircularFrameBuffer::calculate_frame_size(winrt::com_ptr texture)
35 | {
36 | if (!texture)
37 | return 0;
38 |
39 | D3D11_TEXTURE2D_DESC desc;
40 | texture->GetDesc(&desc);
41 |
42 | UINT bpp = 0;
43 | switch (desc.Format)
44 | {
45 | case DXGI_FORMAT_R32G32B32A32_FLOAT:
46 | case DXGI_FORMAT_R32G32B32A32_UINT:
47 | case DXGI_FORMAT_R32G32B32A32_SINT:
48 | bpp = 128;
49 | break;
50 | case DXGI_FORMAT_R32G32B32_FLOAT:
51 | case DXGI_FORMAT_R32G32B32_UINT:
52 | case DXGI_FORMAT_R32G32B32_SINT:
53 | bpp = 96;
54 | break;
55 | case DXGI_FORMAT_R16G16B16A16_FLOAT:
56 | case DXGI_FORMAT_R16G16B16A16_UNORM:
57 | case DXGI_FORMAT_R16G16B16A16_UINT:
58 | case DXGI_FORMAT_R16G16B16A16_SNORM:
59 | case DXGI_FORMAT_R16G16B16A16_SINT:
60 | case DXGI_FORMAT_R32G32_FLOAT:
61 | case DXGI_FORMAT_R32G32_UINT:
62 | case DXGI_FORMAT_R32G32_SINT:
63 | bpp = 64;
64 | break;
65 | case DXGI_FORMAT_R10G10B10A2_UNORM:
66 | case DXGI_FORMAT_R10G10B10A2_UINT:
67 | case DXGI_FORMAT_R11G11B10_FLOAT:
68 | case DXGI_FORMAT_R8G8B8A8_UNORM:
69 | case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
70 | case DXGI_FORMAT_R8G8B8A8_UINT:
71 | case DXGI_FORMAT_R8G8B8A8_SNORM:
72 | case DXGI_FORMAT_R8G8B8A8_SINT:
73 | case DXGI_FORMAT_B8G8R8A8_UNORM:
74 | case DXGI_FORMAT_B8G8R8X8_UNORM:
75 | case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
76 | case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
77 | case DXGI_FORMAT_R16G16_FLOAT:
78 | case DXGI_FORMAT_R16G16_UNORM:
79 | case DXGI_FORMAT_R16G16_UINT:
80 | case DXGI_FORMAT_R16G16_SNORM:
81 | case DXGI_FORMAT_R16G16_SINT:
82 | bpp = 32;
83 | break;
84 | }
85 |
86 | size_t size = desc.Width * desc.Height * bpp / 8;
87 |
88 | return size;
89 | }
90 |
91 | void CircularFrameBuffer::save_frames(winrt::Windows::Storage::StorageFolder storageFolder)
92 | {
93 | for (const auto& frame : m_frames)
94 | {
95 | auto file = storageFolder.CreateFileAsync(winrt::to_hstring(frame.filename), winrt::Windows::Storage::CreationCollisionOption::ReplaceExisting).get();
96 |
97 | // Get the file stream
98 | auto stream = file.OpenAsync(winrt::Windows::Storage::FileAccessMode::ReadWrite).get();
99 |
100 | // Initialize the encoder
101 | auto encoder = winrt::Windows::Graphics::Imaging::BitmapEncoder::CreateAsync(winrt::Windows::Graphics::Imaging::BitmapEncoder::JpegEncoderId(), stream).get();
102 |
103 | // Encode the image
104 | D3D11_TEXTURE2D_DESC desc = {};
105 | frame.texture->GetDesc(&desc);
106 | auto bytes = util::CopyBytesFromTexture(frame.texture);
107 | encoder.SetPixelData(
108 | winrt::Windows::Graphics::Imaging::BitmapPixelFormat::Bgra8,
109 | winrt::Windows::Graphics::Imaging::BitmapAlphaMode::Premultiplied,
110 | desc.Width,
111 | desc.Height,
112 | 1.0,
113 | 1.0,
114 | bytes);
115 | encoder.FlushAsync().get();
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/screenrecorder/ScreenRecorder/SimpleCapture.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "SimpleCapture.h"
3 | #include "ScreenRecorderProvider.h"
4 |
5 | namespace winrt
6 | {
7 | using namespace Windows::Foundation;
8 | using namespace Windows::Foundation::Numerics;
9 | using namespace Windows::Graphics;
10 | using namespace Windows::Graphics::Capture;
11 | using namespace Windows::Graphics::DirectX;
12 | using namespace Windows::Graphics::DirectX::Direct3D11;
13 | using namespace Windows::System;
14 | using namespace Windows::UI;
15 | using namespace Windows::UI::Composition;
16 | }
17 |
18 | namespace util
19 | {
20 | using namespace robmikh::common::uwp;
21 | }
22 |
23 | SimpleCapture::SimpleCapture(winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice const& device,
24 | winrt::Windows::Graphics::Capture::GraphicsCaptureItem const& item,
25 | int framerate, CircularFrameBuffer frameBuffer) : m_frameInterval(1000 / framerate), m_frameBuffer(frameBuffer)
26 | {
27 | m_item = item;
28 | m_device = device;
29 | m_fileFormatGuid = winrt::BitmapEncoder::JpegEncoderId();
30 | m_bitmapPixelFormat = winrt::BitmapPixelFormat::Bgra8;
31 | auto pixelFormat = winrt::DirectXPixelFormat::B8G8R8A8UIntNormalized;
32 |
33 | m_d3dDevice = GetDXGIInterfaceFromObject(m_device);
34 | m_d3dDevice->GetImmediateContext(m_d3dContext.put());
35 |
36 | // Creating our frame pool with 'Create' instead of 'CreateFreeThreaded'
37 | // means that the frame pool's FrameArrived event is called on the thread
38 | // the frame pool was created on. This also means that the creating thread
39 | // must have a DispatcherQueue. If you use this method, it's best not to do
40 | // it on the UI thread.
41 | m_framePool = winrt::Direct3D11CaptureFramePool::CreateFreeThreaded(m_device, pixelFormat, 2, m_item.Size());
42 | m_session = m_framePool.CreateCaptureSession(m_item);
43 | m_lastSize = m_item.Size();
44 | m_framePool.FrameArrived({ this, &SimpleCapture::OnFrameArrived });
45 | }
46 |
47 | void SimpleCapture::StartCapture()
48 | {
49 | CheckClosed();
50 | m_lastFrameTime = std::chrono::steady_clock::now();
51 | m_session.StartCapture();
52 | }
53 |
54 | void SimpleCapture::Close()
55 | {
56 | auto expected = false;
57 | if (m_closed.compare_exchange_strong(expected, true))
58 | {
59 | m_session.Close();
60 | m_framePool.Close();
61 |
62 | m_framePool = nullptr;
63 | m_session = nullptr;
64 | m_item = nullptr;
65 | }
66 | }
67 |
68 | void SimpleCapture::CloseAndSave(StorageFolder storageFolder)
69 | {
70 | auto expected = false;
71 | if (m_closed.compare_exchange_strong(expected, true))
72 | {
73 |
74 | m_session.Close();
75 | m_framePool.Close();
76 |
77 | m_frameBuffer.save_frames(storageFolder);
78 |
79 | m_framePool = nullptr;
80 | m_session = nullptr;
81 | m_item = nullptr;
82 | }
83 | }
84 |
85 | void SimpleCapture::OnFrameArrived(winrt::Direct3D11CaptureFramePool const& sender, winrt::IInspectable const&)
86 | {
87 | auto frame = sender.TryGetNextFrame();
88 |
89 | auto now = std::chrono::steady_clock::now();
90 | auto timeSinceLastFrame = std::chrono::duration_cast(now - m_lastFrameTime).count();
91 |
92 | if (timeSinceLastFrame >= m_frameInterval)
93 | {
94 | auto now_sysclock = std::chrono::system_clock::now();
95 | auto now_time_t = std::chrono::system_clock::to_time_t(now_sysclock);
96 | auto now_us = std::chrono::duration_cast(now_sysclock.time_since_epoch()) % 1000000;
97 | std::stringstream ss;
98 | std::tm now_tm = {};
99 | localtime_s(&now_tm, &now_time_t);
100 | ss << std::put_time(&now_tm, "%Y-%m-%d_%H-%M-%S-") << std::setw(6) << std::setfill('0') << now_us.count();
101 | std::string timestamp = ss.str();
102 | std::string filename = "screenshot_" + timestamp + ".jpg";
103 |
104 | ReceivedFrameEvent(filename);
105 |
106 | // Store frame
107 |
108 | auto surfaceTexture = GetDXGIInterfaceFromObject(frame.Surface());
109 |
110 | D3D11_TEXTURE2D_DESC desc{};
111 | surfaceTexture->GetDesc(&desc);
112 |
113 | winrt::com_ptr frameTexture;
114 | winrt::check_hresult(m_d3dDevice->CreateTexture2D(&desc, nullptr, frameTexture.put()));
115 |
116 | m_d3dContext->CopyResource(frameTexture.get(), surfaceTexture.get());
117 |
118 | m_frameBuffer.add_frame(frameTexture, filename);
119 |
120 | m_lastFrameTime = now;
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/screenrecorder/LaunchDetectorScript/LaunchDetectorScript.py:
--------------------------------------------------------------------------------
1 | import argparse
2 | from pathlib import Path
3 | import torch.nn as nn
4 | import torch
5 | from PIL import Image
6 | import os
7 | from torchvision import transforms as T
8 | import shutil
9 | import sys
10 |
11 | class CropBottomPercent:
12 | def __init__(self, percentage):
13 | self.percentage = percentage
14 |
15 | def __call__(self, image):
16 | width, height = image.size
17 | crop_height = int(height * self.percentage)
18 |
19 | return image.crop((0, 0, width, height - crop_height))
20 |
21 | #Creating a class that loads the dataset from the directories
22 | class launchDetector(torch.utils.data.Dataset):
23 | def __init__(self, path, train = True, transforms = None):
24 | self.path = path
25 | self.transforms = transforms
26 | self.images = list(sorted(os.listdir(path)))
27 |
28 | def __getitem__(self, index):
29 | image_path = os.path.join(self.path, self.images[index])
30 | image = Image.open(image_path).convert("RGB")
31 |
32 | if self.transforms is not None:
33 | image = self.transforms(image)
34 |
35 | return image
36 |
37 | def __len__(self):
38 | return len(self.images)
39 |
40 |
41 | #Create the transforms that will with which the data will be preprocessed
42 | img_transforms = T.Compose([CropBottomPercent(0.05),
43 | T.Resize((224,224)),
44 | T.ToTensor(),
45 | T.Normalize([0.485, 0.456, 0.406],
46 | [0.229, 0.224, 0.225])])
47 |
48 | ## CNN Module
49 | class CNN(nn.Module):
50 | def __init__(self):
51 | super(CNN, self).__init__()
52 | self.max_pool1 = nn.MaxPool2d(kernel_size = 4, stride = 2)
53 |
54 | # Progresses data across layers
55 | def forward(self, x):
56 | output = self.max_pool1(x)
57 | return output
58 |
59 | def has_non_image_files(file_path):
60 | for file in os.listdir(file_path):
61 | if not file.endswith('.jpg') and not file.endswith('.png'):
62 | return True
63 | return False
64 |
65 | def clean_directory(folder_path):
66 | # Clean non-image files from folder
67 | for file in os.listdir(folder_path): # Loop through all files in directory
68 | file_path = os.path.join(folder_path, file) # Get full file path
69 | try:
70 | im = Image.open(file_path) # Try to open file as image
71 | except:
72 | non_image_folder = folder_path + "_non_images" # If file is not image, create folder for non-images
73 | if not os.path.exists(non_image_folder):
74 | os.mkdir(non_image_folder) # Create folder if it doesn't exist already
75 | shutil.move(file_path, os.path.join(non_image_folder, file)) # Move non-image file to non-image folder
76 | continue
77 |
78 | def imageSimilarityIndexGenerator(img_1, img_2):
79 | img_1 = torch.reshape(img_1, (-1,))
80 | img_2 = torch.reshape(img_2, (-1,))
81 | cos = nn.CosineSimilarity(dim=0, eps=1e-6)
82 | return cos(img_1, img_2).numpy()
83 |
84 | def launchFrameDetector(cosine_similarity_list, file_names):
85 | similarity_threshold = 0.999
86 | for similarity_value in reversed(range(len(cosine_similarity_list))):
87 | if float(cosine_similarity_list[similarity_value]) < similarity_threshold:
88 | return file_names[similarity_value + 1]
89 |
90 | parser = argparse.ArgumentParser(description='This script analyzes a directory of images and returns the name of the image that is most similar to the reference image.\n\n'
91 | 'Any files that are not images in the folder given in file_path will be removed from the folder and moved to a folder in the parent folder with the name "folder_path" + "_non_images".\n')
92 | parser.add_argument("file_path", type=Path, help='path to the directory containing the images to be analyzed')
93 |
94 | p = parser.parse_args()
95 | images_path = str(p.file_path)
96 |
97 | if has_non_image_files(images_path):
98 | clean_directory(images_path)
99 | print("Non-image files were found in the directory and have been moved to a folder called " + images_path + "_non_images")
100 |
101 | # Get the list of image file names
102 | file_names = [f for f in os.listdir(images_path) if f.endswith('.jpg') or f.endswith('.png')]
103 |
104 | train_dataset = launchDetector(images_path, transforms=img_transforms)
105 |
106 | model = CNN()
107 | pooled_tensors = []
108 | for tensor in train_dataset:
109 | pooled_tensors.append(model.forward(tensor))
110 |
111 | launch_cosine_similarity = []
112 | for current_image_index in range(len(pooled_tensors)-1):
113 | launch_cosine_similarity.append(imageSimilarityIndexGenerator(train_dataset[current_image_index],train_dataset[current_image_index+1]))
114 |
115 | sys.stdout.write(str(launchFrameDetector(launch_cosine_similarity, file_names)))
116 |
--------------------------------------------------------------------------------
/screenrecorder/GAUSS/MeasureCommand.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Windows.EventTracing;
2 | using Microsoft.Windows.EventTracing.Cpu;
3 | using Microsoft.Windows.EventTracing.Events;
4 | using Microsoft.Windows.EventTracing.Processes;
5 | using System.Text.RegularExpressions;
6 |
7 | namespace GAUSS
8 | {
9 | public class MeasureCommand : ICommand
10 | {
11 | public static readonly string WprExecutable = "wpr.exe";
12 | public static readonly string ScreenRecorderExecutable = "ScreenRecorder.exe";
13 | public static readonly string TraceProfile = "profile.wprp";
14 | public static readonly string LaunchDetectorScriptExecutable = "LaunchDetectorScript.exe";
15 | public static readonly string DefaultOutputPath = Path.GetTempPath();
16 |
17 | public Duration Duration { get; set; }
18 |
19 | public double Framerate { get; set; }
20 |
21 | public string OutputPath { get; set; }
22 |
23 | public string TracePath => Path.Combine(OutputPath, "trace.etl");
24 |
25 | public string ScreenshotsPath => Path.Combine(OutputPath, "screenshots");
26 |
27 | public MeasureCommand(Duration duration, double framerate)
28 | {
29 | Duration = duration;
30 | Framerate = framerate;
31 | OutputPath = DefaultOutputPath;
32 | }
33 |
34 | public bool CanPerform()
35 | {
36 | if (!Directory.Exists(OutputPath))
37 | {
38 | Console.WriteLine($"Data path {OutputPath} does not exist.");
39 |
40 | return false;
41 | }
42 |
43 | if (File.Exists(TracePath))
44 | {
45 | Console.WriteLine($"Trace path {TracePath} already exists. Please delete or remove.");
46 |
47 | return false;
48 | }
49 |
50 | if (Directory.Exists(ScreenshotsPath))
51 | {
52 | Console.WriteLine($"Screenshot folder {ScreenshotsPath} already exists. Please delete or remove.");
53 |
54 | return false;
55 | }
56 |
57 | if (!File.Exists(TraceProfile))
58 | {
59 | Console.WriteLine($"Failed to find trace profile {TraceProfile}.");
60 |
61 | return false;
62 | }
63 |
64 | if (!Utilities.ExistsOnPath(WprExecutable))
65 | {
66 | Console.WriteLine($"Failed to find {WprExecutable} on path.");
67 |
68 | return false;
69 | }
70 |
71 | if (!Utilities.ExistsOnPath(ScreenRecorderExecutable))
72 | {
73 | Console.WriteLine($"Failed to find {ScreenRecorderExecutable} on path.");
74 |
75 | return false;
76 | }
77 |
78 | if (!Utilities.ExistsOnPath(LaunchDetectorScriptExecutable))
79 | {
80 | Console.WriteLine($"Failed to find {LaunchDetectorScriptExecutable} on path.");
81 |
82 | return false;
83 | }
84 |
85 | if (!Utilities.IsWindowsAdmin())
86 | {
87 | Console.WriteLine($"Please run as admin to measure a scenario.");
88 |
89 | return false;
90 | }
91 |
92 | return true;
93 | }
94 |
95 | public void Perform()
96 | {
97 | if (!CanPerform())
98 | {
99 | return;
100 | }
101 |
102 | if (Utilities.RunExecutable(WprExecutable, $"-start {TraceProfile}") != 0)
103 | {
104 | Console.WriteLine($"WPR failed.");
105 |
106 | return;
107 | }
108 |
109 | Directory.CreateDirectory(ScreenshotsPath);
110 | int framebuffer = (int)((decimal)Framerate * Duration.TotalSeconds);
111 |
112 | if (Utilities.RunExecutable(ScreenRecorderExecutable, $"-start -framerate {Framerate} -framebuffer {framebuffer}") != 0)
113 | {
114 | Console.WriteLine($"ScreenRecorder failed.");
115 |
116 | return;
117 | }
118 |
119 | Console.WriteLine("Started recording...");
120 |
121 | Thread.Sleep((int)Duration.TotalMilliseconds);
122 |
123 | Console.WriteLine("Stopping recording...");
124 |
125 | if (Utilities.RunExecutable(ScreenRecorderExecutable, $"-stop {ScreenshotsPath}") != 0)
126 | {
127 | Console.WriteLine($"ScreenRecorder failed.");
128 |
129 | return;
130 | }
131 |
132 | if (Utilities.RunExecutable(WprExecutable, $"-stop {TracePath}", out string wprstopout) != 0)
133 | {
134 | Console.WriteLine($"WPR failed.");
135 |
136 | return;
137 | }
138 |
139 | Console.WriteLine("Processing data...");
140 |
141 | ITraceProcessor trace = TraceProcessor.Create(TracePath);
142 |
143 | IPendingResult pendingProcessDataSource = trace.UseProcesses();
144 | IPendingResult pendingCpuSampleDataSource = trace.UseCpuSamplingData();
145 | IPendingResult pendingGenericEventDataSource = trace.UseGenericEvents();
146 |
147 | trace.Process();
148 |
149 | IProcessDataSource processDataSource = pendingProcessDataSource.Result;
150 | ICpuSampleDataSource cpuSampleDataSource = pendingCpuSampleDataSource.Result;
151 | IGenericEventDataSource genericEventDataSource = pendingGenericEventDataSource.Result;
152 |
153 | Timestamp lastClickTimestamp;
154 |
155 | try
156 | {
157 | lastClickTimestamp = genericEventDataSource.Events
158 | .Where(e => e.ProviderName == "Microsoft.Windows.Win32kBase.Input" && e.TaskName == "MousePacketLatency" && e.Fields[1].AsUInt32 == 1)
159 | .OrderBy(e => e.Timestamp)
160 | .Last().Timestamp.RelativeTimestamp;
161 | }
162 | catch (InvalidOperationException)
163 | {
164 | lastClickTimestamp = Timestamp.Zero;
165 | }
166 |
167 | if (Utilities.RunExecutable(LaunchDetectorScriptExecutable, ScreenshotsPath, out string launchDetectorScriptOutput) != 0)
168 | {
169 | Console.WriteLine($"LaunchDetectorScript failed.");
170 |
171 | return;
172 | }
173 |
174 | string pattern = @"[a-zA-Z0-9_-]*\.jpg";
175 |
176 | Match match = Regex.Match(launchDetectorScriptOutput, pattern);
177 | string settledScreenshotName = match.Value;
178 |
179 | Timestamp settledTimestamp;
180 |
181 | try
182 | {
183 | settledTimestamp = genericEventDataSource.Events
184 | .Where(e => e.ProviderName == "ScreenRecorder" && e.ActivityName == "ReceivedFrame")
185 | .Where(e => e.Fields[0].AsString == settledScreenshotName).Single().Timestamp.RelativeTimestamp;
186 | }
187 | catch (InvalidOperationException)
188 | {
189 | settledTimestamp = Timestamp.Zero;
190 | }
191 |
192 | Console.WriteLine($"Settled screenshot name: {settledScreenshotName}");
193 |
194 | if (lastClickTimestamp == Timestamp.Zero || settledTimestamp == Timestamp.Zero)
195 | {
196 | Console.WriteLine(lastClickTimestamp == Timestamp.Zero ? $"No clicks found in trace." : $"lastClickTimestamp: {lastClickTimestamp.TotalSeconds} seconds.");
197 | Console.WriteLine(settledTimestamp == Timestamp.Zero ? $"No settled screenshot found in trace." : $"settledTimestamp: {settledTimestamp.TotalSeconds} seconds.");
198 | }
199 | else
200 | {
201 | Duration interactionDuration = settledTimestamp - lastClickTimestamp;
202 | Console.WriteLine($"Measured interaction duration: {interactionDuration.TotalSeconds} seconds");
203 | }
204 |
205 | if (OutputPath.Equals(DefaultOutputPath))
206 | {
207 | File.Delete(TracePath);
208 | Directory.Delete(ScreenshotsPath, recursive: true);
209 | }
210 | }
211 | }
212 | }
213 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Ww][Ii][Nn]32/
27 | [Aa][Rr][Mm]/
28 | [Aa][Rr][Mm]64/
29 | bld/
30 | [Bb]in/
31 | [Oo]bj/
32 | [Ll]og/
33 | [Ll]ogs/
34 |
35 | # Visual Studio 2015/2017 cache/options directory
36 | .vs/
37 | # Uncomment if you have tasks that create the project's static files in wwwroot
38 | #wwwroot/
39 |
40 | # Visual Studio 2017 auto generated files
41 | Generated\ Files/
42 |
43 | # MSTest test Results
44 | [Tt]est[Rr]esult*/
45 | [Bb]uild[Ll]og.*
46 |
47 | # NUnit
48 | *.VisualState.xml
49 | TestResult.xml
50 | nunit-*.xml
51 |
52 | # Build Results of an ATL Project
53 | [Dd]ebugPS/
54 | [Rr]eleasePS/
55 | dlldata.c
56 |
57 | # Benchmark Results
58 | BenchmarkDotNet.Artifacts/
59 |
60 | # .NET Core
61 | project.lock.json
62 | project.fragment.lock.json
63 | artifacts/
64 |
65 | # ASP.NET Scaffolding
66 | ScaffoldingReadMe.txt
67 |
68 | # StyleCop
69 | StyleCopReport.xml
70 |
71 | # Files built by Visual Studio
72 | *_i.c
73 | *_p.c
74 | *_h.h
75 | *.ilk
76 | *.meta
77 | *.obj
78 | *.iobj
79 | *.pch
80 | *.pdb
81 | *.ipdb
82 | *.pgc
83 | *.pgd
84 | *.rsp
85 | *.sbr
86 | *.tlb
87 | *.tli
88 | *.tlh
89 | *.tmp
90 | *.tmp_proj
91 | *_wpftmp.csproj
92 | *.log
93 | *.tlog
94 | *.vspscc
95 | *.vssscc
96 | .builds
97 | *.pidb
98 | *.svclog
99 | *.scc
100 |
101 | # Chutzpah Test files
102 | _Chutzpah*
103 |
104 | # Visual C++ cache files
105 | ipch/
106 | *.aps
107 | *.ncb
108 | *.opendb
109 | *.opensdf
110 | *.sdf
111 | *.cachefile
112 | *.VC.db
113 | *.VC.VC.opendb
114 |
115 | # Visual Studio profiler
116 | *.psess
117 | *.vsp
118 | *.vspx
119 | *.sap
120 |
121 | # Visual Studio Trace Files
122 | *.e2e
123 |
124 | # TFS 2012 Local Workspace
125 | $tf/
126 |
127 | # Guidance Automation Toolkit
128 | *.gpState
129 |
130 | # ReSharper is a .NET coding add-in
131 | _ReSharper*/
132 | *.[Rr]e[Ss]harper
133 | *.DotSettings.user
134 |
135 | # TeamCity is a build add-in
136 | _TeamCity*
137 |
138 | # DotCover is a Code Coverage Tool
139 | *.dotCover
140 |
141 | # AxoCover is a Code Coverage Tool
142 | .axoCover/*
143 | !.axoCover/settings.json
144 |
145 | # Coverlet is a free, cross platform Code Coverage Tool
146 | coverage*.json
147 | coverage*.xml
148 | coverage*.info
149 |
150 | # Visual Studio code coverage results
151 | *.coverage
152 | *.coveragexml
153 |
154 | # NCrunch
155 | _NCrunch_*
156 | .*crunch*.local.xml
157 | nCrunchTemp_*
158 |
159 | # MightyMoose
160 | *.mm.*
161 | AutoTest.Net/
162 |
163 | # Web workbench (sass)
164 | .sass-cache/
165 |
166 | # Installshield output folder
167 | [Ee]xpress/
168 |
169 | # DocProject is a documentation generator add-in
170 | DocProject/buildhelp/
171 | DocProject/Help/*.HxT
172 | DocProject/Help/*.HxC
173 | DocProject/Help/*.hhc
174 | DocProject/Help/*.hhk
175 | DocProject/Help/*.hhp
176 | DocProject/Help/Html2
177 | DocProject/Help/html
178 |
179 | # Click-Once directory
180 | publish/
181 |
182 | # Publish Web Output
183 | *.[Pp]ublish.xml
184 | *.azurePubxml
185 | # Note: Comment the next line if you want to checkin your web deploy settings,
186 | # but database connection strings (with potential passwords) will be unencrypted
187 | *.pubxml
188 | *.publishproj
189 |
190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
191 | # checkin your Azure Web App publish settings, but sensitive information contained
192 | # in these scripts will be unencrypted
193 | PublishScripts/
194 |
195 | # NuGet Packages
196 | *.nupkg
197 | # NuGet Symbol Packages
198 | *.snupkg
199 | # The packages folder can be ignored because of Package Restore
200 | **/[Pp]ackages/*
201 | # except build/, which is used as an MSBuild target.
202 | !**/[Pp]ackages/build/
203 | # Uncomment if necessary however generally it will be regenerated when needed
204 | #!**/[Pp]ackages/repositories.config
205 | # NuGet v3's project.json files produces more ignorable files
206 | *.nuget.props
207 | *.nuget.targets
208 |
209 | # Microsoft Azure Build Output
210 | csx/
211 | *.build.csdef
212 |
213 | # Microsoft Azure Emulator
214 | ecf/
215 | rcf/
216 |
217 | # Windows Store app package directories and files
218 | AppPackages/
219 | BundleArtifacts/
220 | Package.StoreAssociation.xml
221 | _pkginfo.txt
222 | *.appx
223 | *.appxbundle
224 | *.appxupload
225 |
226 | # Visual Studio cache files
227 | # files ending in .cache can be ignored
228 | *.[Cc]ache
229 | # but keep track of directories ending in .cache
230 | !?*.[Cc]ache/
231 |
232 | # Others
233 | ClientBin/
234 | ~$*
235 | *~
236 | *.dbmdl
237 | *.dbproj.schemaview
238 | *.jfm
239 | *.pfx
240 | *.publishsettings
241 | orleans.codegen.cs
242 |
243 | # Including strong name files can present a security risk
244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
245 | #*.snk
246 |
247 | # Since there are multiple workflows, uncomment next line to ignore bower_components
248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
249 | #bower_components/
250 |
251 | # RIA/Silverlight projects
252 | Generated_Code/
253 |
254 | # Backup & report files from converting an old project file
255 | # to a newer Visual Studio version. Backup files are not needed,
256 | # because we have git ;-)
257 | _UpgradeReport_Files/
258 | Backup*/
259 | UpgradeLog*.XML
260 | UpgradeLog*.htm
261 | ServiceFabricBackup/
262 | *.rptproj.bak
263 |
264 | # SQL Server files
265 | *.mdf
266 | *.ldf
267 | *.ndf
268 |
269 | # Business Intelligence projects
270 | *.rdl.data
271 | *.bim.layout
272 | *.bim_*.settings
273 | *.rptproj.rsuser
274 | *- [Bb]ackup.rdl
275 | *- [Bb]ackup ([0-9]).rdl
276 | *- [Bb]ackup ([0-9][0-9]).rdl
277 |
278 | # Microsoft Fakes
279 | FakesAssemblies/
280 |
281 | # GhostDoc plugin setting file
282 | *.GhostDoc.xml
283 |
284 | # Node.js Tools for Visual Studio
285 | .ntvs_analysis.dat
286 | node_modules/
287 |
288 | # Visual Studio 6 build log
289 | *.plg
290 |
291 | # Visual Studio 6 workspace options file
292 | *.opt
293 |
294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
295 | *.vbw
296 |
297 | # Visual Studio 6 auto-generated project file (contains which files were open etc.)
298 | *.vbp
299 |
300 | # Visual Studio 6 workspace and project file (working project files containing files to include in project)
301 | *.dsw
302 | *.dsp
303 |
304 | # Visual Studio 6 technical files
305 | *.ncb
306 | *.aps
307 |
308 | # Visual Studio LightSwitch build output
309 | **/*.HTMLClient/GeneratedArtifacts
310 | **/*.DesktopClient/GeneratedArtifacts
311 | **/*.DesktopClient/ModelManifest.xml
312 | **/*.Server/GeneratedArtifacts
313 | **/*.Server/ModelManifest.xml
314 | _Pvt_Extensions
315 |
316 | # Paket dependency manager
317 | .paket/paket.exe
318 | paket-files/
319 |
320 | # FAKE - F# Make
321 | .fake/
322 |
323 | # CodeRush personal settings
324 | .cr/personal
325 |
326 | # Python Tools for Visual Studio (PTVS)
327 | __pycache__/
328 | *.pyc
329 |
330 | # Cake - Uncomment if you are using it
331 | # tools/**
332 | # !tools/packages.config
333 |
334 | # Tabs Studio
335 | *.tss
336 |
337 | # Telerik's JustMock configuration file
338 | *.jmconfig
339 |
340 | # BizTalk build output
341 | *.btp.cs
342 | *.btm.cs
343 | *.odx.cs
344 | *.xsd.cs
345 |
346 | # OpenCover UI analysis results
347 | OpenCover/
348 |
349 | # Azure Stream Analytics local run output
350 | ASALocalRun/
351 |
352 | # MSBuild Binary and Structured Log
353 | *.binlog
354 |
355 | # NVidia Nsight GPU debugger configuration file
356 | *.nvuser
357 |
358 | # MFractors (Xamarin productivity tool) working folder
359 | .mfractor/
360 |
361 | # Local History for Visual Studio
362 | .localhistory/
363 |
364 | # Visual Studio History (VSHistory) files
365 | .vshistory/
366 |
367 | # BeatPulse healthcheck temp database
368 | healthchecksdb
369 |
370 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
371 | MigrationBackup/
372 |
373 | # Ionide (cross platform F# VS Code tools) working folder
374 | .ionide/
375 |
376 | # Fody - auto-generated XML schema
377 | FodyWeavers.xsd
378 |
379 | # VS Code files for those working on multiple tools
380 | .vscode/*
381 | !.vscode/settings.json
382 | !.vscode/tasks.json
383 | !.vscode/launch.json
384 | !.vscode/extensions.json
385 | *.code-workspace
386 |
387 | # Local History for Visual Studio Code
388 | .history/
389 |
390 | # Windows Installer files from build outputs
391 | *.cab
392 | *.msi
393 | *.msix
394 | *.msm
395 | *.msp
396 |
397 | # JetBrains Rider
398 | *.sln.iml
399 |
400 | # Pyinstaller build folders
401 | **/build
402 | **/dist
403 |
--------------------------------------------------------------------------------
/screenrecorder/ScreenRecorder/ScreenRecorder.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Debug
7 | ARM64
8 |
9 |
10 | Debug
11 | Win32
12 |
13 |
14 | Release
15 | ARM64
16 |
17 |
18 | Release
19 | Win32
20 |
21 |
22 | Debug
23 | x64
24 |
25 |
26 | Release
27 | x64
28 |
29 |
30 |
31 | 17.0
32 | Win32Proj
33 | {96df8515-4ab5-4213-acc0-3cfbea8fdee1}
34 | ScreenRecorder
35 | 10.0
36 |
37 |
38 |
39 | Application
40 | true
41 | v143
42 | Unicode
43 |
44 |
45 | Application
46 | false
47 | v143
48 | true
49 | Unicode
50 |
51 |
52 | Application
53 | true
54 | v143
55 | Unicode
56 |
57 |
58 | Application
59 | true
60 | v143
61 | Unicode
62 |
63 |
64 | Application
65 | false
66 | v143
67 | true
68 | Unicode
69 |
70 |
71 | Application
72 | false
73 | v143
74 | true
75 | Unicode
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 | Level3
104 | true
105 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
106 | true
107 |
108 |
109 | Console
110 | true
111 |
112 |
113 |
114 |
115 | Level3
116 | true
117 | true
118 | true
119 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
120 | true
121 |
122 |
123 | Console
124 | true
125 | true
126 | true
127 |
128 |
129 |
130 |
131 | Level3
132 | true
133 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
134 | true
135 |
136 |
137 | Console
138 | true
139 |
140 |
141 |
142 |
143 | Level3
144 | true
145 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
146 | true
147 |
148 |
149 | Console
150 | true
151 |
152 |
153 |
154 |
155 | Level3
156 | true
157 | true
158 | true
159 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
160 | true
161 |
162 |
163 | Console
164 | true
165 | true
166 | true
167 |
168 |
169 |
170 |
171 | Level3
172 | true
173 | true
174 | true
175 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
176 | true
177 |
178 |
179 | Console
180 | true
181 | true
182 | true
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
226 |
227 |
228 |
229 |
230 |
231 |
232 |
--------------------------------------------------------------------------------
/screenrecorder/ScreenRecorder/main.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "Server.h"
3 | #include "Client.h"
4 | #include "CommandLine.h"
5 | #include "Request.h"
6 | #include "Response.h"
7 |
8 | TRACELOGGING_DEFINE_PROVIDER(
9 | g_hMyComponentProvider,
10 | "ScreenRecorder",
11 | // Human-readable guid: fe8fc3d0-1e6a-42f2-be28-9f8a0fcf7b04
12 | (0xfe8fc3d0, 0x1e6a, 0x42f2, 0xbe, 0x28, 0x9f, 0x8a, 0x0f, 0xcf, 0x7b, 0x04));
13 |
14 | const std::string helpMessage = "\n\tUsage: screenrecorder.exe options ...\n\n"
15 | "\t-help start\t- for screen recording start command\n"
16 | "\t-help stop\t- for screen recording stop commands\n";
17 |
18 | const std::string startHelpMessage = "\n screenrecorder.exe -start ... Starts screen recording.\n"
19 | "\tUsage:\tscreenrecorder.exe -start [-framerate ] [-monitor ] [-framebuffer -mb <# of frames>] \n"
20 | "\tEx>\tscreenrecorder.exe -start -framerate 10\n"
21 | "\tEx>\tscreenrecorder.exe -start -framerate 1 -monitor 0 -framebuffer -mb 100\n\n"
22 | "\t-framerate\tSpecifies the rate at which screenshots will be taken, in frames per second.\n"
23 | "\t-monitor\tSpecifies the monitor to record, as an index. The highest index will record all monitors.\n"
24 | "\t-framebuffer\tSpecifies the size of the circular memory buffer in which to store screenshots, in number of screenshots. Adding the -mb flag specifies the size of the buffer in megabytes.\n";
25 |
26 | const std::string stopHelpMessage = "\n screenrecorder.exe -stop ... Stops screen recording saves all screenshots in buffer to a folder.\n"
27 | "\tUsage:\tscreenrecorder.exe -stop \n"
28 | "\tEx>\tscreenrecorder.exe -stop \"D:\\screenrecorder\"\n"
29 | "\n screenrecorder.exe -cancel ... Cancels the screen recording.\n"
30 | "\tUsage:\tscreenrecorder.exe -cancel\n";
31 |
32 | const std::string invalidCommandSynatxMessage = "\b\tInvalid command syntax.\n";
33 |
34 | const std::string recordingAlreadyStarted = "\b\tThere is already a recording in process.\n";
35 | const std::string recordingNotStartedMessage = "\b\tThere is no recording in process.\n";
36 |
37 | const std::string failedToCommunicateWithServerProcessMessage = "\b\tFailed to communicate with recording process.\n";
38 | const std::string failedToCreateServerProcessMessage = "\b\tFailed to create the recording process.\n";
39 | const std::string failedToConnectToServerProcessMessage = "\b\tFailed to connect to the recording process.\n";
40 |
41 | const std::string unknownEnumCaseMessage = "\b\tReceived an unknown response from the recording process.\n";
42 | const std::string defaultEnumCaseMessage = "\b\tReceived an unhandled response from the recording process.\n";
43 |
44 | const std::string defaultSeverExceptioinMessage = "\b\tReceived an unknown exception from the recording process.\n";
45 |
46 | bool TryCreateRecordingProcess()
47 | {
48 | TCHAR szPath[MAX_PATH];
49 |
50 | if (!GetModuleFileName(NULL, szPath, MAX_PATH))
51 | {
52 | return false;
53 | }
54 |
55 | std::wstring cmdLine = L"\"" + std::wstring(szPath) + L"\" -newserver"; // Wrap szPath in quotes
56 | STARTUPINFO info = { sizeof(info) };
57 | info.dwFlags = STARTF_USESTDHANDLES;
58 | info.hStdOutput = NULL;
59 | info.hStdError = NULL;
60 | PROCESS_INFORMATION processInfo;
61 |
62 | if (!CreateProcess(szPath, &cmdLine[0], NULL, NULL, TRUE, 0, NULL, NULL, &info, &processInfo))
63 | {
64 | CloseHandle(processInfo.hProcess);
65 | CloseHandle(processInfo.hThread);
66 |
67 | return false;
68 | }
69 |
70 | CloseHandle(processInfo.hProcess);
71 | CloseHandle(processInfo.hThread);
72 |
73 | return true;
74 | }
75 |
76 | void start(CommandLine& commandLine)
77 | {
78 | int framerate, monitorIndex, bufferCapacity;
79 | bool isMegabytes;
80 |
81 | try
82 | {
83 | commandLine.GetStartArgs(framerate, monitorIndex, bufferCapacity, isMegabytes);
84 | }
85 | catch (const std::invalid_argument&)
86 | {
87 | std::cout << invalidCommandSynatxMessage << std::endl;
88 | std::cout << startHelpMessage << std::endl;
89 |
90 | return;
91 | }
92 |
93 | Request startRequest = Request::BuildStartRequest(framerate, monitorIndex, bufferCapacity, isMegabytes);
94 | Request disconnectRequest = Request::BuildDisconnectRequest();
95 | Request killRequest = Request::BuildKillRequest();
96 | Response response;
97 | Client client;
98 |
99 | if (client.try_connect())
100 | {
101 | std::cout << recordingAlreadyStarted << std::endl;
102 |
103 | try
104 | {
105 | client.send(disconnectRequest);
106 | }
107 | catch (const std::ios_base::failure&)
108 | {
109 | std::cout << failedToCommunicateWithServerProcessMessage << std::endl;
110 | }
111 |
112 | return;
113 | }
114 |
115 | if (!TryCreateRecordingProcess())
116 | {
117 | std::cout << failedToCreateServerProcessMessage << std::endl;
118 |
119 | return;
120 | }
121 |
122 | if (!client.try_connect(3))
123 | {
124 | std::cout << failedToConnectToServerProcessMessage << std::endl;
125 |
126 | return;
127 | }
128 |
129 | try
130 | {
131 | response = client.send(startRequest);
132 | }
133 | catch (const std::ios_base::failure&)
134 | {
135 | std::cout << failedToCommunicateWithServerProcessMessage << std::endl;
136 |
137 | return;
138 | }
139 |
140 | std::exception e;
141 |
142 | switch (response.ParseResponseType())
143 | {
144 | case ResponseType::Success:
145 | break;
146 | case ResponseType::Exception:
147 | try
148 | {
149 | response.ParseExceptionArgs(e);
150 |
151 | std::cout << e.what() << std::endl;
152 | }
153 | catch (const std::invalid_argument&)
154 | {
155 | std::cout << defaultSeverExceptioinMessage << std::endl;
156 | }
157 |
158 | try
159 | {
160 | client.send(killRequest);
161 | }
162 | catch (const std::ios_base::failure&)
163 | {
164 | std::cout << failedToCommunicateWithServerProcessMessage << std::endl;
165 | }
166 |
167 | return;
168 | case ResponseType::Unknown:
169 | std::cout << unknownEnumCaseMessage << std::endl;
170 |
171 | try
172 | {
173 | client.send(killRequest);
174 | }
175 | catch (const std::ios_base::failure&)
176 | {
177 | std::cout << failedToCommunicateWithServerProcessMessage << std::endl;
178 | }
179 |
180 | return;
181 | default:
182 | std::cout << defaultEnumCaseMessage << std::endl;
183 |
184 | try
185 | {
186 | client.send(killRequest);
187 | }
188 | catch (const std::ios_base::failure&)
189 | {
190 | std::cout << failedToCommunicateWithServerProcessMessage << std::endl;
191 | }
192 |
193 | return;
194 | }
195 |
196 | try
197 | {
198 | client.send(disconnectRequest);
199 | }
200 | catch (const std::ios_base::failure&)
201 | {
202 | std::cout << failedToCommunicateWithServerProcessMessage << std::endl;
203 | }
204 | }
205 |
206 | void stop(CommandLine& commandLine)
207 | {
208 | std::string folder;
209 |
210 | try
211 | {
212 | commandLine.GetStopArgs(folder);
213 | }
214 | catch (const std::invalid_argument&)
215 | {
216 | std::cout << invalidCommandSynatxMessage << std::endl;
217 | std::cout << stopHelpMessage << std::endl;
218 |
219 | return;
220 | }
221 |
222 | Request stopRequest = Request::BuildStopRequest(folder);
223 | Request disconnectRequest = Request::BuildDisconnectRequest();
224 | Request killRequest = Request::BuildKillRequest();
225 | Response response;
226 | Client client;
227 |
228 | if (!client.try_connect())
229 | {
230 | std::cout << recordingNotStartedMessage << std::endl;
231 |
232 | return;
233 | }
234 |
235 | try
236 | {
237 | response = client.send(stopRequest);
238 | }
239 | catch (const std::ios_base::failure&)
240 | {
241 | std::cout << failedToCommunicateWithServerProcessMessage << std::endl;
242 |
243 | return;
244 | }
245 |
246 | std::exception e;
247 |
248 | switch (response.ParseResponseType())
249 | {
250 | case ResponseType::Success:
251 | break;
252 | case ResponseType::Exception:
253 | try
254 | {
255 | response.ParseExceptionArgs(e);
256 |
257 | std::cout << e.what() << std::endl;
258 | }
259 | catch (const std::invalid_argument&)
260 | {
261 | std::cout << defaultSeverExceptioinMessage << std::endl;
262 | }
263 |
264 | try
265 | {
266 | client.send(disconnectRequest);
267 | }
268 | catch (const std::ios_base::failure&)
269 | {
270 | std::cout << failedToCommunicateWithServerProcessMessage << std::endl;
271 | }
272 |
273 | return;
274 | case ResponseType::Unknown:
275 | std::cout << unknownEnumCaseMessage << std::endl;
276 |
277 | try
278 | {
279 | client.send(disconnectRequest);
280 | }
281 | catch (const std::ios_base::failure&)
282 | {
283 | std::cout << failedToCommunicateWithServerProcessMessage << std::endl;
284 | }
285 |
286 | return;
287 | default:
288 | std::cout << defaultEnumCaseMessage << std::endl;
289 |
290 | try
291 | {
292 | client.send(disconnectRequest);
293 | }
294 | catch (const std::ios_base::failure&)
295 | {
296 | std::cout << failedToCommunicateWithServerProcessMessage << std::endl;
297 | }
298 |
299 | return;
300 | }
301 |
302 | try
303 | {
304 | client.send(killRequest);
305 | }
306 | catch (const std::ios_base::failure&)
307 | {
308 | // print could not commnicate with server or something
309 | }
310 | }
311 |
312 | void cancel(CommandLine& commandLine)
313 | {
314 | Request request = Request::BuildCancelRequest();
315 | Request disconnectRequest = Request::BuildDisconnectRequest();
316 | Request killRequest = Request::BuildKillRequest();
317 | Response response;
318 | Client client;
319 |
320 | if (!client.try_connect())
321 | {
322 | std::cout << recordingNotStartedMessage << std::endl;
323 |
324 | return;
325 | }
326 |
327 | try
328 | {
329 | response = client.send(request);
330 | }
331 | catch (const std::ios_base::failure&)
332 | {
333 | std::cout << failedToCommunicateWithServerProcessMessage << std::endl;
334 |
335 | return;
336 | }
337 |
338 | std::exception e;
339 |
340 | switch (response.ParseResponseType())
341 | {
342 | case ResponseType::Success:
343 | break;
344 | case ResponseType::Exception:
345 | try
346 | {
347 | response.ParseExceptionArgs(e);
348 |
349 | std::cout << e.what() << std::endl;
350 | }
351 | catch (const std::invalid_argument&)
352 | {
353 | std::cout << defaultSeverExceptioinMessage << std::endl;
354 | }
355 |
356 | try
357 | {
358 | client.send(disconnectRequest);
359 | }
360 | catch (const std::ios_base::failure&)
361 | {
362 | std::cout << failedToCommunicateWithServerProcessMessage << std::endl;
363 | }
364 |
365 | return;
366 | case ResponseType::Unknown:
367 | std::cout << unknownEnumCaseMessage << std::endl;
368 |
369 | try
370 | {
371 | client.send(disconnectRequest);
372 | }
373 | catch (const std::ios_base::failure&)
374 | {
375 | std::cout << failedToCommunicateWithServerProcessMessage << std::endl;
376 | }
377 |
378 | return;
379 | default:
380 | std::cout << defaultEnumCaseMessage << std::endl;
381 |
382 | try
383 | {
384 | client.send(disconnectRequest);
385 | }
386 | catch (const std::ios_base::failure&)
387 | {
388 | std::cout << failedToCommunicateWithServerProcessMessage << std::endl;
389 | }
390 |
391 | return;
392 | }
393 |
394 | try
395 | {
396 | client.send(killRequest);
397 | }
398 | catch (const std::ios_base::failure&)
399 | {
400 | std::cout << failedToCommunicateWithServerProcessMessage << std::endl;
401 | }
402 | }
403 |
404 | void new_server()
405 | {
406 | Request disconnectRequest = Request::BuildDisconnectRequest();
407 | Response response;
408 | Client client;
409 |
410 | if (client.try_connect())
411 | {
412 | try
413 | {
414 | client.send(disconnectRequest);
415 | }
416 | catch (const std::ios_base::failure&)
417 | {
418 | }
419 |
420 | return;
421 | }
422 |
423 | std::unique_ptr server = std::make_unique();
424 |
425 | if (!server->try_init())
426 | {
427 | return;
428 | }
429 |
430 | server->run();
431 | }
432 |
433 | void help(CommandLine& commandLine)
434 | {
435 | std::string arg;
436 |
437 | try
438 | {
439 | commandLine.GetHelpArgs(arg);
440 | }
441 | catch (const std::invalid_argument&)
442 | {
443 | std::cout << helpMessage << std::endl;
444 |
445 | return;
446 | }
447 |
448 | if (arg.compare("start") == 0)
449 | {
450 | std::cout << startHelpMessage << std::endl;
451 | }
452 |
453 | else if (arg.compare("stop") == 0)
454 | {
455 | std::cout << stopHelpMessage << std::endl;
456 | }
457 | else
458 | {
459 | std::cout << invalidCommandSynatxMessage << std::endl;
460 | std::cout << helpMessage << std::endl;
461 | }
462 | }
463 |
464 | int main(int argc, char* argv[])
465 | {
466 | CommandLine commandLine(argc, argv);
467 |
468 | switch (commandLine.GetCommandType())
469 | {
470 | case CommandType::Start:
471 | start(commandLine);
472 |
473 | break;
474 | case CommandType::Stop:
475 | stop(commandLine);
476 |
477 | break;
478 | case CommandType::Cancel:
479 | cancel(commandLine);
480 |
481 | break;
482 | case CommandType::NewServer:
483 | new_server();
484 |
485 | break;
486 | case CommandType::Help:
487 | help(commandLine);
488 |
489 | break;
490 | case CommandType::Unknown:
491 | default:
492 | std::cout << invalidCommandSynatxMessage << std::endl;
493 | std::cout << helpMessage << std::endl;
494 | }
495 | }
--------------------------------------------------------------------------------
/screenrecorder/GAUSS/profile.wprp:
--------------------------------------------------------------------------------
1 |
2 |
7 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
540 |
541 |
542 |
543 |
544 |
545 |
546 |
547 |
548 |
549 |
550 |
551 |
552 |
553 |
554 |
555 |
556 |
557 |
558 |
559 |
560 |
561 |
562 |
563 |
564 |
565 |
566 |
567 |
568 |
569 |
570 |
571 |
572 |
573 |
574 |
575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 |
583 |
584 |
585 |
586 |
587 |
588 |
589 |
590 |
591 |
592 |
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 |
601 |
602 |
603 |
604 |
605 |
606 |
607 |
608 |
609 |
610 |
611 |
612 |
613 |
614 |
615 |
616 |
617 |
618 |
619 |
620 |
621 |
622 |
623 |
624 |
625 |
626 |
627 |
628 |
629 |
630 |
631 |
632 |
633 |
634 |
635 |
636 |
637 |
638 |
639 |
640 |
641 |
642 |
643 |
644 |
645 |
646 |
647 |
648 |
649 |
650 |
651 |
652 |
653 |
654 |
655 |
656 |
657 |
658 |
659 |
660 |
661 |
662 |
663 |
664 |
665 |
666 |
667 |
668 |
669 |
670 |
671 |
672 |
673 |
674 |
675 |
676 |
677 |
678 |
679 |
680 |
681 |
682 |
683 |
684 |
685 |
686 |
687 |
688 |
689 |
690 |
691 |
692 |
693 |
694 |
695 |
696 |
697 |
698 |
699 |
700 |
701 |
702 |
703 |
704 |
705 |
706 |
707 |
708 |
709 |
710 |
711 |
712 |
713 |
714 |
715 |
716 |
717 |
718 |
719 |
720 |
721 |
722 |
723 |
724 |
725 |
726 |
727 |
728 |
729 |
730 |
731 |
732 |
733 |
734 |
735 |
736 |
737 |
738 |
739 |
740 |
741 |
742 |
743 |
744 |
745 |
746 |
747 |
748 |
749 |
750 |
751 |
752 |
753 |
754 |
755 |
756 |
757 |
758 |
759 |
760 |
761 |
762 |
763 |
764 |
765 |
766 |
767 |
768 |
769 |
770 |
771 |
772 |
773 |
774 |
775 |
776 |
777 |
778 |
779 |
780 |
781 |
782 |
783 |
784 |
785 |
786 |
787 |
788 |
789 |
790 |
791 |
792 |
793 |
794 |
795 |
796 |
797 |
798 |
799 |
800 |
801 |
802 |
803 |
804 |
805 |
806 |
807 |
808 |
809 |
810 |
811 |
812 |
813 |
814 |
815 |
816 |
817 |
818 |
819 |
820 |
821 |
822 |
823 |
824 |
825 |
826 |
827 |
828 |
829 |
830 |
831 |
832 |
833 |
834 |
835 |
836 |
837 |
838 |
839 |
840 |
841 |
842 |
843 |
844 |
845 |
846 |
847 |
848 |
849 |
850 |
851 |
852 |
853 |
854 |
855 |
856 |
857 |
858 |
859 |
860 |
861 |
862 |
863 |
864 |
865 |
866 |
867 |
868 |
869 |
870 |
871 |
872 |
873 |
874 |
875 |
876 |
877 |
878 |
879 |
880 |
881 |
882 |
883 |
884 |
885 |
886 |
887 |
888 |
889 |
890 |
891 |
892 |
893 |
894 |
895 |
896 |
897 |
898 |
899 |
900 |
901 |
902 |
903 |
904 |
905 |
906 |
907 |
908 |
909 |
910 |
911 |
912 |
913 |
914 |
915 |
916 |
917 |
918 |
919 |
920 |
921 |
922 |
923 |
924 |
925 |
926 |
927 |
928 |
929 |
930 |
931 |
932 |
933 |
934 |
935 |
936 |
937 |
938 |
939 |
940 |
941 |
942 |
943 |
944 |
945 |
946 |
947 |
948 |
949 |
950 |
951 |
952 |
953 |
954 |
955 |
956 |
957 |
958 |
959 |
960 |
961 |
962 |
963 |
964 |
965 |
966 |
967 |
968 |
969 |
970 |
971 |
972 |
973 |
974 |
975 |
976 |
977 |
978 |
979 |
980 |
981 |
982 |
983 |
984 |
985 |
986 |
987 |
988 |
989 |
990 |
991 |
992 |
993 |
994 |
995 |
996 |
997 |
998 |
999 |
1000 |
1001 |
1002 |
1003 |
1004 |
1005 |
1006 |
1007 |
1008 |
1009 |
1010 |
1011 |
1012 |
1013 |
1014 |
1015 |
1016 |
1017 |
1018 |
1019 |
1020 |
1021 |
1022 |
1023 |
1024 |
1025 |
1026 |
1027 |
1028 |
1029 |
1030 |
1031 |
1032 |
1033 |
1034 |
1035 |
1036 |
1037 |
1038 |
1039 |
1040 |
1041 |
1042 |
1043 |
1044 |
1045 |
1046 |
1047 |
1048 |
1049 |
1050 |
1051 |
1052 |
1053 |
1054 |
1055 |
1056 |
1057 |
1058 |
1059 |
1060 |
1061 |
1062 |
1063 |
1064 |
1065 |
1066 |
1067 |
1068 |
1069 |
1070 |
1071 |
1072 |
1073 |
1074 |
1075 |
1076 |
1077 |
1078 |
1079 |
1080 |
1081 |
1082 |
1083 |
1084 |
1085 |
1086 |
1087 |
1088 |
1089 |
1090 |
1091 |
1092 |
1093 |
1094 |
1095 |
1096 |
1097 |
1098 |
1099 |
1100 |
1101 |
1102 |
1103 |
1104 |
1105 |
1106 |
1107 |
1108 |
1109 |
1110 |
1111 |
1112 |
1113 |
1114 |
1115 |
1116 |
1117 |
1118 |
1119 |
1120 |
1121 |
1122 |
1123 |
1124 |
1125 |
1126 |
1127 |
1128 |
1129 |
1130 |
1131 |
1132 |
1133 |
1134 |
1135 |
1136 |
1137 |
1138 |
1139 |
1140 |
1141 |
1142 |
1143 |
1144 |
1145 |
1146 |
1147 |
1148 |
1149 |
1150 |
1151 |
1152 |
1153 |
1154 |
1155 |
1156 |
1157 |
1158 |
1159 |
1160 |
1161 |
1162 |
1163 |
1164 |
1165 |
1166 |
1167 |
1168 |
1169 |
1170 |
1171 |
1172 |
1173 |
1174 |
1175 |
1176 |
1177 |
1178 |
1179 |
1180 |
1181 |
1182 |
1183 |
1184 |
1185 |
1186 |
1187 |
1188 |
1189 |
1190 |
1191 |
1192 |
1193 |
1194 |
1195 |
1196 |
1197 |
1198 |
1199 |
1200 |
1201 |
1202 |
1203 |
1204 |
1205 |
1206 |
1207 |
1208 |
1209 |
1210 |
1211 |
1212 |
1213 |
1214 |
1215 |
1216 |
1217 |
1218 |
1219 |
1220 |
1221 |
1222 |
1223 |
1224 |
1225 |
1226 |
1227 |
1228 |
1229 |
1230 |
1231 |
1232 |
1233 |
1234 |
1235 |
1236 |
1237 |
1238 |
1239 |
1240 |
1241 |
1242 |
1243 |
1244 |
1245 |
1246 |
1247 |
1248 |
1249 |
1250 |
1251 |
1252 |
1253 |
1254 |
1255 |
1256 |
1257 |
1258 |
1259 |
1260 |
1261 |
1262 |
1263 |
1264 |
1265 |
1266 |
1267 |
1268 |
1269 |
1270 |
1271 |
1272 |
1273 |
1274 |
1275 |
1276 |
1277 |
1278 |
1279 |
1280 |
1281 |
1282 |
1283 |
1284 |
1285 |
1286 |
1287 |
1288 |
1289 |
1290 |
1291 |
1292 |
1293 |
1294 |
1295 |
1296 |
1297 |
1298 |
1299 |
1300 |
1301 |
1302 |
1303 |
1304 |
1305 |
1306 |
1307 |
1308 |
1309 |
1310 |
1311 |
1312 |
1313 |
1314 |
1315 |
1316 |
1317 |
1318 |
1319 |
1320 |
1321 |
1322 |
1323 |
1324 |
1325 |
1326 |
1327 |
1328 |
--------------------------------------------------------------------------------