Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User/sotteson/guid scraping and bugs #344

Merged
merged 2 commits into from
Mar 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions generation/emitter/requiredNamespacesForNames.rsp
Original file line number Diff line number Diff line change
Expand Up @@ -13957,8 +13957,10 @@ SORTIDFROMLCID=Windows.Win32.Intl
SORTVERSIONFROMLCID=Windows.Win32.Intl
SUBLANGID=Windows.Win32.Intl
TEXT=Windows.Win32.Intl
CreateNamedPipeA=Windows.Win32.Ipc
WaitNamedPipeA=Windows.Win32.Ipc
CreateNamedPipeA=Windows.Win32.SystemServices
CreateNamedPipeW=Windows.Win32.SystemServices
WaitNamedPipeA=Windows.Win32.SystemServices
WaitNamedPipeW=Windows.Win32.SystemServices
Icmp6CreateFile=Windows.Win32.IpHelper
Icmp6ParseReplies=Windows.Win32.IpHelper
Icmp6SendEcho2=Windows.Win32.IpHelper
Expand Down Expand Up @@ -21269,6 +21271,8 @@ RasDialDlgA=Windows.Win32.RoutingAndRemoteAccessService
RasDialDlgW=Windows.Win32.RoutingAndRemoteAccessService
RasEntryDlgA=Windows.Win32.RoutingAndRemoteAccessService
RasEntryDlgW=Windows.Win32.RoutingAndRemoteAccessService
RASENTRYA=Windows.Win32.RoutingAndRemoteAccessService
RASENTRYW=Windows.Win32.RoutingAndRemoteAccessService
RasPhonebookDlgA=Windows.Win32.RoutingAndRemoteAccessService
RasPhonebookDlgW=Windows.Win32.RoutingAndRemoteAccessService
RasSecurityDialogBegin=Windows.Win32.RoutingAndRemoteAccessService
Expand Down
1 change: 1 addition & 0 deletions generation/scraper/enums.json
Original file line number Diff line number Diff line change
Expand Up @@ -31121,6 +31121,7 @@
{
"name": "MPR_ET",
"flags": false,
"type": "uint",
"members": [
{
"name": "MPR_ET_None"
Expand Down
69 changes: 69 additions & 0 deletions generation/scraper/manualEnums.json
Original file line number Diff line number Diff line change
Expand Up @@ -1509,5 +1509,74 @@
"value": "( 1 << (int)CERT_QUERY_FORMAT_TYPE.CERT_QUERY_FORMAT_BINARY)"
}
]
},
{
"name": "Uri_CREATE_FLAGS",
"flags": true,
"autoPopulate":
{
"filter": "Uri_CREATE_",
"header": "urlmon.h"
},
"uses": [
{
"method": "CreateUri",
"parameter": "dwFlags"
}
]
},
{
"name": "MPR_INTERFACE_DIAL_MODE",
"flags": false,
"type": "uint",
"members": [
{
"name": "MPRDM_DialFirst",
"value": "0"
},
{
"name": "MPRDM_DialAll",
"value": "RASENTRY_DIAL_MODE.RASEDM_DialAll"
},
{
"name": "MPRDM_DialAsNeeded",
"value": "RASENTRY_DIAL_MODE.RASEDM_DialAsNeeded"
}
],
"uses": [
{
"struct": "MPR_INTERFACE_3",
"field": "dwDialMode"
},
{
"struct": "MPR_INTERFACE_2",
"field": "dwDialMode"
}
]
},
{
"name": "RASENTRY_DIAL_MODE",
"flags": false,
"type": "uint",
"members": [
{
"name": "RASEDM_DialAll",
"value": "1"
},
{
"name": "RASEDM_DialAsNeeded",
"value": "2"
}
],
"uses": [
{
"struct": "RASENTRYA",
"field": "dwDialMode"
},
{
"struct": "RASENTRYW",
"field": "dwDialMode"
}
]
}
]
105 changes: 96 additions & 9 deletions sources/ClangSharpSourceToWinmd/ClangSharpSourceWinmdGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public class ClangSharpSourceWinmdGenerator
public const string Win32StringType = "Windows.Win32.SystemServices.PSTR";

