mirror of
https://github.com/amerkoleci/Vortice.Win32.git
synced 2026-01-14 16:16:04 +08:00
Generator: Add Enum and Struct
Win32: IUnknown and DXGI generation.
This commit is contained in:
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "src/Generator/win32json"]
|
||||||
|
path = src/Generator/win32json
|
||||||
|
url = https://github.com/marlersoft/win32json.git
|
||||||
64
src/Generator/ApiData.cs
Normal file
64
src/Generator/ApiData.cs
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
// Copyright © Amer Koleci and Contributors.
|
||||||
|
// Licensed under the MIT License (MIT). See LICENSE in the repository root for more information.
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Generator;
|
||||||
|
|
||||||
|
public class ApiDataArrayShape
|
||||||
|
{
|
||||||
|
public int Size { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ApiDataType
|
||||||
|
{
|
||||||
|
public string Kind { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
// Kind == Array
|
||||||
|
public ApiDataArrayShape Shape { get; set; }
|
||||||
|
public ApiDataType Child { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ApiDataConstant
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public ApiDataType Type { get; set; }
|
||||||
|
public string ValueType { get; set; }
|
||||||
|
public object Value { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ApiEnumValue
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public object Value { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ApiStructField
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public ApiDataType Type { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ApiType
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Kind { get; set; }
|
||||||
|
|
||||||
|
// Enum
|
||||||
|
public bool Flags { get; set; }
|
||||||
|
public bool Scoped { get; set; }
|
||||||
|
public string IntegerBase { get; set; }
|
||||||
|
public ApiEnumValue[] Values { get; set; }
|
||||||
|
|
||||||
|
// Struct
|
||||||
|
public int Size { get; set; }
|
||||||
|
public int PackingSize { get; set; }
|
||||||
|
public ApiStructField[] Fields { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class ApiData
|
||||||
|
{
|
||||||
|
public ApiDataConstant[] Constants { get; set; }
|
||||||
|
public ApiType[] Types { get; set; }
|
||||||
|
}
|
||||||
@@ -12,7 +12,7 @@ public sealed class CodeWriter : IDisposable
|
|||||||
|
|
||||||
public int IndentLevel { get; private set; }
|
public int IndentLevel { get; private set; }
|
||||||
|
|
||||||
public CodeWriter(string fileName, bool enableNullable, params string[] namespaces)
|
public CodeWriter(string fileName, string ns, params string[] usingNamespaces)
|
||||||
{
|
{
|
||||||
_indentStrings = new string[10];
|
_indentStrings = new string[10];
|
||||||
for (int i = 0; i < _indentStrings.Length; i++)
|
for (int i = 0; i < _indentStrings.Length; i++)
|
||||||
@@ -31,23 +31,18 @@ public sealed class CodeWriter : IDisposable
|
|||||||
_writer.WriteLine("// ------------------------------------------------------------------------------");
|
_writer.WriteLine("// ------------------------------------------------------------------------------");
|
||||||
_writer.WriteLine();
|
_writer.WriteLine();
|
||||||
|
|
||||||
if (enableNullable)
|
_writer.WriteLine($"using System;");
|
||||||
|
_writer.WriteLine($"using System.Runtime.CompilerServices;");
|
||||||
|
_writer.WriteLine($"using System.Diagnostics.CodeAnalysis;");
|
||||||
|
|
||||||
|
foreach (string usingNamespace in usingNamespaces)
|
||||||
{
|
{
|
||||||
_writer.WriteLine($"#nullable enable");
|
_writer.WriteLine($"using {usingNamespace};");
|
||||||
|
}
|
||||||
|
|
||||||
_writer.WriteLine();
|
_writer.WriteLine();
|
||||||
}
|
|
||||||
|
|
||||||
foreach (string ns in namespaces)
|
_writer.WriteLine($"namespace {ns};");
|
||||||
{
|
|
||||||
_writer.WriteLine($"using {ns};");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (namespaces.Length > 0)
|
|
||||||
{
|
|
||||||
_writer.WriteLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
_writer.WriteLine("namespace Vortice.Vulkan;");
|
|
||||||
_writer.WriteLine();
|
_writer.WriteLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,6 +74,12 @@ public sealed class CodeWriter : IDisposable
|
|||||||
_shouldIndent = true;
|
_shouldIndent = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteUndindented(string @string)
|
||||||
|
{
|
||||||
|
_writer.WriteLine(@string);
|
||||||
|
_shouldIndent = true;
|
||||||
|
}
|
||||||
|
|
||||||
public void BeginBlock(string content)
|
public void BeginBlock(string content)
|
||||||
{
|
{
|
||||||
WriteLine(content);
|
WriteLine(content);
|
||||||
|
|||||||
@@ -8,10 +8,11 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="vulkan/*.*">
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.2-beta2" />
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
</ItemGroup>
|
||||||
</Content>
|
|
||||||
<Content Include="vk_video/*.*">
|
<ItemGroup>
|
||||||
|
<Content Include="win32json/api/*.*">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -1,10 +1,59 @@
|
|||||||
// Copyright © Amer Koleci and Contributors.
|
// Copyright © Amer Koleci and Contributors.
|
||||||
// Licensed under the MIT License (MIT). See LICENSE in the repository root for more information.
|
// Licensed under the MIT License (MIT). See LICENSE in the repository root for more information.
|
||||||
|
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Text;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
using Microsoft.VisualBasic.FileIO;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Generator;
|
namespace Generator;
|
||||||
|
|
||||||
public static class Program
|
public static class Program
|
||||||
{
|
{
|
||||||
|
private static readonly string[] jsons = new[]
|
||||||
|
{
|
||||||
|
"Graphics.Dxgi.Common.json"
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly Dictionary<string, string> s_csNameMappings = new()
|
||||||
|
{
|
||||||
|
{"Void", "void" },
|
||||||
|
{"Byte", "byte" },
|
||||||
|
{"SByte", "sbyte" },
|
||||||
|
{"Int8", "sbyte" },
|
||||||
|
{"Int16", "short" },
|
||||||
|
{"Int32", "int" },
|
||||||
|
{"Int64", "long" },
|
||||||
|
{"UInt8", "byte" },
|
||||||
|
{"UInt16", "ushort" },
|
||||||
|
{"UInt32", "uint" },
|
||||||
|
{"UInt64", "ulong" },
|
||||||
|
{"Single", "float" },
|
||||||
|
{"Double", "double" },
|
||||||
|
|
||||||
|
{ "BOOL", "Bool32" },
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly Dictionary<string, string> s_knownTypesPrefixes = new()
|
||||||
|
{
|
||||||
|
{ "DXGI_COLOR_SPACE_TYPE", "DXGI_COLOR_SPACE" },
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly Dictionary<string, string> s_knownEnumValueNames = new()
|
||||||
|
{
|
||||||
|
{ "DXGI_FORMAT_420_OPAQUE", "Opaque420" }
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly HashSet<string> s_ignoredParts = new(StringComparer.OrdinalIgnoreCase)
|
||||||
|
{
|
||||||
|
"DXGI"
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly HashSet<string> s_preserveCaps = new(StringComparer.OrdinalIgnoreCase)
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
public static int Main(string[] args)
|
public static int Main(string[] args)
|
||||||
{
|
{
|
||||||
string outputPath = AppContext.BaseDirectory;
|
string outputPath = AppContext.BaseDirectory;
|
||||||
@@ -23,6 +72,374 @@ public static class Program
|
|||||||
Directory.CreateDirectory(outputPath);
|
Directory.CreateDirectory(outputPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (string jsonFile in jsons)
|
||||||
|
{
|
||||||
|
string outputFolder = Path.Combine(outputPath, "Graphics");
|
||||||
|
if (!Directory.Exists(outputFolder))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(outputFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
string finalPath = Path.Combine(AppContext.BaseDirectory, "win32json", "api", jsonFile);
|
||||||
|
string jsonData = File.ReadAllText(finalPath);
|
||||||
|
ApiData? api = JsonConvert.DeserializeObject<ApiData>(jsonData);
|
||||||
|
Generate(api!, outputFolder);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void Generate(ApiData api, string outputPath)
|
||||||
|
{
|
||||||
|
using var writer = new CodeWriter(
|
||||||
|
Path.Combine(outputPath, "Dxgi.Common.cs"),
|
||||||
|
"Win32.Graphics.Dxgi");
|
||||||
|
|
||||||
|
GenerateConstants(writer, api);
|
||||||
|
GenerateTypes(writer, api);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GenerateConstants(CodeWriter writer, ApiData api)
|
||||||
|
{
|
||||||
|
using (writer.PushBlock($"public static partial class Apis"))
|
||||||
|
{
|
||||||
|
foreach (var constant in api.Constants)
|
||||||
|
{
|
||||||
|
if (ShouldSkipConstant(constant))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
string typeName = GetTypeName(constant.ValueType);
|
||||||
|
writer.WriteLine($"public const {typeName} {constant.Name} = {constant.Value};");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GenerateTypes(CodeWriter writer, ApiData api)
|
||||||
|
{
|
||||||
|
writer.WriteLine($"#region Enums");
|
||||||
|
foreach (ApiType enumType in api.Types.Where(item => item.Kind.ToLowerInvariant() == "enum"))
|
||||||
|
{
|
||||||
|
GenerateEnum(writer, enumType);
|
||||||
|
}
|
||||||
|
writer.WriteLine($"#endregion Enums");
|
||||||
|
writer.WriteLine();
|
||||||
|
|
||||||
|
writer.WriteLine($"#region Structs");
|
||||||
|
foreach (ApiType structType in api.Types.Where(item => item.Kind.ToLowerInvariant() == "struct"))
|
||||||
|
{
|
||||||
|
GenerateStruct(writer, structType);
|
||||||
|
}
|
||||||
|
writer.WriteLine($"#endregion Structs");
|
||||||
|
writer.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GenerateEnum(CodeWriter writer, ApiType enumType)
|
||||||
|
{
|
||||||
|
if (enumType.Flags)
|
||||||
|
{
|
||||||
|
writer.WriteLine("[Flags]");
|
||||||
|
}
|
||||||
|
|
||||||
|
string csTypeName = GetDataTypeName(enumType.Name, out string enumPrefix);
|
||||||
|
string baseTypeName = GetTypeName(enumType.IntegerBase);
|
||||||
|
AddCsMapping(enumType.Name, csTypeName);
|
||||||
|
|
||||||
|
writer.WriteLine($"/// <unmanaged>{enumType.Name}</unmanaged>");
|
||||||
|
using (writer.PushBlock($"public enum {csTypeName} : {baseTypeName}"))
|
||||||
|
{
|
||||||
|
foreach (ApiEnumValue value in enumType.Values)
|
||||||
|
{
|
||||||
|
if (value.Name.EndsWith("_FORCE_DWORD") ||
|
||||||
|
value.Name.EndsWith("_FORCE_UINT"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
string enumValueName = GetPrettyFieldName(value.Name, enumPrefix);
|
||||||
|
writer.WriteLine($"/// <unmanaged>{value.Name}</unmanaged>");
|
||||||
|
writer.WriteLine($"{enumValueName} = {value.Value},");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GenerateStruct(CodeWriter writer, ApiType structType)
|
||||||
|
{
|
||||||
|
string csTypeName = GetDataTypeName(structType.Name, out string structPrefix);
|
||||||
|
AddCsMapping(structType.Name, csTypeName);
|
||||||
|
|
||||||
|
writer.WriteLine($"/// <unmanaged>{structType.Name}</unmanaged>");
|
||||||
|
using (writer.PushBlock($"public partial struct {csTypeName}"))
|
||||||
|
{
|
||||||
|
foreach (ApiStructField field in structType.Fields)
|
||||||
|
{
|
||||||
|
if (field.Name.EndsWith("_FORCE_DWORD"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
string fieldValueName = GetPrettyFieldName(field.Name, structPrefix);
|
||||||
|
string fieldTypeName = GetTypeName(field.Type);
|
||||||
|
//writer.WriteLine($"/// <unmanaged>{field.Name}</unmanaged>");
|
||||||
|
|
||||||
|
if (fieldTypeName == "Array")
|
||||||
|
{
|
||||||
|
bool canUseFixed = false;
|
||||||
|
if (field.Type.Child.Kind == "Native")
|
||||||
|
{
|
||||||
|
canUseFixed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldTypeName = GetTypeName(field.Type.Child);
|
||||||
|
|
||||||
|
if (canUseFixed)
|
||||||
|
{
|
||||||
|
writer.WriteLine($"public unsafe fixed {fieldTypeName} {fieldValueName}[{field.Type.Shape.Size}];");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
writer.WriteLine($"public {fieldValueName}__FixedBuffer {fieldValueName};");
|
||||||
|
writer.WriteLine();
|
||||||
|
|
||||||
|
using (writer.PushBlock($"public unsafe struct {fieldValueName}__FixedBuffer"))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < field.Type.Shape.Size; i++)
|
||||||
|
{
|
||||||
|
writer.WriteLine($"public {fieldTypeName} e{i};");
|
||||||
|
}
|
||||||
|
writer.WriteLine();
|
||||||
|
|
||||||
|
writer.WriteLine("[UnscopedRef]");
|
||||||
|
using (writer.PushBlock($"public ref {fieldTypeName} this[int index]"))
|
||||||
|
{
|
||||||
|
writer.WriteLine("[MethodImpl(MethodImplOptions.AggressiveInlining)]");
|
||||||
|
using (writer.PushBlock("get"))
|
||||||
|
{
|
||||||
|
writer.WriteLine($"return ref AsSpan()[index];");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer.WriteLine();
|
||||||
|
|
||||||
|
writer.WriteLine("[UnscopedRef]");
|
||||||
|
writer.WriteLine("[MethodImpl(MethodImplOptions.AggressiveInlining)]");
|
||||||
|
using (writer.PushBlock($"public Span<{fieldTypeName}> AsSpan()"))
|
||||||
|
{
|
||||||
|
writer.WriteUndindented("#if NET6_0_OR_GREATER");
|
||||||
|
writer.WriteLine($"return MemoryMarshal.CreateSpan(ref e0, {field.Type.Shape.Size});");
|
||||||
|
writer.WriteUndindented("#else");
|
||||||
|
writer.WriteLine($"return new(Unsafe.AsPointer(ref e0), {field.Type.Shape.Size});");
|
||||||
|
writer.WriteUndindented("#endif");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
writer.WriteLine($"public {fieldTypeName} {fieldValueName};");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool ShouldSkipConstant(ApiDataConstant constant)
|
||||||
|
{
|
||||||
|
if (constant.Name == "_FACDXGI")
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetDataTypeName(string typeName, out string prefix)
|
||||||
|
{
|
||||||
|
prefix = typeName;
|
||||||
|
if (s_knownTypesPrefixes.TryGetValue(typeName, out string? knowPrefix))
|
||||||
|
{
|
||||||
|
prefix = knowPrefix!;
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] parts = typeName.Split(new[] { '_' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
foreach (string part in parts)
|
||||||
|
{
|
||||||
|
if (s_ignoredParts.Contains(part))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_preserveCaps.Contains(part))
|
||||||
|
{
|
||||||
|
sb.Append(part);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (part.Equals("DESC", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
sb.Append("Description");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.Append(char.ToUpper(part[0]));
|
||||||
|
for (int i = 1; i < part.Length; i++)
|
||||||
|
{
|
||||||
|
sb.Append(char.ToLower(part[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string prettyName = sb.ToString();
|
||||||
|
return (char.IsNumber(prettyName[0])) ? "_" + prettyName : prettyName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetPrettyFieldName(string value, string enumPrefix)
|
||||||
|
{
|
||||||
|
if (s_knownEnumValueNames.TryGetValue(value, out string? knownName))
|
||||||
|
{
|
||||||
|
return knownName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.IndexOf(enumPrefix) != 0)
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isDXGIFormat = enumPrefix == "DXGI_FORMAT";
|
||||||
|
|
||||||
|
string[] parts = value[enumPrefix.Length..].Split(new[] { '_' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
foreach (string part in parts)
|
||||||
|
{
|
||||||
|
if (s_ignoredParts.Contains(part))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_preserveCaps.Contains(part))
|
||||||
|
{
|
||||||
|
sb.Append(part);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (isDXGIFormat)
|
||||||
|
{
|
||||||
|
if (part.Equals("UNKNOWN", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
sb.Append("Unknown");
|
||||||
|
}
|
||||||
|
else if (part.Equals("TYPELESS", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
sb.Append("Typeless");
|
||||||
|
}
|
||||||
|
else if (part.Equals("UNORM", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
sb.Append("Unorm");
|
||||||
|
}
|
||||||
|
else if (part.Equals("SNORM", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
sb.Append("Snorm");
|
||||||
|
}
|
||||||
|
else if (part.Equals("UINT", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
sb.Append("Uint");
|
||||||
|
}
|
||||||
|
else if (part.Equals("SINT", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
sb.Append("Sint");
|
||||||
|
}
|
||||||
|
else if (part.Equals("FLOAT", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
sb.Append("Float");
|
||||||
|
}
|
||||||
|
else if (part.Equals("SRGB", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
sb.Append("Srgb");
|
||||||
|
}
|
||||||
|
else if (part.Equals("SHAREDEXP", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
sb.Append("SharedExp");
|
||||||
|
}
|
||||||
|
else if (part.Equals("SAMPLER", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
sb.Append("Sampler");
|
||||||
|
}
|
||||||
|
else if (part.Equals("FEEDBACK", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
sb.Append("Feedback");
|
||||||
|
}
|
||||||
|
else if (part.Equals("MIN", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
sb.Append("Min");
|
||||||
|
}
|
||||||
|
else if (part.Equals("MIP", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
sb.Append("Mip");
|
||||||
|
}
|
||||||
|
else if (part.Equals("OPAQUE", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
sb.Append("Opaque");
|
||||||
|
}
|
||||||
|
else if (part.Equals("REGION", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
sb.Append("Region");
|
||||||
|
}
|
||||||
|
else if (part.Equals("USED", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
sb.Append("Used");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.Append(part);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.Append(char.ToUpper(part[0]));
|
||||||
|
for (int i = 1; i < part.Length; i++)
|
||||||
|
{
|
||||||
|
sb.Append(char.ToLower(part[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string prettyName = sb.ToString();
|
||||||
|
return (char.IsNumber(prettyName[0])) ? "_" + prettyName : prettyName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetTypeName(ApiDataType dataType)
|
||||||
|
{
|
||||||
|
if (dataType.Kind == "ApiRef")
|
||||||
|
{
|
||||||
|
return GetTypeName(dataType.Name);
|
||||||
|
}
|
||||||
|
else if (dataType.Kind == "Array")
|
||||||
|
{
|
||||||
|
return "Array";
|
||||||
|
}
|
||||||
|
else if (dataType.Kind == "PointerTo")
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetTypeName(dataType.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddCsMapping(string typeName, string csTypeName)
|
||||||
|
{
|
||||||
|
s_csNameMappings[typeName] = csTypeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetTypeName(string name)
|
||||||
|
{
|
||||||
|
if (s_csNameMappings.TryGetValue(name, out string? mappedName))
|
||||||
|
{
|
||||||
|
return mappedName;
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1
src/Generator/win32json
Submodule
1
src/Generator/win32json
Submodule
Submodule src/Generator/win32json added at d7c046e698
39
src/Vortice.Win32/Attributes.cs
Normal file
39
src/Vortice.Win32/Attributes.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
// Copyright © Amer Koleci and Contributors.
|
||||||
|
// Licensed under the MIT License (MIT). See LICENSE in the repository root for more information.
|
||||||
|
// Copyright © Tanner Gooding and Contributors. Licensed under the MIT License (MIT). See License.md in the repository root for more information.
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace Win32;
|
||||||
|
|
||||||
|
/// <summary>Defines the type of a member as it was used in the native signature.</summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = false, Inherited = true)]
|
||||||
|
[Conditional("DEBUG")]
|
||||||
|
internal sealed partial class NativeTypeNameAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>Initializes a new instance of the <see cref="NativeTypeNameAttribute" /> class.</summary>
|
||||||
|
/// <param name="name">The name of the type that was used in the native signature.</param>
|
||||||
|
public NativeTypeNameAttribute(string name)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Gets the name of the type that was used in the native signature.</summary>
|
||||||
|
public string Name { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Defines the vtbl index of a method as it was in the native signature.</summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
|
||||||
|
[Conditional("DEBUG")]
|
||||||
|
internal sealed partial class VtblIndexAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>Initializes a new instance of the <see cref="VtblIndexAttribute" /> class.</summary>
|
||||||
|
/// <param name="index">The vtbl index of a method as it was in the native signature.</param>
|
||||||
|
public VtblIndexAttribute(uint index)
|
||||||
|
{
|
||||||
|
Index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Gets the vtbl index of a method as it was in the native signature.</summary>
|
||||||
|
public uint Index { get; }
|
||||||
|
}
|
||||||
99
src/Vortice.Win32/Bool32.cs
Normal file
99
src/Vortice.Win32/Bool32.cs
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
// Copyright © Amer Koleci and Contributors.
|
||||||
|
// Licensed under the MIT License (MIT). See LICENSE in the repository root for more information.
|
||||||
|
|
||||||
|
namespace Win32;
|
||||||
|
|
||||||
|
public readonly partial struct Bool32 : IComparable, IComparable<Bool32>, IEquatable<Bool32>, IFormattable
|
||||||
|
{
|
||||||
|
public readonly int Value;
|
||||||
|
|
||||||
|
public Bool32(int value)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Bool32 True => new Bool32(1);
|
||||||
|
public static Bool32 False => new Bool32(0);
|
||||||
|
|
||||||
|
public static bool operator ==(Bool32 left, Bool32 right) => left.Value == right.Value;
|
||||||
|
|
||||||
|
public static bool operator !=(Bool32 left, Bool32 right) => left.Value != right.Value;
|
||||||
|
|
||||||
|
public static bool operator <(Bool32 left, Bool32 right) => left.Value < right.Value;
|
||||||
|
|
||||||
|
public static bool operator <=(Bool32 left, Bool32 right) => left.Value <= right.Value;
|
||||||
|
|
||||||
|
public static bool operator >(Bool32 left, Bool32 right) => left.Value > right.Value;
|
||||||
|
|
||||||
|
public static bool operator >=(Bool32 left, Bool32 right) => left.Value >= right.Value;
|
||||||
|
|
||||||
|
public static implicit operator bool(Bool32 value) => value.Value != 0;
|
||||||
|
|
||||||
|
public static implicit operator Bool32(bool value) => new Bool32(value ? 1 : 0);
|
||||||
|
|
||||||
|
public static bool operator false(Bool32 value) => value.Value == 0;
|
||||||
|
|
||||||
|
public static bool operator true(Bool32 value) => value.Value != 0;
|
||||||
|
|
||||||
|
public static implicit operator Bool32(byte value) => new Bool32(value);
|
||||||
|
|
||||||
|
public static explicit operator byte(Bool32 value) => (byte)(value.Value);
|
||||||
|
|
||||||
|
public static implicit operator Bool32(short value) => new Bool32(value);
|
||||||
|
|
||||||
|
public static explicit operator short(Bool32 value) => (short)(value.Value);
|
||||||
|
|
||||||
|
public static implicit operator Bool32(int value) => new Bool32(value);
|
||||||
|
|
||||||
|
public static implicit operator int(Bool32 value) => value.Value;
|
||||||
|
|
||||||
|
public static explicit operator Bool32(long value) => new Bool32(unchecked((int)(value)));
|
||||||
|
|
||||||
|
public static implicit operator long(Bool32 value) => value.Value;
|
||||||
|
|
||||||
|
public static explicit operator Bool32(nint value) => new Bool32(unchecked((int)(value)));
|
||||||
|
|
||||||
|
public static implicit operator nint(Bool32 value) => value.Value;
|
||||||
|
|
||||||
|
public static implicit operator Bool32(sbyte value) => new Bool32(value);
|
||||||
|
|
||||||
|
public static explicit operator sbyte(Bool32 value) => (sbyte)(value.Value);
|
||||||
|
|
||||||
|
public static implicit operator Bool32(ushort value) => new Bool32(value);
|
||||||
|
|
||||||
|
public static explicit operator ushort(Bool32 value) => (ushort)(value.Value);
|
||||||
|
|
||||||
|
public static explicit operator Bool32(uint value) => new Bool32(unchecked((int)(value)));
|
||||||
|
|
||||||
|
public static explicit operator uint(Bool32 value) => (uint)(value.Value);
|
||||||
|
|
||||||
|
public static explicit operator Bool32(ulong value) => new Bool32(unchecked((int)(value)));
|
||||||
|
|
||||||
|
public static explicit operator ulong(Bool32 value) => (ulong)(value.Value);
|
||||||
|
|
||||||
|
public static explicit operator Bool32(nuint value) => new Bool32(unchecked((int)(value)));
|
||||||
|
|
||||||
|
public static explicit operator nuint(Bool32 value) => (nuint)(value.Value);
|
||||||
|
|
||||||
|
public int CompareTo(object? obj)
|
||||||
|
{
|
||||||
|
if (obj is Bool32 other)
|
||||||
|
{
|
||||||
|
return CompareTo(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (obj is null) ? 1 : throw new ArgumentException("obj is not an instance of Bool32.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CompareTo(Bool32 other) => Value.CompareTo(other.Value);
|
||||||
|
|
||||||
|
public override bool Equals(object? obj) => (obj is Bool32 other) && Equals(other);
|
||||||
|
|
||||||
|
public bool Equals(Bool32 other) => Value.Equals(other.Value);
|
||||||
|
|
||||||
|
public override int GetHashCode() => Value.GetHashCode();
|
||||||
|
|
||||||
|
public override string ToString() => Value.ToString();
|
||||||
|
|
||||||
|
public string ToString(string? format, IFormatProvider? formatProvider) => Value.ToString(format, formatProvider);
|
||||||
|
}
|
||||||
318
src/Vortice.Win32/ComPtr.cs
Normal file
318
src/Vortice.Win32/ComPtr.cs
Normal file
@@ -0,0 +1,318 @@
|
|||||||
|
// Copyright © Tanner Gooding and Contributors. Licensed under the MIT License (MIT). See License.md in the repository root for more information.
|
||||||
|
// Ported from winrt/wrl/client.h in the Windows SDK for Windows 10.0.22621.0
|
||||||
|
// Original source is Copyright © Microsoft. All rights reserved.
|
||||||
|
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using static Win32.Apis;
|
||||||
|
|
||||||
|
namespace Win32;
|
||||||
|
|
||||||
|
/// <summary>A type that allows working with pointers to COM objects more securely.</summary>
|
||||||
|
/// <typeparam name="T">The type to wrap in the current <see cref="ComPtr{T}"/> instance.</typeparam>
|
||||||
|
/// <remarks>While this type is not marked as <see langword="ref"/> so that it can also be used in fields, make sure to keep the reference counts properly tracked if you do store <see cref="ComPtr{T}"/> instances on the heap.</remarks>
|
||||||
|
public unsafe struct ComPtr<T> : IDisposable
|
||||||
|
where T : unmanaged, IUnknown.Interface
|
||||||
|
{
|
||||||
|
/// <summary>The raw pointer to a COM object, if existing.</summary>
|
||||||
|
private T* ptr_;
|
||||||
|
|
||||||
|
/// <summary>Creates a new <see cref="ComPtr{T}"/> instance from a raw pointer and increments the ref count.</summary>
|
||||||
|
/// <param name="other">The raw pointer to wrap.</param>
|
||||||
|
public ComPtr(T* other)
|
||||||
|
{
|
||||||
|
ptr_ = other;
|
||||||
|
InternalAddRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Creates a new <see cref="ComPtr{T}"/> instance from a second one and increments the ref count.</summary>
|
||||||
|
/// <param name="other">The other <see cref="ComPtr{T}"/> instance to copy.</param>
|
||||||
|
public ComPtr(ComPtr<T> other)
|
||||||
|
{
|
||||||
|
ptr_ = other.ptr_;
|
||||||
|
InternalAddRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Converts a raw pointer to a new <see cref="ComPtr{T}"/> instance and increments the ref count.</summary>
|
||||||
|
/// <param name="other">The raw pointer to wrap.</param>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static implicit operator ComPtr<T>(T* other)
|
||||||
|
=> new ComPtr<T>(other);
|
||||||
|
|
||||||
|
/// <summary>Unwraps a <see cref="ComPtr{T}"/> instance and returns the internal raw pointer.</summary>
|
||||||
|
/// <param name="other">The <see cref="ComPtr{T}"/> instance to unwrap.</param>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static implicit operator T*(ComPtr<T> other)
|
||||||
|
=> other.Get();
|
||||||
|
|
||||||
|
/// <summary>Converts the current object reference to type <typeparamref name="U"/> and assigns that to a target <see cref="ComPtr{T}"/> value.</summary>
|
||||||
|
/// <typeparam name="U">The interface type to use to try casting the current COM object.</typeparam>
|
||||||
|
/// <param name="p">A raw pointer to the target <see cref="ComPtr{T}"/> value to write to.</param>
|
||||||
|
/// <returns>The result of <see cref="IUnknown.QueryInterface"/> for the target type <typeparamref name="U"/>.</returns>
|
||||||
|
/// <remarks>This method will automatically release the target COM object pointed to by <paramref name="p"/>, if any.</remarks>
|
||||||
|
public readonly HResult As<U>(ComPtr<U>* p)
|
||||||
|
where U : unmanaged, IUnknown.Interface
|
||||||
|
{
|
||||||
|
return ptr_->QueryInterface(__uuidof<U>(), (void**)p->ReleaseAndGetAddressOf());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Converts the current object reference to type <typeparamref name="U"/> and assigns that to a target <see cref="ComPtr{T}"/> value.</summary>
|
||||||
|
/// <typeparam name="U">The interface type to use to try casting the current COM object.</typeparam>
|
||||||
|
/// <param name="other">A reference to the target <see cref="ComPtr{T}"/> value to write to.</param>
|
||||||
|
/// <returns>The result of <see cref="IUnknown.QueryInterface"/> for the target type <typeparamref name="U"/>.</returns>
|
||||||
|
/// <remarks>This method will automatically release the target COM object pointed to by <paramref name="other"/>, if any.</remarks>
|
||||||
|
public readonly HResult As<U>(ref ComPtr<U> other)
|
||||||
|
where U : unmanaged, IUnknown.Interface
|
||||||
|
{
|
||||||
|
U* ptr;
|
||||||
|
HResult result = ptr_->QueryInterface(__uuidof<U>(), (void**)&ptr);
|
||||||
|
|
||||||
|
other.Attach(ptr);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Converts the current object reference to a type indicated by the given IID and assigns that to a target <see cref="ComPtr{T}"/> value.</summary>
|
||||||
|
/// <param name="riid">The IID indicating the interface type to convert the COM object reference to.</param>
|
||||||
|
/// <param name="other">A raw pointer to the target <see cref="ComPtr{T}"/> value to write to.</param>
|
||||||
|
/// <returns>The result of <see cref="IUnknown.QueryInterface"/> for the target IID.</returns>
|
||||||
|
/// <remarks>This method will automatically release the target COM object pointed to by <paramref name="other"/>, if any.</remarks>
|
||||||
|
public readonly HResult AsIID(Guid* riid, ComPtr<IUnknown>* other)
|
||||||
|
{
|
||||||
|
return ptr_->QueryInterface(riid, (void**)other->ReleaseAndGetAddressOf());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Converts the current object reference to a type indicated by the given IID and assigns that to a target <see cref="ComPtr{T}"/> value.</summary>
|
||||||
|
/// <param name="riid">The IID indicating the interface type to convert the COM object reference to.</param>
|
||||||
|
/// <param name="other">A reference to the target <see cref="ComPtr{T}"/> value to write to.</param>
|
||||||
|
/// <returns>The result of <see cref="IUnknown.QueryInterface"/> for the target IID.</returns>
|
||||||
|
/// <remarks>This method will automatically release the target COM object pointed to by <paramref name="other"/>, if any.</remarks>
|
||||||
|
public readonly HResult AsIID(Guid* riid, ref ComPtr<IUnknown> other)
|
||||||
|
{
|
||||||
|
IUnknown* ptr;
|
||||||
|
HResult result = ptr_->QueryInterface(riid, (void**)&ptr);
|
||||||
|
|
||||||
|
other.Attach(ptr);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Releases the current COM object, if any, and replaces the internal pointer with an input raw pointer.</summary>
|
||||||
|
/// <param name="other">The input raw pointer to wrap.</param>
|
||||||
|
/// <remarks>This method will release the current raw pointer, if any, but it will not increment the references for <paramref name="other"/>.</remarks>
|
||||||
|
public void Attach(T* other)
|
||||||
|
{
|
||||||
|
if (ptr_ != null)
|
||||||
|
{
|
||||||
|
var @ref = ptr_->Release();
|
||||||
|
Debug.Assert((@ref != 0) || (ptr_ != other));
|
||||||
|
}
|
||||||
|
ptr_ = other;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Returns the raw pointer wrapped by the current instance, and resets the current <see cref="ComPtr{T}"/> value.</summary>
|
||||||
|
/// <returns>The raw pointer wrapped by the current <see cref="ComPtr{T}"/> value.</returns>
|
||||||
|
/// <remarks>This method will not change the reference count for the COM object in use.</remarks>
|
||||||
|
public T* Detach()
|
||||||
|
{
|
||||||
|
T* ptr = ptr_;
|
||||||
|
ptr_ = null;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Increments the reference count for the current COM object, if any, and copies its address to a target raw pointer.</summary>
|
||||||
|
/// <param name="ptr">The target raw pointer to copy the address of the current COM object to.</param>
|
||||||
|
/// <returns>This method always returns <see cref="HResult.Ok"/>.</returns>
|
||||||
|
public readonly HResult CopyTo(T** ptr)
|
||||||
|
{
|
||||||
|
InternalAddRef();
|
||||||
|
*ptr = ptr_;
|
||||||
|
return HResult.Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Increments the reference count for the current COM object, if any, and copies its address to a target <see cref="ComPtr{T}"/>.</summary>
|
||||||
|
/// <param name="p">The target raw pointer to copy the address of the current COM object to.</param>
|
||||||
|
/// <returns>This method always returns <see cref="HResult.Ok"/>.</returns>
|
||||||
|
public readonly HResult CopyTo(ComPtr<T>* p)
|
||||||
|
{
|
||||||
|
InternalAddRef();
|
||||||
|
*p->ReleaseAndGetAddressOf() = ptr_;
|
||||||
|
return HResult.Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Increments the reference count for the current COM object, if any, and copies its address to a target <see cref="ComPtr{T}"/>.</summary>
|
||||||
|
/// <param name="other">The target reference to copy the address of the current COM object to.</param>
|
||||||
|
/// <returns>This method always returns <see cref="HResult.Ok"/>.</returns>
|
||||||
|
public readonly HResult CopyTo(ref ComPtr<T> other)
|
||||||
|
{
|
||||||
|
InternalAddRef();
|
||||||
|
other.Attach(ptr_);
|
||||||
|
return HResult.Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Converts the current COM object reference to a given interface type and assigns that to a target raw pointer.</summary>
|
||||||
|
/// <param name="ptr">The target raw pointer to copy the address of the current COM object to.</param>
|
||||||
|
/// <returns>The result of <see cref="IUnknown.QueryInterface"/> for the target type <typeparamref name="U"/>.</returns>
|
||||||
|
public readonly HResult CopyTo<U>(U** ptr)
|
||||||
|
where U : unmanaged, IUnknown.Interface
|
||||||
|
{
|
||||||
|
return ptr_->QueryInterface(__uuidof<U>(), (void**)ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Converts the current COM object reference to a given interface type and assigns that to a target <see cref="ComPtr{T}"/>.</summary>
|
||||||
|
/// <param name="p">The target raw pointer to copy the address of the current COM object to.</param>
|
||||||
|
/// <returns>The result of <see cref="IUnknown.QueryInterface"/> for the target type <typeparamref name="U"/>.</returns>
|
||||||
|
public readonly HResult CopyTo<U>(ComPtr<U>* p)
|
||||||
|
where U : unmanaged, IUnknown.Interface
|
||||||
|
{
|
||||||
|
return ptr_->QueryInterface(__uuidof<U>(), (void**)p->ReleaseAndGetAddressOf());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Converts the current COM object reference to a given interface type and assigns that to a target <see cref="ComPtr{T}"/>.</summary>
|
||||||
|
/// <param name="other">The target reference to copy the address of the current COM object to.</param>
|
||||||
|
/// <returns>The result of <see cref="IUnknown.QueryInterface"/> for the target type <typeparamref name="U"/>.</returns>
|
||||||
|
public readonly HResult CopyTo<U>(ref ComPtr<U> other)
|
||||||
|
where U : unmanaged, IUnknown.Interface
|
||||||
|
{
|
||||||
|
U* ptr;
|
||||||
|
HResult result = ptr_->QueryInterface(__uuidof<U>(), (void**)&ptr);
|
||||||
|
|
||||||
|
other.Attach(ptr);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Converts the current object reference to a type indicated by the given IID and assigns that to a target address.</summary>
|
||||||
|
/// <param name="riid">The IID indicating the interface type to convert the COM object reference to.</param>
|
||||||
|
/// <param name="ptr">The target raw pointer to copy the address of the current COM object to.</param>
|
||||||
|
/// <returns>The result of <see cref="IUnknown.QueryInterface"/> for the target IID.</returns>
|
||||||
|
public readonly HResult CopyTo(Guid* riid, void** ptr)
|
||||||
|
{
|
||||||
|
return ptr_->QueryInterface(riid, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Converts the current object reference to a type indicated by the given IID and assigns that to a target <see cref="ComPtr{T}"/> value.</summary>
|
||||||
|
/// <param name="riid">The IID indicating the interface type to convert the COM object reference to.</param>
|
||||||
|
/// <param name="p">The target raw pointer to copy the address of the current COM object to.</param>
|
||||||
|
/// <returns>The result of <see cref="IUnknown.QueryInterface"/> for the target IID.</returns>
|
||||||
|
public readonly HResult CopyTo(Guid* riid, ComPtr<IUnknown>* p)
|
||||||
|
{
|
||||||
|
return ptr_->QueryInterface(riid, (void**)p->ReleaseAndGetAddressOf());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Converts the current object reference to a type indicated by the given IID and assigns that to a target <see cref="ComPtr{T}"/> value.</summary>
|
||||||
|
/// <param name="riid">The IID indicating the interface type to convert the COM object reference to.</param>
|
||||||
|
/// <param name="other">The target reference to copy the address of the current COM object to.</param>
|
||||||
|
/// <returns>The result of <see cref="IUnknown.QueryInterface"/> for the target IID.</returns>
|
||||||
|
public readonly HResult CopyTo(Guid* riid, ref ComPtr<IUnknown> other)
|
||||||
|
{
|
||||||
|
IUnknown* ptr;
|
||||||
|
HResult result = ptr_->QueryInterface(riid, (void**)&ptr);
|
||||||
|
|
||||||
|
other.Attach(ptr);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
T* pointer = ptr_;
|
||||||
|
|
||||||
|
if (pointer != null)
|
||||||
|
{
|
||||||
|
ptr_ = null;
|
||||||
|
_ = pointer->Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Gets the currently wrapped raw pointer to a COM object.</summary>
|
||||||
|
/// <returns>The raw pointer wrapped by the current <see cref="ComPtr{T}"/> instance.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public readonly T* Get()
|
||||||
|
{
|
||||||
|
return ptr_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Gets the address of the current <see cref="ComPtr{T}"/> instance as a raw <typeparamref name="T"/> double pointer. This method is only valid when the current <see cref="ComPtr{T}"/> instance is on the stack or pinned.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The raw pointer to the current <see cref="ComPtr{T}"/> instance.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public readonly T** GetAddressOf()
|
||||||
|
{
|
||||||
|
return (T**)Unsafe.AsPointer(ref Unsafe.AsRef(in this));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Gets the address of the current <see cref="ComPtr{T}"/> instance as a raw <typeparamref name="T"/> double pointer.</summary>
|
||||||
|
/// <returns>The raw pointer to the current <see cref="ComPtr{T}"/> instance.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
|
public readonly ref T* GetPinnableReference()
|
||||||
|
{
|
||||||
|
fixed (T** ptr = &ptr_)
|
||||||
|
{
|
||||||
|
return ref *ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Releases the current COM object in use and gets the address of the <see cref="ComPtr{T}"/> instance as a raw <typeparamref name="T"/> double pointer. This method is only valid when the current <see cref="ComPtr{T}"/> instance is on the stack or pinned.</summary>
|
||||||
|
/// <returns>The raw pointer to the current <see cref="ComPtr{T}"/> instance.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public T** ReleaseAndGetAddressOf()
|
||||||
|
{
|
||||||
|
_ = InternalRelease();
|
||||||
|
return GetAddressOf();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Resets the current instance by decrementing the reference count for the target COM object and setting the internal raw pointer to <see langword="null"/>.</summary>
|
||||||
|
/// <returns>The updated reference count for the COM object that was in use, if any.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public uint Reset()
|
||||||
|
{
|
||||||
|
return InternalRelease();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Swaps the current COM object reference with that of a given <see cref="ComPtr{T}"/> instance.</summary>
|
||||||
|
/// <param name="r">The target <see cref="ComPtr{T}"/> instance to swap with the current one.</param>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Swap(ComPtr<T>* r)
|
||||||
|
{
|
||||||
|
T* tmp = ptr_;
|
||||||
|
ptr_ = r->ptr_;
|
||||||
|
r->ptr_ = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Swaps the current COM object reference with that of a given <see cref="ComPtr{T}"/> instance.</summary>
|
||||||
|
/// <param name="other">The target <see cref="ComPtr{T}"/> instance to swap with the current one.</param>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Swap(ref ComPtr<T> other)
|
||||||
|
{
|
||||||
|
T* tmp = ptr_;
|
||||||
|
ptr_ = other.ptr_;
|
||||||
|
other.ptr_ = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increments the reference count for the current COM object, if any
|
||||||
|
private readonly void InternalAddRef()
|
||||||
|
{
|
||||||
|
T* temp = ptr_;
|
||||||
|
|
||||||
|
if (temp != null)
|
||||||
|
{
|
||||||
|
_ = temp->AddRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrements the reference count for the current COM object, if any
|
||||||
|
private uint InternalRelease()
|
||||||
|
{
|
||||||
|
uint @ref = 0;
|
||||||
|
T* temp = ptr_;
|
||||||
|
|
||||||
|
if (temp != null)
|
||||||
|
{
|
||||||
|
ptr_ = null;
|
||||||
|
@ref = temp->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
return @ref;
|
||||||
|
}
|
||||||
|
}
|
||||||
1510
src/Vortice.Win32/Generated/Graphics/Dxgi.Common.cs
Normal file
1510
src/Vortice.Win32/Generated/Graphics/Dxgi.Common.cs
Normal file
File diff suppressed because it is too large
Load Diff
66
src/Vortice.Win32/Graphics/Dxgi.Common.Manual.cs
Normal file
66
src/Vortice.Win32/Graphics/Dxgi.Common.Manual.cs
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
// Copyright © Amer Koleci and Contributors.
|
||||||
|
// Licensed under the MIT License (MIT). See LICENSE in the repository root for more information.
|
||||||
|
|
||||||
|
namespace Win32.Graphics.Dxgi;
|
||||||
|
|
||||||
|
public partial struct Rgb
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize instance of <see cref="Rgb"/> struct.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="red"></param>
|
||||||
|
/// <param name="green"></param>
|
||||||
|
/// <param name="blue"></param>
|
||||||
|
public Rgb(float red, float green, float blue)
|
||||||
|
{
|
||||||
|
Red = red;
|
||||||
|
Green = green;
|
||||||
|
Blue = blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{nameof(Rgb)}(Red: {Red}, Green: {Green}, Blue: {Blue})";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial struct Rational
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize instance of <see cref="Rational"/> struct.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="numerator"></param>
|
||||||
|
/// <param name="denominator"></param>
|
||||||
|
public Rational(uint numerator, uint denominator)
|
||||||
|
{
|
||||||
|
Numerator = numerator;
|
||||||
|
Denominator = denominator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{nameof(Rational)}(Numerator: {Numerator}, Denominator: {Denominator})";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial struct SampleDescription
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A <see cref="SampleDescription"/> with Count=1 and Quality=0.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly SampleDescription Default = new(1, 0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create new instance of <see cref="SampleDescription"/> struct.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="count"></param>
|
||||||
|
/// <param name="quality"></param>
|
||||||
|
public SampleDescription(uint count, uint quality)
|
||||||
|
{
|
||||||
|
Count = count;
|
||||||
|
Quality = quality;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() => $"Count: {Count}, Quality: {Quality}";
|
||||||
|
}
|
||||||
|
|
||||||
61
src/Vortice.Win32/HResult.Constants.cs
Normal file
61
src/Vortice.Win32/HResult.Constants.cs
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
// Copyright © Amer Koleci and Contributors.
|
||||||
|
// Licensed under the MIT License (MIT). See LICENSE in the repository root for more information.
|
||||||
|
|
||||||
|
namespace Win32;
|
||||||
|
|
||||||
|
public readonly partial struct HResult
|
||||||
|
{
|
||||||
|
/// <unmanaged>S_OK</unmanaged>
|
||||||
|
public static readonly HResult Ok = 0;
|
||||||
|
|
||||||
|
/// <unmanaged>S_FALSE</unmanaged>
|
||||||
|
public static readonly HResult False = 1;
|
||||||
|
|
||||||
|
/// <unmanaged>E_ABORT</unmanaged>
|
||||||
|
public static readonly HResult Abort = unchecked((int)0x80004004);
|
||||||
|
|
||||||
|
/// <unmanaged>E_ACCESSDENIED</unmanaged>
|
||||||
|
public static readonly HResult AccessDenied = unchecked((int)0x80070005);
|
||||||
|
|
||||||
|
/// <unmanaged>E_FAIL</unmanaged>
|
||||||
|
public static readonly HResult Fail = unchecked((int)0x80004005);
|
||||||
|
|
||||||
|
/// <unmanaged>E_HANDLE</unmanaged>
|
||||||
|
public static readonly HResult Handle = unchecked((int)0x80070006);
|
||||||
|
|
||||||
|
/// <unmanaged>E_INVALIDARG</unmanaged>
|
||||||
|
public static readonly HResult InvalidArg = unchecked((int)0x80070057);
|
||||||
|
|
||||||
|
/// <unmanaged>E_NOINTERFACE</unmanaged>
|
||||||
|
public static readonly HResult NoInterface = unchecked((int)0x80004002);
|
||||||
|
|
||||||
|
/// <unmanaged>E_NOTIMPL</unmanaged>
|
||||||
|
public static readonly HResult NotImplemented = unchecked((int)0x80004001);
|
||||||
|
|
||||||
|
/// <unmanaged>E_OUTOFMEMORY</unmanaged>
|
||||||
|
public static readonly HResult OutOfMemory = unchecked((int)0x8007000E);
|
||||||
|
|
||||||
|
/// <unmanaged>E_POINTER</unmanaged>
|
||||||
|
public static readonly HResult InvalidPointer = unchecked((int)0x80004003);
|
||||||
|
|
||||||
|
/// <unmanaged>E_UNEXPECTED</unmanaged>
|
||||||
|
public static readonly HResult UnexpectedFailure = unchecked((int)0x8000FFFF);
|
||||||
|
|
||||||
|
/// <unmanaged>WAIT_ABANDONED</unmanaged>
|
||||||
|
public static readonly HResult WaitAbandoned = unchecked((int)0x00000080);
|
||||||
|
|
||||||
|
/// <unmanaged>WAIT_TIMEOUT</unmanaged>
|
||||||
|
public static readonly HResult WaitTimeout = unchecked((int)0x00000102);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The data necessary to complete this operation is not yet available.
|
||||||
|
/// </summary>
|
||||||
|
/// <unmanaged>E_PENDING</unmanaged>
|
||||||
|
public static readonly HResult Pending = unchecked((int)0x8000000A);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The data area passed to a system call is too small.
|
||||||
|
/// </summary>
|
||||||
|
/// <unmanaged>E_NOT_SUFFICIENT_BUFFER</unmanaged>
|
||||||
|
public static readonly HResult InsufficientBuffer = unchecked((int)0x8007007A);
|
||||||
|
}
|
||||||
92
src/Vortice.Win32/HResult.cs
Normal file
92
src/Vortice.Win32/HResult.cs
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
// Copyright © Amer Koleci and Contributors.
|
||||||
|
// Licensed under the MIT License (MIT). See LICENSE in the repository root for more information.
|
||||||
|
|
||||||
|
namespace Win32;
|
||||||
|
|
||||||
|
public readonly partial struct HResult : IComparable, IComparable<HResult>, IEquatable<HResult>, IFormattable
|
||||||
|
{
|
||||||
|
public readonly int Value;
|
||||||
|
|
||||||
|
public HResult(int value)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(HResult left, HResult right) => left.Value == right.Value;
|
||||||
|
|
||||||
|
public static bool operator !=(HResult left, HResult right) => left.Value != right.Value;
|
||||||
|
|
||||||
|
public static bool operator <(HResult left, HResult right) => left.Value < right.Value;
|
||||||
|
|
||||||
|
public static bool operator <=(HResult left, HResult right) => left.Value <= right.Value;
|
||||||
|
|
||||||
|
public static bool operator >(HResult left, HResult right) => left.Value > right.Value;
|
||||||
|
|
||||||
|
public static bool operator >=(HResult left, HResult right) => left.Value >= right.Value;
|
||||||
|
|
||||||
|
public static implicit operator HResult(byte value) => new HResult(value);
|
||||||
|
|
||||||
|
public static explicit operator byte(HResult value) => (byte)(value.Value);
|
||||||
|
|
||||||
|
public static implicit operator HResult(short value) => new HResult(value);
|
||||||
|
|
||||||
|
public static explicit operator short(HResult value) => (short)(value.Value);
|
||||||
|
|
||||||
|
public static implicit operator HResult(int value) => new HResult(value);
|
||||||
|
|
||||||
|
public static implicit operator int(HResult value) => value.Value;
|
||||||
|
|
||||||
|
public static explicit operator HResult(long value) => new HResult(unchecked((int)(value)));
|
||||||
|
|
||||||
|
public static implicit operator long(HResult value) => value.Value;
|
||||||
|
|
||||||
|
public static explicit operator HResult(nint value) => new HResult(unchecked((int)(value)));
|
||||||
|
|
||||||
|
public static implicit operator nint(HResult value) => value.Value;
|
||||||
|
|
||||||
|
public static implicit operator HResult(sbyte value) => new HResult(value);
|
||||||
|
|
||||||
|
public static explicit operator sbyte(HResult value) => (sbyte)(value.Value);
|
||||||
|
|
||||||
|
public static implicit operator HResult(ushort value) => new HResult(value);
|
||||||
|
|
||||||
|
public static explicit operator ushort(HResult value) => (ushort)(value.Value);
|
||||||
|
|
||||||
|
public static explicit operator HResult(uint value) => new HResult(unchecked((int)(value)));
|
||||||
|
|
||||||
|
public static explicit operator uint(HResult value) => (uint)(value.Value);
|
||||||
|
|
||||||
|
public static explicit operator HResult(ulong value) => new HResult(unchecked((int)(value)));
|
||||||
|
|
||||||
|
public static explicit operator ulong(HResult value) => (ulong)(value.Value);
|
||||||
|
|
||||||
|
public static explicit operator HResult(nuint value) => new HResult(unchecked((int)(value)));
|
||||||
|
|
||||||
|
public static explicit operator nuint(HResult value) => (nuint)(value.Value);
|
||||||
|
|
||||||
|
public int CompareTo(object? obj)
|
||||||
|
{
|
||||||
|
if (obj is HResult other)
|
||||||
|
{
|
||||||
|
return CompareTo(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (obj is null) ? 1 : throw new ArgumentException("obj is not an instance of HResult.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CompareTo(HResult other) => Value.CompareTo(other.Value);
|
||||||
|
|
||||||
|
public override bool Equals(object? obj) => (obj is HResult other) && Equals(other);
|
||||||
|
|
||||||
|
public bool Equals(HResult other) => Value.Equals(other.Value);
|
||||||
|
|
||||||
|
public override int GetHashCode() => Value.GetHashCode();
|
||||||
|
|
||||||
|
public override string ToString() => Value.ToString("X8");
|
||||||
|
|
||||||
|
public string ToString(string? format, IFormatProvider? formatProvider) => Value.ToString(format, formatProvider);
|
||||||
|
|
||||||
|
public bool Failure => Value < 0;
|
||||||
|
|
||||||
|
public bool Success => Value >= 0;
|
||||||
|
}
|
||||||
65
src/Vortice.Win32/IUnknown.cs
Normal file
65
src/Vortice.Win32/IUnknown.cs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
// Copyright © Amer Koleci and Contributors.
|
||||||
|
// Licensed under the MIT License (MIT). See LICENSE in the repository root for more information.
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using static Win32.Apis;
|
||||||
|
|
||||||
|
namespace Win32;
|
||||||
|
|
||||||
|
[Guid("00000000-0000-0000-C000-000000000046")]
|
||||||
|
public unsafe partial struct IUnknown : IUnknown.Interface
|
||||||
|
{
|
||||||
|
public static Guid* NativeGuid => (Guid*)Unsafe.AsPointer(ref Unsafe.AsRef(in IID_IUnknown));
|
||||||
|
|
||||||
|
public void** lpVtbl;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
[VtblIndex(0)]
|
||||||
|
public HResult QueryInterface([NativeTypeName("const IID &")] Guid* riid, void** ppvObject)
|
||||||
|
{
|
||||||
|
return ((delegate* unmanaged[Stdcall]<IUnknown*, Guid*, void**, int>)(lpVtbl[0]))((IUnknown*)Unsafe.AsPointer(ref this), riid, ppvObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
[VtblIndex(1)]
|
||||||
|
[return: NativeTypeName("ULONG")]
|
||||||
|
public uint AddRef()
|
||||||
|
{
|
||||||
|
return ((delegate* unmanaged[Stdcall]<IUnknown*, uint>)(lpVtbl[1]))((IUnknown*)Unsafe.AsPointer(ref this));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
[VtblIndex(2)]
|
||||||
|
[return: NativeTypeName("ULONG")]
|
||||||
|
public uint Release()
|
||||||
|
{
|
||||||
|
return ((delegate* unmanaged[Stdcall]<IUnknown*, uint>)(lpVtbl[2]))((IUnknown*)Unsafe.AsPointer(ref this));
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Interface
|
||||||
|
{
|
||||||
|
[VtblIndex(0)]
|
||||||
|
HResult QueryInterface([NativeTypeName("const IID &")] Guid* riid, void** ppvObject);
|
||||||
|
|
||||||
|
[VtblIndex(1)]
|
||||||
|
[return: NativeTypeName("ULONG")]
|
||||||
|
uint AddRef();
|
||||||
|
|
||||||
|
[VtblIndex(2)]
|
||||||
|
[return: NativeTypeName("ULONG")]
|
||||||
|
uint Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial struct Vtbl<TSelf>
|
||||||
|
where TSelf : unmanaged, Interface
|
||||||
|
{
|
||||||
|
[NativeTypeName("HRESULT (const IID &, void **) __attribute__((stdcall))")]
|
||||||
|
public delegate* unmanaged[Stdcall]<TSelf*, Guid*, void**, int> QueryInterface;
|
||||||
|
|
||||||
|
[NativeTypeName("ULONG () __attribute__((stdcall))")]
|
||||||
|
public delegate* unmanaged[Stdcall]<TSelf*, uint> AddRef;
|
||||||
|
|
||||||
|
[NativeTypeName("ULONG () __attribute__((stdcall))")]
|
||||||
|
public delegate* unmanaged[Stdcall]<TSelf*, uint> Release;
|
||||||
|
}
|
||||||
|
}
|
||||||
36
src/Vortice.Win32/UnscopedRefAttribute.cs
Normal file
36
src/Vortice.Win32/UnscopedRefAttribute.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
|
||||||
|
namespace System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used to indicate a byref escapes and is not scoped.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// There are several cases where the C# compiler treats a <see langword="ref"/> as implicitly
|
||||||
|
/// <see langword="scoped"/> - where the compiler does not allow the <see langword="ref"/> to escape the method.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// For example:
|
||||||
|
/// <list type="number">
|
||||||
|
/// <item><see langword="this"/> for <see langword="struct"/> instance methods.</item>
|
||||||
|
/// <item><see langword="ref"/> parameters that refer to <see langword="ref"/> <see langword="struct"/> types.</item>
|
||||||
|
/// <item><see langword="out"/> parameters.</item>
|
||||||
|
/// </list>
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// This attribute is used in those instances where the <see langword="ref"/> should be allowed to escape.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// Applying this attribute, in any form, has impact on consumers of the applicable API. It is necessary for
|
||||||
|
/// API authors to understand the lifetime implications of applying this attribute and how it may impact their users.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
[AttributeUsage(
|
||||||
|
AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter,
|
||||||
|
AllowMultiple = false,
|
||||||
|
Inherited = false)]
|
||||||
|
internal sealed class UnscopedRefAttribute : Attribute
|
||||||
|
{
|
||||||
|
}
|
||||||
110
src/Vortice.Win32/Win32.cs
Normal file
110
src/Vortice.Win32/Win32.cs
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
// Copyright © Amer Koleci and Contributors.
|
||||||
|
// Licensed under the MIT License (MIT). See LICENSE in the repository root for more information.
|
||||||
|
|
||||||
|
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace Win32;
|
||||||
|
|
||||||
|
public static partial class Apis
|
||||||
|
{
|
||||||
|
public static ref readonly Guid IID_IUnknown
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
ReadOnlySpan<byte> data = new byte[] {
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00,
|
||||||
|
0x00, 0x00,
|
||||||
|
0xC0,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x46
|
||||||
|
};
|
||||||
|
|
||||||
|
Debug.Assert(data.Length == Unsafe.SizeOf<Guid>());
|
||||||
|
return ref Unsafe.As<byte, Guid>(ref MemoryMarshal.GetReference(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Retrieves the GUID of of a specified type.</summary>
|
||||||
|
/// <param name="value">A value of type <typeparamref name="T"/>.</param>
|
||||||
|
/// <typeparam name="T">The type to retrieve the GUID for.</typeparam>
|
||||||
|
/// <returns>A <see cref="UuidOfType"/> value wrapping a pointer to the GUID data for the input type. This value can be either converted to a <see cref="Guid"/> pointer, or implicitly assigned to a <see cref="Guid"/> value.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static unsafe UuidOfType __uuidof<T>(T value) // for type inference similar to C++'s __uuidof
|
||||||
|
where T : unmanaged
|
||||||
|
{
|
||||||
|
return new UuidOfType(UUID<T>.RIID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Retrieves the GUID of of a specified type.</summary>
|
||||||
|
/// <param name="value">A pointer to a value of type <typeparamref name="T"/>.</param>
|
||||||
|
/// <typeparam name="T">The type to retrieve the GUID for.</typeparam>
|
||||||
|
/// <returns>A <see cref="UuidOfType"/> value wrapping a pointer to the GUID data for the input type. This value can be either converted to a <see cref="Guid"/> pointer, or implicitly assigned to a <see cref="Guid"/> value.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static unsafe UuidOfType __uuidof<T>(T* value) // for type inference similar to C++'s __uuidof
|
||||||
|
where T : unmanaged
|
||||||
|
{
|
||||||
|
return new UuidOfType(UUID<T>.RIID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Retrieves the GUID of of a specified type.</summary>
|
||||||
|
/// <typeparam name="T">The type to retrieve the GUID for.</typeparam>
|
||||||
|
/// <returns>A <see cref="UuidOfType"/> value wrapping a pointer to the GUID data for the input type. This value can be either converted to a <see cref="Guid"/> pointer, or implicitly assigned to a <see cref="Guid"/> value.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static unsafe UuidOfType __uuidof<T>()
|
||||||
|
where T : unmanaged
|
||||||
|
{
|
||||||
|
return new UuidOfType(UUID<T>.RIID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>A proxy type that wraps a pointer to GUID data. Values of this type can be implicitly converted to and assigned to <see cref="Guid"/>* or <see cref="Guid"/> parameters.</summary>
|
||||||
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
|
public readonly unsafe ref struct UuidOfType
|
||||||
|
{
|
||||||
|
private readonly Guid* riid;
|
||||||
|
|
||||||
|
internal UuidOfType(Guid* riid)
|
||||||
|
{
|
||||||
|
this.riid = riid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Reads a <see cref="Guid"/> value from the GUID buffer for a given <see cref="UuidOfType"/> instance.</summary>
|
||||||
|
/// <param name="guid">The input <see cref="UuidOfType"/> instance to read data for.</param>
|
||||||
|
public static implicit operator Guid(UuidOfType guid) => *guid.riid;
|
||||||
|
|
||||||
|
/// <summary>Returns the <see cref="Guid"/>* pointer to the GUID buffer for a given <see cref="UuidOfType"/> instance.</summary>
|
||||||
|
/// <param name="guid">The input <see cref="UuidOfType"/> instance to read data for.</param>
|
||||||
|
public static implicit operator Guid*(UuidOfType guid) => guid.riid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>A helper type to provide static GUID buffers for specific types.</summary>
|
||||||
|
/// <typeparam name="T">The type to allocate a GUID buffer for.</typeparam>
|
||||||
|
private static unsafe class UUID<T>
|
||||||
|
where T : unmanaged
|
||||||
|
{
|
||||||
|
/// <summary>The pointer to the <see cref="Guid"/> value for the current type.</summary>
|
||||||
|
/// <remarks>The target memory area should never be written to.</remarks>
|
||||||
|
public static readonly Guid* RIID = CreateRIID();
|
||||||
|
|
||||||
|
/// <summary>Allocates memory for a <see cref="Guid"/> value and initializes it.</summary>
|
||||||
|
/// <returns>A pointer to memory holding the <see cref="Guid"/> value for the current type.</returns>
|
||||||
|
private static Guid* CreateRIID()
|
||||||
|
{
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
var p = (Guid*)RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(T), sizeof(Guid));
|
||||||
|
#else
|
||||||
|
var p = (Guid*)Marshal.AllocHGlobal(sizeof(Guid));
|
||||||
|
#endif
|
||||||
|
*p = typeof(T).GUID;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user