封送消息 table 资源
Marshaling a message table resource
我需要阅读 C# 中的消息 Table 资源。
我基本上是在尝试将这个问题的答案中的代码移植到 C#:Listing message IDs and symbolic names stored in a resource-only library (DLL) using Win32 API
我的问题是我无法正确编组 MESSAGE_RESOURCE_DATA
和 MESSAGE_RESOURCE_BLOCK
结构,它们的定义如下(在 <winnt.h>
中):
typedef struct _MESSAGE_RESOURCE_BLOCK {
DWORD LowId;
DWORD HighId;
DWORD OffsetToEntries;
} MESSAGE_RESOURCE_BLOCK, *PMESSAGE_RESOURCE_BLOCK;
typedef struct _MESSAGE_RESOURCE_DATA {
DWORD NumberOfBlocks;
MESSAGE_RESOURCE_BLOCK Blocks[ 1 ];
} MESSAGE_RESOURCE_DATA, *PMESSAGE_RESOURCE_DATA;
在MESSAGE_RESOURCE_DATA
中,NumberOfBlocks
是Blocks
数组中MESSAGE_RESOURCE_BLOCK
条目的数量(即使它被声明为具有单个元素的数组)。
因为我在编译时不知道数组大小,所以我尝试编组声明 Blocks
为指针的结构,然后像这样使用 Marshal.PtrToStructure
:
using System;
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
struct MESSAGE_RESOURCE_BLOCK {
public IntPtr LowId;
public IntPtr HighId;
public IntPtr OffsetToEntries;
}
[StructLayout(LayoutKind.Sequential)]
struct MESSAGE_RESOURCE_DATA {
public IntPtr NumberOfBlocks;
public IntPtr Blocks;
}
class Program {
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr LoadLibrary(string fileName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr FindResource(IntPtr hModule, int lpID, int lpType);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr LoadResource(IntPtr hModule, IntPtr hResInfo);
[DllImport("kernel32.dll")]
public static extern IntPtr LockResource(IntPtr hResData);
static void Main(string[] args) {
const int RT_MESSAGETABLE = 11;
IntPtr hModule = LoadLibrary(@"C:\WINDOWS\system32\msobjs.dll");
IntPtr msgTableInfo = FindResource(hModule, 1, RT_MESSAGETABLE);
IntPtr msgTable = LoadResource(hModule, msgTableInfo);
var data = Marshal.PtrToStructure<MESSAGE_RESOURCE_DATA>(LockResource(msgTable));
int blockSize = Marshal.SizeOf<MESSAGE_RESOURCE_BLOCK>();
for (int i = 0; i < data.NumberOfBlocks.ToInt32(); i++) {
IntPtr blockPtr = IntPtr.Add(data.Blocks, blockSize * i);
// the following line causes an access violation
var block = Marshal.PtrToStructure<MESSAGE_RESOURCE_BLOCK>(blockPtr);
}
}
}
但是,这不起作用,我遇到了访问冲突错误。
如何整理这样的结构?
你没有关闭,这些结构不包含 IntPtr。 DWORD 是一个 32 位整数。资源格式中使用的可变长度结构在 C# 中非常尴尬,没有像样的方法来声明它们。最好的办法是使用 Marshal.ReadXxx() 来读取字段。
唯一仍然有用的结构声明是:
[StructLayout(LayoutKind.Sequential)]
struct MESSAGE_RESOURCE_BLOCK {
public int LowId;
public int HighId;
public int OffsetToEntries;
}
然后你就这样一决高下:
static void Main(string[] args) {
const int RT_MESSAGETABLE = 11;
IntPtr hModule = LoadLibrary(@"C:\WINDOWS\system32\msobjs.dll");
IntPtr msgTableInfo = FindResource(hModule, 1, RT_MESSAGETABLE);
IntPtr msgTable = LoadResource(hModule, msgTableInfo);
IntPtr memTable = LockResource(msgTable);
int numberOfBlocks = Marshal.ReadInt32(memTable);
IntPtr blockPtr = IntPtr.Add(memTable, 4);
int blockSize = Marshal.SizeOf<MESSAGE_RESOURCE_BLOCK>();
for (int i = 0; i < numberOfBlocks; i++) {
var block = Marshal.PtrToStructure<MESSAGE_RESOURCE_BLOCK>(blockPtr);
IntPtr entryPtr = IntPtr.Add(memTable, block.OffsetToEntries);
for (int id = block.LowId; id <= block.HighId; id++) {
var length = Marshal.ReadInt16(entryPtr);
var flags = Marshal.ReadInt16(entryPtr, 2);
var textPtr = IntPtr.Add(entryPtr, 4);
var text = "Bad flags??";
if (flags == 0) {
text = Marshal.PtrToStringAnsi(textPtr);
}
else if (flags == 1) {
text = Marshal.PtrToStringUni(textPtr);
}
text = text.Replace("\r\n", "");
Console.WriteLine("{0} : {1}", id, text);
entryPtr = IntPtr.Add(entryPtr, length);
}
blockPtr = IntPtr.Add(blockPtr, blockSize);
}
}
32 位和 64 位模式下的输出:
279 : Undefined Access (no effect) Bit 7
1536 : Unused message ID
1537 : DELETE
1538 : READ_CONTROL
1539 : WRITE_DAC
1540 : WRITE_OWNER
1541 : SYNCHRONIZE
1542 : ACCESS_SYS_SEC
1543 : MAX_ALLOWED
1552 : Unknown specific access (bit 0)
1553 : Unknown specific access (bit 1)
1554 : Unknown specific access (bit 2)
1555 : Unknown specific access (bit 3)
1556 : Unknown specific access (bit 4)
1557 : Unknown specific access (bit 5)
...etc...
请记住,当您在 32 位模式下对 运行 程序使用抖动强制时,您将不会读取您认为的文件。文件系统重定向器会让您改为读取 C:\WINDOWS\SysWow64\msobjs.dll。
我需要阅读 C# 中的消息 Table 资源。
我基本上是在尝试将这个问题的答案中的代码移植到 C#:Listing message IDs and symbolic names stored in a resource-only library (DLL) using Win32 API
我的问题是我无法正确编组 MESSAGE_RESOURCE_DATA
和 MESSAGE_RESOURCE_BLOCK
结构,它们的定义如下(在 <winnt.h>
中):
typedef struct _MESSAGE_RESOURCE_BLOCK {
DWORD LowId;
DWORD HighId;
DWORD OffsetToEntries;
} MESSAGE_RESOURCE_BLOCK, *PMESSAGE_RESOURCE_BLOCK;
typedef struct _MESSAGE_RESOURCE_DATA {
DWORD NumberOfBlocks;
MESSAGE_RESOURCE_BLOCK Blocks[ 1 ];
} MESSAGE_RESOURCE_DATA, *PMESSAGE_RESOURCE_DATA;
在MESSAGE_RESOURCE_DATA
中,NumberOfBlocks
是Blocks
数组中MESSAGE_RESOURCE_BLOCK
条目的数量(即使它被声明为具有单个元素的数组)。
因为我在编译时不知道数组大小,所以我尝试编组声明 Blocks
为指针的结构,然后像这样使用 Marshal.PtrToStructure
:
using System;
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
struct MESSAGE_RESOURCE_BLOCK {
public IntPtr LowId;
public IntPtr HighId;
public IntPtr OffsetToEntries;
}
[StructLayout(LayoutKind.Sequential)]
struct MESSAGE_RESOURCE_DATA {
public IntPtr NumberOfBlocks;
public IntPtr Blocks;
}
class Program {
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr LoadLibrary(string fileName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr FindResource(IntPtr hModule, int lpID, int lpType);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr LoadResource(IntPtr hModule, IntPtr hResInfo);
[DllImport("kernel32.dll")]
public static extern IntPtr LockResource(IntPtr hResData);
static void Main(string[] args) {
const int RT_MESSAGETABLE = 11;
IntPtr hModule = LoadLibrary(@"C:\WINDOWS\system32\msobjs.dll");
IntPtr msgTableInfo = FindResource(hModule, 1, RT_MESSAGETABLE);
IntPtr msgTable = LoadResource(hModule, msgTableInfo);
var data = Marshal.PtrToStructure<MESSAGE_RESOURCE_DATA>(LockResource(msgTable));
int blockSize = Marshal.SizeOf<MESSAGE_RESOURCE_BLOCK>();
for (int i = 0; i < data.NumberOfBlocks.ToInt32(); i++) {
IntPtr blockPtr = IntPtr.Add(data.Blocks, blockSize * i);
// the following line causes an access violation
var block = Marshal.PtrToStructure<MESSAGE_RESOURCE_BLOCK>(blockPtr);
}
}
}
但是,这不起作用,我遇到了访问冲突错误。
如何整理这样的结构?
你没有关闭,这些结构不包含 IntPtr。 DWORD 是一个 32 位整数。资源格式中使用的可变长度结构在 C# 中非常尴尬,没有像样的方法来声明它们。最好的办法是使用 Marshal.ReadXxx() 来读取字段。
唯一仍然有用的结构声明是:
[StructLayout(LayoutKind.Sequential)]
struct MESSAGE_RESOURCE_BLOCK {
public int LowId;
public int HighId;
public int OffsetToEntries;
}
然后你就这样一决高下:
static void Main(string[] args) {
const int RT_MESSAGETABLE = 11;
IntPtr hModule = LoadLibrary(@"C:\WINDOWS\system32\msobjs.dll");
IntPtr msgTableInfo = FindResource(hModule, 1, RT_MESSAGETABLE);
IntPtr msgTable = LoadResource(hModule, msgTableInfo);
IntPtr memTable = LockResource(msgTable);
int numberOfBlocks = Marshal.ReadInt32(memTable);
IntPtr blockPtr = IntPtr.Add(memTable, 4);
int blockSize = Marshal.SizeOf<MESSAGE_RESOURCE_BLOCK>();
for (int i = 0; i < numberOfBlocks; i++) {
var block = Marshal.PtrToStructure<MESSAGE_RESOURCE_BLOCK>(blockPtr);
IntPtr entryPtr = IntPtr.Add(memTable, block.OffsetToEntries);
for (int id = block.LowId; id <= block.HighId; id++) {
var length = Marshal.ReadInt16(entryPtr);
var flags = Marshal.ReadInt16(entryPtr, 2);
var textPtr = IntPtr.Add(entryPtr, 4);
var text = "Bad flags??";
if (flags == 0) {
text = Marshal.PtrToStringAnsi(textPtr);
}
else if (flags == 1) {
text = Marshal.PtrToStringUni(textPtr);
}
text = text.Replace("\r\n", "");
Console.WriteLine("{0} : {1}", id, text);
entryPtr = IntPtr.Add(entryPtr, length);
}
blockPtr = IntPtr.Add(blockPtr, blockSize);
}
}
32 位和 64 位模式下的输出:
279 : Undefined Access (no effect) Bit 7
1536 : Unused message ID
1537 : DELETE
1538 : READ_CONTROL
1539 : WRITE_DAC
1540 : WRITE_OWNER
1541 : SYNCHRONIZE
1542 : ACCESS_SYS_SEC
1543 : MAX_ALLOWED
1552 : Unknown specific access (bit 0)
1553 : Unknown specific access (bit 1)
1554 : Unknown specific access (bit 2)
1555 : Unknown specific access (bit 3)
1556 : Unknown specific access (bit 4)
1557 : Unknown specific access (bit 5)
...etc...
请记住,当您在 32 位模式下对 运行 程序使用抖动强制时,您将不会读取您认为的文件。文件系统重定向器会让您改为读取 C:\WINDOWS\SysWow64\msobjs.dll。