Generator: WIP Com types generation.

This commit is contained in:
Amer Koleci
2022-09-02 12:56:31 +02:00
parent 953fbfb207
commit 5f6cd6abdd
9 changed files with 700 additions and 347 deletions

View File

@@ -42,6 +42,21 @@ public class ApiStructField
public ApiDataType Type { get; set; } public ApiDataType Type { get; set; }
} }
public class ApiParameter
{
public string Name { get; set; }
public ApiDataType Type { get; set; }
}
public class ApiFunction
{
public string Name { get; set; }
public bool SetLastError { get; set; }
public ApiDataType ReturnType { get; set; }
public IList<ApiParameter> Params { get; set; } = new List<ApiParameter>();
public List<object> Attrs { get; set; }
}
public class ApiType public class ApiType
{ {
public string Name { get; set; } public string Name { get; set; }
@@ -57,6 +72,11 @@ public class ApiType
public int Size { get; set; } public int Size { get; set; }
public int PackingSize { get; set; } public int PackingSize { get; set; }
public ApiStructField[] Fields { get; set; } public ApiStructField[] Fields { get; set; }
// Com
public string Guid { get; set; }
public ApiDataType Interface { get; set; }
public IList<ApiFunction> Methods { get; set; } = new List<ApiFunction>();
} }
public sealed class ApiData public sealed class ApiData

View File

