Click here to Skip to main content
Click here to Skip to main content

Extract List of Codes of Windows-Messages from WinUser.H

, 23 Feb 2014
Rate this:
Please Sign up or sign in to vote.

Introduction

This small piece of F#-code extracts the "WM_XXXX-Names of Windows-messages" and their system-defined numeric codes from the Windows header file, WinUser.H, and stores them in a text file. The produced list of message-codes is also attached. One can use such a list for example, to translate message-codes passed by Windows to a Window-Procedure function to the correspondig WM_XXXX string.

Background

I was trapped in a programming hardship and in order to get rid of it, I decided to check, if a particular Windows-message is really sent to the window-procedure or not - It was a Win32-Application containing native code written in C using MS-Visual Studio, who had to receive some user defined messages from a DLL containing a hook-procedure. So I tried to store the list of selected messages in a file. Hence I needed the corresponding name strings, WM_XXXX, assigned to each Windows-message-code sent by Windows to Window Procedure, and instead of searching the Internet to find the ready to use material, as we usually do, this time I decided to put my recently being developed experiences in F# language into practice. The following F# code produces my needed list of Windows-messages and their corresponding codes. Herewith I upload both F#-code and the produced list used in a C-Function that returns the WM_XXXX-Names of message-codes, to be used by the other programmers in order to save their time.

Using the Code

The F# code here can be treated as a single-file F# console-application in MS-Visual Studio:

open System
open System.IO

//
// Returns the part of the line, containing a Windows-message name.
//
let FindWMDefName string_aWMDefLine =
    // A substring of the line, containing "WM_" contains a Windows-message name,
    //  and we will return it :
    List.find ( fun object_string_PartsOfWMDefLine -> -1 <> 
    ( string object_string_PartsOfWMDefLine).IndexOf ( "WM_")) ( List.ofArray string_aWMDefLine)

//
// Returns the part of the line, containing a Windows-message code.
//
let FindWMDefCode string_aWMDefLine =
    // The codes in WinUser.H are stored as hexadecimal numbers,
    //  so a substring of the line, containing "0x" contains a code,
    //  and we will return it :
    List.find ( fun object_string_PartsOfWMDefLine -> -1 <> 
    ( string object_string_PartsOfWMDefLine).IndexOf ( "0x")) ( List.ofArray string_aWMDefLine)

//
// This function extracts integer numbers from strings. The number can be given in decimal or hexadecimal bases.
//
let ConvertStringTOInt32 ( string_WMDef_Code : String) =
    // Some of codes in WinUser.H are specified with a trailing 'L' type specifier, that they are long integers,
    //  and we need the index of this 'L' to remove it :
    let nIdexOfTypeSpecifier = ( string_WMDef_Code.ToUpper ()).IndexOf ( "L")
    // Remove the trailing type specifier, if exists :
    let string_WMDef_Code =
        if nIdexOfTypeSpecifier <> -1
        then string_WMDef_Code.Substring ( 0, nIdexOfTypeSpecifier)
        else string_WMDef_Code
    // Translate the number in the string, depending on its base :
    if string_WMDef_Code.IndexOf ( "0x") <> -1
    then Int32.Parse ( string_WMDef_Code.Substring ( 2), Globalization.NumberStyles.AllowHexSpecifier)
    else Int32.Parse ( string_WMDef_Code)

//
// Extracts the list :
//
let Extract_WM_WinMsg_hashDefs_OutOfWinHeaderFile string_FileFullName_WinUser_H =
    // Lists are more efficient as arrays in F# :
    List.ofArray ( File.ReadAllLines ( string_FileFullName_WinUser_H))
    // Sieve the simple "#define WM_XXXX ..." lines :
    |> List.filter  ( fun string_Line       -> -1 <> 
    ( string string_Line).IndexOf ( "#define")  &&  -1 <> 
    ( string string_Line).IndexOf ( "WM_")  &&  -1 <> 
    ( string string_Line).IndexOf ( "0x"))
    // Omit lines containing phrases such as "XXXWM_XXX" :
    |> List.filter  ( fun string_Line       -> 
    string_Line.[ ( string string_Line).IndexOf ( "WM_") - 1] = ' ')
    // Split line to words :
    |> List.map     ( fun string_WMDefLine  ->  string_WMDefLine.Split [| ' '|])
    // Build list of message names and their corresponding codes :
    |> List.map     ( fun string_aWMDefLine -> ( ConvertStringTOInt32 
    ( FindWMDefCode string_aWMDefLine)), ( FindWMDefName string_aWMDefLine))
    // Sort the list by code :
    |> List.sortBy  ( fun tuple_nWMDefCode_string_WMDefName -> 
    fst tuple_nWMDefCode_string_WMDefName)

