mirror of
https://github.com/amerkoleci/Vortice.Win32.git
synced 2026-01-14 16:16:04 +08:00
Generator: Completed initial step of Com Types generation and various improvements.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
// Copyright © Amer Koleci and Contributors.
|
||||
// Licensed under the MIT License (MIT). See LICENSE in the repository root for more information.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml;
|
||||
@@ -66,6 +67,7 @@ public static class Program
|
||||
{ "Foundation.SIZE", "System.Drawing.Size" },
|
||||
|
||||
{ "Graphics.Gdi.HMONITOR", "IntPtr" },
|
||||
{ "Graphics.Gdi.HDC", "IntPtr" },
|
||||
};
|
||||
|
||||
private static readonly Dictionary<string, string> s_knownTypesPrefixes = new()
|
||||
@@ -130,6 +132,9 @@ public static class Program
|
||||
{ "DXGI_SWAP_CHAIN_DESC1::Flags", "DXGI_SWAP_CHAIN_FLAG" },
|
||||
};
|
||||
|
||||
private static readonly HashSet<string> s_visitedEnums = new();
|
||||
private static readonly HashSet<string> s_visitedStructs = new();
|
||||
|
||||
private static bool s_generateUnmanagedDocs = true;
|
||||
|
||||
public static int Main(string[] args)
|
||||
@@ -443,7 +448,10 @@ public static class Program
|
||||
foreach (ApiType enumType in api.Types.Where(item => item.Kind.ToLowerInvariant() == "enum"))
|
||||
{
|
||||
GenerateEnum(writer, enumType, false);
|
||||
|
||||
s_visitedEnums.Add($"{writer.Api}.{enumType.Name}");
|
||||
}
|
||||
|
||||
writer.WriteLine($"#endregion Enums");
|
||||
writer.WriteLine();
|
||||
|
||||
@@ -504,6 +512,8 @@ public static class Program
|
||||
foreach (ApiType structType in api.Types.Where(item => item.Kind.ToLowerInvariant() == "struct"))
|
||||
{
|
||||
GenerateStruct(writer, structType);
|
||||
|
||||
s_visitedStructs.Add($"{writer.Api}.{structType.Name}");
|
||||
}
|
||||
writer.WriteLine($"#endregion Structs");
|
||||
writer.WriteLine();
|
||||
@@ -512,10 +522,35 @@ public static class Program
|
||||
writer.WriteLine($"#region COM Types");
|
||||
foreach (ApiType comType in api.Types.Where(item => item.Kind.ToLowerInvariant() == "com"))
|
||||
{
|
||||
GenerateComType(writer, comType);
|
||||
//if (comType.Name != "IDXGIObject" &&
|
||||
// comType.Name != "IDXGIDeviceSubObject")
|
||||
//{
|
||||
// break;
|
||||
//}
|
||||
|
||||
// Generate methods
|
||||
List<KeyValuePair<ApiFunction, string>> methodsToGenerate = new();
|
||||
ApiType iterateType = comType;
|
||||
while (iterateType.Interface != null && iterateType.Interface.Name != "IUnknown")
|
||||
{
|
||||
iterateType = api.Types.First(item => item.Name == iterateType.Interface.Name);
|
||||
|
||||
foreach (var method in iterateType.Methods)
|
||||
{
|
||||
methodsToGenerate.Add(new(method, iterateType.Name));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
foreach (var method in comType.Methods)
|
||||
{
|
||||
methodsToGenerate.Add(new(method, comType.Name));
|
||||
}
|
||||
|
||||
GenerateComType(api, writer, comType, methodsToGenerate);
|
||||
}
|
||||
writer.WriteLine($"#endregion COM Types");
|
||||
writer.WriteLine();
|
||||
|
||||
writer.WriteLine($"#endregion Com Types");
|
||||
}
|
||||
|
||||
private static void GenerateEnum(CodeWriter writer, ApiType enumType, bool autoGenerated)
|
||||
@@ -671,20 +706,20 @@ public static class Program
|
||||
|
||||
writer.WriteLine($"public {unsafePrefix}{fieldTypeName} {fieldValueName};");
|
||||
}
|
||||
|
||||
writer.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
writer.WriteLine();
|
||||
}
|
||||
|
||||
private static void GenerateComType(CodeWriter writer, ApiType comType)
|
||||
private static void GenerateComType(
|
||||
ApiData api,
|
||||
CodeWriter writer,
|
||||
ApiType comType,
|
||||
List<KeyValuePair<ApiFunction, string>> methodsToGenerate)
|
||||
{
|
||||
if (comType.Name != "IDXGIObject" /*&&
|
||||
comType.Name != "IDXGIDeviceSubObject"*/)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string csTypeName = comType.Name;
|
||||
//AddCsMapping(writer.Api, comType.Name, csTypeName);
|
||||
|
||||
@@ -701,7 +736,6 @@ public static class Program
|
||||
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)]");
|
||||
@@ -756,7 +790,17 @@ public static class Program
|
||||
writer.WriteLine();
|
||||
|
||||
int vtblIndex = 0;
|
||||
if (comType.Interface.Name == "IUnknown")
|
||||
|
||||
bool generateIUnknown = false;
|
||||
var iterateType = comType;
|
||||
|
||||
while (iterateType != null)
|
||||
{
|
||||
generateIUnknown = iterateType.Interface.Name == "IUnknown";
|
||||
iterateType = api.Types.FirstOrDefault(item => item.Name == iterateType.Interface.Name);
|
||||
}
|
||||
|
||||
if (generateIUnknown)
|
||||
{
|
||||
writer.WriteLine("/// <inheritdoc cref=\"IUnknown.QueryInterface\" />");
|
||||
writer.WriteLine("[MethodImpl(MethodImplOptions.AggressiveInlining)]");
|
||||
@@ -791,8 +835,11 @@ public static class Program
|
||||
vtblIndex = 3;
|
||||
}
|
||||
|
||||
foreach (var method in comType.Methods)
|
||||
foreach (var methodPair in methodsToGenerate)
|
||||
{
|
||||
var method = methodPair.Key;
|
||||
string docName = methodPair.Value;
|
||||
|
||||
// TODO: Handle inherit
|
||||
string returnType = GetTypeName(method.ReturnType);
|
||||
|
||||
@@ -801,12 +848,43 @@ public static class Program
|
||||
StringBuilder argumentsNameBuilder = new();
|
||||
int parameterIndex = 0;
|
||||
|
||||
if (method.Name == "SetEvictionPriority")
|
||||
{
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
foreach (var parameter in method.Params)
|
||||
{
|
||||
string parameterType = GetTypeName(parameter.Type);
|
||||
bool asPointer = false;
|
||||
if (parameter.Type.Kind == "ApiRef")
|
||||
{
|
||||
string fullTypeName = $"{parameter.Type.Api}.{parameter.Type.Name}";
|
||||
if (!IsEnum(fullTypeName))
|
||||
{
|
||||
asPointer = true;
|
||||
}
|
||||
//string typeName = GetTypeName($"{dataType.Api}.{dataType.Name}");
|
||||
}
|
||||
|
||||
string parameterType = GetTypeName(parameter.Type, asPointer);
|
||||
parameterType = NormalizeTypeName(writer.Api, parameterType);
|
||||
string parameterName = parameter.Name;
|
||||
|
||||
bool isOptional = parameter.Attrs.Any(item => item is string str && str == "Optional");
|
||||
if (parameter.Attrs.Any(item => item is string str && str == "ComOutPtr"))
|
||||
{
|
||||
if (!IsPrimitive(parameter.Type))
|
||||
{
|
||||
parameterType += "*";
|
||||
}
|
||||
}
|
||||
|
||||
argumentBuilder.Append(parameterType).Append(' ').Append(parameterName);
|
||||
if (isOptional == true)
|
||||
{
|
||||
//argumentBuilder.Append(" = default");
|
||||
}
|
||||
|
||||
argumentsTypesBuilder.Append(parameterType);
|
||||
argumentsNameBuilder.Append(parameterName);
|
||||
|
||||
@@ -827,13 +905,30 @@ public static class Program
|
||||
returnMarshalType = "int";
|
||||
}
|
||||
|
||||
argumentsTypesBuilder.Append(", ").Append(returnMarshalType);
|
||||
if (method.Params.Count > 0)
|
||||
{
|
||||
argumentsTypesBuilder.Append(", ");
|
||||
}
|
||||
|
||||
argumentsTypesBuilder.Append(returnMarshalType);
|
||||
|
||||
string argumentsString = argumentBuilder.ToString();
|
||||
string argumentTypesString = argumentsTypesBuilder.ToString();
|
||||
string argumentNamesString = argumentsNameBuilder.ToString();
|
||||
if (method.Params.Count > 0)
|
||||
{
|
||||
argumentNamesString = ", " + argumentNamesString;
|
||||
}
|
||||
|
||||
if (comType.Name == docName)
|
||||
{
|
||||
writer.WriteLine($"/// <include file='../{writer.DocFileName}.xml' path='doc/member[@name=\"{comType.Name}::{method.Name}\"]/*' />");
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteLine($"/// <inheritdoc cref=\"{docName}.{method.Name}\" />");
|
||||
}
|
||||
|
||||
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})"))
|
||||
@@ -841,14 +936,13 @@ public static class Program
|
||||
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.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.WriteLine($"((delegate* unmanaged[Stdcall]<{comType.Name}*, {argumentTypesString}>)(lpVtbl[{vtblIndex}]))(({comType.Name}*)Unsafe.AsPointer(ref this){argumentNamesString});");
|
||||
writer.WriteLineUndindented("#endif");
|
||||
}
|
||||
|
||||
writer.WriteLine();
|
||||
|
||||
vtblIndex++;
|
||||
@@ -857,7 +951,7 @@ public static class Program
|
||||
using (writer.PushBlock($"public interface Interface : {comType.Interface.Name}.Interface"))
|
||||
{
|
||||
}
|
||||
writer.WriteLine();
|
||||
//writer.WriteLine();
|
||||
}
|
||||
|
||||
writer.WriteLine();
|
||||
@@ -877,7 +971,9 @@ public static class Program
|
||||
private static string NormalizeTypeName(string api, string typeName)
|
||||
{
|
||||
if (!typeName.StartsWith(api))
|
||||
{
|
||||
return typeName;
|
||||
}
|
||||
|
||||
return typeName.Replace(api + ".", "");
|
||||
}
|
||||
@@ -1084,17 +1180,21 @@ public static class Program
|
||||
return $"new Guid({a}, {b}, {c}, {d}, {e}, {f}, {g}, {h}, {i}, {j}, {k})";
|
||||
}
|
||||
|
||||
|
||||
private static string GetTypeName(ApiDataType dataType)
|
||||
private static string GetTypeName(ApiDataType dataType, bool asPointer = false)
|
||||
{
|
||||
if (dataType.Kind == "ApiRef")
|
||||
{
|
||||
return GetTypeName($"{dataType.Api}.{dataType.Name}");
|
||||
string typeName = GetTypeName($"{dataType.Api}.{dataType.Name}");
|
||||
return asPointer ? typeName + "*" : typeName;
|
||||
}
|
||||
else if (dataType.Kind == "Array")
|
||||
{
|
||||
return "Array";
|
||||
}
|
||||
else if (dataType.Kind == "LPArray")
|
||||
{
|
||||
return GetTypeName(dataType.Child) + "*";
|
||||
}
|
||||
else if (dataType.Kind == "PointerTo")
|
||||
{
|
||||
return GetTypeName(dataType.Child) + "*";
|
||||
@@ -1103,6 +1203,48 @@ public static class Program
|
||||
return GetTypeName(dataType.Name);
|
||||
}
|
||||
|
||||
private static bool IsPrimitive(ApiDataType dataType)
|
||||
{
|
||||
if (dataType.Kind == "ApiRef")
|
||||
{
|
||||
string apiRefType = GetTypeName($"{dataType.Api}.{dataType.Name}");
|
||||
}
|
||||
else if (dataType.Kind == "PointerTo")
|
||||
{
|
||||
return IsPrimitive(dataType.Child);
|
||||
}
|
||||
|
||||
if (dataType.Kind != "Native")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string typeName = GetTypeName(dataType.Name);
|
||||
switch (typeName)
|
||||
{
|
||||
case "void":
|
||||
case "int":
|
||||
case "uint":
|
||||
return true;
|
||||
|
||||
case "nint":
|
||||
case "nuint":
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsEnum(string typeName)
|
||||
{
|
||||
return s_visitedEnums.Contains(typeName);
|
||||
}
|
||||
|
||||
private static bool IsStruct(string typeName)
|
||||
{
|
||||
return s_visitedStructs.Contains(typeName);
|
||||
}
|
||||
|
||||
private static void AddCsMapping(string api, string typeName, string csTypeName)
|
||||
{
|
||||
s_csNameMappings[$"{api}.{typeName}"] = $"{api}.{csTypeName}";
|
||||
|
||||
Reference in New Issue
Block a user