C# UpdateResource function fails - c#

I'm coding a simple application in C# that allows to add a resource to a .EXE file chosen by me.
The problem is that the call to UpdateResource function fails with the error 6, that according to MSDN is InvalidHandle(despite it seems that the call to BeginUpdateResource is successful) (The code is copied and pasted from a bigger file, so if some { lacks, don't care, the code compiles, but doesn't work as expected)
public partial class Form1 : Form
{
[DllImport("kernel32.dll", SetLastError=true)]
static extern bool UpdateResource(IntPtr hUpdate, string lpType, string lpName, ushort wLanguage, IntPtr lpData, uint cbData);
[DllImport("kernel32.dll",SetLastError=true)]
static extern IntPtr BeginUpdateResource(string pFileName, [MarshalAs(UnmanagedType.Bool)]bool bDeleteExistingResources);
[DllImport("kernel32.dll",SetLastError=true)]
static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);
static unsafe void SetRes(string path)
{
IntPtr beginPointer = BeginUpdateResource(path, false);
if (beginPointer != null)
{
MessageBox.Show("Begin works");//This is shown
ushort id = (ushort)Language.MakeLanguageID();
string newMessage = "hello world!";
Byte[] bytes = new ASCIIEncoding().GetBytes(newMessage);
GCHandle bHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
IntPtr ptr = bHandle.AddrOfPinnedObject();
bool update = UpdateResource(beginPointer,"FILE", "Test", id,ptr, (uint)bytes.Length);
if (update == true)
{
MessageBox.Show("Update");
EndUpdateResource(beginPointer, false);
}
else
{
MessageBox.Show(Marshal.GetLastWin32Error().ToString()); //It gives error 6
}
}
}

Related

Access violation calling CreateProcess in C#

I am trying to write C# code that, running in an elevated process, creates a non-elevated process. The (only) answer to the SO question How to call CreateProcess() with STARTUPINFOEX from C# and re-parent the child contains ready-to-use code. I copied this code, but instead of creating a process, it throws an AccessViolationException. The exception text Attempted to read or write protected memory. This is often an indication that other memory is corrupt. does not help to identify the culprit, however from low-level debugging I can see that the processor is trying to read from memory at a very small address like 0x00000004 which, of course, goes wrong.
The code, briefly explained, retrieves a handle of the desktop process, then calls InitializeProcThreadAttributeList and UpdateProcThreadAttribute to initialize the respective fields of a STARTUPINFOEX struct which is then passed into the CreateProcess Windows API function. CreateProcess should then create the new process as a child of the desktop process.
This function expects in its 9th parameter a pointer to either a STARTUPINFO or a STARTUPINFOEX (which contains a STATUPINFO at its begin). If it's a STARTUPINFOEX, the 6th parameter should contain the EXTENDED_STARTUPINFO_PRESENT flag.
When I don't pass the EXTENDED_STARTUPINFO_PRESENT flag so that CreateProcess think it's being passed just a STARTUPINFO, all works fine except that the created process is elevated (as is the calling process). However, as soon as I add this flag, the access violation occurs. For hours I have tried modifying parameter attributes etc., but the problem persists. I have the essentially same code running in C++, so I know it can work. What am I doing wrong?
The code below doesn't contain elaborated error checking, but it should compile and demonstrate the problem out of the box.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace RunNonElevatedCSharp
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
StartNonElevated(#"C:\WINDOWS\system32\cmd.exe", "");
}
public static int StartNonElevated(string strAppPath, string strCommandLine)
{
bool bSuccess = false;
IntPtr hShellProcess = IntPtr.Zero;
var pInfo = new PROCESS_INFORMATION();
var sInfoEx = new STARTUPINFOEX();
sInfoEx.StartupInfo.cb = Marshal.SizeOf(sInfoEx);
try
{
IntPtr hShellWnd = GetShellWindow();
if (hShellWnd == IntPtr.Zero)
{
return 0;
}
UInt32 pid;
if (GetWindowThreadProcessId(hShellWnd, out pid) == 0)
{
return 0;
}
hShellProcess = OpenProcess(PROCESS_CREATE_PROCESS, FALSE, pid);
if (hShellProcess == IntPtr.Zero)
{
return 0;
}
IntPtr nBufferSize = IntPtr.Zero;
InitializeProcThreadAttributeList(IntPtr.Zero, 1, 0, ref nBufferSize);
if (nBufferSize == IntPtr.Zero)
{
return 0;
}
sInfoEx.lpAttributeList = Marshal.AllocHGlobal(nBufferSize);
if (sInfoEx.lpAttributeList == IntPtr.Zero)
{
return 0;
}
if (!InitializeProcThreadAttributeList(sInfoEx.lpAttributeList, 1, 0, ref nBufferSize))
{
return 0;
}
if (!UpdateProcThreadAttribute(sInfoEx.lpAttributeList, 0, (IntPtr)PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, hShellProcess, (IntPtr)IntPtr.Size, IntPtr.Zero, IntPtr.Zero))
{
return 0;
}
// s1 and s2 may not be required
string s1 = "" + strAppPath + "";
string s2 = "";
// The next line causes an access violation unless you remove the 'EXTENDED_STARTUPINFO_PRESENT' flag
if (!CreateProcess(s1, s2, IntPtr.Zero, IntPtr.Zero, false, CREATE_NEW_CONSOLE | EXTENDED_STARTUPINFO_PRESENT | 0,
IntPtr.Zero, null, ref sInfoEx, out pInfo))
{
return 0;
}
bSuccess = true;
CloseHandle(pInfo.hThread);
CloseHandle(pInfo.hProcess);
return pInfo.dwProcessId;
}
finally
{
if (!bSuccess)
{
var lastError = Marshal.GetLastWin32Error();
Debug.WriteLine("Error: " + lastError.ToString());
}
if (sInfoEx.lpAttributeList != IntPtr.Zero)
{
DeleteProcThreadAttributeList(sInfoEx.lpAttributeList);
Marshal.FreeHGlobal(sInfoEx.lpAttributeList);
}
if (hShellProcess != IntPtr.Zero)
CloseHandle(hShellProcess);
}
}
[DllImport("User32.dll", SetLastError = true)]
public static extern IntPtr GetShellWindow();
[DllImport("User32.dll", SetLastError = true)]
public static extern UInt32 GetWindowThreadProcessId(IntPtr hWnd, out UInt32 lpdwProcessId);
[DllImport("Kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess(UInt32 dwDesiredAccess, int bInheritHandle, UInt32 dwProcessId);
[DllImport("kernel32.dll", SetLastError = true)][return: MarshalAs(UnmanagedType.Bool)]
public static extern bool InitializeProcThreadAttributeList(IntPtr lpAttributeList, int dwAttributeCount, int dwFlags, ref IntPtr lpSize);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UpdateProcThreadAttribute(IntPtr lpAttributeList, uint dwFlags, IntPtr Attribute, IntPtr lpValue, IntPtr cbSize,
IntPtr lpPreviousValue, IntPtr lpReturnSize);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, EntryPoint = "CreateProcessW", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CreateProcess(string lpApplicationName, string lpCommandLine,
[In, Optional] IntPtr lpProcessAttributes, [In, Optional] IntPtr lpThreadAttributes,
bool bInheritHandles, uint dwCreationFlags,
[In, Optional] IntPtr lpEnvironment, [In, Optional] string lpCurrentDirectory,
[In] ref STARTUPINFOEX lpStartupInfo, [Out] out PROCESS_INFORMATION lpProcessInformation);
[DllImport("Kernel32.dll", SetLastError = true)]
public static extern int CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll")]
private static extern void DeleteProcThreadAttributeList(IntPtr lpAttributeList);
public const UInt32 PROCESS_CREATE_PROCESS = 0x0080;
public const int FALSE = 0;
public const int PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = 0x00020000;
public const uint CREATE_NEW_CONSOLE = 0x00000010;
public const uint EXTENDED_STARTUPINFO_PRESENT = 0x00080000;
}
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct STARTUPINFOEX
{
public STARTUPINFO StartupInfo;
public IntPtr lpAttributeList;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct STARTUPINFO
{
public Int32 cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public Int32 dwX;
public Int32 dwY;
public Int32 dwXSize;
public Int32 dwYSize;
public Int32 dwXCountChars;
public Int32 dwYCountChars;
public Int32 dwFillAttribute;
public Int32 dwFlags;
public Int16 wShowWindow;
public Int16 cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
}
When the access violation occurs, the program cannot continue; the "finally" block isn't executed.
Looking forward to any replies...
Hans
Your call to UpdateProcThreadAttribute() is wrong. The 4th parameter needs the address of hShellProcess, not the value. This is even stated as much in this answer to the other question you linked to (the code in the other question has the same bug):
Second, the lpValue parameter of the UpdateProcThreadAttribute function must be a pointer to the attribute value (in your case, parentHandle), not the value itself.
The documentation for PROC_THREAD_ATTRIBUTE_PARENT_PROCESS says:
The lpValue parameter is a pointer to a handle to a process to use instead of the calling process as the parent for the process being created. The process to use must have the PROCESS_CREATE_PROCESS access right.
You said that you copied the other answer's code, but your code does not look like the other answer's code, and certainly does not contain the fix that the other answer had provided.
In your code, change this:
if (!UpdateProcThreadAttribute(..., hShellProcess, ...))
To this:
IntPtr lpValue = IntPtr.Zero;
...
lpValue = Marshal.AllocHGlobal(IntPtr.Size);
Marshal.WriteIntPtr(lpValue, hShellProcess);
if (!UpdateProcThreadAttribute(..., lpValue, ...))
...
Marshal.FreeHGlobal(lpValue);

Correct passing struct to FindText function using PInvoke

I am using this code to call FindText function (https://msdn.microsoft.com/en-us/library/ms646918.aspx) from Comdlg32.dll:
delegate IntPtr FRHookProc(IntPtr hdlg, uint uiMsg, IntPtr wParam,
IntPtr lParam);
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
struct FINDREPLACE
{
public uint lStructSize;
public IntPtr hwndOwner;
public IntPtr hInstance;
public uint Flags;
public IntPtr lpstrFindWhat;
public IntPtr lpstrReplaceWith;
public ushort wFindWhatLen;
public ushort wReplaceWithLen;
public IntPtr lCustData;
public FRHookProc lpfnHook;
public IntPtr lpTemplateName;
}
[DllImport("comdlg32.dll", CharSet=CharSet.Auto)]
static extern IntPtr FindText(ref FINDREPLACE lpfr);
public void SearchText(string text)
{
try
{
_lpfrStruct.hwndOwner = _windowHandle;
_lpfrStruct.lpstrFindWhat = Marshal.StringToHGlobalAnsi(text);
_lpfrStruct.wFindWhatLen = (ushort)text.Length;
//_lpfrStruct.lStructSize = (uint)Marshal.SizeOf(_lpfrStruct);
_ptrFindTextHandle = FindText(ref _lpfrStruct);
if(_ptrFindTextHandle == IntPtr.Zero)
{
int error = CommDlgExtendedError();
Debug.WriteLine("[VI] Cannot create FindText dialog, error: " + error.ToString());
}
}
catch (Exception)
{
}
}
I suppose the line //_lpfrStruct.lStructSize = (uint)Marshal.SizeOf(_lpfrStruct); is an issue
If commented out the CommDlgExtendedError returns 1 (CDERR_STRUCTSIZE = 0x0001 - The lStructSize member of the initialization structure for the corresponding common dialog box is invalid.) when I keep it I get an Exception (writing to protected memory).

Attempted to read or write protected memory, No issues with Memory or Version of Built

I am trying to Access a third Party .dll(unmanaged) in C#.
My Methods are as shown below
static class NativeMethods
{
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
}
class VTCCAN
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int CAN_Transmission(ref can_msg message);
static readonly string dllfile = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + #"\VTC1010_CAN_Bus.dll";
public int SendCAN(ref can_msg msg)
{
IntPtr pDll = NativeMethods.LoadLibrary(dllfile);
if (pDll == IntPtr.Zero)
{
MessageBox.Show("Loading Failed");
}
IntPtr pAddressOfFunctionToCall = NativeMethods.GetProcAddress(pDll, "CAN_Transmission");
CAN_Transmission sendCAN = (CAN_Transmission)Marshal.GetDelegateForFunctionPointer(pAddressOfFunctionToCall, typeof(CAN_Transmission));
int result = sendCAN(ref msg);
bool iresult = NativeMethods.FreeLibrary(pDll);
return result;
}
}
}
I am getting an error when I access the function 'SendCAN'
the error is
"Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt." I looked at some suggestions but its not applicable for my code. Is there something wrong here. Please suggest. I cant find answer for my case. (64 bit Windows 7 OS)
The assosiated Struct as provided by Abe
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Ansi)]
public struct can_msg
{
/// unsigned short
public short ide;
/// unsigned int
public int id;
/// unsigned short
public short dlc;
/// unsigned char[100]
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = NativeConstants.CAN_MSG_DATA_LEN)]
public string data;
/// unsigned short
public short rtr;
}