private const string InteropNamespace = "Windows.Win32.Interop";
private const string ScannedSuffix = "__scanned__";

private static readonly Regex TypeImportRegex = new Regex(@"<(([^,]+),\s*Version=(\d+\.\d+\.\d+\.\d+),\s*Culture=([^,]+),\s*PublicKeyToken=([^>]+))>(\S+)");

Expand Down Expand Up @@ -52,6 +53,8 @@ public class ClangSharpSourceWinmdGenerator
private Dictionary<string, AssemblyReferenceHandle> assemblyNamesToRefHandles = new Dictionary<string, AssemblyReferenceHandle>();
private Dictionary<string, ITypeSymbol> nameToSymbols = new Dictionary<string, ITypeSymbol>();
private Dictionary<StructDeclarationSyntax, ISymbol> structNodesToInheritedSymbols = new Dictionary<StructDeclarationSyntax, ISymbol>();
private Dictionary<string, FieldDeclarationSyntax> nameToGuidConstFields = new Dictionary<string, FieldDeclarationSyntax>();
private HashSet<string> structNameWithGuids = new HashSet<string>();

private ClangSharpSourceWinmdGenerator(
CSharpCompilation compilation,
Expand Down Expand Up @@ -195,14 +198,26 @@ private static byte[] ConvertKeyToByteArray(string key)
return ret;
}

private void AddDiagnostic(string text)
private static string GetQualifiedName(string @namespace, string name)
{
Console.WriteLine(text);
return $"{@namespace}.{name}";
}

private static string GetQualifiedName(string @namespace, string name)
private static bool HasGuidAttribute(SyntaxList<AttributeListSyntax> attributeLists)
{
return $"{@namespace}.{name}";
bool ret = attributeLists.Any(list => list.Attributes.Any(attr => attr.Name.ToString() == "Windows.Win32.Interop.Guid"));
return ret;
}

private static bool HasPropertyKeyAttribute(SyntaxList<AttributeListSyntax> attributeLists)
{
bool ret = attributeLists.Any(list => list.Attributes.Any(attr => attr.Name.ToString() == "PropertyKey"));
return ret;
}

private void CacheGuidConst(FieldDeclarationSyntax guidFieldNode)
{
this.nameToGuidConstFields[guidFieldNode.Declaration.Variables.First().Identifier.ValueText] = guidFieldNode;
}

private void CacheInterfaceType(StructDeclarationSyntax interfaceNode)
Expand Down Expand Up @@ -422,6 +437,28 @@ private void WriteInterfaceDef(StructDeclarationSyntax node)
metadataBuilder.AddInterfaceImplementation(destTypeDefHandle, inheritsFromTypeDef);
}

// If this interface node doesn't have a Guid attribute, see if we can
// match it to a Guid constant
if (!HasGuidAttribute(node.AttributeLists))
{
string iidGuidConstName = $"IID_{name}";
if (!this.nameToGuidConstFields.TryGetValue(iidGuidConstName, out var fieldDeclNode))
{
iidGuidConstName += ScannedSuffix;
this.nameToGuidConstFields.TryGetValue(iidGuidConstName, out fieldDeclNode);
}

if (fieldDeclNode != null)
{
ISymbol fieldSymbol = this.compilation.GetSymbolsWithName(iidGuidConstName).FirstOrDefault();

if (fieldSymbol != null)
{
this.AddCustomAttributes(fieldSymbol, destTypeDefHandle);
}
}
}

this.AddCustomAttributes(node, destTypeDefHandle);
}

Expand Down Expand Up @@ -798,22 +835,52 @@ private FieldDefinitionHandle WriteClassFields(ClassDeclarationSyntax node)
var model = this.GetModel(node);
var classSymbol = model.GetDeclaredSymbol(node);
FieldDefinitionHandle firstField = default;

