Closed spineki closed 2 years ago
Afaik IAudioSessionManager2
already holds the pointer, so this should be a cast/transmute to IAudioSessionManager2
instead of *mut IAudioSessionManager2
.
Ideed. Thank you so much @MarijnS95 !
For future readers that didn't find an example online like me before,
here is what it looks like
Before
let audio_session_enumerator_ref = (pinterface as *mut IAudioSessionManager2)
.as_ref()
.expect("Pointer to ref failed");
// -------------------- HERE IS THE PROBLEM--------------------
// The call to GetSessionEnumerator fails.
let audio_session_enumerator = audio_session_enumerator_ref
.GetSessionEnumerator()
.expect("GetSessionEnumerator Failed");
After
let audio_session_enumerator_ref =
std::mem::transmute::<*mut std::ffi::c_void, IAudioSessionManager2>(pinterface);
// The call to GetSessionEnumerator now works!!
let audio_session_enumerator = audio_session_enumerator_ref
.GetSessionEnumerator()
.expect("GetSessionEnumerator Failed");
Works like a charm, I can call for example
let count = audio_session_enumerator.GetCount();
println!("count {:?}", count);
I presume this might be a case of fn Activate
lacking a _COM_Outptr
annotation (and/or the proper uuid, ppv signature) otherwise this should have been turned into a borrow of a generic T: Interface
(or a return of that generic T).
Glad you got there in the end with the raw pointer though!
Generally, COM out params will return ownership of a ref-counted object. You should prefer to do something like this:
let mut pinterface: Option<IAudioSessionManager2> = None;
endpoint.Activate(
&IAudioSessionManager2::IID,
CLSCTX_ALL.0,
std::ptr::null_mut(),
&mut pinterface as *mut _ as _)
.expect("Activate Failed");
Now the pinterface
will own the resulting interface pointer (if any). It is regrettable that the GUID*, void**
pair aren't at the back of the parameter list. In such cases, the method is much easier to call because the Windows crate will take care of the binding automatically. I may ask the win32 metadata folks about making this easier.
@MarijnS95 yes, the metadata is missing the attribute as well, but it is also affected by the fact that the GUID
parameter isn't the second-to-last, as is conventional.
@kennykerr if the iid parameter were to be annotated, or the _com_outptr contains an index argument of said iid parameter, this is could perhaps work for any signature. Would the win32metadata folks be open to add this (probably through an override / heuristics at first) followed by the SDK headers directly?
I'd prefer to avoid adding new attributes if possible. I think perhaps if the void**
parameter had the ComOutPtr
attribute (which this method currently lacks) I could then just walk backward and look for a GUID*
parameter instead of expecting it to be the second-to-last. I'd have to experiment to see how reliable that is.
Opened https://github.com/microsoft/win32metadata/issues/752 to discuss metadata improvements.
I think perhaps if the
void**
parameter had theComOutPtr
attribute (which this method currently lacks) I could then just walk backward and look for aGUID*
parameter instead of expecting it to be the second-to-last. I'd have to experiment to see how reliable that is.
Agree, thought of that too when I was building the DIA sample that has a NoRegCoCreate workflow. Am also concerned about false positives, we'd have to take a closer look.
e.g.
HRESULT STDMETHODCALLTYPE NoRegCoCreate(
const __wchar_t *dllName,
REFCLSID rclsid,
REFIID riid,
void **ppv);
Reopening as https://github.com/microsoft/windows-rs/issues/1354#issuecomment-975895875 can now be implemented (hopefully) to enable this API to be transformed.
Another example is D2D1CreateFactory
but it lacks the ComOutPtr
attribute. https://github.com/microsoft/win32metadata/issues/956
@kennykerr has DXC meanwhile been annotated? I still have a patch sitting that annotates some of the open source repo but that got stuck around nullability vs error cases, iirc.
I'm not sure what you're referring to...
Currently signatures with a trailing pair of GUID*, void**
params that include the appropriate attributes like ComOutPtr
will get the query transformation. You can use a tool like ILSpy to quickly confirm the metadata. For example, here's how ILSpy displays the signature for CoCreateInstance
:
[DllImport("OLE32", ExactSpelling = true, PreserveSig = false)]
[SupportedOSPlatform("windows5.0")]
public unsafe static extern HRESULT CoCreateInstance([In][Const] Guid* rclsid, [Optional][In] IUnknown pUnkOuter, [In] CLSCTX dwClsContext, [In][Const] Guid* riid, [Out][ComOutPtr] void** ppv);
I'm using this issue to track adding support for more interesting cases where the GUID*
and void**
parameters are not in this conventional position, functions like D2D1CreateFactory
:
[DllImport("d2d1", ExactSpelling = true, PreserveSig = false)]
[SupportedOSPlatform("windows6.1")]
public unsafe static extern HRESULT D2D1CreateFactory([In] D2D1_FACTORY_TYPE factoryType, [In][Const] Guid* riid, [Optional][In][Const] D2D1_FACTORY_OPTIONS* pFactoryOptions, [Out] void** ppIFactory);
Does that cover your case? If not, please open a new issue so I can look into that.
@MarijnS95 #1805 affects one or two DXC APIs - let me know if that resolves your concern.
@kennykerr I don't think the problem is related then. The signatures of those functions were initially detected correctly, but disappeared again once windows-rs
started looking for ComOutPtr
which the DXC APIs lack... I have a pending patch to add them but that stagnated.
I don't think my questions really fit windows-rs and should otherwise be small enough to sneak in here, no need to create a separate issue (if anything, they're perhaps better suited elsewhere):
outptr
NULL
if it also returns an error, is that still considered _COM_Outptr_result_maybenull_
or just _COM_Outptr_
? This is convention in for example GLib/GStreamer: if the function sets the output error
every time it would also return NULL
, it is not considered nullable (because you're not supposed to look at function outputs if the function signals an error).Sorry, I'm not very proficient with SAL annotations and I don't know where DXC comes from. You could try asking on the win32metadata repo as those are the same folks who own the Windows SDK.
_COM_Outptr_
parameters must set the output value to null if they return failure. This is alluded to in the documentation where it says:
The returned pointer has COM semantics, which is why it carries an
_On_failure_
post-condition that the returned pointer is null.
In sal.h it says:
// Annotations for _Outptr_ parameters which return a pointer to a ref-counted COM object,
// following the COM convention of setting the output to NULL on failure.
// The current implementation is identical to _Outptr_result_nullonfailure_.
// For pointers to types that are not COM objects, _Outptr_result_nullonfailure_ is preferred.
These DXC functions are returning pointers to interfaces that follow COM semantics, and so _COM_Outptr_
can be used here. The definitions in sal.h are also useful to try and figure out what these annotations mean:
#define _COM_Outptr_ _SAL2_Source_(_COM_Outptr_, (), _Outptr_ _On_failure_(_Deref_post_null_))
#define _COM_Outptr_result_maybenull_ _SAL2_Source_(_COM_Outptr_result_maybenull_, (), _Outptr_result_maybenull_ _On_failure_(_Deref_post_null_))
#define _COM_Outptr_opt_ _SAL2_Source_(_COM_Outptr_opt_, (), _Outptr_opt_ _On_failure_(_Deref_post_null_))
#define _COM_Outptr_opt_result_maybenull_ _SAL2_Source_(_COM_Outptr_opt_result_maybenull_, (), _Outptr_opt_result_maybenull_ _On_failure_(_Deref_post_null_))
_COM_Outptr_
must be passed in as a non-null value, and if the function succeeds it will be set to a value and if it fails it will be set to null.
_COM_Outptr_opt_
may be null. If it is non-null then it behaves as for _COM_Outptr_
.
The maybenull versions are as above, but the function is allowed to succeed and set the parameter to null.
I suggest you ask on the dxc repo about when they're next planning to update the SDK with the latest DXC changes.
@damyanp Thanks for the links and detailed info! I've now worked this into https://github.com/microsoft/DirectXShaderCompiler/pull/4524 - it's a bit hacky and quick but I found that I couldn't spend much more time on it than that. It seems the particular function I was having issues with has been overridden in win32metadata anyways (I asked this before: will superfluous annotations be removed there if they have found their way into the headers?), yet I actually need the typedef
now which doesn't have it yet :grimacing:
I'm happy it was useful.
will superfluous annotations be removed there if they have found their way into the headers?
Is the question here about whether or not we'll clean up the overrides in win32metadata once the headers are updated? If so, then this is something that the win32metadata people can help with.
If I've misunderstood the question, then sorry - could you help me understand it?
Is the question here about whether or not we'll clean up the overrides in win32metadata once the headers are updated?
Yes.
If so, then this is something that the win32metadata people can help with.
I don't need an answer per-se, just curious. Since this can be implemented in the tooling itself I figure it's either already available or will be implemented once (the size of) the overrides gets out of hand :)
If the headers get updated and ship in the Windows SDK, the changes should just propagate through win32metadata when the targeted SDK is bumped.
@riverar I'm not worried about that, it'll happen at some point presuming my patches ever get merged (just that it is obviously cleaner to not have lingering overrides when that happens). There's a common theme though with my submissions to Microsoft repositories getting ignored, though.
Is any patch work still needed? (Superfluous annotations?) If we're still missing something in either repo, feel free to holler.
Is any patch work still needed?
https://github.com/microsoft/DirectXShaderCompiler/pull/4524 Would need to get merged, land in win32metadata
and finally end up here. And it's useless to me unless windows-rs
wants to pick up the arguably-niche #1835.
(Superfluous annotations?)
Nothing that needs to happen, just curious. It seems that https://github.com/microsoft/win32metadata/pull/890/files#diff-12f77aafef2c6ee2fa3a7c437254fc543c6e4246ffee487af8ae24db6d8d5bf0R877-R878 is superfluous if/when https://github.com/microsoft/DirectXShaderCompiler/pull/4524 trickles down into win32metadata
, correct?
Regardless, we're straying very far off course for this issue :)
Hello, thank you for this amazing library,
I get an error while retrieving back a pointer that should be filled by the IMMDevice::Activate function.
I have got this error on Windows 10 with the following configuration:
Here is a minimal (non!)working example. Code is commented to highlight the problem.
Cargo.toml
Code: