2015-11-03 74 views
3

我需要在C#中讀取消息表資源。封裝消息表資源

我基本上是試圖移植到C#代碼在回答這個問題:Listing message IDs and symbolic names stored in a resource-only library (DLL) using Win32 API

我的問題是,我不能正確封送MESSAGE_RESOURCE_DATAMESSAGE_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_DATANumberOfBlocksBlocks陣列(即使它被聲明爲具有單個元件的陣列)在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); 
     } 
    } 
} 

這不起作用,但是,我收到訪問衝突錯誤。

我該如何編組這樣的結構?

回答

4

您並不接近,這些結構不包含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。

+0

非常感謝!我認爲DWORD是依賴於平臺的,這就是爲什麼我將它聲明爲IntPtr。 –

+1

@Paolo https://msdn.microsoft.com/en-gb/library/windows/desktop/aa383751(v=vs.85).aspx –