How to use async functions as event handlers in windows-rs?

Chloé MAGLIULO 0 Reputation points
2025-11-19T21:07:37.2833333+00:00

I'm trying to get informations about the current player session in Rust. I have the following code. However, since TryGetMediaPropertiesAsync is async, I can't call it from a sync function.

But since my now-async function is an event handler, it can't be used inside MediaPropertiesChanged.

How can I mitigate this problem ?

fn properties_changed_handler(a: Ref<'_, MediaSession>, _: Ref<'_, PropertiesChangedEventArgs>) -> windows::core::Result<()> {
    let session = a.unwrap();
    let playback_infos = session.TryGetMediaPropertiesAsync()?.await?;
    playback_infos.PlaybackType().unwrap();
    Ok(())
}

fn session_changed_handler(a: Ref<'_, MediaManager>, _: Ref<'_, SessionChangedEventArgs>) -> windows::core::Result<()> {
    let local_manager: &MediaManager = a.unwrap();
    let session = local_manager.GetCurrentSession()?;
    session.MediaPropertiesChanged(&TypedEventHandler::new(properties_changed_handler))?;
    
    Ok(())
}
Windows development | Windows API - Win32
0 comments No comments

2 answers

Sort by: Oldest
  1. AI answer

    2025-11-19T21:07:58.0166667+00:00

    In Rust, when dealing with async functions as event handlers, you can use the async keyword to define your event handler as an asynchronous function. However, since event handlers in Windows APIs often expect a synchronous function, you may need to adapt your approach. One common method is to use a separate async runtime to handle the async call within the event handler.

    Here's how you can modify your properties_changed_handler to use an async runtime:

    use tokio; // Ensure you have the tokio crate in your Cargo.toml
    
    fn properties_changed_handler(a: Ref<'_, MediaSession>, _: Ref<'_, PropertiesChangedEventArgs>) -> windows::core::Result<()> {
        let session = a.unwrap();
        // Spawn a new async task to handle the async call
        tokio::spawn(async move {
            if let Ok(playback_infos) = session.TryGetMediaPropertiesAsync().await {
                let playback_type = playback_infos.PlaybackType().unwrap();
                // Handle playback_type as needed
            }
        });
        Ok(())
    }
    
    fn session_changed_handler(a: Ref<'_, MediaManager>, _: Ref<'_, SessionChangedEventArgs>) -> windows::core::Result<()> {
        let local_manager: &MediaManager = a.unwrap();
        let session = local_manager.GetCurrentSession()?;
        session.MediaPropertiesChanged(&TypedEventHandler::new(properties_changed_handler))?;
        Ok(())
    }
    

    In this modified version, tokio::spawn is used to run the async function in a separate task, allowing you to call TryGetMediaPropertiesAsync without blocking the event handler. Make sure you have the tokio crate added to your project to use this approach.


    References:

    AI-generated content may be incorrect. Read our transparency notes for more information.

    Was this answer helpful?

  2. Deleted

    This answer has been deleted due to a violation of our Code of Conduct. The answer was manually reported or identified through automated detection before action was taken. Please refer to our Code of Conduct for more information.


    Comments have been turned off. Learn more

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.