//
// Calls extracter function and saves the list in the output file :
//
let Store_WM_WinMsg_hashDefs_FromWinHeaderFile string_FileFullName_WM_WinMsg string_FileFullName_WinUser_H =
    let string_a_nWMDefCode_string_WMDefName = 
        // Perform the extraction :
        Extract_WM_WinMsg_hashDefs_OutOfWinHeaderFile string_FileFullName_WinUser_H
        // Format output lines :
        |> List.map ( fun tuple_nWMDefCode_string_WMDefName -> 
        ( string ( fst tuple_nWMDefCode_string_WMDefName)) + "\t\t, 
        \"" + ( string ( snd tuple_nWMDefCode_string_WMDefName)) + "\"")
        // Prepare data to be send to the File.WriteAllLines () :
        |> List.toArray
    File.WriteAllLines ( string_FileFullName_WM_WinMsg, string_a_nWMDefCode_string_WMDefName)

//
// Run the program:
//
[<EntryPoint>]
let main argv = 
    Store_WM_WinMsg_hashDefs_FromWinHeaderFile @"D:\\WinWM.TXT" @"D:\\WinUser.h"
    printfn "Done."
    0

The following C-Function is the code that I have used to find the corresponding Windows-message name, having the message-code, using the produced list:

typedef	struct	SWinMsgDefKodeName_Tag
{
	int		nKode;
	TCHAR		tchar_aName		[ 64];
} SWinMsgDefKodeName, *PSWinMsgDefKodeName;
TCHAR * Code2WM_MSG ( TCHAR* tchar_pStringZero_WM_WinMsgName, UINT unWM_WinMsgCode)
{
SWinMsgDefKodeName swinmsgdefkodename_a	[] =
 {
    { 0		, _T( "WM_NULL"						 )}
  , { 1		, _T( "WM_CREATE"					 )}
  , { 2		, _T( "WM_DESTROY"					 )}
  , { 3		, _T( "WM_MOVE"						 )}
  , { 5		, _T( "WM_SIZE"						 )}
  , { 6		, _T( "WM_ACTIVATE"					 )}
  , { 7		, _T( "WM_SETFOCUS"					 )}
  , { 8		, _T( "WM_KILLFOCUS"					 )}
  , { 10	, _T( "WM_ENABLE"					 )}
  , { 11	, _T( "WM_SETREDRAW"					 )}
  , { 12	, _T( "WM_SETTEXT"					 )}
  , { 13	, _T( "WM_GETTEXT"					 )}
  , { 14	, _T( "WM_GETTEXTLENGTH"				 )}
  , { 15	, _T( "WM_PAINT"					 )}
  , { 16	, _T( "WM_CLOSE"					 )}
  , { 17	, _T( "WM_QUERYENDSESSION"				 )}
  , { 19	, _T( "WM_QUERYOPEN"					 )}
  , { 22	, _T( "WM_ENDSESSION"					 )}
  , { 18	, _T( "WM_QUIT"						 )}
  , { 20	, _T( "WM_ERASEBKGND"					 )}
  , { 21	, _T( "WM_SYSCOLORCHANGE"				 )}
  , { 24	, _T( "WM_SHOWWINDOW"					 )}
  , { 26	, _T( "WM_WININICHANGE"					 )}
  , { 27	, _T( "WM_DEVMODECHANGE"				 )}
  , { 28	, _T( "WM_ACTIVATEAPP"					 )}
  , { 29	, _T( "WM_FONTCHANGE"					 )}
  , { 30	, _T( "WM_TIMECHANGE"					 )}
  , { 31	, _T( "WM_CANCELMODE"					 )}
  , { 32	, _T( "WM_SETCURSOR"					 )}
  , { 33	, _T( "WM_MOUSEACTIVATE"				 )}
  , { 34	, _T( "WM_CHILDACTIVATE"				 )}
  , { 35	, _T( "WM_QUEUESYNC"					 )}
  , { 36	, _T( "WM_GETMINMAXINFO"				 )}
  , { 38	, _T( "WM_PAINTICON"					 )}
  , { 39	, _T( "WM_ICONERASEBKGND"				 )}
  , { 40	, _T( "WM_NEXTDLGCTL"					 )}
  , { 42	, _T( "WM_SPOOLERSTATUS"				 )}
  , { 43	, _T( "WM_DRAWITEM"					 )}
  , { 44	, _T( "WM_MEASUREITEM"					 )}
  , { 45	, _T( "WM_DELETEITEM"					 )}
  , { 46	, _T( "WM_VKEYTOITEM"					 )}
  , { 47	, _T( "WM_CHARTOITEM"					 )}
  , { 48	, _T( "WM_SETFONT"					 )}
  , { 49	, _T( "WM_GETFONT"					 )}
  , { 50	, _T( "WM_SETHOTKEY"					 )}
  , { 51	, _T( "WM_GETHOTKEY"					 )}
  , { 55	, _T( "WM_QUERYDRAGICON"				 )}
  , { 57	, _T( "WM_COMPAREITEM"					 )}
  , { 61	, _T( "WM_GETOBJECT"					 )}
  , { 65	, _T( "WM_COMPACTING"					 )}
  , { 68	, _T( "WM_COMMNOTIFY"					 )}
  , { 70	, _T( "WM_WINDOWPOSCHANGING"			 	 )}
  , { 71	, _T( "WM_WINDOWPOSCHANGED"				 )}
  , { 72	, _T( "WM_POWER"					 )}
  , { 74	, _T( "WM_COPYDATA"					 )}
  , { 75	, _T( "WM_CANCELJOURNAL"				 )}
  , { 78	, _T( "WM_NOTIFY"					 )}
  , { 80	, _T( "WM_INPUTLANGCHANGEREQUEST"		 	 )}
  , { 81	, _T( "WM_INPUTLANGCHANGE"				 )}
  , { 82	, _T( "WM_TCARD"					 )}
  , { 83	, _T( "WM_HELP"						 )}
  , { 84	, _T( "WM_USERCHANGED"					 )}
  , { 85	, _T( "WM_NOTIFYFORMAT"					 )}
  , { 123	, _T( "WM_CONTEXTMENU"					 )}
  , { 124	, _T( "WM_STYLECHANGING"				 )}
  , { 125	, _T( "WM_STYLECHANGED"					 )}
  , { 126	, _T( "WM_DISPLAYCHANGE"				 )}
  , { 127	, _T( "WM_GETICON"					 )}
  , { 128	, _T( "WM_SETICON"					 )}
  , { 129	, _T( "WM_NCCREATE"					 )}
  , { 130	, _T( "WM_NCDESTROY"					 )}
  , { 131	, _T( "WM_NCCALCSIZE"					 )}
  , { 132	, _T( "WM_NCHITTEST"					 )}
  , { 133	, _T( "WM_NCPAINT"					 )}
  , { 134	, _T( "WM_NCACTIVATE"					 )}
  , { 135	, _T( "WM_GETDLGCODE"					 )}
  , { 136	, _T( "WM_SYNCPAINT"					 )}
  , { 160	, _T( "WM_NCMOUSEMOVE"					 )}
  , { 161	, _T( "WM_NCLBUTTONDOWN"				 )}
  , { 162	, _T( "WM_NCLBUTTONUP"					 )}
  , { 163	, _T( "WM_NCLBUTTONDBLCLK"				 )}
  , { 164	, _T( "WM_NCRBUTTONDOWN"				 )}
  , { 165	, _T( "WM_NCRBUTTONUP"					 )}
  , { 166	, _T( "WM_NCRBUTTONDBLCLK"				 )}
  , { 167	, _T( "WM_NCMBUTTONDOWN"				 )}
  , { 168	, _T( "WM_NCMBUTTONUP"					 )}
  , { 169	, _T( "WM_NCMBUTTONDBLCLK"				 )}
  , { 171	, _T( "WM_NCXBUTTONDOWN"				 )}
  , { 172	, _T( "WM_NCXBUTTONUP"					 )}
  , { 173	, _T( "WM_NCXBUTTONDBLCLK"				 )}
  , { 254	, _T( "WM_INPUT_DEVICE_CHANGE"				 )}
  , { 255	, _T( "WM_INPUT"					 )}
  , { 256	, _T( "WM_KEYFIRST"					 )}
  , { 256	, _T( "WM_KEYDOWN"					 )}
  , { 257	, _T( "WM_KEYUP"					 )}
  , { 258	, _T( "WM_CHAR"						 )}
  , { 259	, _T( "WM_DEADCHAR"					 )}
  , { 260	, _T( "WM_SYSKEYDOWN"					 )}
  , { 261	, _T( "WM_SYSKEYUP"					 )}
  , { 262	, _T( "WM_SYSCHAR"					 )}
  , { 263	, _T( "WM_SYSDEADCHAR"					 )}
  , { 265	, _T( "WM_UNICHAR"					 )}
  , { 265	, _T( "WM_KEYLAST"					 )}
  , { 264	, _T( "WM_KEYLAST"					 )}
  , { 269	, _T( "WM_IME_STARTCOMPOSITION"			 	 )}
  , { 270	, _T( "WM_IME_ENDCOMPOSITION"			 	 )}
  , { 271	, _T( "WM_IME_COMPOSITION"				 )}
  , { 271	, _T( "WM_IME_KEYLAST"					 )}
  , { 272	, _T( "WM_INITDIALOG"					 )}
  , { 273	, _T( "WM_COMMAND"					 )}
  , { 274	, _T( "WM_SYSCOMMAND"					 )}
  , { 275	, _T( "WM_TIMER"					 )}
  , { 276	, _T( "WM_HSCROLL"					 )}
  , { 277	, _T( "WM_VSCROLL"					 )}
  , { 278	, _T( "WM_INITMENU"					 )}
  , { 279	, _T( "WM_INITMENUPOPUP"				 )}
  , { 281	, _T( "WM_GESTURE"					 )}
  , { 282	, _T( "WM_GESTURENOTIFY"				 )}
  , { 287	, _T( "WM_MENUSELECT"					 )}
  , { 288	, _T( "WM_MENUCHAR"					 )}
  , { 289	, _T( "WM_ENTERIDLE"					 )}
  , { 290	, _T( "WM_MENURBUTTONUP"				 )}
  , { 291	, _T( "WM_MENUDRAG"					 )}
  , { 292	, _T( "WM_MENUGETOBJECT"				 )}
  , { 293	, _T( "WM_UNINITMENUPOPUP"				 )}
  , { 294	, _T( "WM_MENUCOMMAND"					 )}
  , { 295	, _T( "WM_CHANGEUISTATE"				 )}
  , { 296	, _T( "WM_UPDATEUISTATE"				 )}
  , { 297	, _T( "WM_QUERYUISTATE"					 )}
  , { 306	, _T( "WM_CTLCOLORMSGBOX"				 )}
  , { 307	, _T( "WM_CTLCOLOREDIT"					 )}
  , { 308	, _T( "WM_CTLCOLORLISTBOX"				 )}
  , { 309	, _T( "WM_CTLCOLORBTN"					 )}
  , { 310	, _T( "WM_CTLCOLORDLG"					 )}
  , { 311	, _T( "WM_CTLCOLORSCROLLBAR"			 	 )}
  , { 312	, _T( "WM_CTLCOLORSTATIC"				 )}
  , { 512	, _T( "WM_MOUSEFIRST"					 )}
  , { 512	, _T( "WM_MOUSEMOVE"					 )}
  , { 513	, _T( "WM_LBUTTONDOWN"					 )}
  , { 514	, _T( "WM_LBUTTONUP"					 )}
  , { 515	, _T( "WM_LBUTTONDBLCLK"				 )}
  , { 516	, _T( "WM_RBUTTONDOWN"					 )}
  , { 517	, _T( "WM_RBUTTONUP"					 )}
  , { 518	, _T( "WM_RBUTTONDBLCLK"				 )}
  , { 519	, _T( "WM_MBUTTONDOWN"					 )}
  , { 520	, _T( "WM_MBUTTONUP"					 )}
  , { 521	, _T( "WM_MBUTTONDBLCLK"				 )}
  , { 522	, _T( "WM_MOUSEWHEEL"					 )}
  , { 523	, _T( "WM_XBUTTONDOWN"					 )}
  , { 524	, _T( "WM_XBUTTONUP"					 )}
  , { 525	, _T( "WM_XBUTTONDBLCLK"				 )}
  , { 526	, _T( "WM_MOUSEHWHEEL"					 )}
  , { 526	, _T( "WM_MOUSELAST"					 )}
  , { 525	, _T( "WM_MOUSELAST"					 )}
  , { 522	, _T( "WM_MOUSELAST"					 )}
  , { 521	, _T( "WM_MOUSELAST"					 )}
  , { 528	, _T( "WM_PARENTNOTIFY"					 )}
  , { 529	, _T( "WM_ENTERMENULOOP"				 )}
  , { 530	, _T( "WM_EXITMENULOOP"					 )}
  , { 531	, _T( "WM_NEXTMENU"					 )}
  , { 532	, _T( "WM_SIZING"					 )}
  , { 533	, _T( "WM_CAPTURECHANGED"				 )}
  , { 534	, _T( "WM_MOVING"					 )}
  , { 536	, _T( "WM_POWERBROADCAST"				 )}
  , { 537	, _T( "WM_DEVICECHANGE"					 )}
  , { 544	, _T( "WM_MDICREATE"					 )}
  , { 545	, _T( "WM_MDIDESTROY"					 )}
  , { 546	, _T( "WM_MDIACTIVATE"					 )}
  , { 547	, _T( "WM_MDIRESTORE"					 )}
  , { 548	, _T( "WM_MDINEXT"					 )}
  , { 549	, _T( "WM_MDIMAXIMIZE"					 )}
  , { 550	, _T( "WM_MDITILE"					 )}
  , { 551	, _T( "WM_MDICASCADE"					 )}
  , { 552	, _T( "WM_MDIICONARRANGE"				 )}
  , { 553	, _T( "WM_MDIGETACTIVE"					 )}
  , { 560	, _T( "WM_MDISETMENU"					 )}
  , { 561	, _T( "WM_ENTERSIZEMOVE"				 )}
  , { 562	, _T( "WM_EXITSIZEMOVE"					 )}
  , { 563	, _T( "WM_DROPFILES"					 )}
  , { 564	, _T( "WM_MDIREFRESHMENU"				 )}
  , { 576	, _T( "WM_TOUCH"					 )}
  , { 641	, _T( "WM_IME_SETCONTEXT"				 )}
  , { 642	, _T( "WM_IME_NOTIFY"					 )}
  , { 643	, _T( "WM_IME_CONTROL"					 )}
  , { 644	, _T( "WM_IME_COMPOSITIONFULL"			 	 )}
  , { 645	, _T( "WM_IME_SELECT"					 )}
  , { 646	, _T( "WM_IME_CHAR"					 )}
  , { 648	, _T( "WM_IME_REQUEST"					 )}
  , { 656	, _T( "WM_IME_KEYDOWN"					 )}
  , { 657	, _T( "WM_IME_KEYUP"					 )}
  , { 673	, _T( "WM_MOUSEHOVER"					 )}
  , { 675	, _T( "WM_MOUSELEAVE"					 )}
  , { 672	, _T( "WM_NCMOUSEHOVER"					 )}
  , { 674	, _T( "WM_NCMOUSELEAVE"					 )}
  , { 689	, _T( "WM_WTSSESSION_CHANGE"			 	 )}
  , { 704	, _T( "WM_TABLET_FIRST"					 )}
  , { 735	, _T( "WM_TABLET_LAST"					 )}
  , { 768	, _T( "WM_CUT"						 )}
  , { 769	, _T( "WM_COPY"						 )}
  , { 770	, _T( "WM_PASTE"					 )}
  , { 771	, _T( "WM_CLEAR"					 )}
  , { 772	, _T( "WM_UNDO"						 )}
  , { 773	, _T( "WM_RENDERFORMAT"					 )}
  , { 774	, _T( "WM_RENDERALLFORMATS"				 )}
  , { 775	, _T( "WM_DESTROYCLIPBOARD"				 )}
  , { 776	, _T( "WM_DRAWCLIPBOARD"				 )}
  , { 777	, _T( "WM_PAINTCLIPBOARD"				 )}
  , { 778	, _T( "WM_VSCROLLCLIPBOARD"				 )}
  , { 779	, _T( "WM_SIZECLIPBOARD"				 )}
  , { 780	, _T( "WM_ASKCBFORMATNAME"				 )}
  , { 781	, _T( "WM_CHANGECBCHAIN"				 )}
  , { 782	, _T( "WM_HSCROLLCLIPBOARD"				 )}
  , { 783	, _T( "WM_QUERYNEWPALETTE"				 )}
  , { 784	, _T( "WM_PALETTEISCHANGING"			 	 )}
  , { 785	, _T( "WM_PALETTECHANGED"				 )}
  , { 786	, _T( "WM_HOTKEY"					 )}
  , { 791	, _T( "WM_PRINT"					 )}
  , { 792	, _T( "WM_PRINTCLIENT"					 )}
  , { 793	, _T( "WM_APPCOMMAND"					 )}
  , { 794	, _T( "WM_THEMECHANGED"					 )}
  , { 797	, _T( "WM_CLIPBOARDUPDATE"				 )}
  , { 798	, _T( "WM_DWMCOMPOSITIONCHANGED"		 	 )}
  , { 799	, _T( "WM_DWMNCRENDERINGCHANGED"		 	 )}
  , { 800	, _T( "WM_DWMCOLORIZATIONCOLORCHANGED"	 		 )}
  , { 801	, _T( "WM_DWMWINDOWMAXIMIZEDCHANGE"		 	 )}
  , { 803	, _T( "WM_DWMSENDICONICTHUMBNAIL"		 	 )}
  , { 806	, _T( "WM_DWMSENDICONICLIVEPREVIEWBITMAP"		 )}
  , { 831	, _T( "WM_GETTITLEBARINFOEX"			 	 )}
  , { 856	, _T( "WM_HANDHELDFIRST"				 )}
  , { 863	, _T( "WM_HANDHELDLAST"					 )}
  , { 864	, _T( "WM_AFXFIRST"					 )}
  , { 895	, _T( "WM_AFXLAST"					 )}
  , { 896	, _T( "WM_PENWINFIRST"					 )}
  , { 911	, _T( "WM_PENWINLAST"					 )}
  , { 32768	, _T( "WM_APP"						 )}
  , { 1024	, _T( "WM_USER"						 )}
  , { 32	, _T( "WM_NCCALCSIZE"					 )}
  , { 1024	, _T( "WM_WINDOWPOSCHANGING"			 	 )}
  , { 4		, _T( "WM_ERASEBACKGROUND"				 )}
  , { 256	, _T( "WM_ENTERIDLE"					 )}
  , { 128	, _T( "WM_CHAR"						 )}
	};

for ( int i = 0; i <= sizeof ( swinmsgdefkodename_a) / sizeof ( SWinMsgDefKodeName); i++)
  if ( swinmsgdefkodename_a [ i].nKode == unWM_WinMsgCode)
  {
    lstrcpy ( tchar_pStringZero_WM_WinMsgName, swinmsgdefkodename_a [ i].tchar_aName);
    return tchar_pStringZero_WM_WinMsgName;
  }

 return ( tchar_pStringZero_WM_WinMsgName = NULL);
} 

Keep in mind that the function does not allocate the required memory, so the caller must do this duty, like this:

TCHAR* tchar_pStringZero_WM_WinMsgName = NULL;
tchar_pStringZero_WM_WinMsgName = ( TCHAR *)( malloc ( sizeof ( TCHAR) * 64));
if ( tchar_pStringZero_WM_WinMsgName != NULL)
{
  Code2WM_MSG ( tchar_pStringZero_WM_WinMsgName, unWM_WinMsgCode);
  if ( tchar_pStringZero_WM_WinMsgName != NULL)
  {
    // Make use of it.
  }
  free ( tchar_pStringZero_WM_WinMsgName);
}  

Here, I have assumed that the message-code is stored in a variable, named, unWM_WinMsgCode.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Saeed Masoumy Rad
Engineer
Iran (Islamic Republic Of) Iran (Islamic Republic Of)
I am an electronics engineer with great interests in computer science since childhood. I have already developed some useful software-projects, which are being used in different industries to solve data processing and management problems.

Comments and Discussions

 
Suggestion[My vote of 2] A number of issues with the code Pinmember.:floyd:.2-Mar-14 2:59 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140721.1 | Last Updated 23 Feb 2014
Article Copyright 2014 by Saeed Masoumy Rad
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid