【问题标题】:Invoke delegate on main thread in console application在控制台应用程序的主线程上调用委托
【发布时间】:2011-04-09 01:08:03
【问题描述】:

在 Windows 应用程序中,当使用多个线程时,我知道需要调用主线程来更新 GUI 组件。这是如何在控制台应用程序中完成的?

例如,我有两个线程,一个主线程和一个辅助线程。辅助线程始终在监听全局热键;当它被按下时,辅助线程会执行一个到达 win32 api 方法 AnimateWindow 的事件。我收到一个错误,因为只允许主线程执行所述功能。

当“Invoke”不可用时,如何有效地告诉主线程执行该方法?


更新: 如果有帮助,这里是代码。要查看 HotKeyManager 的内容(另一个线程正在发挥作用),请查看this question 的答案
class Hud
{
    bool isHidden = false;
    int keyId;

    private static IntPtr windowHandle;

    public void Init(string[] args)
    {
        windowHandle = Process.GetCurrentProcess().MainWindowHandle;
        SetupHotkey();
        InitPowershell(args);
        Cleanup();
    }

    private void Cleanup()
    {
        HotKeyManager.UnregisterHotKey(keyId);
    }

    private void SetupHotkey()
    {

        keyId = HotKeyManager.RegisterHotKey(Keys.Oemtilde, KeyModifiers.Control);
        HotKeyManager.HotKeyPressed += new EventHandler<HotKeyEventArgs>(HotKeyManager_HotKeyPressed);
    }

    void HotKeyManager_HotKeyPressed(object sender, HotKeyEventArgs e)
    {
       ToggleWindow();
    }

    private void ToggleWindow()
    {
        //exception is thrown because a thread other than the one the console was created in is trying to call AnimateWindow

        if (isHidden)
        {
            if (!User32.AnimateWindow(windowHandle, 200, AnimateWindowFlags.AW_VER_NEGATIVE | AnimateWindowFlags.AW_SLIDE))
                throw new Win32Exception(Marshal.GetLastWin32Error());
        }
        else
        {
            if (!User32.AnimateWindow(windowHandle, 200, AnimateWindowFlags.AW_VER_POSITIVE | AnimateWindowFlags.AW_HIDE))
                throw new Win32Exception(Marshal.GetLastWin32Error());
        }
        isHidden = !isHidden;
    }

    private void InitPowershell(string[] args)
    {
        var config = RunspaceConfiguration.Create();
        ConsoleShell.Start(config, "", "", args);
    }
}

【问题讨论】:

    标签: c# multithreading winapi console-application


    【解决方案1】:

    通常不会在控制台应用程序中完成。如果您尝试使用 Win32 GUI API,我怀疑您确实应该运行消息循环。

    您可以从控制台应用程序调用Application.Run()Application.Run(ApplicationContext) 来启动新的消息循环。这个想法是然后使用SynchronizationContext.Current 编组回主线程。但是,我还没有设法让它工作......你需要以某种方式强制它注册它的消息循环作为当前同步上下文,我还没有设法说服它这样做:(

    【讨论】:

      【解决方案2】:

      我在考虑 backgroundworker,但由于您没有 UI 线程,这是不可能的 (see this question)

      使用信号量的“经典”线程方法应该可以工作。使用线程安全队列或集合来存储事件,并通过同步对象通知主线程有工作要做。

      【讨论】:

        【解决方案3】:

        正如documentation on MSDN 所说:

        在以下情况下该函数会失败:

        • [...]
        • 如果线程不拥有窗口。 [...]

        所以这里不存在有问题的“主”线程(AFAIK Win32Api 不关心执行程序入口点的女巫线程)。

        唯一的条件是您必须在拥有您正在制作动画的窗口的线程上执行 AnimateWindow。那就是调用 CreateWindow 的那个,因为它是定义线程/消息循环 afinity 的函数。

        • 大多数时候,正如 Jon 所说,该线程应该运行由 Application.Run 创建的消息循环。
          从另一个线程,您可以使用 Control.Invoke 方法强制主线程执行代码。如果您没有 Control 引用,只需在主线程中创建一个并调用它的 CreateHandle 方法。如果你有一个主窗体就用它
        • 消息循环也可以用老式方法创建,特别是如果您已经通过 PInvoke 创建了窗口。主线程应该有一个标准的PeekMessage 循环,至少等待您定义的 WM_QUIT 和 WM_EXECUTE_ANIMATE_WINDOW。通过 PostMessage 或 PostThreadMessage 发布此消息的辅助线程。

        既然您已经发布了您的示例代码,那么您将遇到的问题是您并没有尝试为任何窗口设置动画...但是您正在尝试为控制台窗口本身设置动画...而您不是t 在它的所有者线程上(否则当您在应用程序中创建无限循环时它不会刷新)...所以调用 AnimateWindow 是不可能的,除非您设法强制窗口在该线程上执行代码。

        事实上,控制台窗口归 CSRSS 所有,女巫是一个以提升的权限执行的系统进程,无论如何弄乱它们真的很危险。

        由于windows vista,由于进程保护,甚至不可能向此类窗口发送消息,因此以前可以利用来强制该线程执行代码的任何漏洞现在都应该不可用了。

        有关控制台窗口特殊性的详细信息,请参阅 Raymond Chen 博客上的 Why aren't console windows themed on Windows XP? 帖子(来自 microsoft windows shell 团队,因此它几乎来自源代码)

        【讨论】:

        • 我知道它并不真正关心主线程。由于它是控制台应用程序,因此窗口由主应用程序线程创建。所以,我只是这么说,因为它是我需要调用我的代表的那个。有意义吗?
        • 它不是来自不同的程序。这是同一个应用程序......我只需要让委托在正确的线程上执行。听起来 PeekMessage 可能会起作用。我去看看,谢谢
        • 我添加了有关我的解决方案的详细信息,但是对于您的示例,您似乎尝试做的事情看起来不可能,我在帖子中解释了原因。
        • 是的,实际上,当我找到问题的解决方案后,我自己才意识到这一点。哦,好吧,看起来我想做的事情无法完成。感谢您的帮助
        • 附带说明,为什么我可以调用 SetWindowPos 但不能调用 AnimateWindow?似乎一个并不比另一个更安全。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多