在非托管主机下的托管组件中获取一部分空闲处理

2024-04-23

我有一个用 C# 编写的托管组件,它由旧版 Win32 应用程序作为 ActiveX 控件托管。在我的组件内部,我需要能够获得通常情况下的内容Application.Idle http://msdn.microsoft.com/en-us/library/system.windows.forms.application.idle%28v=vs.110%29.aspx事件,即获取 UI 线程上的空闲处理时间的时间片(必须是主 UI 线程)。

然而在这个托管场景中,Application.Idle不会被解雇,因为没有托管消息循环(即,没有Application.Run).

可悲的是,主机也没有实现IMsoComponentManager http://msdn.microsoft.com/en-us/library/office/ff518963(v=office.12).aspx,这可能适合我的需要。以及一个冗长的嵌套消息循环(带有Application.DoEvents) 出于许多充分的理由而不是一个选择。

到目前为止,我能想到的唯一解决方案是使用普通Win32 定时器 http://msdn.microsoft.com/en-us/library/windows/desktop/ms632592(v=vs.85).aspx。 据此(现已灭亡)MSKB 文章 https://web.archive.org/web/20130627005845/http://support.microsoft.com/kb/96006, WM_TIMER具有最低优先级之一,其次是WM_PAINT,这应该让我尽可能接近空闲状态。

对于这种情况,我是否缺少其他选项?

这是原型代码:

// Do the idle work in the async loop

while (true)
{
    token.ThrowIfCancellationRequested();

    // yield via a low-priority WM_TIMER message
    await TimerYield(DELAY, token); // e.g., DELAY = 50ms

    // check if there is a pending user input in Windows message queue
    if (Win32.GetQueueStatus(Win32.QS_KEY | Win32.QS_MOUSE) >> 16 != 0)
        continue;

    // do the next piece of the idle work on the UI thread
    // ...
}       

// ...
    
static async Task TimerYield(int delay, CancellationToken token) 
{
    // All input messages are processed before WM_TIMER and WM_PAINT messages.
    // System.Windows.Forms.Timer uses WM_TIMER 
    // This could be further improved to re-use the timer object

    var tcs = new TaskCompletionSource<bool>();
    using (var timer = new System.Windows.Forms.Timer())
    using (token.Register(() => tcs.TrySetCanceled(), useSynchronizationContext: true))
    {
        timer.Interval = delay;
        timer.Tick += (s, e) => tcs.TrySetResult(true);
        timer.Enabled = true;
        await tcs.Task;
        timer.Enabled = false;
    }
}

    

我不认为Task.Delay适合这种方法,因为它使用内核计时器对象,这些对象独立于消息循环及其优先级。

Updated,我又发现了一个选择:WH_FOREGROUNDIDLE/ForegroundIdleProc http://msdn.microsoft.com/en-us/library/windows/desktop/ms644980%28v=vs.85%29.aspx。看起来和我需要的一模一样。

Updated,我还发现了一个Win32计时器技巧is used http://referencesource.microsoft.com/#WindowsBase/src/Base/System/Windows/Threading/Dispatcher.cs#ad208569500b2a1d由 WPF 用于低优先级调度程序操作,即Dispatcher.BeginInvoke(DispatcherPriority.Background, ...):


Well, WH_FOREGROUNDIDLE/ForegroundIdleProc http://msdn.microsoft.com/en-us/library/windows/desktop/ms644980%28v=vs.85%29.aspx钩子很棒。它的行为方式非常类似于Application.Idle:当线程的消息队列为空并且底层消息循环的GetMessage呼叫即将进入阻塞等待状态。

然而,我忽略了一件重要的事情。事实证明,我正在处理的主机应用程序有自己的计时器,并且它的 UI 线程正在运行WM_TIMER不断且频繁地发送消息。如果我一开始就用 Spy++ 查看它,我就可以了解到这一点。

For ForegroundIdleProc(并且对于Application.Idle, 对于这个问题),WM_TIMER与任何其他消息没有什么不同。每个新的钩子都会被调用WM_TIMER已经被调度并且队列又变空了。这导致ForegroundIdleProc接到的电话比我真正需要的要多得多。

