microsoft / CsWin32

A source generator to add a user-defined set of Win32 P/Invoke methods and supporting types to a C# project.
MIT License
2k stars 84 forks source link

Generated COM interface guid does not match winmd #1032

Closed youyuanwu closed 9 months ago

youyuanwu commented 10 months ago

See details in: https://github.com/youyuanwu/service-fabric-cs/issues/3

        var guidgen = typeof(IFabricQueryClient).GUID; //This does not work.
        var guid = Guid.Parse("c629e422-90ba-4efd-8f64-cecf51bc3df0");
        Debug.Assert(Debug.Equals(guid, guidgen), $"Not equal {guid} and {guidgen}");
        // Not equal c629e422-90ba-4efd-8f64-cecf51bc3df0 and 872b8dc7-d6af-3a59-9ecc-2edbb26e1ffc

The generated COM interface class IFabricQueryClient does not have the right guid that matches the COM definition. The query interface failed.

Compile the program here to get repro: https://github.com/youyuanwu/service-fabric-cs/blob/a8a890b3be9d1bb6a7c4c905509c1dcd158c54be/src/examples/Program.cs

It is likely that IID_Guid property of the generated interface is not present.

AArnott commented 10 months ago

Your repro interface isn't in the metadata that CsWin32 generates from by default. But when I look at another COM interface like IFileIo that is included in the default metadata, I see this:

[Windows.Win32.Foundation.Metadata.Guid(295252374u, 4676, 18496, 171, 68, 72, 9, 117, 196, byte.MaxValue, 228)]
public interface IFileIo : IUnknown

The CsWin32-emitted code looks like this:

[Guid("11993196-1244-4840-AB44-480975C4FFE4"),InterfaceType(ComInterfaceType.InterfaceIsIUnknown),ComImport()]
[global::System.CodeDom.Compiler.GeneratedCode("Microsoft.Windows.CsWin32", "0.3.18-beta+dc807e7787")]
internal interface IFileIo

This is a correct guid. Since CsWin32 doesn't discriminate metadata sources when generating guid attributes on interfaces, I can only speculate that the metadata you're drawing from doesn't define its guid the same way.

Can you review the attributes in the metadata for your interface as verify that it's using the same Metadata.Guid attribute? If so, can you include the ILSpy-decompiled form of it here for my review?

youyuanwu commented 9 months ago

Seems like generated interface does not have Guid attribute, even though there is guid in winmd.

ILSpy for the cs dll:

// ServiceFabric, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// Microsoft.ServiceFabric.FabricCommon.FabricClient.IFabricQueryClient
using System.CodeDom.Compiler;
using Microsoft.ServiceFabric;
using Microsoft.ServiceFabric.FabricCommon;
using Microsoft.ServiceFabric.FabricCommon.FabricClient;

[GeneratedCode("Microsoft.Windows.CsWin32", "0.3.18-beta+dc807e7787")]
public interface IFabricQueryClient
{
    unsafe void BeginGetNodeList(FABRIC_NODE_QUERY_DESCRIPTION* queryDescription, uint timeoutMilliseconds, IFabricAsyncOperationCallback callback, out IFabricAsyncOperationContext context);

    void EndGetNodeList(IFabricAsyncOperationContext context, out IFabricGetNodeListResult result);

ILSpy for winmd:

// Microsoft.ServiceFabric.winmd, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null
// Microsoft.ServiceFabric.FabricCommon.FabricClient.IFabricQueryClient
using System.Runtime.InteropServices;
using Microsoft.ServiceFabric;
using Microsoft.ServiceFabric.FabricCommon;
using Microsoft.ServiceFabric.FabricCommon.FabricClient;
using Windows.Win32.Foundation;
using Windows.Win32.Interop;
using Windows.Win32.System.Com;

[Guid(3324634146u, 37050, 20221, 143, 100, 206, 207, 81, 188, 61, 240)]
public interface IFabricQueryClient : IUnknown
{
    unsafe HRESULT BeginGetNodeList([In][Const] FABRIC_NODE_QUERY_DESCRIPTION* queryDescription, [In] uint timeoutMilliseconds, [In] IFabricAsyncOperationCallback callback, [Out][RetVal] IFabricAsyncOperationContext* context);

    unsafe HRESULT EndGetNodeList([In] IFabricAsyncOperationContext context, [Out][RetVal] IFabricGetNodeListResult* result);
AArnott commented 9 months ago

Your metadata apparently is using System.Runtime.InteropServices.GuidAttribute. That is not supported. You must use Windows.Win32.Foundation.Metadata.GuidAttribute, as I mentioned in my last message.