C# CoWaitForMultipleHandles API不';不要表现得像文件所记载的那样
这是由我看到的触发的。这本书可能太长了,所以请耐心听我说 显然,其行为与MSDN上的记录不符。 下面的代码(基于原始问题)是一个控制台应用程序,它使用测试Win32窗口启动STA线程,并尝试post和发送一些消息。它对C# CoWaitForMultipleHandles API不';不要表现得像文件所记载的那样,c#,.net,windows,winapi,com,C#,.net,Windows,Winapi,Com,这是由我看到的触发的。这本书可能太长了,所以请耐心听我说 显然,其行为与MSDN上的记录不符。 下面的代码(基于原始问题)是一个控制台应用程序,它使用测试Win32窗口启动STA线程,并尝试post和发送一些消息。它对CoWaitForMultipleHandles执行三种不同的测试,所有测试都不带COWAIT_WAITALL标志 测试#1旨在验证: COWAIT\u INPUTAVAILABLE如果设置,对CoWaitForMultipleHandles的调用将处理 如果队列存在输入,则返回S
CoWaitForMultipleHandles
执行三种不同的测试,所有测试都不带COWAIT_WAITALL
标志
测试#1旨在验证:
COWAIT\u INPUTAVAILABLE如果设置,对CoWaitForMultipleHandles的调用将处理
如果队列存在输入,则返回S_OK,即使输入已存在
已使用调用另一个函数看到(但未删除),例如
偷看消息
这种情况不会发生,CoWaitForMultipleHandles
阻塞,并且在发出等待句柄信号之前不会返回。我确实假设任何挂起的消息都应该被视为输入(与MsgWaitForMultipleObjectsEx
的MWMO\u INPUTAVAILABLE
相同,它可以按预期工作)
测试#2旨在验证:
COWAIT_DISPATCH_WINDOW_消息启用窗口消息的发送
来自ASTA或STA中的CoWaitForMultipleHandles。ASTA中的默认值是no
窗口消息已调度,STA中的默认值仅为一小部分
已发送特殊情况的消息。该值在MTA和中没有意义
被忽略了
这也不行。当仅使用COWAIT\u DISPATCH\u WINDOW\u MESSAGES
标志调用CoWaitForMultipleHandles
时,它会立即返回错误CO\u E\u NOT \u SUPPORTED
(0x80004021)。如果它是COWAIT\u DISPATCH\u WINDOW\u MESSAGES | COWAIT\u DISPATCH\u CALLS
的组合,则调用会阻塞,但不会输出任何消息。
Test#3演示了使调用线程的Windows消息队列运行的唯一方法。它是COWAIT_DISPATCH_WINDOW_MESSAGES | COWAIT_DISPATCH_CALLS | COWAIT_INPUTAVAILABLE
的组合虽然这显然是一种未记录的行为,但它确实会发送消息。
测试代码(准备运行的控制台应用程序):
使用系统;
使用System.Runtime.InteropServices;
使用系统线程;
使用System.Threading.Tasks;
名称空间控制台STAPP
{
静态类程序
{
//主要
静态void Main(字符串[]参数)
{
WriteLine(“启动STA线程…”);
RunStaThread();
Console.WriteLine(“\nSTA线程已完成”);
控制台。WriteLine(“按Enter键退出”);
Console.ReadLine();
}
//启动并运行STA线程
静态void RunStaThread()
{
变量线程=新线程(()=>
{
//创建一个简单的Win32窗口
IntPtr hwnd=CreateTestWindow();
//发布一些WM_测试消息
WriteLine(“发布一些WM_测试消息…”);
NativeMethods.PostMessage(hwnd,NativeMethods.WM_测试,新IntPtr(1),IntPtr.Zero);
NativeMethods.PostMessage(hwnd,NativeMethods.WM_测试,新IntPtr(2),IntPtr.Zero);
NativeMethods.PostMessage(hwnd,NativeMethods.WM_测试,新IntPtr(3),IntPtr.Zero);
//测试#1
Console.WriteLine(“\nTest#1.CoWaitForMultipleHandles,仅可输入COWAIT#U,按Enter键停止…”);
var task=ReadLineAsync();
uint指数;
var result=NativeMethods.CoWaitForMultipleHandles(
NativeMethods.COWAIT_可输入,
NativeMethods.INFINITE,
1,新[]{task.AsUnmanagedHandle()},
指数);
WriteLine(“结果:“+Result+”,队列中挂起的消息:”+(NativeMethods.GetQueueStatus(0x1FF)>>16!=0));
//测试#2
Console.WriteLine(\nTest#2.CoWaitForMultipleHandles与COWAIT(发送)窗口(发送)消息| COWAIT(发送)呼叫,按回车键停止));
task=ReadLineAsync();
结果=NativeMethods.CoWaitForMultipleHandles(
NativeMethods.COWAIT_调度_窗口_消息|
NativeMethods.COWAIT_调度_调用,
NativeMethods.INFINITE,
1,新[]{task.AsUnmanagedHandle()},
指数);
WriteLine(“结果:“+Result+”,队列中挂起的消息:”+(NativeMethods.GetQueueStatus(0x1FF)>>16!=0));
//测试#3
Console.WriteLine(\nTest#3.CoWaitForMultipleHandles,带有COWAIT_DISPATCH_WINDOW_消息| COWAIT_DISPATCH_CALLS | COWAIT_INPUTAVAILABLE,按Enter键停止…);
task=ReadLineAsync();
结果=NativeMethods.CoWaitForMultipleHandles(
NativeMethods.COWAIT_调度_窗口_消息|
NativeMethods.COWAIT_调度_调用|
NativeMethods.COWAIT_可输入,
NativeMethods.INFINITE,
1,新[]{task.AsUnmanagedHandle()},
指数);
WriteLine(“结果:“+Result+”,队列中挂起的消息:”+(NativeMethods.GetQueueStatus(0x1FF)>>16!=0));
});
SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
}
//
//助手
//
//创建一个窗口来处理消息
静态IntPtr CreateTestWindow()
{
//创建一个简单的Win32窗口
var hwndStatic=NativeMethods.CreateWindowEx(0,“Sta
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: True
Test #2. CoWaitForMultipleHandles with COWAIT_DISPATCH_WINDOW_MESSAGES | COWAIT_DISPATCH_CALLS, press Enter to stop...
Result: 0, pending messages in the queue: True
Test #3. CoWaitForMultipleHandles with COWAIT_DISPATCH_WINDOW_MESSAGES | COWAIT_DISPATCH_CALLS | COWAIT_INPUTAVAILABLE, press Enter to stop...
WM_TEST processed: 1
WM_TEST processed: 2
WM_TEST processed: 3
Result: 0, pending messages in the queue: False
STA thread finished.
Press Enter to exit.