如何查找已注册消息的名称?
发表于:
2023-10-22 20:00
3701
TL;DR
在 Windows
中,通过 RegisterWindowMessage() 注册的消息,其消息 ID
在 0xC000 ~ 0xFFFF
之间。可以使用 GetClipboardFormatName() 根据消息 ID
反向查找已注册消息的名称。
缘起
前一阵子,我在学习 c#
中的 async/await
工作机制时遇到了一个有趣的现象 —— 在下列代码片段中,await
后面的代码是在 UI
线程执行的,不论执行多少次,都是在 UI
线程中执行的。
1
2
3
4
5
6
private
async
void
Button2_Click(
object
sender, EventArgs e)
{
Debug.WriteLine(
string
.Format(
"Btn Click Begin(), in thread {0}"
, Thread.CurrentThread.ManagedThreadId));
await Task.Delay(10000);
Debug.WriteLine(
string
.Format(
"Btn Click End(), in thread {0}"
, Thread.CurrentThread.ManagedThreadId));
}
如果把 Button2_Click
中的三行代码放到控制台程序中,await
后面的代码会在哪个线程执行,是不确定的,很有可能与 await
前面的那行代码不在同一个线程中。
await
后面的代码会在哪个线程中执行,情况非常复杂,不在本文讨论范围。
那么问题来了,为什么 await
后面的代码可以在 UI
线程执行呢?或者说是怎么做到的呢?
查看调用栈
通过下图中的调用栈可以猜测,await
后面的代码能在 UI
线程执行是通过消息机制实现的。 而且根据上图中调用栈信息可知,这是一个已注册的消息,因为消息 ID
为0xc396
,位于0xC000 ~ 0xFFFF
的范围内。根据 MSDN 文档 可知,这个消息是通过 RegisterWindowMessage()
注册的。
1
The system returns a message identifier
in
the
range
0xC000
through
0xFFFF
when an application calls the RegisterWindowMessage function to register a message. The message identifier returned by this function
is
guaranteed to be unique throughout the system. Use of this function prevents conflicts that can arise
if
other applications use the same message identifier
for
different purposes.
那么本文的重点来了,这个注册的消息对应的名字是什么?因为数字对我们来说是冰冷的,无意义的,名字才是有意义的。
注册消息的名字
在 google
中输入 get registered message name
,第一条记录是 stackoverflow
上的一篇文章 ,里面介绍了可以通过 GetClipboardFormatName() 来根据消息 ID
获取对应的消息名字。这是因为操作系统内部将已注册的消息视为剪贴板格式,并且 GetClipboardFormatName()
函数可以根据特定格式获取名称。
测试代码
以下是使用 C#
编写的获取注册消息名称的示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[DllImport(
"user32.dll"
)]
static
extern
int
GetClipboardFormatName(
int
format, StringBuilder lpszFormatName,
int
cchMaxCount);
public
static
string
GetRegisteredMessageName(
int
msg)
{
var
sb =
new
StringBuilder(256);
GetClipboardFormatName(msg, sb, sb.Capacity);
return
sb.ToString();
}
static
void
Main(
string
[] args)
{
try
{
int
msgId = Convert.ToInt32(args[0], 16);
Console.WriteLine(
string
.Format(
"MsgName: {0}"
, GetRegisteredMessageName(msgId)));
}
catch
(Exception)
{
Console.WriteLine(
"Usage: GetRegisteredMessageName 0xc001"
);
}
}
希望本篇文章可以帮助您了解如何查找已注册消息的名称。
总结
await
后面的代码执行在哪个线程中是不确定的,写代码的时候要注意线程相关问题。
可以使用 GetClipboardFormatName()
获取注册的消息名称。
参考资料
https://stackoverflow.com/questions/40417023/get-name-of-message-registered-by-registerwindowmessage
https://linux.m2osw.com/recover-name-message-registered-registerwindowmessage
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2023-10-24 13:21
被编程难编辑
,原因: 上传图片