@@ -37,6 +37,7 @@ public sealed class CodeWriter : IDisposable
_writer.WriteLine(); _writer.WriteLine();
_writer.WriteLine($"using System;"); _writer.WriteLine($"using System;");
_writer.WriteLine($"using System.Diagnostics;");
_writer.WriteLine($"using System.Runtime.CompilerServices;"); _writer.WriteLine($"using System.Runtime.CompilerServices;");
_writer.WriteLine($"using System.Diagnostics.CodeAnalysis;"); _writer.WriteLine($"using System.Diagnostics.CodeAnalysis;");
@@ -46,7 +47,7 @@ public sealed class CodeWriter : IDisposable
} }
_writer.WriteLine(); _writer.WriteLine();
_writer.WriteLine("#if NETSTANDARD2_0"); _writer.WriteLine("#if !NET6_0_OR_GREATER");
_writer.WriteLine("using MemoryMarshal = Win32.MemoryMarshal;"); _writer.WriteLine("using MemoryMarshal = Win32.MemoryMarshal;");
_writer.WriteLine("#endif"); _writer.WriteLine("#endif");
_writer.WriteLine(); _writer.WriteLine();
@@ -83,7 +84,7 @@ public sealed class CodeWriter : IDisposable
_shouldIndent = true; _shouldIndent = true;
} }
public void WriteUndindented(string @string) public void WriteLineUndindented(string @string)
{ {
_writer.WriteLine(@string); _writer.WriteLine(@string);
_shouldIndent = true; _shouldIndent = true;

View File

@@ -7,7 +7,6 @@ using System.Xml;
using MessagePack; using MessagePack;
using Microsoft.Windows.SDK.Win32Docs; using Microsoft.Windows.SDK.Win32Docs;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Generator; namespace Generator;
@@ -45,6 +44,8 @@ public static class Program
{ "Foundation.LUID", "Luid" }, { "Foundation.LUID", "Luid" },
{ "Foundation.LARGE_INTEGER", "LargeInterger" }, { "Foundation.LARGE_INTEGER", "LargeInterger" },
{ "System.Com.IUnknown", "IUnknown" },
// TODO: Understand those -> // TODO: Understand those ->
{ "Foundation.HWND", "IntPtr" }, { "Foundation.HWND", "IntPtr" },
{ "Foundation.HANDLE", "IntPtr" }, { "Foundation.HANDLE", "IntPtr" },
@@ -208,38 +209,38 @@ public static class Program
{ {
writer.WriteStartElement(null, "param", null); writer.WriteStartElement(null, "param", null);
string paramName = param.Key; string paramName = param.Key;
if (paramName.StartsWith("pp") && char.IsUpper(paramName[2])) //if (paramName.StartsWith("pp") && char.IsUpper(paramName[2]))
{ //{
paramName = paramName.Substring(2); // paramName = paramName.Substring(2);
paramName = paramName[0].ToString().ToLower() + paramName.Substring(1); // paramName = paramName[0].ToString().ToLower() + paramName.Substring(1);
} //}
else if (paramName.StartsWith("p") && char.IsUpper(paramName[1])) //else if (paramName.StartsWith("p") && char.IsUpper(paramName[1]))
{ //{
paramName = paramName.Substring(1); // paramName = paramName.Substring(1);
paramName = paramName[0].ToString().ToLower() + paramName.Substring(1); // paramName = paramName[0].ToString().ToLower() + paramName.Substring(1);
} //}
else if (paramName.StartsWith("u") && char.IsUpper(paramName[1])) //else if (paramName.StartsWith("u") && char.IsUpper(paramName[1]))
{ //{
paramName = paramName.Substring(1); // paramName = paramName.Substring(1);
paramName = paramName[0].ToString().ToLower() + paramName.Substring(1); // paramName = paramName[0].ToString().ToLower() + paramName.Substring(1);
} //}
else if (paramName.StartsWith("b") && char.IsUpper(paramName[1])) // bEnable //else if (paramName.StartsWith("b") && char.IsUpper(paramName[1])) // bEnable
{ //{
paramName = paramName.Substring(1); // paramName = paramName.Substring(1);
paramName = paramName[0].ToString().ToLower() + paramName.Substring(1); // paramName = paramName[0].ToString().ToLower() + paramName.Substring(1);
} //}
else if (char.IsUpper(paramName[0]) && paramName.Length > 1 && char.IsLower(paramName[1])) //else if (char.IsUpper(paramName[0]) && paramName.Length > 1 && char.IsLower(paramName[1]))
{ //{
paramName = paramName[0].ToString().ToLower() + paramName.Substring(1); // paramName = paramName[0].ToString().ToLower() + paramName.Substring(1);
} //}
else if (paramName == "ID") //else if (paramName == "ID")
{ //{
paramName = "id"; // paramName = "id";
} //}
else if (paramName == "dwCookie") //else if (paramName == "dwCookie")
{ //{
paramName = "cookie"; // paramName = "cookie";
} //}
writer.WriteAttributeString("name", paramName); writer.WriteAttributeString("name", paramName);
@@ -492,6 +493,15 @@ public static class Program
} }
writer.WriteLine($"#endregion Structs"); writer.WriteLine($"#endregion Structs");
writer.WriteLine(); writer.WriteLine();
// Com types
writer.WriteLine($"#region COM Types");
foreach (ApiType comType in api.Types.Where(item => item.Kind.ToLowerInvariant() == "com"))
{
GenerateComType(writer, comType);
}
writer.WriteLine($"#endregion COM Types");
writer.WriteLine();
} }
private static void GenerateEnum(CodeWriter writer, ApiType enumType, bool autoGenerated) private static void GenerateEnum(CodeWriter writer, ApiType enumType, bool autoGenerated)
@@ -653,6 +663,192 @@ public static class Program
writer.WriteLine(); writer.WriteLine();
} }
private static void GenerateComType(CodeWriter writer, ApiType comType)
{
if (comType.Name != "IDXGIObject" /*&&
comType.Name != "IDXGIDeviceSubObject"*/)
{
return;
}
string csTypeName = comType.Name;
//AddCsMapping(writer.Api, comType.Name, csTypeName);
writer.WriteLine($"/// <include file='../{writer.DocFileName}.xml' path='doc/member[@name=\"{comType.Name}\"]/*' />");
if (s_generateUnmanagedDocs)
{
writer.WriteLine($"/// <unmanaged>{comType.Name}</unmanaged>");
}
writer.WriteLine($"[Guid(\"{comType.Guid}\")]");
writer.WriteLine($"[NativeTypeName(\"struct {comType.Name} : {comType.Interface.Name}\")]");
writer.WriteLine($"[NativeInheritance(\"{comType.Interface.Name}\")]");
using (writer.PushBlock($"public unsafe partial struct {csTypeName} : {csTypeName}.Interface"))
{
// Generate IID
writer.WriteLine($"[NativeTypeName(\"const GUID\")]");
using (writer.PushBlock($"public static ref readonly Guid IID_{csTypeName}"))
{
writer.WriteLine("[MethodImpl(MethodImplOptions.AggressiveInlining)]");
using (writer.PushBlock("get"))
{
var guid = Guid.Parse(comType.Guid).ToString("N");
var _1 = "0x" + guid.Substring(6, 2).ToUpperInvariant();
var _2 = "0x" + guid.Substring(4, 2).ToUpperInvariant();
var _3 = "0x" + guid.Substring(2, 2).ToUpperInvariant();
var _4 = "0x" + guid.Substring(0, 2).ToUpperInvariant();
var _5 = "0x" + guid.Substring(10, 2).ToUpperInvariant();
var _6 = "0x" + guid.Substring(8, 2).ToUpperInvariant();
var _7 = "0x" + guid.Substring(14, 2).ToUpperInvariant();
var _8 = "0x" + guid.Substring(12, 2).ToUpperInvariant();
var d = "0x" + guid.Substring(16, 2).ToUpperInvariant();
var e = "0x" + guid.Substring(18, 2).ToUpperInvariant();
var f = "0x" + guid.Substring(20, 2).ToUpperInvariant();
var g = "0x" + guid.Substring(22, 2).ToUpperInvariant();
var h = "0x" + guid.Substring(24, 2).ToUpperInvariant();
var i = "0x" + guid.Substring(26, 2).ToUpperInvariant();
var j = "0x" + guid.Substring(28, 2).ToUpperInvariant();
var k = "0x" + guid.Substring(30, 2).ToUpperInvariant();
writer.WriteLine("ReadOnlySpan<byte> data = new byte[] {");
writer.WriteLine($"{'\t'}{_1}, {_2}, {_3}, {_4},");
writer.WriteLine($"{'\t'}{_5}, {_6},");
writer.WriteLine($"{'\t'}{_7}, {_8},");
writer.WriteLine($"{'\t'}{d},");
writer.WriteLine($"{'\t'}{e},");
writer.WriteLine($"{'\t'}{f},");
writer.WriteLine($"{'\t'}{g},");
writer.WriteLine($"{'\t'}{h},");
writer.WriteLine($"{'\t'}{i},");
writer.WriteLine($"{'\t'}{j},");
writer.WriteLine($"{'\t'}{k}");
writer.WriteLine("};");
writer.WriteLine();
writer.WriteLine("Debug.Assert(data.Length == Unsafe.SizeOf<Guid>());");
writer.WriteLine("return ref Unsafe.As<byte, Guid>(ref MemoryMarshal.GetReference(data));");
}
}
writer.WriteLine();
writer.WriteLine($"public static Guid* NativeGuid => (Guid*)Unsafe.AsPointer(ref Unsafe.AsRef(in IID_{csTypeName}));");
writer.WriteLine();
writer.WriteLine($"public void** lpVtbl;");
writer.WriteLine();
int vtblIndex = 0;
if (comType.Interface.Name == "IUnknown")
{
writer.WriteLine("/// <inheritdoc cref=\"IUnknown.QueryInterface\" />");
writer.WriteLine("[MethodImpl(MethodImplOptions.AggressiveInlining)]");
writer.WriteLine("[VtblIndex(0)]");
using (writer.PushBlock($"public HResult QueryInterface([NativeTypeName(\"const IID &\")] Guid* riid, void** ppvObject)"))
{
writer.WriteLine("return ((delegate* unmanaged[Stdcall]<IUnknown*, Guid*, void**, int>)(lpVtbl[0]))((IUnknown*)Unsafe.AsPointer(ref this), riid, ppvObject);");
}
writer.WriteLine();
// AddRef
writer.WriteLine("/// <inheritdoc cref=\"IUnknown.AddRef\" />");
writer.WriteLine("[MethodImpl(MethodImplOptions.AggressiveInlining)]");
writer.WriteLine("[VtblIndex(1)]");
writer.WriteLine("[return: NativeTypeName(\"ULONG\")]");
using (writer.PushBlock($"public uint AddRef()"))
{
writer.WriteLine("return ((delegate* unmanaged[Stdcall]<IUnknown*, uint>)(lpVtbl[1]))((IUnknown*)Unsafe.AsPointer(ref this));");
}
writer.WriteLine();
// Release
writer.WriteLine("/// <inheritdoc cref=\"IUnknown.Release\" />");
writer.WriteLine("[MethodImpl(MethodImplOptions.AggressiveInlining)]");
writer.WriteLine("[VtblIndex(2)]");
writer.WriteLine("[return: NativeTypeName(\"ULONG\")]");
using (writer.PushBlock($"public uint Release()"))
{
writer.WriteLine("return ((delegate* unmanaged[Stdcall]<IUnknown*, uint>)(lpVtbl[2]))((IUnknown*)Unsafe.AsPointer(ref this));");
}
writer.WriteLine();
vtblIndex = 3;
}
foreach (var method in comType.Methods)
{
// TODO: Handle inherit
string returnType = GetTypeName(method.ReturnType);
StringBuilder argumentBuilder = new();
StringBuilder argumentsTypesBuilder = new();
StringBuilder argumentsNameBuilder = new();
int parameterIndex = 0;
foreach (var parameter in method.Params)
{
string parameterType = GetTypeName(parameter.Type);
string parameterName = parameter.Name;
argumentBuilder.Append(parameterType).Append(' ').Append(parameterName);
argumentsTypesBuilder.Append(parameterType);
argumentsNameBuilder.Append(parameterName);
if (parameterIndex < method.Params.Count - 1)
{
argumentBuilder.Append(", ");
argumentsTypesBuilder.Append(", ");
argumentsNameBuilder.Append(", ");
}
parameterIndex++;
}
// Return type
string returnMarshalType = returnType;
if (returnMarshalType.ToLower() == "hresult")
{
returnMarshalType = "int";
}
argumentsTypesBuilder.Append(", ").Append(returnMarshalType);
string argumentsString = argumentBuilder.ToString();
string argumentTypesString = argumentsTypesBuilder.ToString();
string argumentNamesString = argumentsNameBuilder.ToString();
writer.WriteLine($"/// <include file='../{writer.DocFileName}.xml' path='doc/member[@name=\"{comType.Name}::{method.Name}\"]/*' />");
writer.WriteLine("[MethodImpl(MethodImplOptions.AggressiveInlining)]");
writer.WriteLine($"[VtblIndex({vtblIndex})]");
using (writer.PushBlock($"public {returnType} {method.Name}({argumentsString})"))
{
writer.WriteLineUndindented("#if NET6_0_OR_GREATER");
if (returnType != "void")
writer.Write("return ");
writer.WriteLine($"((delegate* unmanaged<{comType.Name}*, {argumentTypesString}>)(lpVtbl[{vtblIndex}]))(({comType.Name}*)Unsafe.AsPointer(ref this), {argumentNamesString});");
writer.WriteLineUndindented("#else");
if (returnType != "void")
writer.Write("return ");
writer.WriteLine($"((delegate* unmanaged[Stdcall]<{comType.Name}*, {argumentTypesString}>)(lpVtbl[{vtblIndex}]))(({comType.Name}*)Unsafe.AsPointer(ref this), {argumentNamesString});");
writer.WriteLineUndindented("#endif");
}
writer.WriteLine();
vtblIndex++;
}
using (writer.PushBlock($"public interface Interface : {comType.Interface.Name}.Interface"))
{
}
writer.WriteLine();
}
writer.WriteLine();
}
private static bool ShouldSkipConstant(ApiDataConstant constant) private static bool ShouldSkipConstant(ApiDataConstant constant)
{ {
if (constant.Name == "_FACDXGI" || if (constant.Name == "_FACDXGI" ||

View File

@@ -22,6 +22,22 @@ internal sealed partial class NativeTypeNameAttribute : Attribute
public string Name { get; } public string Name { get; }
} }
/// <summary>Defines the base type of a struct as it was in the native signature.</summary>
[AttributeUsage(AttributeTargets.Struct, AllowMultiple = false, Inherited = true)]
[Conditional("DEBUG")]
internal sealed partial class NativeInheritanceAttribute : Attribute
{
/// <summary>Initializes a new instance of the <see cref="NativeInheritanceAttribute" /> class.</summary>
/// <param name="name">The name of the base type that was inherited from in the native signature.</param>
public NativeInheritanceAttribute(string name)
{
Name = name;
}
/// <summary>Gets the name of the base type that was inherited from 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> /// <summary>Defines the vtbl index of a method as it was in the native signature.</summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
[Conditional("DEBUG")] [Conditional("DEBUG")]

File diff suppressed because it is too large Load Diff

View File

@@ -8,10 +8,11 @@
// ------------------------------------------------------------------------------ // ------------------------------------------------------------------------------
using System; using System;
using System.Diagnostics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
#if NETSTANDARD2_0 #if !NET6_0_OR_GREATER
using MemoryMarshal = Win32.MemoryMarshal; using MemoryMarshal = Win32.MemoryMarshal;
#endif #endif
@@ -1724,3 +1725,6 @@ public partial struct JpegQuantizationTable
#endregion Structs #endregion Structs
#region COM Types
#endregion COM Types

View File

@@ -8,10 +8,11 @@
// ------------------------------------------------------------------------------ // ------------------------------------------------------------------------------
using System; using System;
using System.Diagnostics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
#if NETSTANDARD2_0 #if !NET6_0_OR_GREATER
using MemoryMarshal = Win32.MemoryMarshal; using MemoryMarshal = Win32.MemoryMarshal;
#endif #endif
@@ -2174,3 +2175,122 @@ public partial struct InfoQueueFilter
#endregion Structs #endregion Structs
#region COM Types
/// <include file='../DXGI.xml' path='doc/member[@name="IDXGIObject"]/*' />
/// <unmanaged>IDXGIObject</unmanaged>
[Guid("aec22fb8-76f3-4639-9be0-28eb43a67a2e")]
[NativeTypeName("struct IDXGIObject : IUnknown")]
[NativeInheritance("IUnknown")]
public unsafe partial struct IDXGIObject : IDXGIObject.Interface
{
[NativeTypeName("const GUID")]
public static ref readonly Guid IID_IDXGIObject
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
ReadOnlySpan<byte> data = new byte[] {
0xB8, 0x2F, 0xC2, 0xAE,
0xF3, 0x76,
0x39, 0x46,
0x9B,
0xE0,
0x28,
0xEB,
0x43,
0xA6,
0x7A,
0x2E
};
Debug.Assert(data.Length == Unsafe.SizeOf<Guid>());
return ref Unsafe.As<byte, Guid>(ref MemoryMarshal.GetReference(data));
}
}
public static Guid* NativeGuid => (Guid*)Unsafe.AsPointer(ref Unsafe.AsRef(in IID_IDXGIObject));
public void** lpVtbl;
/// <inheritdoc cref="IUnknown.QueryInterface" />
[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);
}
/// <inheritdoc cref="IUnknown.AddRef" />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[VtblIndex(1)]
[return: NativeTypeName("ULONG")]
public uint AddRef()
{
return ((delegate* unmanaged[Stdcall]<IUnknown*, uint>)(lpVtbl[1]))((IUnknown*)Unsafe.AsPointer(ref this));
}
/// <inheritdoc cref="IUnknown.Release" />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[VtblIndex(2)]
[return: NativeTypeName("ULONG")]
public uint Release()
{
return ((delegate* unmanaged[Stdcall]<IUnknown*, uint>)(lpVtbl[2]))((IUnknown*)Unsafe.AsPointer(ref this));
}
/// <include file='../DXGI.xml' path='doc/member[@name="IDXGIObject::SetPrivateData"]/*' />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[VtblIndex(3)]
public HResult SetPrivateData(Guid* Name, uint DataSize, void* pData)
{
#if NET6_0_OR_GREATER
return ((delegate* unmanaged<IDXGIObject*, Guid*, uint, void*, int>)(lpVtbl[3]))((IDXGIObject*)Unsafe.AsPointer(ref this), Name, DataSize, pData);
#else
return ((delegate* unmanaged[Stdcall]<IDXGIObject*, Guid*, uint, void*, int>)(lpVtbl[3]))((IDXGIObject*)Unsafe.AsPointer(ref this), Name, DataSize, pData);
#endif
}
/// <include file='../DXGI.xml' path='doc/member[@name="IDXGIObject::SetPrivateDataInterface"]/*' />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[VtblIndex(4)]
public HResult SetPrivateDataInterface(Guid* Name, IUnknown pUnknown)
{
#if NET6_0_OR_GREATER
return ((delegate* unmanaged<IDXGIObject*, Guid*, IUnknown, int>)(lpVtbl[4]))((IDXGIObject*)Unsafe.AsPointer(ref this), Name, pUnknown);
#else
return ((delegate* unmanaged[Stdcall]<IDXGIObject*, Guid*, IUnknown, int>)(lpVtbl[4]))((IDXGIObject*)Unsafe.AsPointer(ref this), Name, pUnknown);
#endif
}
/// <include file='../DXGI.xml' path='doc/member[@name="IDXGIObject::GetPrivateData"]/*' />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[VtblIndex(5)]
public HResult GetPrivateData(Guid* Name, uint* pDataSize, void* pData)
{
#if NET6_0_OR_GREATER
return ((delegate* unmanaged<IDXGIObject*, Guid*, uint*, void*, int>)(lpVtbl[5]))((IDXGIObject*)Unsafe.AsPointer(ref this), Name, pDataSize, pData);
#else
return ((delegate* unmanaged[Stdcall]<IDXGIObject*, Guid*, uint*, void*, int>)(lpVtbl[5]))((IDXGIObject*)Unsafe.AsPointer(ref this), Name, pDataSize, pData);
#endif
}
/// <include file='../DXGI.xml' path='doc/member[@name="IDXGIObject::GetParent"]/*' />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[VtblIndex(6)]
public HResult GetParent(Guid* riid, void** ppParent)
{
#if NET6_0_OR_GREATER
return ((delegate* unmanaged<IDXGIObject*, Guid*, void**, int>)(lpVtbl[6]))((IDXGIObject*)Unsafe.AsPointer(ref this), riid, ppParent);
#else
return ((delegate* unmanaged[Stdcall]<IDXGIObject*, Guid*, void**, int>)(lpVtbl[6]))((IDXGIObject*)Unsafe.AsPointer(ref this), riid, ppParent);
#endif
}
public interface Interface : IUnknown.Interface
{
}
}
#endregion COM Types

View File

@@ -1,7 +1,7 @@
// 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.
#if NETSTANDARD2_0 #if !NET6_0_OR_GREATER
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;

View File

@@ -10,9 +10,5 @@ public static unsafe class Program
{ {
public static void Main() public static void Main()
{ {
SampleDescription desc = new(1, 0);
desc.Count
Scaling scaling = Scaling.Stretch;
} }
} }