You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
IDataTransferManagerInterop with void** parameter #246
When I try to use IDataTransferManagerInterop the generated code uses a void** to return the requested DataTransferManager. I believe more comfortable code can and should be generated e.g. using an out DataTansferManager parameter.
usingWinRT;// riid of DataTransferManager, not IDataTransferManagerInterop varguid=Guid.Parse("a5caee9b-8708-49d1-8d36-67d25a8da00c");variop=DataTransferManager.As<IDataTransferManagerInterop>();vartransferManager=IntPtr.Zero;iop.GetForWindow(PInvoke.GetActiveWindow(),guid,(void**)&transferManager);varrealManager=DataTransferManager.FromAbi(transferManager);
The type of the out parameter comes from the metadata, which comes from the header file. As seen in the docs, void** is the output type--it isn't typed as DataTransferManager in the API.
Now, things can still be improved here. Newer versions of the metadata attribute this output parameter as a COM object pointer, so soon you'll see out object instead of void** or out void* in me CsWin32 method signature. So that will make it much simpler, but you'll still have to cast to DataTransferManager yourself.
But I'm not sure where you'll get the definition of DataTransferManager from. It's not in the metadata as the metadata is of Win32 but DataTransferManager is a WinRT type. And if WinRT, I wonder if you should actually be getting this IDataTransferManagerInterop interface from a ref assembly produced by CsWinRT instead.
out object is great! Thank you sir. That avoids all the unsafe operations that I was struggling with.
CsWinRT delivers both IDataTransferManagerInterop and DataTransferManager. The Interop interface acts as a factory for the manager itself if I understand it correctly. Anyway, that is obviously not a topic for this repo.
However, how can I cast that object to DataTransferManager? It's a System.__ComObject and I'm trying to cast to Windows.ApplicationModel.DataTransfer.DataTransferManager.
If DataTransferManager is a class, I imagine the cast is failing because that is a COM object and can only be cast to an interface. As to where you get an equivalent interface, I don't know.
Andrew Arnott (@AArnott) That's disappointing, thanks for the reply. There does not seem to be any interface for that class. Could this class/method be reverted to the earlier signature with the void** return method? Or would it be CsWinRT responsibility to generate the needed interface?
CsWinRT only generates interfaces that appear in the win32metadata. I find it very odd that the metadata includes this method but for the "interface" you use it with, WinRT is required. So I'm a bit lost here.
You can always get the void** signature by setting allowMarshaling: false in NativeMethods.json.
But if I were you, I'd look at the COM class and declare it as an interface myself (complete with [Guid] attribute) as I expect that cast would succeed.
Thank you for all your help here, but I'm ready to give up.
If I set allowMarshaling: false then
var iop = DataTransferManager.As<IDataTransferManagerInterop>();
Results in an exception stating: "Unable to cast object of type 'WinRT.IInspectable' to type 'Windows.Win32.UI.Shell.IDataTransferManagerInterop'."
I am not aware of any other way to get a class implementing IDataTransferManagerInterop.
And as far as declaring the interface myself: I tried. But I cannot figure out how to marshal Windows.Foundation.TypedEventHandler<Windows.ApplicationModel.DataTransfer.DataTransferManager, Windows.ApplicationModel.DataTransfer.DataRequestedEventArgs> correctly, so the cast appears to work with my interface declaration, but the event does not.
Andrew Arnott (@AArnott) According to microsoft/CsWinRT#970 (comment) returning object in this case is not correct and does not work.
A suggested return type is IntPtr which can then be read using MarshalInterface<DataTransferManager>.FromAbi(result);.
I'm unsure how this connects with #374. But I believe the current object return value needs to be fixed.
Steve Otteson (@sotteson1) I tried your new WinRTCustomMarshaler as released a couple days ago in v0.1.560 this does not yet work for DataTransferManager. I managed to fix it by modifing the generated IDataTransferManagerInterop like this:
// instead of [return:MarshalAs(UnmanagedType.IUnknown)]unsafeobjectGetForWindow(win32.Foundation.HWNDappWindow,global::System.Guid*riid);// this:[return:MarshalAs(UnmanagedType.CustomMarshaler,MarshalCookie="Windows.ApplicationModel.DataTransfer.DataTransferManager",MarshalType="Windows.Win32.CsWin32.InteropServices.WinRTCustomMarshaler")]unsafeobjectGetForWindow(win32.Foundation.HWNDappWindow,global::System.Guid*riid);
As well as manually adding your WinRTCustomMarshaler class because it does not get generated automatically.
I think some metadata on IDataTransferManagerInterop might be missing?
Maybe an option could be added to manually output the WinRTCustomMarshaler?
Assigning to Steve Otteson (@sotteson1) to investigate if there are any metadata changes required here on IDataTransferManagerInterop and the concerns around WinRTCustomMarshaler not being autogenerated when you need it (#397).
Activity
[-]IDataTransferManagerInterop[/-][+]IDataTransferManagerInterop with void** parameter[/+]AArnott commentedon Apr 26, 2021
The type of the out parameter comes from the metadata, which comes from the header file. As seen in the docs,
void**is the output type--it isn't typed asDataTransferManagerin the API.Now, things can still be improved here. Newer versions of the metadata attribute this output parameter as a COM object pointer, so soon you'll see
out objectinstead ofvoid**orout void*in me CsWin32 method signature. So that will make it much simpler, but you'll still have to cast toDataTransferManageryourself.But I'm not sure where you'll get the definition of
DataTransferManagerfrom. It's not in the metadata as the metadata is of Win32 butDataTransferManageris a WinRT type. And if WinRT, I wonder if you should actually be getting thisIDataTransferManagerInteropinterface from a ref assembly produced by CsWinRT instead.Marv51 commentedon Apr 27, 2021
out objectis great! Thank you sir. That avoids all the unsafe operations that I was struggling with.CsWinRT delivers both
IDataTransferManagerInteropandDataTransferManager. The Interop interface acts as a factory for the manager itself if I understand it correctly. Anyway, that is obviously not a topic for this repo.Marv51 commentedon May 27, 2021
So with the newest CsWin32 preview (0.1.476-beta) the signature is now:
Like you mentioned Andrew Arnott (@AArnott).
However, how can I cast that
objecttoDataTransferManager? It's aSystem.__ComObjectand I'm trying to cast toWindows.ApplicationModel.DataTransfer.DataTransferManager.All these attempts are failing:
AArnott commentedon Jun 9, 2021
If
DataTransferManageris a class, I imagine the cast is failing because that is a COM object and can only be cast to an interface. As to where you get an equivalent interface, I don't know.Marv51 commentedon Jun 10, 2021
Andrew Arnott (@AArnott) That's disappointing, thanks for the reply. There does not seem to be any interface for that class. Could this class/method be reverted to the earlier signature with the
void**return method? Or would it be CsWinRT responsibility to generate the needed interface?AArnott commentedon Jun 11, 2021
CsWinRT only generates interfaces that appear in the win32metadata. I find it very odd that the metadata includes this method but for the "interface" you use it with, WinRT is required. So I'm a bit lost here.
You can always get the
void**signature by settingallowMarshaling: falsein NativeMethods.json.But if I were you, I'd look at the COM class and declare it as an interface myself (complete with
[Guid]attribute) as I expect that cast would succeed.Marv51 commentedon Jun 14, 2021
Thank you for all your help here, but I'm ready to give up.
If I set
allowMarshaling: falsethenvar iop = DataTransferManager.As<IDataTransferManagerInterop>();Results in an exception stating:
"Unable to cast object of type 'WinRT.IInspectable' to type 'Windows.Win32.UI.Shell.IDataTransferManagerInterop'."I am not aware of any other way to get a class implementing
IDataTransferManagerInterop.And as far as declaring the interface myself: I tried. But I cannot figure out how to marshal
Windows.Foundation.TypedEventHandler<Windows.ApplicationModel.DataTransfer.DataTransferManager, Windows.ApplicationModel.DataTransfer.DataRequestedEventArgs>correctly, so the cast appears to work with my interface declaration, but the event does not.I have filed microsoft/Windows-classic-samples#190 in the hope that people there already know how this works.
mikebattista commentedon Aug 25, 2021
I think #374 would help with this scenario. Interop with WinRT interop interfaces is something we want to improve on here.
Marv51 commentedon Sep 1, 2021
Andrew Arnott (@AArnott) According to microsoft/CsWinRT#970 (comment) returning
objectin this case is not correct and does not work.A suggested return type is IntPtr which can then be read using
MarshalInterface<DataTransferManager>.FromAbi(result);.I'm unsure how this connects with #374. But I believe the current
objectreturn value needs to be fixed.asklar commentedon Sep 1, 2021
CC Ryan Shepherd (@DefaultRyan)
AArnott commentedon Sep 2, 2021
Marvin Rühe (@Marv51) I believe in the WinRT object case, #384 will satisfy your concern. Steve Otteson (@sotteson1) can you confirm?
sotteson1 commentedon Sep 2, 2021
It should work, but I'm going to try it out to make sure.
Marv51 commentedon Sep 10, 2021
Steve Otteson (@sotteson1) I tried your new
WinRTCustomMarshaleras released a couple days ago in v0.1.560 this does not yet work forDataTransferManager. I managed to fix it by modifing the generatedIDataTransferManagerInteroplike this:As well as manually adding your WinRTCustomMarshaler class because it does not get generated automatically.
I think some metadata on IDataTransferManagerInterop might be missing?
Maybe an option could be added to manually output the WinRTCustomMarshaler?
mikebattista commentedon Sep 29, 2021
Assigning to Steve Otteson (@sotteson1) to investigate if there are any metadata changes required here on IDataTransferManagerInterop and the concerns around WinRTCustomMarshaler not being autogenerated when you need it (#397).
Also we need to validate if the improved support here addresses issues like microsoft/WindowsAppSDK#1335.
MicroBuild to 1ES PT template transition (#246)