foreach (FieldDeclarationSyntax field in node.Members.Where(m => m is FieldDeclarationSyntax))
{
var fieldVariable = field.Declaration.Variables.First();
IFieldSymbol fieldSymbol = (IFieldSymbol)model.GetDeclaredSymbol(fieldVariable);
string name = fieldSymbol.Name;

FieldAttributes fieldAttributes;

if (!fieldSymbol.IsConst)
{
continue;
fieldAttributes = FieldAttributes.Public | FieldAttributes.Static;

if (!HasGuidAttribute(field.AttributeLists) && !HasPropertyKeyAttribute(field.AttributeLists))
{
continue;
}

if (fieldSymbol.Name.StartsWith("IID_"))
{
continue;
}

if (name.EndsWith(ScannedSuffix))
{
name = name.Substring(0, name.Length - ScannedSuffix.Length);
}

if (name.StartsWith("CLSID_"))
{
string testClassName = name.Substring("CLSID_".Length);
if (this.structNameWithGuids.Contains(testClassName))
{
continue;
}
}
}
else
{
fieldAttributes = FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal | FieldAttributes.HasDefault;
}

var fieldSignature = this.EncodeFieldSignature(className, model, field, out string name);
var fieldSignature = this.EncodeFieldSignature(className, model, field, out _);

var fieldDefinitionHandle =
metadataBuilder.AddFieldDefinition(
FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal | FieldAttributes.HasDefault,
fieldAttributes,
metadataBuilder.GetOrAddString(name),
metadataBuilder.GetOrAddBlob(fieldSignature));
if (fieldSymbol.HasConstantValue)
Expand Down Expand Up @@ -1378,12 +1445,17 @@ private void AddCustomAttributes(IEnumerable<AttributeData> attrs, EntityHandle
}
}

private void AddCustomAttributes(ISymbol symbol, EntityHandle entityHandle)
{
this.AddCustomAttributes(symbol.GetAttributes(), entityHandle);
}

private void AddCustomAttributes(SyntaxNode node, EntityHandle entityHandle)
{
var model = this.GetModel(node);
var symbol = model.GetDeclaredSymbol(node);

this.AddCustomAttributes(symbol.GetAttributes(), entityHandle);
this.AddCustomAttributes(symbol, entityHandle);
}

private ISymbol GetInheritedInterfaceSymbol(StructDeclarationSyntax node)
Expand Down Expand Up @@ -1728,10 +1800,25 @@ public InterfaceWalker(ClangSharpSourceWinmdGenerator parent)

public override void VisitStructDeclaration(StructDeclarationSyntax node)
{
base.VisitStructDeclaration(node);

if (this.parent.IsInterfaceDef(node))
{
this.parent.CacheInterfaceType(node);
}

if (HasGuidAttribute(node.AttributeLists))
{
this.parent.structNameWithGuids.Add(node.Identifier.ValueText);
}
}

public override void VisitFieldDeclaration(FieldDeclarationSyntax node)
{
if (node.Modifiers.ToString() == "public static readonly" && node.Declaration.Type.ToString() == "Guid")
{
this.parent.CacheGuidConst(node);
}
}
}

Expand Down
23 changes: 23 additions & 0 deletions sources/ClangSharpSourceToWinmd/EncodeHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ public static uint ParseHex(string text)
text = text.Substring(2);
}

if (char.ToUpperInvariant(text[text.Length - 1]) == 'L')
{
text = text.Substring(0, text.Length - 1);
}

return uint.Parse(text, System.Globalization.NumberStyles.HexNumber);
}

Expand Down Expand Up @@ -280,5 +285,23 @@ public static void FixedArguments(this FixedArgumentsEncoder argumentsEncoder, I
argumentsEncoder.AddArgument().TypedConstant(argument);
}
}

public static AttributeListSyntax ConvertGuidToAttributeList(Guid guid)
{
// Outputs in format: {0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
string formattedGuid = guid.ToString("x");

// Get rid of leading { and trailing }}
formattedGuid = formattedGuid.Substring(1, formattedGuid.Length - 3);
// There's one more { we need to get rid of
formattedGuid = formattedGuid.Replace("{", string.Empty);
string args = $"({formattedGuid})";
return
SyntaxFactory.AttributeList(
SyntaxFactory.SingletonSeparatedList<AttributeSyntax>(
SyntaxFactory.Attribute(
SyntaxFactory.ParseName("Windows.Win32.Interop.Guid"),
SyntaxFactory.ParseAttributeArgumentList(args))));
}
}
}
Loading