- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
这是由 another question 触发的我在看。阅读时间可能太长,请耐心等待。
显然,CoWaitForMultipleHandles
不的行为与 MSDN 上记录的一样。
下面的代码(基于原始问题)是一个控制台应用程序,它使用测试 Win32 窗口启动 STA 线程并尝试发布和发送一些消息。它对 CoWaitForMultipleHandles
进行三种不同的测试,所有测试都没有 COWAIT_WAITALL
标志。
测试 #1 旨在验证 this :
COWAIT_INPUTAVAILABLE If set, the call to CoWaitForMultipleHandles will return S_OK if input exists for the queue, even if the input has been seen (but not removed) using a call to another function, such as PeekMessage.
这不会发生,CoWaitForMultipleHandles
会阻塞并且不会返回,直到等待句柄发出信号。我确实假设任何未决消息都应被视为输入(与 MsgWaitForMultipleObjectsEx
的 MWMO_INPUTAVAILABLE
相同,它按预期工作)。
测试 #2 旨在验证 this :
COWAIT_DISPATCH_WINDOW_MESSAGES Enables dispatch of window messages from CoWaitForMultipleHandles in an ASTA or STA. Default in ASTA is no window messages dispatched, default in STA is only a small set of special-cased messages dispatched. The value has no meaning in MTA and is ignored.
这也行不通。当单独使用 COWAIT_DISPATCH_WINDOW_MESSAGES
标志调用 CoWaitForMultipleHandles
时,它会立即返回错误 CO_E_NOT_SUPPORTED
(0x80004021)。如果它是 COWAIT_DISPATCH_WINDOW_MESSAGES | 的组合COWAIT_DISPATCH_CALLS
,调用会阻塞但不会发送任何消息。
测试 #3 演示了我可以使 CoWaitForMultipleHandles
抽取调用线程的 Windows 消息队列的唯一方法。它是 COWAIT_DISPATCH_WINDOW_MESSAGES | 的组合COWAIT_DISPATCH_CALLS | COWAIT_INPUTAVAILABLE
。 这确实会发送和发送消息,但显然这是一种未记录的行为。
测试代码(准备运行的控制台应用程序):
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleTestApp
{
static class Program
{
// Main
static void Main(string[] args)
{
Console.WriteLine("Starting an STA thread...");
RunStaThread();
Console.WriteLine("\nSTA thread finished.");
Console.WriteLine("Press Enter to exit.");
Console.ReadLine();
}
// start and run an STA thread
static void RunStaThread()
{
var thread = new Thread(() =>
{
// create a simple Win32 window
IntPtr hwnd = CreateTestWindow();
// Post some WM_TEST messages
Console.WriteLine("Post some WM_TEST messages...");
NativeMethods.PostMessage(hwnd, NativeMethods.WM_TEST, new IntPtr(1), IntPtr.Zero);
NativeMethods.PostMessage(hwnd, NativeMethods.WM_TEST, new IntPtr(2), IntPtr.Zero);
NativeMethods.PostMessage(hwnd, NativeMethods.WM_TEST, new IntPtr(3), IntPtr.Zero);
// Test #1
Console.WriteLine("\nTest #1. CoWaitForMultipleHandles with COWAIT_INPUTAVAILABLE only, press Enter to stop...");
var task = ReadLineAsync();
uint index;
var result = NativeMethods.CoWaitForMultipleHandles(
NativeMethods.COWAIT_INPUTAVAILABLE,
NativeMethods.INFINITE,
1, new[] { task.AsUnmanagedHandle() },
out index);
Console.WriteLine("Result: " + result + ", pending messages in the queue: " + (NativeMethods.GetQueueStatus(0x1FF) >> 16 != 0));
// Test #2
Console.WriteLine("\nTest #2. CoWaitForMultipleHandles with COWAIT_DISPATCH_WINDOW_MESSAGES | COWAIT_DISPATCH_CALLS, press Enter to stop...");
task = ReadLineAsync();
result = NativeMethods.CoWaitForMultipleHandles(
NativeMethods.COWAIT_DISPATCH_WINDOW_MESSAGES |
NativeMethods.COWAIT_DISPATCH_CALLS,
NativeMethods.INFINITE,
1, new[] { task.AsUnmanagedHandle() },
out index);
Console.WriteLine("Result: " + result + ", pending messages in the queue: " + (NativeMethods.GetQueueStatus(0x1FF) >> 16 != 0));
// Test #3
Console.WriteLine("\nTest #3. CoWaitForMultipleHandles with COWAIT_DISPATCH_WINDOW_MESSAGES | COWAIT_DISPATCH_CALLS | COWAIT_INPUTAVAILABLE, press Enter to stop...");
task = ReadLineAsync();
result = NativeMethods.CoWaitForMultipleHandles(
NativeMethods.COWAIT_DISPATCH_WINDOW_MESSAGES |
NativeMethods.COWAIT_DISPATCH_CALLS |
NativeMethods.COWAIT_INPUTAVAILABLE,
NativeMethods.INFINITE,
1, new[] { task.AsUnmanagedHandle() },
out index);
Console.WriteLine("Result: " + result + ", pending messages in the queue: " + (NativeMethods.GetQueueStatus(0x1FF) >> 16 != 0));
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
}
//
// Helpers
//
// create a window to handle messages
static IntPtr CreateTestWindow()
{
// Create a simple Win32 window
var hwndStatic = NativeMethods.CreateWindowEx(0, "Static", String.Empty, NativeMethods.WS_POPUP,
0, 0, 0, 0, NativeMethods.HWND_MESSAGE, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
// subclass it with a custom WndProc
IntPtr prevWndProc = IntPtr.Zero;
NativeMethods.WndProc newWndProc = (hwnd, msg, wParam, lParam) =>
{
if (msg == NativeMethods.WM_TEST)
Console.WriteLine("WM_TEST processed: " + wParam);
return NativeMethods.CallWindowProc(prevWndProc, hwnd, msg, wParam, lParam);
};
prevWndProc = NativeMethods.SetWindowLong(hwndStatic, NativeMethods.GWL_WNDPROC,
Marshal.GetFunctionPointerForDelegate(newWndProc));
if (prevWndProc == IntPtr.Zero)
throw new ApplicationException();
return hwndStatic;
}
// call Console.ReadLine on a pool thread
static Task<string> ReadLineAsync()
{
return Task.Run(() => Console.ReadLine());
}
// get Win32 waitable handle of Task object
static IntPtr AsUnmanagedHandle(this Task task)
{
return ((IAsyncResult)task).AsyncWaitHandle.SafeWaitHandle.DangerousGetHandle();
}
}
// Interop
static class NativeMethods
{
[DllImport("user32")]
public static extern IntPtr SetWindowLong(IntPtr hwnd, int nIndex, IntPtr dwNewLong);
[DllImport("user32")]
public static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
public static extern IntPtr CreateWindowEx(
uint dwExStyle, string lpClassName, string lpWindowName, uint dwStyle,
int x, int y, int nWidth, int nHeight,
IntPtr hWndParent, IntPtr hMenu, IntPtr hInstance, IntPtr lpParam);
[DllImport("user32.dll")]
public static extern bool PostMessage(IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
public static extern int MessageBox(IntPtr hwnd, string text, String caption, int options);
[DllImport("ole32.dll", SetLastError = true)]
public static extern uint CoWaitForMultipleHandles(uint dwFlags, uint dwTimeout,
int cHandles, IntPtr[] pHandles, out uint lpdwindex);
[DllImport("user32.dll")]
public static extern uint GetQueueStatus(uint flags);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate IntPtr WndProc(IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam);
public static IntPtr HWND_MESSAGE = new IntPtr(-3);
public const int GWL_WNDPROC = -4;
public const uint WS_POPUP = 0x80000000;
public const uint WM_USER = 0x0400;
public const uint WM_TEST = WM_USER + 1;
public const uint COWAIT_WAITALL = 1;
public const uint COWAIT_ALERTABLE = 2;
public const uint COWAIT_INPUTAVAILABLE = 4;
public const uint COWAIT_DISPATCH_CALLS = 8;
public const uint COWAIT_DISPATCH_WINDOW_MESSAGES = 0x10;
public const uint RPC_S_CALLPENDING = 0x80010115;
public const uint WAIT_TIMEOUT = 0x00000102;
public const uint WAIT_FAILED = 0xFFFFFFFF;
public const uint WAIT_OBJECT_0 = 0;
public const uint WAIT_ABANDONED_0 = 0x00000080;
public const uint WAIT_IO_COMPLETION = 0x000000C0;
public const uint INFINITE = 0xFFFFFFFF;
}
}
输出:
Starting an STA thread...Post some WM_TEST messages...Test #1. CoWaitForMultipleHandles with COWAIT_INPUTAVAILABLE only, press Enter to stop...Result: 0, pending messages in the queue: TrueTest #2. CoWaitForMultipleHandles with COWAIT_DISPATCH_WINDOW_MESSAGES | COWAIT_DISPATCH_CALLS, press Enter to stop...Result: 0, pending messages in the queue: TrueTest #3. CoWaitForMultipleHandles with COWAIT_DISPATCH_WINDOW_MESSAGES | COWAIT_DISPATCH_CALLS | COWAIT_INPUTAVAILABLE, press Enter to stop...WM_TEST processed: 1WM_TEST processed: 2WM_TEST processed: 3Result: 0, pending messages in the queue: FalseSTA thread finished.Press Enter to exit.
所有测试均在 Windows 8.1 Pro 64bit + NET v4.5.1 下完成。
我是不是误读了文档或遗漏了其他内容?
我应该将此报告为错误(至少,文档中的错误)吗?
是否应该避免 CoWaitForMultipleHandles
并替换为基于 MsgWaitForMultipleObjectsEx
的解决方案(其行为与文档一致)?
[UPDATE] 在 Windows 7 下,COWAIT_DISPATCH_WINDOW_MESSAGES
和 COWAIT_DISPATCH_CALLS
均不受支持,CoWaitForMultipleHandles
失败并返回 E_INVALIDARG
(0x80070057)。当以零作为标志调用时,它会在不抽取的情况下阻塞。
最佳答案
CoWaitForMultipleHandles
用于在 STA 中处理 COM 窗口消息(例如跨公寓编码)和其他一些消息(不要问我是哪个),或者只是在 MTA 中阻塞。在 this blog post, «Managed blocking» by Chris Brumme ,它说 CWFMH
处理“恰到好处”的窗口消息。但是,由于它在队列中留下任何非 COM 发布的窗口消息,队列可能仍会填满,只是不会填满 COM 窗口消息。
根据 this document, «Migrating your Windows 8 Consumer Preview app to Windows 8 Release Preview» ,它说:
CoWaitForMultipleHandles function is no longer supported in Windows Store apps. In addition the following CoWait_Flags have been removed:
COWAIT_DISPATCH_CALLS
COWAIT_DISPATCH_WINDOW_MESSAGES
如果你真的想处理所有消息,你应该在消息循环中使用 MsgWaitForMultipleObjectsEx
和 GetMessage
或者 PeekMessage
和 PM_REMOVE
。这样做意味着潜在的重入狂潮。您仍然无法控制堆栈中其他组件对 STA 的进一步调用。也就是说,模态对话框(例如打开的通用对话框)可能会在普通的旧窗口消息循环中抽取每条消息,但某些框架可能会调用 CoWaitForMultipleHandles
。
底线是,如果您正在进行密集处理或阻塞操作,请将其委托(delegate)给另一个线程(可能使用队列),并在需要时告诉调用 UI 线程在操作完成后进行更新。
这不同于例如冗长的 UI 调用,例如 OLE 嵌入或模态对话框,其中通常在堆栈的某处有一个窗口消息循环。或者从冗长但可分块/可恢复的操作(例如状态机)中,您可以通过偶尔处理消息进行合作,或者使用在有消息时返回的等待函数,以便您可以在再次等待之前处理它们。
小心,这只适用于一个 handle ;对于多个 handle ,例如互斥体,你想要全部或没有,下一个最好的方法是一个主动循环,超时调用 WaitForMultipleObjects
然后是 PeekMessage
和 PM_REMOVE
窗口消息循环。这是一个边界线案例,对于作为用户关注中心的 UI 应用程序来说是可以接受的(例如,这是他们的主要工作),但如果此类代码可能在无人值守和按需运行时是 Not Acceptable 。除非您确定它需要在 STA 或 UI 线程中发生,否则我的建议是不要这样做。
最后,您可能应该在 Microsoft Connect 上打开一个错误,至少要更新文档。或者实际上让它按“预期”工作。
关于c# - CoWaitForMultipleHandles API 的行为与记录不符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21226600/
我有一个网站。 必须登录才能看到里面的内容。 但是,我使用此代码登录。 doc = Jsoup.connect("http://46.137.207.181/Account/Login.aspx")
我正在尝试为我的域创建一个 SPF 记录并使我的邮件服务器能够对其进行评估。我在邮件服务器上使用 Postfix 并使用 policyd-spf (Python) 来评估记录。目前,我通过我的私有(p
我需要为负载平衡的 AWS 站点 mywebsite.com 添加 CName 记录。记录应该是: @ CNAME mywebsite.us-east-1.elb.amazon
我目前正在开发一个相当大的多层应用程序,该应用程序将部署在海外。虽然我希望它在解聚后不会折叠或爆炸,但我不能 100% 确定这一点。因此,如果我知道我可以请求日志文件,以准确找出问题所在以及原因,那就
我使用以下命令从我的网络摄像头录制音频和视频 gst-launch-0.10 v4l2src ! video/x-raw-yuv,width=640,height=480,framerate=30/1
我刚刚开始使用 ffmpeg 将视频分割成图像。我想知道是否可以将控制台输出信息保存到日志文件中。我试过“-v 10”参数,也试过“-loglevel”参数。我在另一个 SO 帖子上看到使用 ffmp
我想针对两个日期查询我的表并检索其中的记录。 我这样声明我的变量; DECLARE @StartDate datetime; DECLARE @EndDate datetime; 并像这样设置我的变量
在 javascript 中,我可以使用简单的 for 循环访问对象的每个属性,如下所示 var myObj = {x:1, y:2}; var i, sum=0; for(i in myObj) s
最近加入了一个需要处理大量代码的项目,我想开始记录和可视化调用图的一些流程,让我更好地理解一切是如何组合在一起的。这是我希望在我的理想工具中看到的: 每个节点都是一个函数/方法 如果一个函数可以调用另
如何使用反射在F#中创建记录类型?谢谢 最佳答案 您可以使用 FSharpValue.MakeRecord [MSDN]创建一个记录实例,但是我认为F#中没有任何定义记录类型的东西。但是,记录会编译为
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 3年前关闭。 Improve thi
我是 Sequelize 的新手并且遇到了一些语法问题。我制作了以下模型: // User sequelize.define('user', { name: { type: DataTyp
${student.name} Notify 这是我的output.jsp。请注意,我已经放置了一个链接“Notify”以将其转发到 display.jsp 上。但我不确定如何将 Stud
例如,这是我要做的查询: server:"xxx.xxx.com" AND request_url:"/xxx/xxx/xxx" AND http_X_Forwarded_Proto:(https O
我一直在开发大量 Java、PHP 和 Python。所有这些都提供了很棒的日志记录包(分别是 Log4J、Log 或logging)。这在调试应用程序时有很大帮助。特别是当应用程序 headless
在我的Grails应用程序中,我异步运行一些批处理过程,并希望该过程记录各种状态消息,以便管理员以后可以检查它们。 我考虑过将log4j JDBC附加程序用作最简单的解决方案,但是据我所知,它不使用D
我想将进入 MQ 队列的消息记录到数据库/文件或其他日志队列,并且我无法修改现有代码。是否有任何方法可以实现某种类似于 HTTP 嗅探器的消息记录实用程序?或者也许 MQ 有一些内置的功能来记录消息?
如果我有一条包含通用字段的记录,在更改通用字段时是否有任何方法可以模仿方便的 with 语法? 即如果我有 type User = // 'photo can be Bitmap or Url {
假设我有一个名为 Car 的自定义对象。其中的所有字段都是私有(private)的。 public class Car { private String mName; private
当记录具有特定字段时,我需要返回 true 的函数,反之亦然。示例: -record(robot, {name, type=industrial, ho
我是一名优秀的程序员,十分优秀!