first commit

This commit is contained in:
Luis Reich
2026-09-22 22:41:43 +02:00
parent e513c7aacc
commit 9d0e837622
55 changed files with 5109 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="SharpDX" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View File

@@ -0,0 +1,58 @@
using System;
using System.Diagnostics;
using System.IO;
namespace Overlay.NET.Common {
public sealed class FileLogger : ILogger {
public string Path { get; set; }
public bool IsDisposed { get; set; }
public bool MustBeDisposed { get; set; } = true;
public void WriteLine(string entry) {
try {
_stream.WriteLine(entry);
}
catch (Exception e) {
Trace.WriteLine(e.Message);
}
}
public static readonly FileLogger Instance = new FileLogger();
private readonly StreamWriter _stream;
public FileLogger(RelativeFile file) {
Path = file.GetFullPath();
_stream = new StreamWriter(Path, true) {AutoFlush = true};
}
public FileLogger(string file) {
Path = file;
_stream = new StreamWriter(Path, true) {AutoFlush = true};
}
private FileLogger() {
var file = new RelativeFile {
Name = "AppLog",
Extension = ".txt",
SubDirectory = "Logs",
TimeStampFile = true,
UseDetailedTimeStamp = false
};
Path = file.GetFullPath();
_stream = new StreamWriter(Path, true) {AutoFlush = true};
}
public void Dispose() {
if (IsDisposed) {
return;
}
IsDisposed = true;
_stream.Flush();
_stream.Close();
}
}
}

View File

@@ -0,0 +1,42 @@
using System.Text;
namespace Overlay.NET.Common {
/// <summary>
/// Interface that defines common ways to serialize/deserialize objects to and from strings.
/// </summary>
public interface ISerializer {
/// <summary>
/// Serializes the specified object and returns the document.
/// </summary>
/// <typeparam name="T">The type of the object to serialize.</typeparam>
/// <param name="obj">The object to serialize.</param>
/// <returns>XML document of the serialized object.</returns>
string ExportToString<T>(T obj);
/// <summary>
/// Deserializes the document to the specified object.
/// </summary>
/// <typeparam name="T">The type of the object to deserialize.</typeparam>
/// <param name="serializedObj">The string representing the serialized object.</param>
/// <returns>The deserialized object.</returns>
T ImportFromString<T>(string serializedObj);
/// <summary>
/// Serializes the specified object and writes the document to the specified path.
/// </summary>
/// <typeparam name="T">The type of the object to serialize.</typeparam>
/// <param name="obj">The object to serialize.</param>
/// <param name="file">The path where the file is saved.</param>
/// <param name="encoding">The encoding to generate.</param>
void ExportToFile<T>(T obj, string file, Encoding encoding);
/// <summary>
/// Deserializes the specified file into an object.
/// </summary>
/// <typeparam name="T">The type of the object to deserialize.</typeparam>
/// <param name="path">The path where the object is read.</param>
/// <param name="encoding">The character encoding to use. </param>
/// <returns>The deserialized object.</returns>
T ImportFromFile<T>(string path, Encoding encoding);
}
}

View File

@@ -0,0 +1,27 @@
namespace Overlay.NET.Common {
/// <summary>
/// Interface that defines a way to load and save settings.
/// </summary>
/// <typeparam name="T"></typeparam>
public interface ISettings<out T> {
/// <summary>
/// Gets the current settings instance
/// </summary>
/// <value>
/// The current settings.
/// </value>
T Current { get; }
/// <summary>
/// Saves the settings to the specified target.
/// </summary>
/// <param name="target">The target.</param>
void Save(string target = "");
/// <summary>
/// Loads the settings from the specified location.
/// </summary>
/// <param name="location">The location.</param>
void Load(string location = "");
}
}

View File

@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Overlay.NET.Common {
public enum LogLevel {
Normal,
Debug,
Information,
Warning,
Error,
Fatal
}
public interface ILogger {
void WriteLine(string line);
}
public static class Log {
public static Func<LogLevel, string, object[], string> LogFormatterFunc { get; set; }
private static Dictionary<string, ILogger> Loggers { get; }
static Log() {
Loggers = new Dictionary<string, ILogger>();
LogFormatterFunc = DefaultFormatter;
Loggers.Add("File", FileLogger.Instance);
}
public static void Register(string publicKey, ILogger logger) => Loggers.Add(publicKey, logger);
public static bool Unregister(string publicKey) => Loggers.Remove(publicKey);
public static ILogger Get(string key) => !Loggers.ContainsKey(key) ? Loggers["File"] : Loggers[key];
public static void WriteLine(string format, params object[] args) => WriteLogEntry(LogLevel.Normal, format, args);
public static void Debug(string format, params object[] args) => WriteLogEntry(LogLevel.Debug, format, args);
public static void Info(string format, params object[] args) => WriteLogEntry(LogLevel.Information, format, args);
public static void Warn(string format, params object[] args) => WriteLogEntry(LogLevel.Warning, format, args);
public static void Error(string format, params object[] args) => WriteLogEntry(LogLevel.Error, format, args);
public static void Fatal(string format, params object[] args) => WriteLogEntry(LogLevel.Fatal, format, args);
private static void WriteLogEntry(LogLevel logLevel, string format, params object[] args) {
var formatted = LogFormatterFunc(logLevel, format, args);
foreach (var logger in Loggers.ToArray()) {
logger.Value.WriteLine(formatted);
}
}
private static string DefaultFormatter(LogLevel type, string format, params object[] args) {
if (args != null && args.Any()) {
format = string.Format(format, args);
}
var time = DateTime.Now;
var logType = type == LogLevel.Normal ? "" : $"[{type}]";
return $"{logType}[{time}] {format}";
}
}
}

View File

@@ -0,0 +1,91 @@
using System;
using System.Runtime.InteropServices;
namespace Overlay.NET.Common {
internal class Native {
[DllImport("user32.dll")]
public static extern IntPtr CreateWindowEx(
uint dwExStyle,
string lpClassName,
string lpWindowName,
uint dwStyle,
int x,
int y,
int nWidth,
int nHeight,
IntPtr hWndParent,
IntPtr hMenu,
IntPtr hInstance,
IntPtr lpParam);
[DllImport("user32.dll")]
public static extern int DestroyWindow(IntPtr hwnd);
[DllImport("user32.dll")]
public static extern int SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int y, int cx, int cy,
uint uFlags);
[DllImport("user32.dll")]
public static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")]
public static extern int GetSystemMetrics(int index);
[DllImport("user32.dll")]
public static extern int ShowWindow(IntPtr hWnd, uint nCmdShow);
[DllImport("user32.dll")]
public static extern int GetWindowRect(IntPtr hwnd, out Rect lpRect);
[DllImport("user32.dll")]
public static extern bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags);
[DllImport("user32.dll")]
public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdc, ref Point point, ref Point size,
IntPtr hdcSrc, IntPtr pptSrc, int crKey, IntPtr blend, uint flags);
[DllImport("dwmapi.dll")]
public static extern void DwmExtendFrameIntoClientArea(IntPtr hWnd, ref RawMargin pMargins);
public static IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong)
=> IntPtr.Size == 8 ? SetWindowLongPtr64(hWnd, nIndex, dwNewLong) : new IntPtr(SetWindowLong32(hWnd, nIndex, dwNewLong.ToInt32()));
[DllImport("user32.dll", EntryPoint = "SetWindowLong")]
private static extern int SetWindowLong32(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")]
private static extern IntPtr SetWindowLongPtr64(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
private static extern IntPtr GetWindowLongPtr32(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")]
private static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, int nIndex);
// This static method is required because Win32 does not support
// GetWindowLongPtr directly
public static IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex) => IntPtr.Size == 8 ? GetWindowLongPtr64(hWnd, nIndex) : GetWindowLongPtr32(hWnd, nIndex);
[StructLayout(LayoutKind.Sequential)]
public struct Rect {
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[StructLayout(LayoutKind.Sequential)]
public struct Point {
public int X;
public int Y;
}
[StructLayout(LayoutKind.Sequential)]
public struct RawMargin {
public int cxLeftWidth;
public int cxRightWidth;
public int cyTopHeight;
public int cyBottomHeight;
}
}
}

View File

