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

Add Ref and OutRef to enhance COM authoring support #3025

Merged
merged 4 commits into from
May 9, 2024
Merged

Add Ref and OutRef to enhance COM authoring support #3025

merged 4 commits into from
May 9, 2024

Conversation

kennykerr
Copy link
Collaborator

@kennykerr kennykerr commented May 9, 2024

This update introduces a number of improvements to the implement and interface macros as well as the windows-core crate that work together to enhance support for COM interface declarations and implementations as well as general FFI/ABI support.

Consider the following C++ function signature:

HRESULT __stdcall DllGetActivationFactory(HSTRING, IActivationFactory**)

This function must be exported by DLLs for WinRT (COM) support. The ABI requirements are such that the HSTRING and IActivationFactory types are "borrowed" in the sense that neither the caller nor the callee must free or drop those values as part of the call itself. This leads to Rust developers having to write something like this:

unsafe extern "system" fn DllGetActivationFactory(
    name: std::mem::ManuallyDrop<HSTRING>,
    factory: *mut std::mem::ManuallyDrop<Option<IActivationFactory>>,
) -> HRESULT

The implementation is then forced to carefully consider and manage lifetimes and transfer ownership and is easy to get wrong.

The Ref and OutRef types represent borrowed types, providing the same memory layout but also offer lifetime management and conveniences to make dealing with in and out parameters safe and convenient:

unsafe extern "system" fn DllGetActivationFactory(
    name: Ref<HSTRING>,
    factory: OutRef<IActivationFactory>,
) -> HRESULT

Ref implements the Deref trait that returns a reference to the borrowed type while OutRef provides the write method that will overwrite the memory location with the given value. The write method can only be called once and checks for null. It also provides the is_null method if you need to conditionally support optional out parameters.

The interface macro will also generate bindings for Ref and OutRef that behave like the bindings generated by the windows-bindgen crate, making it easier to call such interface methods naturally from Rust. This leverages the new ParamMut trait that compliments the existing Param trait for handling out parameters. It takes care of dealing with uninitialized memory in out parameters as well as dropping &mut values in Rust to avoid leaks.

In addition, the interface macro now supports Result return types for convenience. The underlying virtual function will still return an HRESULT but the interface and implement macros will automatically translate that for you:

#[interface("09428a59-5b40-4e4c-9175-e7a78514316d")]
unsafe trait ITest: IUnknown {
    unsafe fn Void(&self);
    unsafe fn Code(&self) -> HRESULT;
    unsafe fn Result(&self) -> Result<()>;
}

@kennykerr kennykerr changed the title Add Ref and RefMut to enhance COM authoring support Add Ref and OutRef to enhance COM authoring support May 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants