leexgone / uiautomation-rs

The uiatomation-rs crate is a wrapper for windows uiautomation. This crate can help you make windows uiautomation API calls conveniently.
Apache License 2.0
83 stars 15 forks source link

[Help Request] Error { code: -2147417850, message: "无法在设置线程模式后对其加以更改。" } #37

Closed niuhuan closed 1 year ago

niuhuan commented 1 year ago

我是试图捕捉windows最上面的窗口,并得到他的位置,以及他所有的子节点的位置和Name。

最后将这些信息放在一个全屏遮罩上绘制,试图达到窗口上所有文字都高亮的效果。

winit太过复杂我没有办法很好的使用。于是我选择了eframe(egui)或者ggez来渲染我的窗口。两个框架都有尝试。在框架的update方法中调用let ua = UIAutomation::new().unwrap();, 都会提示Error { code: -2147417850, message: "无法在设置线程模式后对其加以更改。" }

我又尝试将他储存到OnceCell中,但是他并不是线程安全。

niuhuan commented 1 year ago

我想做的程序类似 https://github.com/JeffersonQin/Ayase . 用键盘代替鼠标,并增加一些快捷键。

现在已经实现了捕捉文字和位置,现在没有办法展示窗口,希望您给一些建议。

leexgone commented 1 year ago

你在自己的程序代码中,是否也有初始化com环境? UIAutomation::new()时每次也会执行com初始化操作:CoInitializeEx(None, COINIT_MULTITHREADED) 如果我们指定的初始化模式不同就可能会出这个错误。 如果是这个原因的话,我可以增加一个不执行com初始化的创建方法;或者你把初始化参数改成相同的也可以。

关于展示窗口,你指的是自己创建窗口展示出来吗?

niuhuan commented 1 year ago

窗口并不是我创建出来的。我并没有显式的初始化com。

我使用了 ggez::event::run , eframe::run_native, 他们都是ui框架。我想这些框架可能执行了COM的初始化。 ggez代码大概如下

fn main() {
    let (mut ctx, event_loop) = ContextBuilder::new("my_game", "Cool Game Author")
        .build()
        .expect("aieee, could not create ggez context!");
    let app = Application::new();
    event::run(ctx, event_loop, app);
}

struct Application {
}

impl EventHandler for Application<'_> {
    fn update(&mut self, _ctx: &mut Context) -> GameResult {
        if something {
                let ua = UIAutomation::new().unwrap();  // panic!
        }
        Ok(())
    }

    fn draw(&mut self, ctx: &mut Context) -> Result<(), GameError> {
        let mut canvas = graphics::Canvas::from_frame(ctx, Color::WHITE);
        // Draw code here...
        canvas.finish(ctx)
    }
}
niuhuan commented 1 year ago

十分感谢您的提醒,他已经工作了, 在main方法中增加了let _ = UIAutomation::new().unwrap(); 设置com。

fn main(){
    let _ = UIAutomation::new().unwrap();
    let (mut ctx, event_loop) = ContextBuilder::new("my_game", "Cool Game Author")
        .build()
        .expect("aieee, could not create ggez context!");
    let app = Application::new();
    event::run(ctx, event_loop, app);
}
leexgone commented 1 year ago

我在v0.5.1版本上增加了一个UIAutomation::new_direct()方法,忽略COM初始化直接创建自动化对象,你可以自行管理COM环境的初始化,或者使用其它类库的初始化操作。

lededev commented 9 months ago

我在v0.5.1版本上增加了一个UIAutomation::new_direct()方法,忽略COM初始化直接创建自动化对象,你可以自行管理COM环境的初始化,或者使用其它类库的初始化操作。

这个新增方法对于我在rust生成的.dll中调用很有帮助,因为.exe的C++已经进行过了COM初始化。

rust-kotlin commented 1 month ago

我在v0.5.1版本上增加了一个UIAutomation::new_direct()方法,忽略COM初始化直接创建自动化对象,你可以自行管理COM环境的初始化,或者使用其它类库的初始化操作。

在Tauri中使用,目的是提供一个自动化操作的Tauri command函数给前端调用,也遇到了这个报错。之前是通过spawn到一个新的线程中解决中