@@ -0,0 +1,123 @@
using System;
using System.Linq;
namespace Overlay.NET.Common {
/// <summary>
/// The abstract base class for plugins.
/// </summary>
public abstract class PluginBase {
/// <summary>
/// Gets the plugin's Author, or empty string if it fails.
/// </summary>
/// <param name="type">The plugin's Type.</param>
/// <returns>The plugin's Author, or empty string if it fails.</returns>
public static string GetAuthor(Type type) {
var attribute = GetAttribute(type);
return attribute == null ? string.Empty : attribute.Author ?? string.Empty;
}
/// <summary>
/// Gets the plugin's Description, or empty string if it fails.
/// </summary>
/// <param name="type">The plugin's Type.</param>
/// <returns>The plugin's Description, or empty string if it fails.</returns>
public static string GetDescription(Type type) {
var attribute = GetAttribute(type);
return attribute == null ? string.Empty : attribute.Description ?? string.Empty;
}
/// <summary>
/// Gets the identifier for the plugin, or empty string if it fails.
/// </summary>
/// <param name="type">The plugin's Type.</param>
/// <returns>The identifier for the plugin, or empty string if it fails.</returns>
public static string GetIdentifier(Type type) {
var attribute = GetAttribute(type);
return attribute == null ? string.Empty : attribute.Identifier ?? string.Empty;
}
/// <summary>
/// Gets the plugin's Name, or empty string if it fails.
/// </summary>
/// <param name="type">The plugin's Type.</param>
/// <returns>The plugin's Name, or empty string if it fails.</returns>
public static string GetName(Type type) {
var attribute = GetAttribute(type);
return attribute == null ? string.Empty : attribute.Name ?? string.Empty;
}
/// <summary>
/// Gets the plugin's Version, or empty string if it fails.
/// </summary>
/// <param name="type">The plugin's Type.</param>
/// <returns>The plugin's Version, or empty string if it fails.</returns>
public static string GetVersion(Type type) {
var attribute = GetAttribute(type);
return attribute == null ? string.Empty : attribute.Version ?? string.Empty;
}
/// <summary>
/// Gets whether the Type is a registered plugin or not.
/// </summary>
/// <param name="type">The plugin's Type.</param>
/// <returns>Whether the Type is a registered plugin or not.</returns>
public static bool IsRegisteredPlugin(Type type) => GetAttribute(type) != null;
/// <summary>
/// Gets the plugin's RegisteredPluginAttribute, or null if it fails.
/// </summary>
/// <param name="type">The plugin's Type.</param>
/// <returns>The plugin's RegisteredPluginAttribute, or null if it fails.</returns>
private static RegisterPluginAttribute GetAttribute(Type type) => (RegisterPluginAttribute)
type.GetCustomAttributes(typeof(RegisterPluginAttribute), false).FirstOrDefault();
/// <summary>
/// Marks a PluginBase derived class as to be loaded and contains some optional information about the plugin.
/// </summary>
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
protected sealed class RegisterPluginAttribute : Attribute {
/// <summary>
/// Gets the plugin's Author.
/// </summary>
public string Author { get; }
/// <summary>
/// Gets the plugin's Description.
/// </summary>
public string Description { get; }
/// <summary>
/// Gets an identifier for the plugin.
/// </summary>
public string Identifier { get; }
/// <summary>
/// Gets the plugin's Name.
/// </summary>
public string Name { get; }
/// <summary>
/// Gets the plugin's Version.
/// </summary>
public string Version { get; }
/// <summary>
/// Creates a new instance of the <see cref="SharpPlugins.PluginBase.RegisterPluginAttribute" /> class
/// with the identifier, given optional information about the plugin to mark it as to be loaded.
/// </summary>
/// <param name="identifier">The identifier for the plugin.</param>
/// <param name="author">The plugin's Author.</param>
/// <param name="name">The plugin's Name.</param>
/// <param name="version">The plugin's Version.</param>
/// <param name="description">The plugin's Description.</param>
public RegisterPluginAttribute(string identifier, string author = "", string name = "", string version = "",
string description = "") {
Identifier = identifier;
Author = author;
Name = name;
Version = version;
Description = description;
}
}
}
}

View File

@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
namespace Overlay.NET.Common {
/// <summary>
/// Contains static methods for loading plugin types from .dll files.
/// </summary>
public static class PluginLoader {
/// <summary>
/// Creates instances of all the given types that are instanciable plugins.
/// </summary>
/// <typeparam name="TPlugin">The PluginBase derived plugin type.</typeparam>
/// <param name="types">The types to create instances from.</param>
/// <returns>Instances of all the types that are instanciable plugins.</returns>
public static IEnumerable<TPlugin> InstanciatePlugins<TPlugin>(IEnumerable<Type> types)
where TPlugin : PluginBase => InstanciatePlugins<TPlugin>(types, new object[0]);
/// <summary>
/// Creates instances of all the given Types that are instanciable plugins using the given arguments for the
/// constructor.
/// </summary>
/// <typeparam name="TPlugin">The PluginBase derived plugin type.</typeparam>
/// <param name="types">The Types to create instances from.</param>
/// <param name="args">The arguments for the constructor.</param>
/// <returns>Instances of all the types that are instanciable plugins.</returns>
public static IEnumerable<TPlugin> InstanciatePlugins<TPlugin>(IEnumerable<Type> types, params object[] args)
where TPlugin : PluginBase => from type in types
where IsInstanciablePlugin(type)
select (TPlugin) Activator.CreateInstance(type, args);
/// <summary>
/// Determines whether the given Type is an instanciable plugin or not.
/// </summary>
/// <param name="type">The Type to check.</param>
/// <returns>Whether the given Type is an instanciable plugin or not.</returns>
public static bool IsInstanciablePlugin(Type type) => PluginBase.IsRegisteredPlugin(type) && !type.IsAbstract;
/// <summary>
/// Takes file paths and checks if each exists, and loads .dll files to find the instanciable plugin types deriving
/// from TPlugin.
/// </summary>
/// <typeparam name="TPlugin">The Type that the plugins have to be derived from.</typeparam>
/// <param name="pluginFiles">The paths to the .dll files to check.</param>
/// <returns>The Types of the found instanciable plugins.</returns>
public static IEnumerable<Type> LoadPluginsFromFiles<TPlugin>(IEnumerable<string> pluginFiles)
where TPlugin : PluginBase => from pluginFile in pluginFiles
let extension = Path.GetExtension(pluginFile)
where
extension != null && File.Exists(pluginFile) &&
extension.Equals(".dll", StringComparison.InvariantCultureIgnoreCase)
let assembly = Assembly.LoadFrom(pluginFile)
from type in assembly.GetExportedTypes()
where typeof(TPlugin).IsAssignableFrom(type) && IsInstanciablePlugin(type)
select type;
/// <summary>
/// Takes directory paths and checks if each exists, and loads .dll files, including from subfolders,
/// to find the instanciable plugin types deriving from TPlugin.
/// </summary>
/// <typeparam name="TPlugin">The Type that the plugins have to be derived from.</typeparam>
/// <param name="pluginFolders">The paths to the folders to check.</param>
/// <returns>The Types of the found instanciable plugins.</returns>
public static IEnumerable<Type> LoadPluginsFromFolders<TPlugin>(IEnumerable<string> pluginFolders)
where TPlugin : PluginBase => from pluginFolder in pluginFolders
where Directory.Exists(pluginFolder)
let files = Directory.EnumerateFiles(pluginFolder, "*.dll", SearchOption.AllDirectories)
let types = LoadPluginsFromFiles<TPlugin>(files)
from type in types
select type;
}
}

View File

