Jump to content
Sign in to follow this  
Memnarch

Possible error in generated Units in "Windows API from WinMD"

Recommended Posts

Hello,
I need a second opinion on this. Either I am drunk or there is a huge error in the generated Windows units one can install through GetIT from Emarcadero called "Windows API from WinMD". If the following is an error, I'll create a ticket. If not, someone needs to explain this to me.

 

I am trying to use IMMDeviceEnumerator from Windows.Media.Audio.pas. Calling GetDefaultAudioEndpoint, I was unable to get the defaultdevice. This is how the interface is declared:
 

  ///<summary>Documentation: https://docs.microsoft.com/windows/win32/api/mmdeviceapi/nn-mmdeviceapi-immdeviceenumerator</summary>
  ///<remarks>
  ///<para>Supported since: <i>windows6.0.6000</i></para>
  ///</remarks>
  IMMDeviceEnumerator = interface(IUnknown)
  ['{A95664D2-9614-4F35-A746-DE8DB63617E6}']
    ///<summary>Documentation: https://docs.microsoft.com/windows/win32/api/mmdeviceapi/nf-mmdeviceapi-immdeviceenumerator-enumaudioendpoints</summary>
    function EnumAudioEndpoints(dataFlow: EDataFlow; dwStateMask: Cardinal; out ppDevices: IMMDeviceCollection): HRESULT; stdcall;
    ///<summary>Documentation: https://docs.microsoft.com/windows/win32/api/mmdeviceapi/nf-mmdeviceapi-immdeviceenumerator-getdefaultaudioendpoint</summary>
    function GetDefaultAudioEndpoint(dataFlow: EDataFlow; role: ERole; out ppEndpoint: IMMDevice): HRESULT; stdcall;
    ///<summary>Documentation: https://docs.microsoft.com/windows/win32/api/mmdeviceapi/nf-mmdeviceapi-immdeviceenumerator-getdevice</summary>
    function GetDevice(pwstrId: PWSTR; out ppDevice: IMMDevice): HRESULT; stdcall;
    ///<summary>Documentation: https://docs.microsoft.com/windows/win32/api/mmdeviceapi/nf-mmdeviceapi-immdeviceenumerator-registerendpointnotificationcallback</summary>
    function RegisterEndpointNotificationCallback(pClient: IMMNotificationClient): HRESULT; stdcall;
    ///<summary>Documentation: https://docs.microsoft.com/windows/win32/api/mmdeviceapi/nf-mmdeviceapi-immdeviceenumerator-unregisterendpointnotificationcallback</summary>
    function UnregisterEndpointNotificationCallback(pClient: IMMNotificationClient): HRESULT; stdcall;
  end;

Suspecting something in the method declaration (i.e. out) was wrong. I copied it over to my code...and it started to work? Like, I didn't change a thing or did I? So after being confused for a moment, I looked at the interafce it inherits from.
When the Interface is in my code, due to the units in my uses, it derives from System.IUnknown which is declared like this:
 

  IInterface = interface
    ['{00000000-0000-0000-C000-000000000046}']
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
  end;

  IUnknown = IInterface;

However, in the generated code, it derives from Windows.Foundation.IUnknown which is declared like this:
 

  IUnknown = interface
  ['{00000000-0000-0000-C000-000000000046}']
    ///<summary>Documentation: https://docs.microsoft.com/windows/win32/api/unknwn/nf-unknwn-iunknown-queryinterface(q)</summary>
    ///<remarks>
    ///<para>Can return errors as success</para>
    ///</remarks>
    function QueryInterface(riid: PGuid; out ppvObject: Pointer): HRESULT; stdcall;
    ///<summary>Documentation: https://docs.microsoft.com/windows/win32/api/unknwn/nf-unknwn-iunknown-addref</summary>
    function AddRef: Cardinal; stdcall;
    ///<summary>Documentation: https://docs.microsoft.com/windows/win32/api/unknwn/nf-unknwn-iunknown-release</summary>
    function Release: Cardinal; stdcall;
  end;

So unless I am missing something crucial, this IUnknown-Interface is adding the same 3 methods it already has thorugh the IInterface-Baseinterface and offsets the entire VMT by 3 entries across the board.
And by adding/removing Windows.Foundation from my uses I can make the copy of the interface work/break at will. So this seems like an oversight and that IUnknown should just inherit from IInterface or be an alias, or am I wrong?

Share this post


Link to post

Hi,

6 hours ago, Memnarch said:

So unless I am missing something crucial, this IUnknown-Interface is adding the same 3 methods it already has thorugh the IInterface-Baseinterface and offsets the entire VMT by 3 entries across the board.
And by adding/removing Windows.Foundation from my uses I can make the copy of the interface work/break at will. So this seems like an oversight and that IUnknown should just inherit from IInterface or be an alias, or am I wrong?

VMT is not a problem here, VMT for such interfaces are different beast from VMT for objects/classes, VMT tables with COM interfaces (interfaces with GUID which i like to call "named interfaces" or "IDed interfaces") are separated into their own tables identified by their GUID, even for one object/interface, so VMT will be alright no matter what inheritance is there, also VMT for each interface are agnostic for other GUID declaration.

 

As for the interfaces you listed IInterface and IUnknown, this might be a problem as they declared with the same GUID (TGUID) hence they will compete to replace one another, they are identical in structure but different in parameters (declaration), so they will work unless the compiler will complain about stuff like Integer vs Cardinal or TGUID vs PGUID..., the problem here is how compiler see them and when.

 

I might be wrong here, but the fix should be removing Windows.Foundation.IUnknown , in other words, the already known interfaces should not be redeclared/generated.

Share this post


Link to post

There were other discussion about WINMD, that seems to be buggy, look there: https://en.delphipraxis.net/topic/13720-bugs-on-winmd-who-can-clarify/?do=findComment&comment=105350

 

In one post, @pcoder suggest the see others metadata provider (like this https://www.winsoft.sk/win32api.htm ).

If you look insede of those sources, you will look that more types were derivered form SYSTEM unit, like IUNKNOWN for example.

Try this instead WINMD.

 

There are in QP some open issues about WINMD.

 

 

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×