How can I use the images within shell32.dll in my C# project?

How can I use the images within shell32.dll in my C# project?
You can extract icons from a DLL with this code:
public class IconExtractor
{
public static Icon Extract(string file, int number, bool largeIcon)
{
IntPtr large;
IntPtr small;
ExtractIconEx(file, number, out large, out small, 1);
try
{
return Icon.FromHandle(largeIcon ? large : small);
}
catch
{
return null;
}
}
[DllImport("Shell32.dll", EntryPoint = "ExtractIconExW", CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern int ExtractIconEx(string sFile, int iIndex, out IntPtr piLargeVersion, out IntPtr piSmallVersion, int amountIcons);
}
...
form.Icon = IconExtractor.Extract("shell32.dll", 42, true);
Of course you need to know the index of the image in the DLL...
This thread on the MSDN developer forums offers a solution:
The typical way to implement these in .NET is to use the graphics provided in the ZIP file located at C:\Program Files\Microsoft Visual Studio X\Common7\VS200XImageLibrary.
You don't state which version of Visual Studio you have installed but you'll need to replace the "200X" with your version number.
The code in the accepted answer leaks one icon handle each time it's called, as it always asks for two icon handles and only gives one back.
Here is a version that doesn't leak a handle:
public static Icon Extract(string filePath, int index, bool largeIcon = true)
{
if (filePath == null)
throw new ArgumentNullException(nameof(filePath));
IntPtr hIcon;
if (largeIcon)
{
ExtractIconEx(filePath, index, out hIcon, IntPtr.Zero, 1);
}
else
{
ExtractIconEx(filePath, index, IntPtr.Zero, out hIcon, 1);
}
return hIcon != IntPtr.Zero ? Icon.FromHandle(hIcon) : null;
}
[DllImport("shell32", CharSet = CharSet.Unicode)]
private static extern int ExtractIconEx(string lpszFile, int nIconIndex, out IntPtr phiconLarge, IntPtr phiconSmall, int nIcons);
[DllImport("shell32", CharSet = CharSet.Unicode)]
private static extern int ExtractIconEx(string lpszFile, int nIconIndex, IntPtr phiconLarge, out IntPtr phiconSmall, int nIcons);
Some of them are available in %Program Files%\Microsoft Visual Studio 10.0\Common7\VS2010ImageLibrary - for others, you'd need to speak to Microsoft's lawyers about licensing them for redistribution in your application
See this code. It will be help
public class ExtractIcon
{
[DllImport("Shell32.dll")]
private static extern int SHGetFileInfo(
string pszPath, uint dwFileAttributes,
out SHFILEINFO psfi, uint cbfileInfo,
SHGFI uFlags);
private struct SHFILEINFO
{
public SHFILEINFO(bool b)
{
hIcon = IntPtr.Zero; iIcon = 0; dwAttributes = 0; szDisplayName = ""; szTypeName = "";
}
public IntPtr hIcon;
public int iIcon;
public uint dwAttributes;
public string szDisplayName;
public string szTypeName;
};
private enum SHGFI
{
SmallIcon = 0x00000001,
OpenIcon = 0x00000002,
LargeIcon = 0x00000000,
Icon = 0x00000100,
DisplayName = 0x00000200,
Typename = 0x00000400,
SysIconIndex = 0x00004000,
LinkOverlay = 0x00008000,
UseFileAttributes = 0x00000010
}
public static Icon GetIcon(string strPath, bool bSmall, bool bOpen)
{
SHFILEINFO info = new SHFILEINFO(true);
int cbFileInfo = Marshal.SizeOf(info);
SHGFI flags;
if (bSmall)
flags = SHGFI.Icon | SHGFI.SmallIcon;
else
flags = SHGFI.Icon | SHGFI.LargeIcon;
if (bOpen) flags = flags | SHGFI.OpenIcon;
SHGetFileInfo(strPath, 0, out info, (uint)cbFileInfo, flags);
return Icon.FromHandle(info.hIcon);
}
}

c# BeginUpdateResource

I would like to add a string resource to an executable file programmatically. Just for example purposes, let's say I am trying to add a string named "String SO" which holds the value of "stringVal"
If this helps anyone - if I were to do this through VS.net I could just right click on my Project => Resources => Add New String Resource etc..
I am using the following Win32 API's:
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr BeginUpdateResource(string pFileName,
[MarshalAs(UnmanagedType.Bool)]bool bDeleteExistingResources);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool UpdateResource(IntPtr hUpdate, uint lpType, uint lpName, ushort wLanguage, byte[] lpData, uint cbData);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);
So, I have found a couple of pages online but none of them seem to help me in what I am trying to do. If any of you are able to find anything I would be very grateful.
Otherwise, I would greatly appreciate any snippets that may help.
Thank you,
Evan
There is a very helpful library for many resource-tasks at github.
Many classes and function do wrap those window-api-calls around UpdateResource(...), etc.
Hope that helps.
I'm injecting an application byte[] as a resource to execute it on runtime. Here's my piece of code, hope it helps:
class AddResource
{
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool UpdateResource(IntPtr hUpdate, string lpType, string lpName, ushort wLanguage, IntPtr lpData, uint cbData);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr BeginUpdateResource(string pFileName,
[MarshalAs(UnmanagedType.Bool)]bool bDeleteExistingResources);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);
private static IntPtr ToPtr(object data)
{
GCHandle h = GCHandle.Alloc(data, GCHandleType.Pinned);
IntPtr ptr;
try
{
ptr = h.AddrOfPinnedObject();
}
finally
{
h.Free();
}
return ptr;
}
public static bool InjectResource(string filename, byte[] bytes, string resourceName)
{
try
{
IntPtr handle = BeginUpdateResource(filename, false);
byte[] file1 = bytes;
IntPtr fileptr = ToPtr(file1);
bool res = UpdateResource(handle, resourceName,
//"RT_RCDATA",
"0", 0, fileptr, Convert.ToUInt32(file1.Length));
EndUpdateResource(handle, false);
}
catch
{
return false;
}
return true;
}
public static void CopyStream(Stream input, Stream output,long sz)
{
// Insert null checking here for production
byte[] buffer = new byte[sz];
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, bytesRead);
}
}
}
Here is how I use it:
using (Stream input = Assembly.GetExecutingAssembly().GetManifestResourceStream("AppLicensing.Resources.SAppStarter.exe"))
using (Stream output = File.Create(outputFilePath))
{
long sz = input.Length;
AddResource.CopyStream(input, output, sz);
}
//inject crypted bytes
AddResource.InjectResource(outputFilePath, Encryptor.cryptedbytes, "RT_RCDATA");
And here is how I extract the resource (notice the "RT_RCDATA" -> that s the name of the resource):
class ReadResource
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr FindResource(IntPtr hModule, string lpName, string lpType);
[DllImport("Kernel32.dll", EntryPoint = "SizeofResource", SetLastError = true)]
private static extern uint SizeofResource(IntPtr hModule, IntPtr hResource);
[DllImport("Kernel32.dll", EntryPoint = "LoadResource", SetLastError = true)]
private static extern IntPtr LoadResource(IntPtr hModule, IntPtr hResource);
public static byte[] GetFromResource(String resourceName)
{
try
{
IntPtr hModule = GetModuleHandle(System.Diagnostics.Process.GetCurrentProcess().MainModule.ModuleName);
IntPtr loc = FindResource(hModule, "0", resourceName);
uint size = SizeofResource(hModule, loc);
IntPtr x = LoadResource(hModule, loc);
byte[] bPtr = new byte[size];
Marshal.Copy(x, bPtr, 0, (int)(size));
return bPtr;
}
catch (Exception e)
{
System.Windows.Forms.MessageBox.Show(e.ToString());
System.Environment.Exit(0);
return null;
}
}
}
byte[] encryptedData = ReadResource.GetFromResource("RT_RCDATA");
The code gets a bit messy... hope this helps.
Although the author is dealing with his own issue right now, the SO question UpdateResource function fails has code snippet for using these calls.
The code from Samson work with String lpType, that mean you can't actually add RT_RCDATA resource either reading from it, it's only create and read lpType named "RT_RCDATA" only. If you want it to read real RT data you'll need to modify lpType from string to uint and this is RT API table:
private const uint RT_CURSOR = 0x00000001;
private const uint RT_BITMAP = 0x00000002;
private const uint RT_ICON = 0x00000003;
private const uint RT_MENU = 0x00000004;
private const uint RT_DIALOG = 0x00000005;
private const uint RT_STRING = 0x00000006;
private const uint RT_FONTDIR = 0x00000007;
private const uint RT_FONT = 0x00000008;
private const uint RT_ACCELERATOR = 0x00000009;
private const uint RT_RCDATA = 0x0000000a;
private const uint RT_MESSAGETABLE = 0x0000000b;

Categories