@@ -0,0 +1,163 @@
using System;
using System.IO;
using System.Linq;
namespace Overlay.NET.Common {
/// <summary>
/// Class representing a relative file on the device's storage.
/// </summary>
public class RelativeFile {
/// <summary>
/// Gets the base directory.
/// </summary>
/// <value>
/// The base directory.
/// </value>
public string Directory {
get {
if (string.IsNullOrEmpty(_directory)) {
_directory = AppDomain.CurrentDomain.BaseDirectory;
}
return _directory;
}
set { _directory = value; }
}
/// <summary>
/// Gets or sets the folder.
/// </summary>
/// <value>
/// The folder.
/// </value>
public string SubDirectory { get; set; }
/// <summary>
/// Gets or sets the name.
/// </summary>
/// <value>
/// The name.
/// </value>
public string Name { get; set; }
/// <summary>
/// Gets or sets the extension.
/// </summary>
/// <value>
/// The extension.
/// </value>
public string Extension { get; set; }
/// <summary>
/// Gets or sets a value indicating whether [use detailed time stamp].
/// </summary>
/// <value>
/// <c>true</c> if [use detailed time stamp]; otherwise, <c>false</c>.
/// </value>
public bool UseDetailedTimeStamp { get; set; }
/// <summary>
/// Gets or sets a value indicating whether [time stamp file].
/// </summary>
/// <value>
/// <c>true</c> if [time stamp file]; otherwise, <c>false</c>.
/// </value>
public bool TimeStampFile { get; set; }
private string _directory;
/// <summary>
/// Initializes a new instance of the <see cref="RelativeFile" /> class.
/// </summary>
/// <param name="directory">The base directory.</param>
public RelativeFile(string directory) {
_directory = directory;
}
/// <summary>
/// Initializes a new instance of the <see cref="RelativeFile" /> class.
/// </summary>
public RelativeFile() : this(AppDomain.CurrentDomain.BaseDirectory) {}
/// <summary>
/// Creates the a text file in a your app domains base directory, or if a subdirectory is set, in a sub directory
/// relative to your app folder.
/// </summary>
/// <param name="fileName">Name of the file.</param>
/// <param name="relativeSubDirectoryName">The name of the relative sub directory, if any.</param>
/// <param name="timeStampFile">if set to <c>true</c> [the file will be time stamped]</param>
/// <param name="useDetailedTimeStamp">if set to <c>true</c> [the time stamp will be more detailed, if one is used].</param>
/// <returns>
/// <see cref="RelativeFile" />
/// </returns>
public static RelativeFile JsonFile(string fileName, string relativeSubDirectoryName = "",
bool timeStampFile = false, bool useDetailedTimeStamp = true) => new RelativeFile {
Name = fileName,
Extension = ".json",
SubDirectory = relativeSubDirectoryName,
TimeStampFile = timeStampFile,
UseDetailedTimeStamp = useDetailedTimeStamp
};
/// <summary>
/// Creates the a text file in a your app domains base directory, or if a subdirectory is set, in a sub directory
/// relative to your app folder.
/// </summary>
/// <param name="fileName">Name of the file.</param>
/// <param name="relativeSubDirectoryName">The name of the relative sub directory, if any.</param>
/// <param name="timeStampFile">if set to <c>true</c> [the file will be time stamped]</param>
/// <param name="useDetailedTimeStamp">if set to <c>true</c> [the time stamp will be more detailed, if one is used].</param>
/// <returns>
/// <see cref="RelativeFile" />
/// </returns>
public static RelativeFile XmlFile(string fileName, string relativeSubDirectoryName = "",
bool timeStampFile = false, bool useDetailedTimeStamp = true) => new RelativeFile {
Name = fileName,
Extension = ".xml",
SubDirectory = relativeSubDirectoryName,
TimeStampFile = timeStampFile,
UseDetailedTimeStamp = useDetailedTimeStamp
};
/// <summary>
/// Gets the full path.
/// </summary>
/// <returns></returns>
/// <exception cref="System.ArgumentException">@The file detail can not be blank or null</exception>
public string GetFullPath() {
var checks = new[] {
Directory, Name, Extension
};
foreach (var fileDetail in checks.Where(string.IsNullOrEmpty)) {
throw new ArgumentException($@"The file detail can not be blank or null {fileDetail}", fileDetail);
}
if (!Extension.StartsWith(".")) {
Extension = "." + Extension;
}
if (TimeStampFile) {
Name = UseDetailedTimeStamp
? $"{Name}-{DateTime.Now:yyyy-MM-dd_hh-mm-ss}"
: $"{Name}-{DateTime.Now:yyyy-MM-dd}";
}
var path = Directory;
var combineDirectory = !string.IsNullOrEmpty(SubDirectory);
if (combineDirectory) {
path = Path.Combine(Directory, SubDirectory);
}
if (!System.IO.Directory.Exists(path)) {
System.IO.Directory.CreateDirectory(path);
}
return combineDirectory
? Path.Combine(Directory, SubDirectory, Name + Extension)
: Path.Combine(Directory, Name + Extension);
}
}
}

View File

@@ -0,0 +1,201 @@
using System;
using System.Globalization;
using System.IO;
using System.Text;
namespace Overlay.NET.Common {
public class SerializableSettings<T> : ISettings<T> where T : new() {
/// <summary>
/// Gets or sets the file.
/// </summary>
/// <value>
/// The file.
/// </value>
public RelativeFile SettingsFile {
get { return _file ?? (_file = RelativeFile.XmlFile(typeof(T).Name, "Settings")); }
set { _file = value; }
}
/// <summary>
/// Gets or sets a value indicating whether [backup on save].
/// </summary>
/// <value>
/// <c>true</c> if [backup on save]; otherwise, <c>false</c>.
/// </value>
public bool BackupOnSave { get; set; } = true;
/// <summary>
/// Gets or sets the path.
/// </summary>
/// <value>
/// The path.
/// </value>
public string Path {
get {
if (string.IsNullOrEmpty(_path)) {
_path = SettingsFile.GetFullPath();
}
return _path;
}
protected set { _path = value; }
}
/// <summary>
/// Gets or sets the name of the settings.
/// </summary>
/// <value>
/// The name.
/// </value>
public string Name {
get {
if (string.IsNullOrEmpty(_name)) {
_name = typeof(T).Name;
}
return _name;
}
set { _name = value; }
}
/// <summary>
/// Gets or sets the encoding.
/// </summary>
/// <value>
/// The encoding.
/// </value>
public Encoding Encoding {
get { return _encoding ?? (_encoding = Encoding.UTF8); }
set { _encoding = value; }
}
/// <summary>
/// Gets or sets the current settings instance.
/// </summary>
/// <value>
/// The current.
/// </value>
public T Current {
get {
if (_currentExist) {
return _current;
}
_current = new T();
_currentExist = true;
return _current;
}
set {
_current = value;
_currentExist = true;
}
}
/// <summary>
/// Gets or sets the serializer.
/// </summary>
/// <value>
/// The serializer.
/// </value>
protected ISerializer Serializer {
get {
if (_serializer != null) {
return _serializer;
}
_serializer = new XmlSerializerEx();
SettingsFile.Extension = ".xml";
SettingsFile.SubDirectory = "XmlSettings";
return _serializer;
}
set { _serializer = value; }
}
/// <summary>
/// Saves the settings to the specified file.
/// </summary>
/// <param name="file">The file.</param>
public void Save(string file = "") {
if (string.IsNullOrEmpty(file)) {
file = Path;
}
if (File.Exists(file) && BackupOnSave) {
BackupSettings(file);
}
Serializer.ExportToFile(Current, file, Encoding.UTF8);
}
/// <summary>
/// Loads the settings from the specified location.
/// </summary>
/// <param name="location">
/// The location of the file./param>
/// <exception cref="System.ArgumentNullException"></exception>
/// </param>
public void Load(string location = "") {
if (string.IsNullOrEmpty(location)) {
location = Path;
}
if (!File.Exists(location)) {
Save(location);
}
var settings = Serializer.ImportFromFile<T>(location, Encoding);
if (settings == null) {
throw new ArgumentNullException(nameof(settings));
}
Current = settings;
RaiseOnSettingsChanged(location);
}
private T _current;
private bool _currentExist;
private Encoding _encoding;
private RelativeFile _file;
private string _name;
private string _path;
private ISerializer _serializer;
/// <summary>
/// Backups the settings if one already exist.
/// </summary>
/// <param name="target">The target to back up settings to.</param>
/// <exception cref="System.ArgumentNullException"></exception>
protected void BackupSettings(string target = "") {
if (string.IsNullOrEmpty(target)) {
target = Path;
}
var extension = System.IO.Path.GetExtension(target);
if (extension == null) {
throw new ArgumentNullException(Path + " does not contain an extension.");
}
var time = DateTime.Now;
var backup = target.Replace(extension,
$"-{time.ToString("yyyy-MM-dd-HH-mm-ss", CultureInfo.InvariantCulture)}{extension}");
Serializer.ExportToFile(Current, backup, Encoding);
}
/// <summary>
/// Occurs when [on settings changed].
/// </summary>
public event EventHandler<string> OnSettingsChanged;
/// <summary>
/// Raises the on settings changed.
/// </summary>
/// <param name="e">The e.</param>
protected virtual void RaiseOnSettingsChanged(string e) => OnSettingsChanged?.Invoke(this, e);
}
}

View File

@@ -0,0 +1,87 @@
using System;
namespace Overlay.NET.Common {
/// <summary>
/// </summary>
public class TickEngine {
/// <summary>
/// Gets or sets the interval.
/// </summary>
/// <value>
/// The interval.
/// </value>
public TimeSpan Interval {
get { return _waitTimer.WaitTime; }
set { _waitTimer.WaitTime = value; }
}
/// <summary>
/// Gets or sets a value indicating whether this instance is ticking.
/// </summary>
/// <value>
/// <c>true</c> if this instance is ticking; otherwise, <c>false</c>.
/// </value>
public bool IsTicking { get; set; }
/// <summary>
/// The wait timer
/// </summary>
private readonly WaitTimer _waitTimer = new WaitTimer();
/// <summary>
/// Occurs when [pre tick].
/// </summary>
public event EventHandler PreTick;
/// <summary>
/// Occurs when [tick].
/// </summary>
public event EventHandler Tick;
/// <summary>
/// Occurs when [post tick].
/// </summary>
public event EventHandler PostTick;
/// <summary>
/// Stops this instance.
/// </summary>
public void Stop() => _waitTimer.Stop();
/// <summary>
/// Pulses this instance.
/// </summary>
public void Pulse() {
if (!IsTicking) {
return;
}
if (!_waitTimer.Update()) {
return;
}
OnPreTick();
OnTick();
OnPostTick();
_waitTimer.Reset();
}
/// <summary>
/// Called when [tick].
/// </summary>
protected virtual void OnTick() => Tick?.Invoke(this, EventArgs.Empty);
/// <summary>
/// Called when [pre tick].
/// </summary>
protected virtual void OnPreTick() => PreTick?.Invoke(this, EventArgs.Empty);
/// <summary>
/// Called when [post tick].
/// </summary>
protected virtual void OnPostTick() => PostTick?.Invoke(this, EventArgs.Empty);
}
}

View File

