├── 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 | --------------------------------------------------------------------------------