RT_MESSAGETABLE

Oct 8, 2009 at 4:23 PM

what a small world.

I was wondering if your library supports recources in the MessageTable (http://www.codeproject.com/KB/system/msgdump.aspx) ? 

I need to pull out the possible events for each EventViewer source defined in EventMessageFile (eg. HKLM\SYSTEM\CurrentControlSet\Services\Eventlog\Application\Chkdsk). 

 

Oct 8, 2009 at 8:47 PM

Not sure if this is relevant but kernel32.dll contains all API errors in its MessageTable, while other Dlls contain event log data in their MessageTable.

Oct 8, 2009 at 11:27 PM

Please comment:

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
        public struct MESSAGE_RESOURCE_DATA
        {
            /// DWORD->unsigned int
            public uint NumberOfBlocks;
            /// MESSAGE_RESOURCE_BLOCK[1]
            [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 1, ArraySubType = System.Runtime.InteropServices.UnmanagedType.Struct)]
            public MESSAGE_RESOURCE_BLOCK[] Blocks;
        }

        [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
        public struct MESSAGE_RESOURCE_BLOCK
        {
            /// DWORD->unsigned int
            public uint LowId;
            /// DWORD->unsigned int
            public uint HighId;
            /// DWORD->unsigned int
            public uint OffsetToEntries;
        }

        [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
        public struct MESSAGE_RESOURCE_ENTRY
        {
            /// WORD->unsigned short
            public ushort Length;
            /// WORD->unsigned short
            public ushort Flags;
            /// BYTE[1]
            [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 1, ArraySubType = System.Runtime.InteropServices.UnmanagedType.I1)]
            public byte[] Text;
        }

 

MessageTableResource.cs           

           

Kernel32.MESSAGE_RESOURCE_DATA pmrd = default(Kernel32.MESSAGE_RESOURCE_DATA);
            pmrd = (Kernel32.MESSAGE_RESOURCE_DATA)Marshal.PtrToStructure(lpRes, typeof(Kernel32.MESSAGE_RESOURCE_DATA));

            IntPtr currentPointer = lpRes;

            for (int dwBlock = 0; dwBlock <= pmrd.NumberOfBlocks; dwBlock++)
            {
                Kernel32.MESSAGE_RESOURCE_ENTRY pmre = default(Kernel32.MESSAGE_RESOURCE_ENTRY);

                currentPointer = new IntPtr((Int32)currentPointer + (Int32)pmrd.Blocks[0].OffsetToEntries );


                pmre = (Kernel32.MESSAGE_RESOURCE_ENTRY)Marshal.PtrToStructure(currentPointer,typeof(Kernel32.MESSAGE_RESOURCE_ENTRY));
                    


            }

Coordinator
Oct 9, 2009 at 12:13 AM

As you figure it out ResourceLib doesn't have support for RT_MESSAGETABLE, but as you also have figured it out, it's fairly easy to add. Your code is somewhat close. I created http://resourcelib.codeplex.com/WorkItem/View.aspx?WorkItemId=4318 so that it's tracked.

For ResourceLib to take it you need to do the following.

  • Implement MessageResourceBlock, MessageResourceEntry and whatever other construct represents a resource or an element of it. Hook it up to ResourceInfo.
  • Write unit tests for reading message resource blocks and writing message resource blocks.
  • Add a paragraph to the codeproject article Article\resourcelibdotnet.html about message resource blocks. Add an .aml page to the documentation about message resource blocks. Modify the whatsnew.html.

If you can send me a patch of all this, we can iterate on checking that in.

Oct 9, 2009 at 1:25 AM

Ok, let me get more familiar with the library and I will work on getting the reads to work first.

Oct 9, 2009 at 2:18 PM

I need some help with the signatures:

internal override IntPtr Read(IntPtr hModule, IntPtr lpRes)
        {
            Kernel32.MESSAGE_RESOURCE_DATA pmrd = new Kernel32.MESSAGE_RESOURCE_DATA();
            pmrd = (Kernel32.MESSAGE_RESOURCE_DATA)Marshal.PtrToStructure(lpRes, typeof(Kernel32.MESSAGE_RESOURCE_DATA));
...

pmrd.NumberOfBlocks = 84, but pmrd.Blocks.Count = 1.  I can force all Blocks in by defining a SizeConst = 84 attrib in the below signature, but that obviously won't work.

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
        public struct MESSAGE_RESOURCE_DATA
        {
            /// DWORD->unsigned int
            public uint NumberOfBlocks;
            /// MESSAGE_RESOURCE_BLOCK[1]
            [MarshalAsAttribute(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct)]
            public MESSAGE_RESOURCE_BLOCK[] Blocks;
        }

Coordinator
Oct 9, 2009 at 2:27 PM

Don't include MESSAGE_RESOURCE_BLOCK into MESSAGE_RESOURCE_DATA at all. Create a separate class for each MESSAGE_RESOURCE_BLOCK (MessageResourceBlock) and read them in a loop (number of blocks times).

Coordinator
Oct 9, 2009 at 2:29 PM

Also please stick to the coding conventions. Look at other structures that  use UInt32 and not uint for CLS compliance and portability. Do document the fields if you can find the explanation in MSDN. DWORD->unsigned int is not much of a comment, but "Number of blocks in the message resource." is. Etc.

Oct 9, 2009 at 3:24 PM

I've got the separate struct for the block but the issue is that SizeConst needs to be defined for the full array to come through from unamanged:

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
        public struct MESSAGE_RESOURCE_BLOCK
        {
            /// DWORD->unsigned int
            public uint LowId;
            /// DWORD->unsigned int
            public uint HighId;
            /// DWORD->unsigned int
            public uint OffsetToEntries;
        }

Coordinator
Oct 9, 2009 at 11:16 PM

Don't include the blocks, any number of them, in the MESSAGE_RESOURCE_DATA struct. One can define MESSAGE_RESOURCE_DATA as [ number of blocks | block 1 | ... | block n ] or as [ number of blocks ][ block 1][block 2] ... [block n]. Conceptually MESSAGE_RESOURCE_DATA "contains" these blocks, but it can also be viewed as a header with a dynamic number of blocks following. And you don't need to read all 84 blocks at once, just one by one in a loop incrementing the pointer.

Look at the implementation of other resource types, it's done all over the place.

Oct 10, 2009 at 1:35 AM

Can you give me a sig of MESSAGE_RESOURCE_DATA that you would use?

Coordinator
Oct 11, 2009 at 1:21 PM

public struct MESSAGE_RESOURCE_DATA
{
            /// Number of message blocks.
            public uint NumberOfBlocks;
}

Oct 12, 2009 at 4:10 PM

I see. So really I don't even need  a struct for MRD.  I can rely on the pointer to the resource returned by LockResource? 

Coordinator
Oct 13, 2009 at 1:14 PM

Yes. At the same time it does make sense to declare a structure, even with one member, because at least it relates to the MSDN documentation. I try to get "as close as possible" to it, even if it's not always "useful" as here.

Apr 28, 2013 at 1:06 PM
I'm also tracking this feature.

What I need is to enumerate message ids and names from system32\msobjs.dll which is in a messagetable.

Will there be support for MESSAGE_TABLE in the near future?
Coordinator
Apr 28, 2013 at 1:09 PM
THIS PROJECT HAS MOVED TO GITHUB, https://github.com/dblock/resourcelib

I am not writing code actively for resourcelib, but feel free to contribute support.