@@ -0,0 +1,15 @@
using System;
namespace Overlay.NET.Common {
public static class TimeSpanExtensions {
public static TimeSpan Days(this int days) => new TimeSpan(days, 0, 0, 0);
public static TimeSpan Hours(this int hours) => new TimeSpan(0, hours, 0, 0);
public static TimeSpan Minutes(this int minutes) => new TimeSpan(0, 0, minutes, 0);
public static TimeSpan Seconds(this int seconds) => new TimeSpan(0, 0, 0, seconds);
public static TimeSpan Milliseconds(this int milliseconds) => new TimeSpan(0, 0, 0, 0, milliseconds);
}
}

View File

@@ -0,0 +1,132 @@
using System;
namespace Overlay.NET.Common {
/// <summary>
/// </summary>
/// <seealso cref="System.EventArgs" />
public sealed class WaitTimerEventArgs : EventArgs {
/// <summary>
/// Gets or sets the time finished.
/// </summary>
/// <value>
/// The time finished.
/// </value>
public DateTime TimeFinished { get; set; }
/// <summary>
/// Gets or sets the wait time.
/// </summary>
/// <value>
/// The wait time.
/// </value>
public TimeSpan WaitTime { get; set; }
/// <summary>
/// Gets or sets the time started.
/// </summary>
/// <value>
/// The time started.
/// </value>
public DateTime TimeStarted { get; set; }
}
/// <summary>
/// </summary>
public class WaitTimer {
/// <summary>
/// Gets or sets the wait time.
/// </summary>
/// <value>
/// The wait time.
/// </value>
public TimeSpan WaitTime { get; set; }
/// <summary>
/// Gets the end time.
/// </summary>
/// <value>
/// The end time.
/// </value>
public DateTime EndTime => StartTime + WaitTime;
/// <summary>
/// Gets the start time.
/// </summary>
/// <value>
/// The start time.
/// </value>
public DateTime StartTime { get; private set; }
/// <summary>
/// Gets a value indicating whether this instance is finished.
/// </summary>
/// <value>
/// <c>true</c> if this instance is finished; otherwise, <c>false</c>.
/// </value>
public bool IsFinished => EndTime <= DateTime.Now;
/// <summary>
/// Gets the time left.
/// </summary>
/// <value>
/// The time left.
/// </value>
public TimeSpan TimeLeft => EndTime - DateTime.Now;
/// <summary>
/// Initializes a new instance of the <see cref="WaitTimer" /> class.
/// </summary>
/// <param name="waitTime">The wait time.</param>
public WaitTimer(TimeSpan waitTime) {
WaitTime = waitTime;
Stop();
}
/// <summary>
/// Initializes a new instance of the <see cref="WaitTimer" /> class.
/// </summary>
public WaitTimer() {
WaitTime = TimeSpan.Zero;
Stop();
}
/// <summary>
/// Occurs when [finished].
/// </summary>
public event EventHandler<WaitTimerEventArgs> Finished;
/// <summary>
/// Resets this instance.
/// </summary>
public void Reset() => StartTime = DateTime.Now;
/// <summary>
/// Stops this instance.
/// </summary>
public void Stop() => StartTime = DateTime.Now.AddDays(-5.0);
/// <summary>
/// Updates this instance.
/// </summary>
/// <returns></returns>
public bool Update() {
if (!IsFinished) {
return false;
}
OnFinished(new WaitTimerEventArgs {
TimeFinished = DateTime.Now,
TimeStarted = StartTime,
WaitTime = WaitTime
});
return true;
}
/// <summary>
/// Raises the <see cref="E:Finished" /> event.
/// </summary>
/// <param name="e">The <see cref="WaitTimerEventArgs" /> instance containing the event data.</param>
protected virtual void OnFinished(WaitTimerEventArgs e) => Finished?.Invoke(this, e);
}
}

View File

