How do I replace resume_background() when migrating a C++/WinRT Xaml App to the Rust Crate for Windows?

152 views Asked by At

Is CoreDispatcher.RunIdleAsync the correct method call to replace the apartment_context, resume_background combination in the main_async function below? If this was correct, would it then follow that the five lines of code from "let stream..." to "let result..." should then be moved into the body of the RunIdleAsync?

#![windows_subsystem = "windows"]
#![allow(non_snake_case)]

use windows::{
    core::*,
    ApplicationModel::Activation::LaunchActivatedEventArgs,
    Win32::System::Com::*,
    UI::{
        Colors,
        Xaml::{
            Controls::{
                TextBlock,
            },
            Application,
            ApplicationInitializationCallback,
            Window,
            Media::{
                FontFamily,
                SolidColorBrush,
            },
            TextAlignment,
            TextWrapping,
            VerticalAlignment,
            FrameworkElement,
            IApplicationOverrides,
            IApplicationOverrides_Impl,
        },
    },
    Storage::{
        Pickers::*,
        FileAccessMode,
        StorageFile,
    },
    Graphics::Imaging::BitmapDecoder,
    Media::Ocr::*,
};

#[implement(IApplicationOverrides)]
struct App();

impl IApplicationOverrides_Impl for App {
    fn OnLaunched(&self, _: &Option<LaunchActivatedEventArgs>) -> Result<()> {
        let block = TextBlock::new()?;
        block.SetFontFamily(FontFamily::CreateInstanceWithName(HSTRING::from("Segoe UI Semibold"))?)?;
        block.SetFontSize(72.0)?;
        block.SetForeground(SolidColorBrush::CreateInstanceWithColor(Colors::Orange()?)?)?;

        let fe = FrameworkElement::from(&block);
        fe.SetVerticalAlignment(VerticalAlignment::Center)?;
        block.SetTextAlignment(TextAlignment::Center)?;
        block.SetTextWrapping(TextWrapping::Wrap)?;
        
        let window = Window::Current()?;
        window.SetContent(&block)?;
        window.Activate()?;
        
        futures::executor::block_on(main_async(block, window))
    }
}

fn main() -> Result<()> {
    unsafe {
        CoInitializeEx(std::ptr::null(), COINIT_MULTITHREADED)?;
    }
    Application::Start(ApplicationInitializationCallback::new(|_| {
        Application::compose(App())?;
        Ok(())
    }))
}

async fn main_async(block: TextBlock, window: Window) -> Result<()> {
    let picker = FileOpenPicker::new()?;
    picker.FileTypeFilter()?.Append(HSTRING::from(".png"))?;
    picker.SetSuggestedStartLocation(PickerLocationId::PicturesLibrary)?;
    let file: StorageFile = picker.PickSingleFileAsync()?.await?;

    //apartment_context ui_thread;
    //co_await resume_background();

    let stream = file.OpenAsync(FileAccessMode::Read)?.await?;
    let decoder = BitmapDecoder::CreateAsync(stream)?.await?;
    let bitmap = decoder.GetSoftwareBitmapAsync()?.await?;
    let engine = OcrEngine::TryCreateFromUserProfileLanguages()?;
    let result = engine.RecognizeAsync(bitmap)?.await?;

    //co_await ui_thread

    block.SetText(result.Text()?)?;

    Ok(())
}
1

There are 1 answers

1
MRahilly On

With further revision:

#![windows_subsystem = "windows"]
#![allow(non_snake_case)]

use windows::{
    core::{
        Result,
        Error,
        HSTRING,
        AgileReference,
        implement,
        HRESULT,
    },
    ApplicationModel::Activation::LaunchActivatedEventArgs,
    Win32::System::Com::{
        CoInitializeEx,
        COINIT_MULTITHREADED,
    },
    UI::{
        Colors,
        Xaml::{
            Controls::{
                TextBlock,
            },
            Application,
            ApplicationInitializationCallback,
            Window,
            Media::{
                FontFamily,
                SolidColorBrush,
            },
            TextAlignment,
            TextWrapping,
            VerticalAlignment,
            FrameworkElement,
            IApplicationOverrides,
            IApplicationOverrides_Impl,
        },
        Core::{
            IdleDispatchedHandler,
            CoreDispatcherPriority,
            DispatchedHandler,
        },
    },
    Foundation::{
        IAsyncOperation,
        AsyncOperationCompletedHandler,
        AsyncStatus,
    },
    Storage::{
        Pickers::{
            FileOpenPicker,
            PickerLocationId,
        },
        FileAccessMode,
        StorageFile,
        Streams::IRandomAccessStream,
    },
    Graphics::Imaging::{
        BitmapDecoder,
        SoftwareBitmap,
    },
    Media::{
        Ocr::{
            OcrEngine,
            OcrResult,
        }
    }
};
use std::sync::{
    Arc,
    Mutex,
    MutexGuard,
};

#[implement(IApplicationOverrides)]
struct App();

impl IApplicationOverrides_Impl for App {
    fn OnLaunched(&self, _: &Option<LaunchActivatedEventArgs>) -> Result<()> {
        futures::executor::block_on(main_async())
    }
}

async fn main_async() -> Result<()> {
    let block = TextBlock::new()?;
    block.SetFontFamily(FontFamily::CreateInstanceWithName(HSTRING::from("Segoe UI Semibold"))?)?;
    block.SetFontSize(72.0)?;
    block.SetForeground(SolidColorBrush::CreateInstanceWithColor(Colors::Orange()?)?)?;

    let fe = FrameworkElement::from(&block);
    fe.SetVerticalAlignment(VerticalAlignment::Center)?;
    block.SetTextAlignment(TextAlignment::Center)?;
    block.SetTextWrapping(TextWrapping::Wrap)?;
    
    let window = Window::Current()?;
    window.SetContent(&block)?;
    window.Activate()?;
    
    let picker = FileOpenPicker::new()?;
    picker.FileTypeFilter()?.Append(HSTRING::from(".png"))?;
    picker.SetSuggestedStartLocation(PickerLocationId::PicturesLibrary)?;
    
    let file: Result<StorageFile> = picker.PickSingleFileAsync()?.await; // await-?
    if file.is_err() {
        return Err(Error::new(HRESULT(-1), HSTRING::from("PickSingleFileAsync error")));
    }

    // capture UI context?
    // switch to background thread?
    
    let stream: IRandomAccessStream = file?.OpenAsync(FileAccessMode::Read)?.await?;
    let decoder: BitmapDecoder = BitmapDecoder::CreateAsync(stream)?.await?;
    let bitmap: SoftwareBitmap = decoder.GetSoftwareBitmapAsync()?.await?;
    let engine: OcrEngine = OcrEngine::TryCreateFromUserProfileLanguages()?;
    let result: OcrResult = engine.RecognizeAsync(bitmap)?.await?;

    // switch back to UI thread?

    let hres: Result<HSTRING> = result.Text();
    let hstr: HSTRING = result.Text()?;
    block.SetText(hstr)?;

    Ok(())
}

fn main() -> Result<()> {
    unsafe {
        CoInitializeEx(std::ptr::null(), COINIT_MULTITHREADED)?;
    }
    Application::Start(ApplicationInitializationCallback::new(|_| {
        Application::compose(App())?;

        Ok(())
    }))
}