无论如何,尽管有外星人计时器消息,ForegroundIdleProc回调仍然表明线程队列中没有更多的用户输入消息(即键盘和鼠标空闲)。因此,我可以开始我的闲置工作并使用async/await,保持 UI 响应。这就是它与我最初的基于计时器的方法的不同之处。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在非托管主机下的托管组件中获取一部分空闲处理 的相关文章

  • Xamarin 中 QR 扫描后的处理对话框

    我在Xamarin应用程序中使用QR码扫描仪 当它扫描QR码时 它会执行一些操作 大约需要一分钟 而在执行操作时 我想在屏幕上显示一个加载对话框 但是 它没有显示在屏幕上 并且在应用程序的其他地方 它运行得很好 Code var expec
  • C 程序的“编译器正确”命令

    这是关于中提到的编译步骤Linux 期刊文章 https www linuxjournal com article 6463 C 程序是使用编译的cpp cc1 as and ld该文章中的命令 我能够执行这些步骤cpp as and ld
  • 如何在cmake中添加cuda源代码的定义

    我使用的是 Visual Studio 2013 Windows 10 CMake 3 5 1 一切都可以使用标准 C 正确编译 例如 CMakeLists txt project Test add definitions D WINDOW
  • 将 XML 转换为 JSON 时保留 json:Array 属性

    我有一段 XML 看起来像
  • Typescript,自动等待所有 Promise 返回函数调用

    我正在使用 async 函数 有时我忘记为内部调用添加 await async function doThreeSteps gt await firstPromiseReturningFunc nonAsyncFunction second
  • 编译使用Basler相机的程序

    我正在尝试使用 Basler 相机捕获图像的 C 程序来工作 我拿到 来自制造商的代码 它应该 非常容易使用 但是 链接它有 成为一场噩梦 我的 C 时代已经过去了 最近只使用 Matlab 所以我可能会犯一些愚蠢的错误 但请赐教 代码如下
  • C++ 标准是否保证未使用的私有字段会影响 sizeof?

    考虑以下结构 class Foo int a 在 g 中测试 我明白了sizeof Foo 4但这是由标准保证的吗 是否允许编译器注意到a是一个未使用的私有字段并将其从类的内存表示中删除 导致更小的 sizeof 我不希望任何编译器真正进行
  • 仅使用 url 嵌入视频

    给定一个 youtube url 我如何使用 net c 将视频嵌入到页面中 只需添加如下一行 将 autoplay 设置为 0 或 1 取决于您是否希望人们真正留在您的页面上
  • GoogleTest:如何跳过测试?

    使用 Google Test 1 6 Windows 7 Visual Studio C 如何关闭给定的测试 又名如何阻止测试运行 除了注释掉整个测试之外 我还能做些什么吗 The docs https github com google
  • 企业库 CacheFactory.GetCacheManager 抛出空引用

    我正在尝试将使用 1 1 版本的企业库缓存块的应用程序转换为 2 0 版本 我认为我真正遇到的问题是不同 EntLib 部分的配置被分成几个文件 显然 这曾经是由ConfigurationManager 部分处理程序 但现在已经过时 取而代
  • BackgroundWorker 如何决定在哪个线程上运行 RunWorkerCompleted 处理程序?

    我试图弄清楚 BGW 在工作完成后如何决定运行 RunWorkerCompleted 处理程序的线程 我的初始测试使用 WinForm 应用程序 在 UI 线程上 我开始bgw1 RunWorkerAsync 然后我尝试开始bgw2 Run
  • 制作 C# 项目 DLL 和 EXE

    我正在开发一个项目 需要有一个可执行文件以便用户可以运行配置界面和一个可以嵌入其他项目以使用其他一些功能的 DLL 有没有办法让 Visual Studio 同时生成可执行文件和 DLL 而不是每次都手动切换 我同意 TJMonk15 的观
  • LINQ 分组依据和选择集合

    我有这个结构 Customer has many Orders has many OrderItems 我想生成一个列表CustomerItems通过 LINQ 给出的子集OrderItems List of new Customer Li
  • HTTP 错误 500.35 - ANCM 同一进程中的多个进程内应用程序 ASP.NET Core 3

    从今天早上开始 没有对项目代码进行任何更改 一个非常简单的 Web API 一个控制器和 3 个方法 使用 Swagger 它不再启动 我收到错误 HTTP 错误 500 35 ANCM 同一进程中有多个进程内应用程序 事件查看器报告最无用
  • docs.microsoft.com 上的 .NET 平台扩展是什么?

    Microsoft Docs 中有一个框架级导航元素 称为 NET 平台扩展 https learn microsoft com en us dotnet api index view dotnet plat ext 2 1 它包含有关最近
  • 指针 (*argv[]) 的指针的指针算术?

    我知道foo bar 等于 foo bar 但是什么是 foo bar 等于 例如访问 argv 2 我对这一点的理解有些困惑 我认为可能是这样的 foo bar 但我不确定 如果这是一个简单的答案 我深表歉意 a b 相当于 a b 由于
  • 如何使用va_start()?

    在具有可变参数的函数中 我们使用函数 va start 初始化 va list ap 类型的对象 如下所示 void va start va list ap parmN 我不明白1 什么类型的对象可以作为 parMN 最后一个已知参数 传递
  • 制作一个未知大小的数组 C# [重复]

    这个问题在这里已经有答案了 可能的重复 C 中未知长度的数组 https stackoverflow com questions 599369 array of an unknown length in c sharp 我想创建一个程序 用
  • C# StreamReader 使用分隔符保存到数组

    我有一个文本文件 其中包含制表符分隔的数据 我在 C 应用程序中需要的是从文本文件中读取一行并将它们保存到一个数组中 在每个位置将它们分开 t 然后我对下一行做同样的事情 My code StreamReader sr new Stream
  • 实现“计时器”的最佳方法是什么? [复制]

    这个问题在这里已经有答案了 实现计时器的最佳方法是什么 代码示例会很棒 对于这个问题 最佳 被定义为最可靠 失火次数最少 和最精确 如果我指定 15 秒的间隔 我希望每 15 秒调用一次目标方法 而不是每 10 20 秒调用一次 另一方面

随机推荐