@@ -0,0 +1,81 @@
namespace Overlay.NET.Common {
/// <summary>
/// </summary>
internal class WindowConstants {
/// <summary>
/// The sm cx screen
/// </summary>
public const int SmCxScreen = 0;
/// <summary>
/// The sm cy screen
/// </summary>
public const int SmCyScreen = 1;
/// <summary>
/// The desktop class
/// </summary>
public const string DesktopClass = "Static"; // System Class for a static control
/// <summary>
/// The window style dx
/// </summary>
public const uint WindowStyleDx = 0x8000000 //WS_DISABLED
| 0x10000000 //WS_VISIBLE
| 0x80000000; //WS_POPUP
/// <summary>
/// The window ex style dx
/// </summary>
public const uint WindowExStyleDx = 0x8000000 //WS_EX_NOACTIVATE
| 0x80000 //WS_EX_LAYERED
| 0x80 //WS_EX_TOOLWINDOW -> Not in taskbar
| 0x8 //WS_EX_TOPMOST
| 0x20; //WS_EX_TRANSPARENT
/// <summary>
/// The layered window attribute alpha (LWA_ALPHA)
/// </summary>
public const int LwaAlpha = 0x00000002;
/// <summary>
/// The HWND notopmost
/// </summary>
public const int HwndNotopmost = -2;
/// <summary>
/// The HWND topmost
/// </summary>
public const int HwndTopmost = -1;
/// <summary>
/// The HWND top
/// </summary>
public const int HwndTop = 0;
/// <summary>
/// The HWND bottom
/// </summary>
public const int HwndBottom = 1;
/// <summary>
/// The SWP flags show
/// </summary>
public const uint SwpFlagsShow = 0x40;
/// <summary>
/// The SWP flags hide
/// </summary>
public const uint SwpFlagsHide = 0x80;
/// <summary>
/// The sw show
/// </summary>
public const uint SwShow = 5;
/// <summary>
/// The sw hide
/// </summary>
public const uint SwHide = 0;
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
namespace Overlay.NET.Common {
public static class WindowExtensions {
private const int GwlExstyle = -20;
private const int WsExTransparent = 0x00000020;
public static void MakeWindowTransparent(this Window wnd) {
if (!wnd.IsInitialized)
throw new Exception("The extension method MakeWindowTransparent can not be called prior to the window being initialized.");
var hwnd = new WindowInteropHelper(wnd).Handle;
var extendedStyle = Native.GetWindowLongPtr(hwnd, GwlExstyle);
Native.SetWindowLongPtr(hwnd, GwlExstyle, new IntPtr(extendedStyle.ToInt32() | WsExTransparent));
}
}
}

View File

@@ -0,0 +1,68 @@
using System.IO;
using System.Text;
using System.Xml.Serialization;
namespace Overlay.NET.Common {
/// <summary>
/// Class to serialize/deserialize XML objects to and from strings, and to and from files.
/// </summary>
/// <seealso cref="ISerializer" />
public class XmlSerializerEx : ISerializer {
/// <summary>
/// Serializes the specified object and returns the document.
/// </summary>
/// <typeparam name="T">The type of the object to serialize.</typeparam>
/// <param name="obj">The object to serialize.</param>
/// <returns>
/// XML document of the serialized object.
/// </returns>
public string ExportToString<T>(T obj) {
var serializer = new XmlSerializer(typeof(T));
using (var stringWriter = new StringWriter()) {
serializer.Serialize(stringWriter, obj);
return stringWriter.ToString();
}
}
/// <summary>
/// Deserializes the document to the specified object.
/// </summary>
/// <typeparam name="T">The type of the object to deserialize.</typeparam>
/// <param name="serializedObj">The string representing the serialized object.</param>
/// <returns>
/// The deserialized object.
/// </returns>
public T ImportFromString<T>(string serializedObj) {
var serializer = new XmlSerializer(typeof(T));
using (var stringWriter = new StringReader(serializedObj)) {
return (T) serializer.Deserialize(stringWriter);
}
}
/// <summary>
/// Serializes the specified object and writes the document to the specified path.
/// </summary>
/// <typeparam name="T">The type of the object to serialize.</typeparam>
/// <param name="obj">The object to serialize.</param>
/// <param name="file">The path where the file is saved.</param>
/// <param name="encoding">The encoding to generate.</param>
public void ExportToFile<T>(T obj, string file, Encoding encoding) {
using (var fileWriter = new StreamWriter(file, false, encoding)) {
fileWriter.Write(ExportToString(obj));
}
}
/// <summary>
/// Deserializes the specified file into an object.
/// </summary>
/// <typeparam name="T">The type of the object to deserialize.</typeparam>
/// <param name="path">The path where the object is read.</param>
/// <param name="encoding">The character encoding to use. </param>
/// <returns>The deserialized object.</returns>
public T ImportFromFile<T>(string path, Encoding encoding) {
using (var fileReader = new StreamReader(path, encoding)) {
return ImportFromString<T>(fileReader.ReadToEnd());
}
}
}
}

View File

@@ -0,0 +1,644 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Overlay.NET.Common;
using SharpDX;
using SharpDX.Direct2D1;
using SharpDX.DirectWrite;
using SharpDX.DXGI;
using SharpDX.Mathematics.Interop;
using AlphaMode = SharpDX.Direct2D1.AlphaMode;
using Color = System.Drawing.Color;
using Factory = SharpDX.DirectWrite.Factory;
using TextAntialiasMode = SharpDX.Direct2D1.TextAntialiasMode;
namespace Overlay.NET.Directx {
/// <summary>
/// </summary>
public class Direct2DRenderer {
/// <summary>
/// Gets the size of the buffer brush.
/// </summary>
/// <value>
/// The size of the buffer brush.
/// </value>
public int BufferBrushSize { get; private set; }
/// <summary>
/// Gets the size of the buffer font.
/// </summary>
/// <value>
/// The size of the buffer font.
/// </value>
public int BufferFontSize { get; private set; }
/// <summary>
/// Gets the size of the buffer layout.
/// </summary>
/// <value>
/// The size of the buffer layout.
/// </value>
public int BufferLayoutSize { get; private set; }
//transparent background color
/// <summary>
/// The GDI transparent
/// </summary>
private static Color _gdiTransparent = Color.Transparent;
/// <summary>
/// The transparent
/// </summary>
private static readonly RawColor4 Transparent = new RawColor4(_gdiTransparent.R, _gdiTransparent.G, _gdiTransparent.B,
_gdiTransparent.A);
//direct x vars
/// <summary>
/// The device
/// </summary>
private readonly WindowRenderTarget _device;
/// <summary>
/// The factory
/// </summary>
private readonly SharpDX.Direct2D1.Factory _factory;
/// <summary>
/// The font factory
/// </summary>
private readonly Factory _fontFactory;
/// <summary>
/// The brush container
/// </summary>
private List<SolidColorBrush> _brushContainer = new List<SolidColorBrush>(32);
//thread safe resizing
/// <summary>
/// The do resize
/// </summary>
private bool _doResize;
/// <summary>
/// The font container
/// </summary>
private List<TextFormat> _fontContainer = new List<TextFormat>(32);
/// <summary>
/// The layout container
/// </summary>
private List<TextLayoutBuffer> _layoutContainer = new List<TextLayoutBuffer>(32);
/// <summary>
/// The resize x
/// </summary>
private int _resizeX;
/// <summary>
/// The resize y
/// </summary>
private int _resizeY;
/// <summary>
/// Initializes a new instance of the <see cref="Direct2DRenderer" /> class.
/// </summary>
/// <param name="hwnd">The HWND.</param>
/// <param name="limitFps">if set to <c>true</c> [limit FPS].</param>
public Direct2DRenderer(IntPtr hwnd, bool limitFps) {
_factory = new SharpDX.Direct2D1.Factory();
_fontFactory = new Factory();
Native.Rect bounds;
Native.GetWindowRect(hwnd, out bounds);
var targetProperties = new HwndRenderTargetProperties {
Hwnd = hwnd,
PixelSize = new Size2(bounds.Right - bounds.Left, bounds.Bottom - bounds.Top),
PresentOptions = limitFps ? PresentOptions.None : PresentOptions.Immediately
};
var prop = new RenderTargetProperties(RenderTargetType.Hardware,
new PixelFormat(Format.B8G8R8A8_UNorm, AlphaMode.Premultiplied), 0, 0, RenderTargetUsage.None,
FeatureLevel.Level_DEFAULT);
_device = new WindowRenderTarget(_factory, prop, targetProperties) {
TextAntialiasMode = TextAntialiasMode.Aliased,
AntialiasMode = AntialiasMode.Aliased
};
}
/// <summary>
/// Do not call if you use OverlayWindow class
/// </summary>
public void Dispose() {
DeleteBrushContainer();
DeleteFontContainer();
DeleteLayoutContainer();
_brushContainer = null;
_fontContainer = null;
_layoutContainer = null;
_fontFactory.Dispose();
_factory.Dispose();
_device.Dispose();
}
/// <summary>
/// tells renderer to resize when possible
/// </summary>
/// <param name="x">Width</param>
/// <param name="y">Height</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AutoResize(int x, int y) {
_doResize = true;
_resizeX = x;
_resizeY = y;
}
/// <summary>
/// Call this after EndScene if you created brushes within a loop
/// </summary>
public void DeleteBrushContainer() {
BufferBrushSize = _brushContainer.Count;
foreach (var solidColorBrush in _brushContainer) {
solidColorBrush.Dispose();
}
_brushContainer = new List<SolidColorBrush>(BufferBrushSize);
}
/// <summary>
/// Call this after EndScene if you created fonts within a loop
/// </summary>
public void DeleteFontContainer() {
BufferFontSize = _fontContainer.Count;
foreach (var textFormat in _fontContainer) {
textFormat.Dispose();
}
_fontContainer = new List<TextFormat>(BufferFontSize);
}
/// <summary>
/// Call this after EndScene if you changed your text's font or have problems with huge memory usage
/// </summary>
public void DeleteLayoutContainer() {
BufferLayoutSize = _layoutContainer.Count;
foreach (var layoutBuffer in _layoutContainer) {
layoutBuffer.Dispose();
}
_layoutContainer = new List<TextLayoutBuffer>(BufferLayoutSize);
}
/// <summary>
/// Creates a new SolidColorBrush
/// </summary>
/// <param name="color">0x7FFFFFF Premultiplied alpha color</param>
/// <returns>
/// int Brush identifier
/// </returns>
public int CreateBrush(int color) {
_brushContainer.Add(new SolidColorBrush(_device,
new RawColor4((color >> 16) & 255L, (color >> 8) & 255L, (byte) color & 255L, (color >> 24) & 255L)));
return _brushContainer.Count - 1;
}
/// <summary>
/// Creates a new SolidColorBrush. Make sure you applied an alpha value
/// </summary>
/// <param name="color">System.Drawing.Color struct</param>
/// <returns>
/// int Brush identifier
/// </returns>
public int CreateBrush(Color color) {
if (color.A == 0) {
color = Color.FromArgb(255, color);
}
_brushContainer.Add(new SolidColorBrush(_device, new RawColor4(color.R, color.G, color.B, color.A / 255.0f)));
return _brushContainer.Count - 1;
}
/// <summary>
/// Creates a new Font
/// </summary>
/// <param name="fontFamilyName">i.e. Arial</param>
/// <param name="size">size in units</param>
/// <param name="bold">print bold text</param>
/// <param name="italic">print italic text</param>
/// <returns></returns>
public int CreateFont(string fontFamilyName, float size, bool bold = false, bool italic = false) {
_fontContainer.Add(new TextFormat(_fontFactory, fontFamilyName, bold ? FontWeight.Bold : FontWeight.Normal,
italic ? FontStyle.Italic : FontStyle.Normal, size));
return _fontContainer.Count - 1;
}
/// <summary>
/// Do your drawing after this
/// </summary>
public void BeginScene() {
if (_doResize) {
_device.Resize(new Size2(_resizeX, _resizeY));
_doResize = false;
}
_device.BeginDraw();
}
/// <summary>
/// Present frame. Do not draw after this.
/// </summary>
public void EndScene() {
_device.EndDraw();
if (!_doResize) {
return;
}
_device.Resize(new Size2(_resizeX, _resizeY));
_doResize = false;
}
/// <summary>
/// Clears the frame
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ClearScene() => _device.Clear(Transparent);
/// <summary>
/// Draws the line.
/// </summary>
/// <param name="startX">The start x.</param>
/// <param name="startY">The start y.</param>
/// <param name="endX">The end x.</param>
/// <param name="endY">The end y.</param>
/// <param name="stroke">The stroke.</param>
/// <param name="brush">The brush.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void DrawLine(int startX, int startY, int endX, int endY, float stroke, int brush) => _device.DrawLine(new RawVector2(startX, startY), new RawVector2(endX, endY), _brushContainer[brush], stroke);
/// <summary>
/// Draws the rectangle.
/// </summary>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="stroke">The stroke.</param>
/// <param name="brush">The brush.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void DrawRectangle(int x, int y, int width, int height, float stroke, int brush) => _device.DrawRectangle(new RawRectangleF(x, y, x + width, y + height), _brushContainer[brush], stroke);
/// <summary>
/// Draws the circle.
/// </summary>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="radius">The radius.</param>
/// <param name="stroke">The stroke.</param>
/// <param name="brush">The brush.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void DrawCircle(int x, int y, int radius, float stroke, int brush) => _device.DrawEllipse(new Ellipse(new RawVector2(x, y), radius, radius), _brushContainer[brush], stroke);
/// <summary>
/// Draws the box2 d.
/// </summary>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="stroke">The stroke.</param>
/// <param name="brush">The brush.</param>
/// <param name="interiorBrush">The interior brush.</param>
public void DrawBox2D(int x, int y, int width, int height, float stroke, int brush, int interiorBrush) {
_device.DrawRectangle(new RawRectangleF(x, y, x + width, y + height), _brushContainer[brush], stroke);
_device.FillRectangle(new RawRectangleF(x + stroke, y + stroke, x + width - stroke, y + height - stroke),
_brushContainer[interiorBrush]);
}
/// <summary>
/// Draws the box3 d.
/// </summary>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="length">The length.</param>
/// <param name="stroke">The stroke.</param>
/// <param name="brush">The brush.</param>
/// <param name="interiorBrush">The interior brush.</param>
public void DrawBox3D(int x, int y, int width, int height, int length, float stroke, int brush,
int interiorBrush) {
var first = new RawRectangleF(x, y, x + width, y + height);
var second = new RawRectangleF(x + length, y - length, first.Right + length, first.Bottom - length);
var lineStart = new RawVector2(x, y);
var lineEnd = new RawVector2(second.Left, second.Top);
_device.DrawRectangle(first, _brushContainer[brush], stroke);
_device.DrawRectangle(second, _brushContainer[brush], stroke);
_device.FillRectangle(first, _brushContainer[interiorBrush]);
_device.FillRectangle(second, _brushContainer[interiorBrush]);
_device.DrawLine(lineStart, lineEnd, _brushContainer[brush], stroke);
lineStart.X += width;
lineEnd.X = lineStart.X + length;
_device.DrawLine(lineStart, lineEnd, _brushContainer[brush], stroke);
lineStart.Y += height;
lineEnd.Y += height;
_device.DrawLine(lineStart, lineEnd, _brushContainer[brush], stroke);
lineStart.X -= width;
lineEnd.X -= width;
_device.DrawLine(lineStart, lineEnd, _brushContainer[brush], stroke);
}
/// <summary>
/// Draws the rectangle3 d.
/// </summary>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="length">The length.</param>
/// <param name="stroke">The stroke.</param>
/// <param name="brush">The brush.</param>
public void DrawRectangle3D(int x, int y, int width, int height, int length, float stroke, int brush) {
var first = new RawRectangleF(x, y, x + width, y + height);
var second = new RawRectangleF(x + length, y - length, first.Right + length, first.Bottom - length);
var lineStart = new RawVector2(x, y);
var lineEnd = new RawVector2(second.Left, second.Top);
_device.DrawRectangle(first, _brushContainer[brush], stroke);
_device.DrawRectangle(second, _brushContainer[brush], stroke);
_device.DrawLine(lineStart, lineEnd, _brushContainer[brush], stroke);
lineStart.X += width;
lineEnd.X = lineStart.X + length;
_device.DrawLine(lineStart, lineEnd, _brushContainer[brush], stroke);
lineStart.Y += height;
lineEnd.Y += height;
_device.DrawLine(lineStart, lineEnd, _brushContainer[brush], stroke);
lineStart.X -= width;
lineEnd.X -= width;
_device.DrawLine(lineStart, lineEnd, _brushContainer[brush], stroke);
}
/// <summary>
/// Draws the plus.
/// </summary>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="length">The length.</param>
/// <param name="stroke">The stroke.</param>
/// <param name="brush">The brush.</param>
public void DrawPlus(int x, int y, int length, float stroke, int brush) {
var first = new RawVector2(x - length, y);
var second = new RawVector2(x + length, y);
var third = new RawVector2(x, y - length);
var fourth = new RawVector2(x, y + length);
_device.DrawLine(first, second, _brushContainer[brush], stroke);
_device.DrawLine(third, fourth, _brushContainer[brush], stroke);
}
/// <summary>
/// Draws the edge.
/// </summary>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="length">The length.</param>
/// <param name="stroke">The stroke.</param>
/// <param name="brush">The brush.</param>
public void DrawEdge(int x, int y, int width, int height, int length, float stroke, int brush) //geht
{
var first = new RawVector2(x, y);
var second = new RawVector2(x, y + length);
var third = new RawVector2(x + length, y);
_device.DrawLine(first, second, _brushContainer[brush], stroke);
_device.DrawLine(first, third, _brushContainer[brush], stroke);
first.Y += height;
second.Y = first.Y - length;
third.Y = first.Y;
third.X = first.X + length;
_device.DrawLine(first, second, _brushContainer[brush], stroke);
_device.DrawLine(first, third, _brushContainer[brush], stroke);
first.X = x + width;
first.Y = y;
second.X = first.X - length;
second.Y = first.Y;
third.X = first.X;
third.Y = first.Y + length;
_device.DrawLine(first, second, _brushContainer[brush], stroke);
_device.DrawLine(first, third, _brushContainer[brush], stroke);
first.Y += height;
second.X += length;
second.Y = first.Y - length;
third.Y = first.Y;
third.X = first.X - length;
_device.DrawLine(first, second, _brushContainer[brush], stroke);
_device.DrawLine(first, third, _brushContainer[brush], stroke);
}
/// <summary>
/// Draws the bar h.
/// </summary>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="value">The value.</param>
/// <param name="stroke">The stroke.</param>
/// <param name="brush">The brush.</param>
/// <param name="interiorBrush">The interior brush.</param>
public void DrawBarH(int x, int y, int width, int height, float value, float stroke, int brush,
int interiorBrush) {
var first = new RawRectangleF(x, y, x + width, y + height);
_device.DrawRectangle(first, _brushContainer[brush], stroke);
if (Math.Abs(value) < 0) {
return;
}
first.Top += height - height / 100.0f * value;
_device.FillRectangle(first, _brushContainer[interiorBrush]);
}
/// <summary>
/// Draws the bar v.
/// </summary>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="value">The value.</param>
/// <param name="stroke">The stroke.</param>
/// <param name="brush">The brush.</param>
/// <param name="interiorBrush">The interior brush.</param>
public void DrawBarV(int x, int y, int width, int height, float value, float stroke, int brush,
int interiorBrush) {
var first = new RawRectangleF(x, y, x + width, y + height);
_device.DrawRectangle(first, _brushContainer[brush], stroke);
if (Math.Abs(value) < 0) {
return;
}
first.Right -= width - width / 100.0f * value;
_device.FillRectangle(first, _brushContainer[interiorBrush]);
}
/// <summary>
/// Fills the rectangle.
/// </summary>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="brush">The brush.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FillRectangle(int x, int y, int width, int height, int brush) => _device.FillRectangle(new RawRectangleF(x, y, x + width, y + height), _brushContainer[brush]);
/// <summary>
/// Fills the circle.
/// </summary>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="radius">The radius.</param>
/// <param name="brush">The brush.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FillCircle(int x, int y, int radius, int brush) => _device.FillEllipse(new Ellipse(new RawVector2(x, y), radius, radius), _brushContainer[brush]);
/// <summary>
/// Bordereds the line.
/// </summary>
/// <param name="startX">The start x.</param>
/// <param name="startY">The start y.</param>
/// <param name="endX">The end x.</param>
/// <param name="endY">The end y.</param>
/// <param name="stroke">The stroke.</param>
/// <param name="brush">The brush.</param>
/// <param name="borderBrush">The border brush.</param>
public void BorderedLine(int startX, int startY, int endX, int endY, float stroke, int brush, int borderBrush) {
_device.DrawLine(new RawVector2(startX, startY), new RawVector2(endX, endY), _brushContainer[brush], stroke);
_device.DrawLine(new RawVector2(startX, startY - stroke), new RawVector2(endX, endY - stroke),
_brushContainer[borderBrush], stroke);
_device.DrawLine(new RawVector2(startX, startY + stroke), new RawVector2(endX, endY + stroke),
_brushContainer[borderBrush], stroke);
_device.DrawLine(new RawVector2(startX - stroke / 2, startY - stroke * 1.5f),
new RawVector2(startX - stroke / 2, startY + stroke * 1.5f), _brushContainer[borderBrush], stroke);
_device.DrawLine(new RawVector2(endX - stroke / 2, endY - stroke * 1.5f),
new RawVector2(endX - stroke / 2, endY + stroke * 1.5f), _brushContainer[borderBrush], stroke);
}
/// <summary>
/// Bordereds the rectangle.
/// </summary>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="stroke">The stroke.</param>
/// <param name="borderStroke">The border stroke.</param>
/// <param name="brush">The brush.</param>
/// <param name="borderBrush">The border brush.</param>
public void BorderedRectangle(int x, int y, int width, int height, float stroke, float borderStroke, int brush,
int borderBrush) {
_device.DrawRectangle(
new RawRectangleF(x - (stroke - borderStroke), y - (stroke - borderStroke),
x + width + stroke - borderStroke, y + height + stroke - borderStroke), _brushContainer[borderBrush],
borderStroke);
_device.DrawRectangle(new RawRectangleF(x, y, x + width, y + height), _brushContainer[brush], stroke);
_device.DrawRectangle(
new RawRectangleF(x + (stroke - borderStroke), y + (stroke - borderStroke),
x + width - stroke + borderStroke, y + height - stroke + borderStroke), _brushContainer[borderBrush],
borderStroke);
}
/// <summary>
/// Bordereds the circle.
/// </summary>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="radius">The radius.</param>
/// <param name="stroke">The stroke.</param>
/// <param name="brush">The brush.</param>
/// <param name="borderBrush">The border brush.</param>
public void BorderedCircle(int x, int y, int radius, float stroke, int brush, int borderBrush) {
_device.DrawEllipse(new Ellipse(new RawVector2(x, y), radius + stroke, radius + stroke),
_brushContainer[borderBrush], stroke);
_device.DrawEllipse(new Ellipse(new RawVector2(x, y), radius, radius), _brushContainer[brush], stroke);
_device.DrawEllipse(new Ellipse(new RawVector2(x, y), radius - stroke, radius - stroke),
_brushContainer[borderBrush], stroke);
}
/// <summary>
/// Do not buffer text if you draw i.e. FPS. Use buffer for player names, rank....
/// </summary>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="brush">The brush.</param>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="bufferText">if set to <c>true</c> [buffer text].</param>
public void DrawText(string text, int font, int brush, int x, int y, bool bufferText = true) {
if (bufferText) {
var bufferPos = -1;
for (var i = 0; i < _layoutContainer.Count; i++) {
if (_layoutContainer[i].Text.Length != text.Length || _layoutContainer[i].Text != text) {
continue;
}
bufferPos = i;
break;
}
if (bufferPos == -1) {
_layoutContainer.Add(new TextLayoutBuffer(text,
new TextLayout(_fontFactory, text, _fontContainer[font], float.MaxValue, float.MaxValue)));
bufferPos = _layoutContainer.Count - 1;
}
_device.DrawTextLayout(new RawVector2(x, y), _layoutContainer[bufferPos].TextLayout,
_brushContainer[brush], DrawTextOptions.NoSnap);
}
else {
var layout = new TextLayout(_fontFactory, text, _fontContainer[font], float.MaxValue, float.MaxValue);
_device.DrawTextLayout(new RawVector2(x, y), layout, _brushContainer[brush]);
layout.Dispose();
}
}
}
}

View File

@@ -0,0 +1,14 @@
namespace Overlay.NET.Directx {
/// <summary>
/// </summary>
/// <seealso cref="Overlay.NET.OverlayPlugin" />
public abstract class DirectXOverlayPlugin : OverlayPlugin {
/// <summary>
/// Gets or sets the overlay window.
/// </summary>
/// <value>
/// The overlay window.
/// </value>
public DirectXOverlayWindow OverlayWindow { get; protected set; }
}
}

View File

@@ -0,0 +1,318 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Overlay.NET.Common;
namespace Overlay.NET.Directx {
public class DirectXOverlayWindow {
/// <summary>
/// Gets a value indicating whether this instance is disposing.
/// </summary>
/// <value>
/// <c>true</c> if this instance is disposing; otherwise, <c>false</c>.
/// </value>
public bool IsDisposing { get; private set; }
/// <summary>
/// Gets a value indicating whether [parent window exists].
/// </summary>
/// <value>
/// <c>true</c> if [parent window exists]; otherwise, <c>false</c>.
/// </value>
public bool ParentWindowExists { get; private set; }
/// <summary>
/// Gets a value indicating whether this instance is top most.
/// </summary>
/// <value>
/// <c>true</c> if this instance is top most; otherwise, <c>false</c>.
/// </value>
public bool IsTopMost { get; private set; }
/// <summary>
/// Gets a value indicating whether this instance is visible.
/// </summary>
/// <value>
/// <c>true</c> if this instance is visible; otherwise, <c>false</c>.
/// </value>
public bool IsVisible { get; private set; }
/// <summary>
/// Gets the x.
/// </summary>
/// <value>
/// The x.
/// </value>
public int X { get; private set; }
/// <summary>
/// Gets the y.
/// </summary>
/// <value>
/// The y.
/// </value>
public int Y { get; private set; }
/// <summary>
/// Gets the width.
/// </summary>
/// <value>
/// The width.
/// </value>
public int Width { get; private set; }
/// <summary>
/// Gets the height.
/// </summary>
/// <value>
/// The height.
/// </value>
public int Height { get; private set; }
/// <summary>
/// Gets the handle.
/// </summary>
/// <value>
/// The handle.
/// </value>
public IntPtr Handle { get; private set; }
/// <summary>
/// Gets the parent window.
/// </summary>
/// <value>
/// The parent window.
/// </value>
public IntPtr ParentWindow { get; }
/// <summary>
/// The margin
/// </summary>
private Native.RawMargin _margin;
/// <summary>
/// The graphics
/// </summary>
public Direct2DRenderer Graphics;
/// <summary>
/// Makes a transparent Fullscreen window
/// </summary>
/// <param name="limitFps">VSync</param>
/// <exception cref="Exception">Could not create OverlayWindow</exception>
public DirectXOverlayWindow(bool limitFps = true) {
IsDisposing = false;
IsVisible = true;
IsTopMost = true;
ParentWindowExists = false;
X = 0;
Y = 0;
Width = Native.GetSystemMetrics(WindowConstants.SmCxScreen);
Height = Native.GetSystemMetrics(WindowConstants.SmCyScreen);
ParentWindow = IntPtr.Zero;
if (!CreateWindow()) {
throw new Exception("Could not create OverlayWindow");
}
Graphics = new Direct2DRenderer(Handle, limitFps);
SetBounds(X, Y, Width, Height);
}
/// <summary>
/// Makes a transparent window which adjust it's size and position to fit the parent window
/// </summary>
/// <param name="parent">HWND/Handle of a window</param>
/// <param name="limitFps">VSync</param>
/// <exception cref="Exception">
/// The handle of the parent window isn't valid
/// or
/// Could not create OverlayWindow
/// </exception>
public DirectXOverlayWindow(IntPtr parent, bool limitFps = true) {
if (parent == IntPtr.Zero) {
throw new Exception("The handle of the parent window isn't valid");
}
Native.Rect bounds;
Native.GetWindowRect(parent, out bounds);
IsDisposing = false;
IsVisible = true;
IsTopMost = true;
ParentWindowExists = true;
X = bounds.Left;
Y = bounds.Top;
Width = bounds.Right - bounds.Left;
Height = bounds.Bottom - bounds.Top;
ParentWindow = parent;
if (!CreateWindow()) {
throw new Exception("Could not create OverlayWindow");
}
Graphics = new Direct2DRenderer(Handle, limitFps);
SetBounds(X, Y, Width, Height);
}
/// <summary>
/// Finalizes an instance of the <see cref="DirectXOverlayWindow" /> class.
/// </summary>
~DirectXOverlayWindow() {
Dispose();
}
/// <summary>
/// Clean up used ressources and destroy window
/// </summary>
public void Dispose() {
IsDisposing = true;
Graphics.Dispose();
Native.DestroyWindow(Handle);
}
/// <summary>
/// Creates a window with the information's stored in this class
/// </summary>
/// <returns>
/// true on success
/// </returns>
private bool CreateWindow() {
Handle = Native.CreateWindowEx(
WindowConstants.WindowExStyleDx,
WindowConstants.DesktopClass,
"",
WindowConstants.WindowStyleDx,
X,
Y,
Width,
Height,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero);
if (Handle == IntPtr.Zero) {
return false;
}
Native.SetLayeredWindowAttributes(Handle, 0, 255, WindowConstants.LwaAlpha);
ExtendFrameIntoClient();
return true;
}
/// <summary>
/// Resize and set new position if the parent window's bounds change
/// </summary>
public void Update() {
if (!ParentWindowExists)
return;
Native.Rect bounds;
Native.GetWindowRect(ParentWindow, out bounds);
if (X != bounds.Left || Y != bounds.Top || Width != bounds.Right - bounds.Left ||
Height != bounds.Bottom - bounds.Top) {
SetBounds(bounds.Left, bounds.Top, bounds.Right - bounds.Left, bounds.Bottom - bounds.Top);
}
}
/// <summary>
/// Extends the frame into client.
/// </summary>
private void ExtendFrameIntoClient() {
_margin.cxLeftWidth = X;
_margin.cxRightWidth = Width;
_margin.cyBottomHeight = Height;
_margin.cyTopHeight = Y;
Native.DwmExtendFrameIntoClientArea(Handle, ref _margin);
}
/// <summary>
/// Sets the position.
/// </summary>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
public void SetPos(int x, int y) {
X = x;
Y = y;
Native.SetWindowPos(Handle, WindowConstants.HwndTopmost, X, Y, Width, Height, 0);
ExtendFrameIntoClient();
}
/// <summary>
/// Sets the size.
/// </summary>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
public void SetSize(int width, int height) {
Width = width;
Height = height;
Native.SetWindowPos(Handle, WindowConstants.HwndTopmost, X, Y, Width, Height, 0);
Graphics.AutoResize(Width, Height);
ExtendFrameIntoClient();
}
/// <summary>
/// Sets the bounds.
/// </summary>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
public void SetBounds(int x, int y, int width, int height) {
X = x;
Y = y;
Width = width;
Height = height;
Native.SetWindowPos(Handle, WindowConstants.HwndTopmost, X, Y, Width, Height, 0);
Graphics?.AutoResize(Width, Height);
ExtendFrameIntoClient();
}
/// <summary>
/// Shows this instance.
/// </summary>
public void Show() {
if (IsVisible) {
return;
}
Native.ShowWindow(Handle, WindowConstants.SwShow);
IsVisible = true;
ExtendFrameIntoClient();
}
/// <summary>
/// Hides this instance.
/// </summary>
public void Hide() {
if (!IsVisible) {
return;
}
Native.ShowWindow(Handle, WindowConstants.SwHide);
IsVisible = false;
}
}
}

View File

@@ -0,0 +1,37 @@
using SharpDX.DirectWrite;
namespace Overlay.NET.Directx {
/// <summary>
/// </summary>
internal class TextLayoutBuffer {
/// <summary>
/// The text
/// </summary>
public string Text { get; set; }
/// <summary>
/// The text layout
/// </summary>
public TextLayout TextLayout { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="TextLayoutBuffer" /> class.
/// </summary>
/// <param name="text">The text.</param>
/// <param name="layout">The layout.</param>
public TextLayoutBuffer(string text, TextLayout layout) {
Text = text;
TextLayout = layout;
TextLayout.TextAlignment = TextAlignment.Leading;
TextLayout.WordWrapping = WordWrapping.NoWrap;
}
/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
public void Dispose() {
TextLayout.Dispose();
Text = null;
}
}
}

View File

@@ -0,0 +1,135 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{2D411EA5-BC00-4630-B25E-43C554323E72}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Overlay.NET</RootNamespace>
<AssemblyName>Overlay.NET</AssemblyName>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Reference Include="Process.NET, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Process.NET.1.0.8\lib\Process.NET.dll</HintPath>
</Reference>
<Reference Include="SharpDX, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\packages\SharpDX.4.2.0\lib\net45\SharpDX.dll</HintPath>
</Reference>
<Reference Include="SharpDX.Direct2D1, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\packages\SharpDX.Direct2D1.4.2.0\lib\net45\SharpDX.Direct2D1.dll</HintPath>
</Reference>
<Reference Include="SharpDX.DXGI, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\packages\SharpDX.DXGI.4.2.0\lib\net45\SharpDX.DXGI.dll</HintPath>
</Reference>
<Reference Include="SharpDX.Mathematics, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\packages\SharpDX.Mathematics.4.2.0\lib\net45\SharpDX.Mathematics.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Drawing" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<Page Include="Wpf\OverlayWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<ItemGroup>
<Compile Include="Common\FileLogger.cs" />
<Compile Include="Common\ISerializer.cs" />
<Compile Include="Common\ISettings.cs" />
<Compile Include="Common\Log.cs" />
<Compile Include="Common\Native.cs" />
<Compile Include="Common\PluginBase.cs" />
<Compile Include="Common\PluginLoader.cs" />
<Compile Include="Common\RelativeFile.cs" />
<Compile Include="Common\SerializableSettings.cs" />
<Compile Include="Common\TickEngine.cs" />
<Compile Include="Common\TimeSpanExtensions.cs" />
<Compile Include="Common\WaitTimer.cs" />
<Compile Include="Common\XmlSerializerEx.cs" />
<Compile Include="Directx\Direct2DRenderer.cs" />
<Compile Include="Directx\DirectExternalXOverlayPlugin.cs" />
<Compile Include="Directx\DirectXOverlayWindow.cs" />
<Compile Include="Directx\TextLayoutBuffer.cs" />
<Compile Include="Common\WindowConstants.cs" />
<Compile Include="OverlayPlugin.cs" />
<Compile Include="Wpf\OverlayWindow.xaml.cs">
<DependentUpon>OverlayWindow.xaml</DependentUpon>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<Compile Include="Common\WindowExtensions.cs" />
<Compile Include="Wpf\WpfOverlayPlugin.cs" />
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<AppDesigner Include="Properties\" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,54 @@
using System;
using Overlay.NET.Common;
using Process.NET.Windows;
namespace Overlay.NET {
/// <summary>
/// Abstract class that defines basic overlay operations and values.
/// </summary>
/// <seealso cref="Overlay.NET.Common.PluginBase" />
/// <seealso cref="System.IDisposable" />
public abstract class OverlayPlugin : PluginBase, IDisposable {
/// <summary>
/// Gets or sets the target window that the overlay is to 'attach' to.
/// </summary>
/// <value>
/// The target window.
/// </value>
public IWindow TargetWindow { get; protected set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is enabled.
/// </summary>
/// <value>
/// <c>true</c> if this instance is enabled; otherwise, <c>false</c>.
/// </value>
public bool IsEnabled { get; protected set; }
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public virtual void Dispose() {}
/// <summary>
/// Enables this instance.
/// </summary>
public virtual void Enable() => IsEnabled = true;
/// <summary>
/// Disables this instance.
/// </summary>
public virtual void Disable() => IsEnabled = false;
/// <summary>
/// Initializes the specified target window.
/// </summary>
/// <param name="targetWindow">The target window.</param>
public virtual void Initialize(IWindow targetWindow) => TargetWindow = targetWindow;
/// <summary>
/// Updates this instance.
/// </summary>
public virtual void Update() {}
}
}

View File

@@ -0,0 +1,54 @@
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Overlay.NET")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Overlay.NET")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Overlay.NET.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Overlay.NET.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

View File

@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,26 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Overlay.NET.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.0.1.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}

View File

@@ -0,0 +1,8 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@@ -0,0 +1,15 @@
<Window x:Class="Overlay.NET.Wpf.OverlayWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="WowSharp Overlay OverlayWindow" Height="300" Width="300"
WindowStyle="None"
Topmost="True"
AllowsTransparency="True">
<Window.Background>
<SolidColorBrush Opacity="0.0" Color="Black" />
</Window.Background>
<Canvas x:Name="OverlayGrid" HorizontalAlignment="Left" Height="300" VerticalAlignment="Top" Width="300" />
</Window>

View File

@@ -0,0 +1,93 @@
using System;
using System.Windows;
using System.Windows.Media;
using Overlay.NET.Common;
using Process.NET.Windows;
namespace Overlay.NET.Wpf {
/// <summary>
/// Interaction logic for OverlayWindow.xaml
/// </summary>
public partial class OverlayWindow : Window {
private readonly IWindow _targetWindow;
/// <summary>
/// Initializes a new instance of the <see cref="OverlayWindow" /> class.
/// </summary>
/// <param name="targetWindow">The window.</param>
public OverlayWindow(IWindow targetWindow) {
_targetWindow = targetWindow;
InitializeComponent();
}
public event EventHandler<DrawingContext> Draw;
/// <summary>
/// Updates this instance.
/// </summary>
public void Update() {
Width = _targetWindow.Width;
Height = _targetWindow.Height;
Left = _targetWindow.X;
Top = _targetWindow.Y;
}
/// <summary>
/// Raises the <see cref="E:System.Windows.Window.SourceInitialized" /> event.
/// </summary>
/// <param name="e">An <see cref="T:System.EventArgs" /> that contains the event data.</param>
protected override void OnSourceInitialized(EventArgs e) {
base.OnSourceInitialized(e);
// We need to do this in order to allow shapes
// drawn on the canvas to be click-through.
// There is no other way to do this.
// Source: https://social.msdn.microsoft.com/Forums/en-US/c32889d3-effa-4b82-b179-76489ffa9f7d/how-to-clicking-throughpassing-shapesellipserectangle?forum=wpf
this.MakeWindowTransparent();
}
/// <summary>
/// When overridden in a derived class, participates in rendering operations that are directed by the layout system.
/// The rendering instructions for this element are not used directly when this method is invoked, and are instead
/// preserved for later asynchronous use by layout and drawing.
/// </summary>
/// <param name="drawingContext">
/// The drawing instructions for a specific element. This context is provided to the layout
/// system.
/// </param>
protected override void OnRender(DrawingContext drawingContext) {
OnDraw(drawingContext);
base.OnRender(drawingContext);
}
/// <summary>
/// Adds the specified element.
/// </summary>
/// <param name="element">The element.</param>
public void Add(UIElement element) => OverlayGrid.Children.Add(element);
/// <summary>
/// Removes the specified element.
/// </summary>
/// <param name="element">The element.</param>
public void Remove(UIElement element) => OverlayGrid.Children.Remove(element);
/// <summary>
/// Adds the specified element.
/// </summary>
/// <param name="element">The element.</param>
/// <param name="index">The index.</param>
public void Add(UIElement element, int index) => OverlayGrid.Children[index] = element;
/// <summary>
/// Removes the specified index.
/// </summary>
/// <param name="index">The index.</param>
public void Remove(int index) => OverlayGrid.Children.RemoveAt(index);
/// <summary>
/// Called when [draw].
/// </summary>
/// <param name="e">The e.</param>
protected virtual void OnDraw(DrawingContext e) => Draw?.Invoke(this, e);
}
}

View File

@@ -0,0 +1,15 @@
namespace Overlay.NET.Wpf {
/// <summary>
/// Abstract overlay that uses a transparent WPF window to do its rendering.
/// </summary>
/// <seealso cref="Overlay.NET.OverlayPlugin" />
public abstract class WpfOverlayPlugin : OverlayPlugin {
/// <summary>
/// Gets or sets the overlay window.
/// </summary>
/// <value>
/// The overlay window.
/// </value>
public OverlayWindow OverlayWindow { get; protected set; }
}
}

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Process.NET" version="1.0.8" targetFramework="net461" />
<package id="SharpDX" version="4.2.0" targetFramework="net462" />
<package id="SharpDX.Direct2D1" version="4.2.0" targetFramework="net462" />
<package id="SharpDX.DXGI" version="4.2.0" targetFramework="net462" />
<package id="SharpDX.Mathematics" version="4.2.0" targetFramework="net462" />
</packages>