Interop: Extending GUI Functionality

This post will describe some ways you can use the new interop features present in version 2 of the .Net Compact Framework to extend the framework's GUI functionality present in the System.Windows.Forms namespace.  An overview of how GUI works under the hood is also provided to give developers an understanding of the limitations and assumptions that the framework will make when using interop to override or extend the framework.

Under the Hood

The functionality exposed through the System.Windows.Forms namespace is implemented in two parts.  There is a native layer, present inside netcfagl2_0.dll, which handles most of the logic required for GUI features and is responsible for interacting with the underlying Windows CE OS.  The second part is the managed layer, present inside System.Windows.Forms.dll, which for the most part is actually a relatively thin wrapper that contains very little logic and mostly just exposes functionality to the managed world. 
There are a couple of implementation details that you should keep in mind when using interop to extend current functionality.

  • The runtime will attempt to maintain the managed state of GUI controls and components.  For example, if you PInvoke to SHFullScreen to hide the task bar, the runtime may override this behavior at a later time with its understanding of the managed state.
  • Forms will have logic under the scenes to support features like tabbing, autoscroll, docking and anchoring.  The logic for these features often involves examining and manipulating controls parented to the form, and can occur in response to messages received by the form as well as in response to GUI API calls.
  • All managed controls use the GWL_USERDATA space, and the runtime expects the data stored here to remain valid.  This area is considered to be reserved for runtime use only and should not be examined or relied upon.
  • Managed forms and controls may be recreated as necessary when their attributes are modified.  Any modifications that were made to the native control via interop are not guaranteed to be re-applied to the newly created control.  Also, the value returned from Control.Handle, associated with the native HWND, will change.
  • Managed controls are often implemented by wrapping functionality exposed in a similar native control present in the OS. 
  • In some cases, a single managed control may be associated with two native controls (such as the NumericUpDown control).  The Control.Handle API will return the handle associated with the major native control of the pair (in the case of NumericUpDown, it will be the Edit control).  You can use the remote spy tool to further examine the hierarchy of managed controls.
  • For performance reasons, not all events are sent up to the managed code layer. 

Using Interop Features

A number of interop features have been added to the .Net Compact Framework, making it possible for developers to dramatically extend the framework without writing native code.

  • Delegate callbacks, which allow you to override the wndproc of native controls and get notified when messages are received by the native control.
  • Marshaling support for more types, including support for more types of fields in structures.
  • The InteropServices.Marshal class has been extended, allowing you to access marshaling functionality from managed code and convert between IntPtrs and objects.  This is especially useful when the interop functions, such as wndprocs, contain parameters that can be either an int or a pointer to a structure based on what context they are called in.  You may find Marshal.PtrToStructure and Marshal.StructureToPtr useful to convert between an IntPtr, representing a native pointer to a structure, and a managed instance of the structure.
  • COM Interop support, which provides the pluming necessary to host ActiveX controls.  An ActiveX container can now be implemented entirely in managed code.

When using interop features to interact with managed controls and components, follow these guidelines:

  • Whenever possible, you should use managed APIs to modify the state of a control or the system, and rely on interop only as a last resort.
  • When parenting native controls inside a managed form, provide a level of indirection between the form and the native control by wrapping the native control inside a managed Control or UserControl.  This will protect the native control from being frequently examined and manipulated by the runtime; since the runtime will instead reference the parent managed Control. 
  • Be aware that sending a message to a managed control may have side-effects (or may start to have side effects in future versions).  The only way to completely prevent runtime logic from executing is to send a message directly to a native control that has been created using interop.  In general, sending messages directly to a managed form must be done with care as there may be assumptions about the existence of a managed control or component that would typically send that message.
  • When spying on messages sent to a managed control by overriding the wndproc, be sure to call the original wndproc (which will often be the runtime).  If the original wndproc is not called, there may be undesirable side-effects causing core features such as tabbing, autoscroll, and layout (among other things) to break.
  • For compatibility against future versions of the framework, it can be safer to wrap a native control from scratch, then to modify the state of a managed control.  When using interop to extend the framework, think about how your code will function if the feature you are implementing is eventually added to the framework.
  • Do not rely on implementation details, as they may change in future versions.  Do not attempt to parse or change any runtime owned data structures. 
  • Do not rely on the order, timing or frequency of events. 

Resources

The following blog posts describe how to extend the functionality of currently exposed controls.  This will show how to use interop to add 'missing' events to managed controls.
Part 1: http://blogs.msdn.com/netcfteam/archive/2005/05/20/420551.aspx
Part 2: http://blogs.msdn.com/netcfteam/archive/2005/05/23/421143.aspx

The following information may be useful when attempting to diagnose and solve issues involving interop.
http://blogs.msdn.com/netcfteam/archive/2005/07/24/442612.aspx

All applications should be tested with Interop Logging turned on, even if there are no known issues.  This will produce a log file that should then be searched for 'ERROR' and 'WARNING'.  The log file will contain more information about the cause of managed exceptions, subtle errors that do not manifest themselves as managed exceptions, as well as assist in debugging interop issues involving native code for which the source is unavailable.
http://blogs.msdn.com/netcfteam/archive/2005/07/24/442609.aspx

There are interop and GUI related guidelines and tips that can drastically improve your application's performance:
http://blogs.msdn.com/netcfteam/archive/2005/05/04/414820.aspx

Sample Code - Wrapping Native Controls

This sample presents a generic WindowHost class that you can use to host any native control on a managed form.  Sample code is shown using this class to host the RichInk control.

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;


namespace GuiInterop
{
 /// <summary>
 /// This is a generic host that will allow you to create a native
 /// control and parent it to your managed form.  You will also be
 /// able to spy and respond to messsages the native control
 /// recieves, and send messages to the native control.
 /// </summary>
 public class WindowHost : Control
 {
  private IntPtr m_hwnd; // the window handle of the native
        // control

  private IntPtr m_wndprocReal; // the original wndproc of
          // the native control before
          // it is subclassed

  private WindowsAPIs.WindowProcCallback m_delegate; // the
          // delegate used to get
          // message callbacks

  /// <summary>
  /// This event will fire before the message is sent down to
  /// the native control for processing, allowing you to
  /// preview and respond to the message.
  /// </summary>
  public event MessageEventHandler MessageReceived;

  /// <summary>
  /// The HWND associated with the native control being hosted.
  /// </summary>
  public IntPtr NativeHandle
  {
   get
   {
    return m_hwnd;
   }
  }

  /// <summary>
  /// Create a native control and embeds it inside the host.
  /// </summary>
  /// <param name="strClassName">The class name of the native
  /// control to be created. This can be either a system class
  /// or a custom native control that has been registered on
  /// the system through RegisterClassEx. </param>
  /// <param name="wsEx">The extended window style of the native
  /// control to be created. </param>
  /// <param name="ws">The style of the native control to be
  /// created. </param>
  public WindowHost(string strClassName, uint wsEx, uint ws)
  {
#if DESKTOP
   /* Under the desktop framework, ensure this control has been fully
    * created and has a valid hwnd.
    */
   this.CreateHandle();
#endif

   Debug.Assert(this.Handle != IntPtr.Zero, "Control should have a handle created by now");

   /* Create the native control and parent it to this control. */

   m_hwnd = WindowsAPIs.CreateWindowExW(wsEx, strClassName,
    null, ws | WindowsAPIs.WS_CHILD | WindowsAPIs.WS_VISIBLE,
    0, 0, 0, 0,
    this.Handle, 0, 0, 0);

   if (m_hwnd == IntPtr.Zero) {

    /* Class not registered */
    
    Debug.Assert(false, "Class not registered");
    throw new OutOfMemoryException();
   }

   /* Latch onto windows messages by subclassing the native
    * control
    */

   m_delegate = new WindowsAPIs.WindowProcCallback(this.WnProc);
   m_wndprocReal = WindowsAPIs.SetWindowLong(m_hwnd,
    WindowsAPIs.GWL_WNDPROC,
    Marshal.GetFunctionPointerForDelegate(m_delegate));

  }

  /// <summary>
  /// Embeds a native control it inside the host.
  /// </summary>
  public WindowHost(IntPtr hwndNativeControl)
  {
#if DESKTOP
   /* Under the desktop framework, ensure this control has been fully
    * created and has a valid hwnd.
    */
   this.CreateHandle();
#endif
   Debug.Assert(hwndNativeControl != IntPtr.Zero, "Control should have a handle created by now");
   Debug.Assert(this.Handle != IntPtr.Zero, "Control should have a handle created by now");

   m_hwnd = hwndNativeControl;

   /* Latch onto windows messages by subclassing the native
    * control
    */

   m_delegate = new WindowsAPIs.WindowProcCallback(this.WnProc);
   m_wndprocReal = WindowsAPIs.SetWindowLong(m_hwnd,
    WindowsAPIs.GWL_WNDPROC,
    Marshal.GetFunctionPointerForDelegate(m_delegate));
  }

  /// <summary>
  /// WnProc called used to monitor all messages the native control
  /// receives.
  /// </summary>
  private int WnProc(IntPtr hwnd, uint msg, uint wParam, uint lParam)
  {
   int ret;
   MessageEventArgs e;

   e = new MessageEventArgs(hwnd, msg, wParam, lParam);
  
   this.OnMessageReceived(e);

   if ((msg == WindowsAPIs.WM_DESTROY) && (!e.Handled))
   {

    /* De-subclass the child hwnd */
   
    WindowsAPIs.SetWindowLong(m_hwnd,
     WindowsAPIs.GWL_WNDPROC, m_wndprocReal);
   }

   if (e.Handled)
   {

    /* Give the original wnd proc a chance to process the
     * message
     */
   
    ret = WindowsAPIs.CallWindowProc(m_wndprocReal,
     hwnd, msg, wParam, lParam);
   }
   else
    ret = e.ReturnValue;
  
   return ret;
  }

  /// <summary>
  /// Used to ensure the native control remains the same size
  /// as the host control.
  /// </summary>
  protected override void OnResize(EventArgs e)
  {
   WindowsAPIs.SetWindowPos(m_hwnd, 0,
    0, 0, this.ClientSize.Width, this.ClientSize.Height,
    WindowsAPIs.SWP_NOZORDER);
  }

  /// <summary>
  /// Applies the window text of the host control to the
  /// native control as well.
  /// </summary>
  protected override void OnTextChanged(EventArgs e)
  {
   WindowsAPIs.SetWindowText(m_hwnd, this.Text);
  }

  /// <summary>
  /// Any time focus is given to the host control, it is passed
  /// down to the hosted native control.
  /// </summary>
  protected override void OnGotFocus(EventArgs e)
  {
   WindowsAPIs.SetFocus(m_hwnd);
  }

  /// <summary>
  /// Called each time a message is received by the native
  /// control, and fires associated event.
  /// </summary>
  protected void OnMessageReceived(MessageEventArgs e)
  {
   if (this.MessageReceived != null)
    this.MessageReceived(this, e);
  }
 }

 /// <summary>
 /// Delegate used to spy and respond to messages received by
 /// the hosted native control.
 /// </summary>
 public delegate void MessageEventHandler(object sender, MessageEventArgs e);

 /// <summary>
 /// Used to encapsulate the data present in a wndproc message.
 /// </summary>
 public class MessageEventArgs : EventArgs
 {
  private IntPtr m_hwnd;
  private uint m_msg;
  private uint m_wParam;
  private uint m_lParam;
  private bool m_fHandled;
  private int m_ret;
 
  public MessageEventArgs(IntPtr hwnd, uint msg, uint wParam,
   uint lParam)
  {
   m_fHandled = true;
  }

  /// <summary>
  /// The window handle associated with the message.
  /// </summary>
  public IntPtr Hwnd
  {
   get
   {
    return m_hwnd;
   }

  }

  /// <summary>
  /// The ID used to identify the message (WM_*).
  /// </summary>
  public uint Msg
  {
   get
   {
    return m_msg;
   }

  }

  /// <summary>
  /// The wParam associated with the message, whose value
  /// depends on the message.
  /// </summary>  
  public uint wParam
  {
   get
   {
    return m_wParam;
   }
  }

  /// <summary>
  /// The lParam associated with the message, whose value
  /// depends on the message.
  /// </summary>  
  public uint lParam
  {
   get
   {
    return m_lParam;
   }
  }

  /// <summary>
  /// Determines if the message is to be sent to the native
  /// control's wndproc for further processing.
  /// </summary>  
  public bool Handled
  {
   get
   {
    return m_fHandled;
   }
   set
   {
    m_fHandled = value;
   }
  }

  /// <summary>
  /// Determines the return value to be returned from the wndproc
  /// to the sender of the message.
  /// </summary> 
  public int ReturnValue
  {
   get
   {
    return m_ret;
   }
   set
   {
    m_ret = value;
   }
  }
 }

}

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using GuiInterop;

namespace HostDemo
{
 public class SampleForm : Form
 {
  private WindowHost m_ctlRichInk;

  public SampleForm()
  {
   InitInkX();
   m_ctlRichInk = new WindowHost("InkX", 0, 0);   
   m_ctlRichInk.Height = 150;
   m_ctlRichInk.Dock = DockStyle.Fill;
   m_ctlRichInk.Parent = this;

   WindowsAPIs.SendMessage(m_ctlRichInk.NativeHandle,
    WindowsAPIs.EM_SETVIEW, WindowsAPIs.VT_DRAWINGVIEW, 0);
   WindowsAPIs.SendMessage(m_ctlRichInk.NativeHandle,
    WindowsAPIs.EM_SETPENMODE, WindowsAPIs.MODE_PEN, 0);
   WindowsAPIs.SendMessage(m_ctlRichInk.NativeHandle,
    WindowsAPIs.EM_SETINKLAYER, WindowsAPIs.VL_DRAWINGINK, 0);
   WindowsAPIs.SendMessage(m_ctlRichInk.NativeHandle,
    WindowsAPIs.EM_SETPAGESTYLE, WindowsAPIs.PS_RULEDLINES, 0);

   this.Text = "Hosting Sample";
   this.MinimizeBox = false;
  }

#if DESKTOP
  [STAThread]
#endif
  static void Main()
  {
   Application.Run(new SampleForm());
  }

  [DllImport ("inkx.dll")]
  public static extern void InitInkX();
 }
}

using System;
using System.Runtime.InteropServices;


namespace GuiInterop
{
 /// <summary>
 /// Contains managed wrappers of windows APIs necessary for pinvokes
 /// and delegate callbacks.
 /// </summary>
 public sealed class WindowsAPIs
 {
  public delegate int WindowProcCallback(IntPtr hwnd, uint msg,
   uint wParam, uint lParam);

#if DESKTOP   
  [DllImport("user32.dll")]
#else   
  [DllImport("coredll.dll")]
#endif   
  public extern static int DefWindowProc(IntPtr hwnd, uint msg,
   uint wParam, uint lParam);

#if DESKTOP   
  [DllImport("user32.dll")]
#else   
  [DllImport("coredll.dll")]
#endif   
  public extern static int CallWindowProc(
   IntPtr lpPrevWndFunc, IntPtr hwnd, uint msg, uint wParam,
   uint lParam);
 
#if DESKTOP   
  [DllImport("user32.dll")]
#else   
  [DllImport("coredll.dll")]
#endif   
  public extern static IntPtr SetWindowLong(IntPtr hwnd,
   int nIndex, IntPtr dwNewLong);

#if DESKTOP   
  [DllImport("user32.dll")]
#else   
  [DllImport("coredll.dll")]
#endif   
  public extern static IntPtr CreateWindowExW(uint dwExStyle,
   string lpClassName, string lpWindowName, uint dwStyle,
   int x, int y, int nWidth, int nHeight, IntPtr hwndParent,
   int hMenu, int hInstance, int lpParam);

#if DESKTOP   
  [DllImport("user32.dll")]
#else   
  [DllImport("coredll.dll")]
#endif   
  public extern static int SetWindowPos(IntPtr hwnd,
   int hwndInsertAfter, int x, int y, int cx, int cy,
   uint flags);

#if DESKTOP   
  [DllImport("user32.dll")]
#else   
  [DllImport("coredll.dll")]
#endif   
  public extern static int SetWindowText(IntPtr hwnd,
   string lpString);

#if DESKTOP   
  [DllImport("user32.dll")]
#else   
  [DllImport("coredll.dll")]
#endif   
  public extern static IntPtr SetFocus(IntPtr hwnd);

#if DESKTOP   
  [DllImport("user32.dll")]
#else   
  [DllImport("coredll.dll")]
#endif   
  public extern static int SendMessage(IntPtr hwnd,
   uint msg, uint wParam, uint lParam);

  public const int
   SWP_NOSIZE              = 0x0001,
   SWP_NOMOVE              = 0x0002,
   SWP_NOZORDER            = 0x0004,
   SWP_NOREDRAW            = 0x0008,
   SWP_NOACTIVATE          = 0x0010,
   SWP_FRAMECHANGED        = 0x0020,
   SWP_SHOWWINDOW          = 0x0040,
   SWP_HIDEWINDOW          = 0x0080,
   SWP_NOCOPYBITS          = 0x0100,
   SWP_NOOWNERZORDER       = 0x0200,
   SWP_NOSENDCHANGING      = 0x0400,
   SWP_DRAWFRAME           = 0x0020,
   SWP_NOREPOSITION        = 0x0200,
   SWP_DEFERERASE          = 0x2000,
   SWP_ASYNCWINDOWPOS      = 0x4000,
   HWND_TOP                = 0,
   HWND_BOTTOM             = 1,
   HWND_TOPMOST            = -1,
   HWND_NOTOPMOST          = -2,
   ES_LEFT     = 0x0000,
   ES_CENTER     = 0x0001,
   ES_RIGHT     = 0x0002,
   ES_MULTILINE    = 0x0004,
   ES_UPPERCASE    = 0x0008,
   ES_LOWERCASE    = 0x0010,
   ES_PASSWORD    = 0x0020,
   ES_AUTOVSCROLL    = 0x0040,
   ES_AUTOHSCROLL    = 0x0080,
   ES_NOHIDESEL    = 0x0100,
   ES_OEMCONVERT    = 0x0400,
   ES_READONLY    = 0x0800,
   ES_WANTRETURN    = 0x1000,
   ES_NUMBER     = 0x2000,
   GWL_EXSTYLE    = (-20),
   GWL_STYLE     = (-16),
   GWL_WNDPROC    = (-4),
   GWL_HINSTANCE   = (-6),
   GWL_HWNDPARENT   = (-8),
   GWL_USERDATA   = (-21),
   GWL_ID     = (-12),
   WHEEL_DELTA    = 120,
   WM_NULL = 0x0000,
   WM_CREATE = 0x0001,
   WM_DESTROY = 0x0002,
   WM_MOVE = 0x0003,
   WM_SIZE = 0x0005,
   WM_ACTIVATE = 0x0006,
   WA_INACTIVE = 0,
   WA_ACTIVE = 1,
   WA_CLICKACTIVE = 2,
   WM_SETFOCUS = 0x0007,
   WM_KILLFOCUS = 0x0008,
   WM_ENABLE = 0x000A,
   WM_SETREDRAW = 0x000B,
   WM_SETTEXT = 0x000C,
   WM_GETTEXT = 0x000D,
   WM_GETTEXTLENGTH = 0x000E,
   WM_PAINT = 0x000F,
   WM_CLOSE = 0x0010,
   WM_QUERYENDSESSION = 0x0011,
   WM_QUIT = 0x0012,
   WM_QUERYOPEN = 0x0013,
   WM_ERASEBKGND = 0x0014,
   WM_SYSCOLORCHANGE = 0x0015,
   WM_ENDSESSION = 0x0016,
   WM_SHOWWINDOW = 0x0018,
   WM_WININICHANGE = 0x001A,
   WM_SETTINGCHANGE = 0x001A,
   WM_DEVMODECHANGE = 0x001B,
   WM_ACTIVATEAPP = 0x001C,
   WM_FONTCHANGE = 0x001D,
   WM_TIMECHANGE = 0x001E,
   WM_CANCELMODE = 0x001F,
   WM_SETCURSOR = 0x0020,
   WM_MOUSEACTIVATE = 0x0021,
   WM_CHILDACTIVATE = 0x0022,
   WM_QUEUESYNC = 0x0023,
   WM_GETMINMAXINFO = 0x0024,
   WM_PAINTICON = 0x0026,
   WM_ICONERASEBKGND = 0x0027,
   WM_NEXTDLGCTL = 0x0028,
   WM_SPOOLERSTATUS = 0x002A,
   WM_DRAWITEM = 0x002B,
   WM_MEASUREITEM = 0x002C,
   WM_DELETEITEM = 0x002D,
   WM_VKEYTOITEM = 0x002E,
   WM_CHARTOITEM = 0x002F,
   WM_SETFONT = 0x0030,
   WM_GETFONT = 0x0031,
   WM_SETHOTKEY = 0x0032,
   WM_GETHOTKEY = 0x0033,
   WM_QUERYDRAGICON = 0x0037,
   WM_COMPAREITEM = 0x0039,
   WM_GETOBJECT = 0x003D,
   WM_COMPACTING = 0x0041,
   WM_COMMNOTIFY = 0x0044,
   WM_WINDOWPOSCHANGING = 0x0046,
   WM_WINDOWPOSCHANGED = 0x0047,
   WM_POWER = 0x0048,
   WM_COPYDATA = 0x004A,
   WM_CANCELJOURNAL = 0x004B,
   WM_NOTIFY = 0x004E,
   WM_INPUTLANGCHANGEREQUEST = 0x0050,
   WM_INPUTLANGCHANGE = 0x0051,
   WM_TCARD = 0x0052,
   WM_HELP = 0x0053,
   WM_USERCHANGED = 0x0054,
   WM_NOTIFYFORMAT = 0x0055,
   WM_CONTEXTMENU = 0x007B,
   WM_STYLECHANGING = 0x007C,
   WM_STYLECHANGED = 0x007D,
   WM_DISPLAYCHANGE = 0x007E,
   WM_GETICON = 0x007F,
   WM_SETICON = 0x0080,
   WM_NCCREATE = 0x0081,
   WM_NCDESTROY = 0x0082,
   WM_NCCALCSIZE = 0x0083,
   WM_NCHITTEST = 0x0084,
   WM_NCPAINT = 0x0085,
   WM_NCACTIVATE = 0x0086,
   WM_GETDLGCODE = 0x0087,
   WM_NCMOUSEMOVE = 0x00A0,
   WM_NCLBUTTONDOWN = 0x00A1,
   WM_NCLBUTTONUP = 0x00A2,
   WM_NCLBUTTONDBLCLK = 0x00A3,
   WM_NCRBUTTONDOWN = 0x00A4,
   WM_NCRBUTTONUP = 0x00A5,
   WM_NCRBUTTONDBLCLK = 0x00A6,
   WM_NCMBUTTONDOWN = 0x00A7,
   WM_NCMBUTTONUP = 0x00A8,
   WM_NCMBUTTONDBLCLK = 0x00A9,
   WM_KEYFIRST = 0x0100,
   WM_KEYDOWN = 0x0100,
   WM_KEYUP = 0x0101,
   WM_CHAR = 0x0102,
   WM_DEADCHAR = 0x0103,
   WM_SYSKEYDOWN = 0x0104,
   WM_SYSKEYUP = 0x0105,
   WM_SYSCHAR = 0x0106,
   WM_SYSDEADCHAR = 0x0107,
   WM_KEYLAST = 0x0108,
   WM_IME_STARTCOMPOSITION = 0x010D,
   WM_IME_ENDCOMPOSITION = 0x010E,
   WM_IME_COMPOSITION = 0x010F,
   WM_IME_KEYLAST = 0x010F,
   WM_INITDIALOG = 0x0110,
   WM_COMMAND = 0x0111,
   WM_SYSCOMMAND = 0x0112,
   WM_TIMER = 0x0113,
   WM_HSCROLL = 0x0114,
   WM_VSCROLL = 0x0115,
   WM_INITMENU = 0x0116,
   WM_INITMENUPOPUP = 0x0117,
   WM_MENUSELECT = 0x011F,
   WM_MENUCHAR = 0x0120,
   WM_ENTERIDLE = 0x0121,
   WM_CHANGEUISTATE = 0x0127,
   WM_UPDATEUISTATE = 0x0128,
   WM_QUERYUISTATE = 0x0129,
   WM_CTLCOLORMSGBOX = 0x0132,
   WM_CTLCOLOREDIT = 0x0133,
   WM_CTLCOLORLISTBOX = 0x0134,
   WM_CTLCOLORBTN = 0x0135,
   WM_CTLCOLORDLG = 0x0136,
   WM_CTLCOLORSCROLLBAR = 0x0137,
   WM_CTLCOLORSTATIC = 0x0138,
   WM_MOUSEFIRST = 0x0200,
   WM_MOUSEMOVE = 0x0200,
   WM_LBUTTONDOWN = 0x0201,
   WM_LBUTTONUP = 0x0202,
   WM_LBUTTONDBLCLK = 0x0203,
   WM_RBUTTONDOWN = 0x0204,
   WM_RBUTTONUP = 0x0205,
   WM_RBUTTONDBLCLK = 0x0206,
   WM_MBUTTONDOWN = 0x0207,
   WM_MBUTTONUP = 0x0208,
   WM_MBUTTONDBLCLK = 0x0209,
   WM_NCMOUSEHOVER = 0x02A0,
   WM_NCMOUSELEAVE = 0x02A2,
   WM_MOUSEWHEEL = 0x020A,
   WM_MOUSELAST = 0x020A,
   WM_PARENTNOTIFY = 0x0210,
   WM_ENTERMENULOOP = 0x0211,
   WM_EXITMENULOOP = 0x0212,
   WM_NEXTMENU = 0x0213,
   WM_SIZING = 0x0214,
   WM_CAPTURECHANGED = 0x0215,
   WM_MOVING = 0x0216,
   WM_POWERBROADCAST = 0x0218,
   WM_DEVICECHANGE = 0x0219,
   WM_IME_SETCONTEXT = 0x0281,
   WM_IME_NOTIFY = 0x0282,
   WM_IME_CONTROL = 0x0283,
   WM_IME_COMPOSITIONFULL = 0x0284,
   WM_IME_SELECT = 0x0285,
   WM_IME_CHAR = 0x0286,
   WM_IME_KEYDOWN = 0x0290,
   WM_IME_KEYUP = 0x0291,
   WM_MDICREATE = 0x0220,
   WM_MDIDESTROY = 0x0221,
   WM_MDIACTIVATE = 0x0222,
   WM_MDIRESTORE = 0x0223,
   WM_MDINEXT = 0x0224,
   WM_MDIMAXIMIZE = 0x0225,
   WM_MDITILE = 0x0226,
   WM_MDICASCADE = 0x0227,
   WM_MDIICONARRANGE = 0x0228,
   WM_MDIGETACTIVE = 0x0229,
   WM_MDISETMENU = 0x0230,
   WM_ENTERSIZEMOVE = 0x0231,
   WM_EXITSIZEMOVE = 0x0232,
   WM_DROPFILES = 0x0233,
   WM_MDIREFRESHMENU = 0x0234,
   WM_MOUSEHOVER = 0x02A1,
   WM_MOUSELEAVE = 0x02A3,
   WM_CUT = 0x0300,
   WM_COPY = 0x0301,
   WM_PASTE = 0x0302,
   WM_CLEAR = 0x0303,
   WM_UNDO = 0x0304,
   WM_RENDERFORMAT = 0x0305,
   WM_RENDERALLFORMATS = 0x0306,
   WM_DESTROYCLIPBOARD = 0x0307,
   WM_DRAWCLIPBOARD = 0x0308,
   WM_PAINTCLIPBOARD = 0x0309,
   WM_VSCROLLCLIPBOARD = 0x030A,
   WM_SIZECLIPBOARD = 0x030B,
   WM_ASKCBFORMATNAME = 0x030C,
   WM_CHANGECBCHAIN = 0x030D,
   WM_HSCROLLCLIPBOARD = 0x030E,
   WM_QUERYNEWPALETTE = 0x030F,
   WM_PALETTEISCHANGING = 0x0310,
   WM_PALETTECHANGED = 0x0311,
   WM_HOTKEY = 0x0312,
   WM_PRINT = 0x0317,
   WM_PRINTCLIENT = 0x0318,
   WM_HANDHELDFIRST = 0x0358,
   WM_HANDHELDLAST = 0x035F,
   WM_AFXFIRST = 0x0360,
   WM_AFXLAST = 0x037F,
   WM_PENWINFIRST = 0x0380,
   WM_PENWINLAST = 0x038F,
   WM_APP = unchecked((int)0x8000),
   WM_USER = 0x0400,
   WM_REFLECT          = WM_USER + 0x1C00,
   WMSZ_LEFT    = 1,
   WMSZ_RIGHT    = 2,
   WMSZ_TOP    = 3,
   WMSZ_TOPLEFT   = 4,
   WMSZ_TOPRIGHT   = 5,
   WMSZ_BOTTOM    = 6,
   WMSZ_BOTTOMLEFT   = 7,
   WMSZ_BOTTOMRIGHT  = 8,
   WS_OVERLAPPED   = 0x00000000,
   WS_POPUP    = unchecked((int)0x80000000),
   WS_CHILD    = 0x40000000,
   WS_MINIMIZE    = 0x20000000,
   WS_VISIBLE    = 0x10000000,
   WS_DISABLED    = 0x08000000,
   WS_CLIPSIBLINGS   = 0x04000000,
   WS_CLIPCHILDREN   = 0x02000000,
   WS_MAXIMIZE    = 0x01000000,
   WS_CAPTION    = 0x00C00000,
   WS_BORDER    = 0x00800000,
   WS_DLGFRAME    = 0x00400000,
   WS_VSCROLL    = 0x00200000,
   WS_HSCROLL    = 0x00100000,
   WS_SYSMENU    = 0x00080000,
   WS_THICKFRAME   = 0x00040000,
   WS_GROUP    = 0x00020000,
   WS_TABSTOP    = 0x00010000,
   WS_MINIMIZEBOX   = 0x00020000,
   WS_MAXIMIZEBOX   = 0x00010000,
   WS_TILED    = 0x00000000,
   WS_ICONIC    = 0x20000000,
   WS_SIZEBOX    = 0x00040000,
   WS_OVERLAPPEDWINDOW  = (0x00000000|0x00C00000|0x00080000|0x00040000|0x00020000|0x00010000),
   WS_POPUPWINDOW   = (unchecked((int)0x80000000)|0x00800000|0x00080000),
   WS_CHILDWINDOW   = 0x40000000,
   WS_EX_DLGMODALFRAME  = 0x00000001,
   WS_EX_NOPARENTNOTIFY = 0x00000004,
   WS_EX_TOPMOST   = 0x00000008,
   WS_EX_ACCEPTFILES  = 0x00000010,
   WS_EX_TRANSPARENT  = 0x00000020,
   WS_EX_MDICHILD   = 0x00000040,
   WS_EX_TOOLWINDOW  = 0x00000080,
   WS_EX_WINDOWEDGE  = 0x00000100,
   WS_EX_CLIENTEDGE  = 0x00000200,
   WS_EX_CONTEXTHELP  = 0x00000400,
   WS_EX_RIGHT    = 0x00001000,
   WS_EX_LEFT    = 0x00000000,
   WS_EX_RTLREADING  = 0x00002000,
   WS_EX_LTRREADING  = 0x00000000,
   WS_EX_LEFTSCROLLBAR  = 0x00004000,
   WS_EX_RIGHTSCROLLBAR = 0x00000000,
   WS_EX_CONTROLPARENT  = 0x00010000,
   WS_EX_STATICEDGE  = 0x00020000,
   WS_EX_APPWINDOW   = 0x00040000,
   WS_EX_OVERLAPPEDWINDOW = (0x00000100|0x00000200),
   WS_EX_PALETTEWINDOW  = (0x00000100|0x00000080|0x00000008),
   WS_EX_LAYERED   = 0x00080000,
   WS_EX_NOINHERITLAYOUT = 0x00100000,
   WS_EX_LAYOUTRTL   = 0x00400000,
   WS_EX_NOACTIVATE  = 0x08000000,
   EM_SETVIEW    = WM_USER + 284,
   EM_CANPASTE    = WM_USER + 50,
   EM_CANREDO    = WM_USER + 246,
   EM_CLEARALL    = WM_USER + 331,
   EM_GETPAGESTYLE   = WM_USER + 323,
   EM_GETPENMODE   = WM_USER + 328,
   EM_GETVIEW    = WM_USER + 254,
   EM_GETWRAPMODE   = WM_USER + 227,
   EM_GETZOOMPERCENT  = WM_USER + 289,
   EM_INSERTLINKS   = WM_USER + 333,
   EM_REDOEVENT   = WM_USER + 235,
   EM_SETINKLAYER   = WM_USER + 288,
   EM_SETPAGESTYLE   = WM_USER + 287,
   EM_SETPENMODE   = WM_USER + 329,
   EM_SETVIEWATTRIBUTES = WM_USER + 332,
   EM_SETWRAPMODE   = WM_USER + 319,
   EM_SETZOOMPERCENT  = WM_USER + 290,
   EM_STREAMIN    = WM_USER + 73,
   EM_STREAMOUT   = WM_USER + 74,
   EM_UNDOEVENT   = WM_USER + 234,
   VT_TYPINGVIEW   = 0,
   VT_WRITINGVIEW   = 2,
   VT_DRAWINGVIEW   = 3,
   VL_SMARTINK    =  0,
   VL_WRITINGINK   =  1,
   VL_DRAWINGINK   =  2,
   VL_LINKS    =  3,
   VL_SMARTLINKS   =  4,
   PS_LEFTMARGIN   = 0x0000,
   PS_TOPMARGIN   = 0x0001,
   PS_RULEDLINES   = 0x0002,
   PS_GRIDLINES   = 0x0004,
   PS_TOPLEFTMARGIN  = 0x0008,
   PS_NONE     = 0x0010,
   PS_DOTTEDLINES   = 0x0020,
   PS_YELLOWBACKGROUND  = 0x0040,
   MODE_PEN    = 0,
   MODE_SELECT    = 1,
   MODE_SPACE    = 2;
 }
}


 

[Author: Katie Blanch]

Disclaimers:
This posting is provided "AS IS" with no warranties, and confers no rights.
Some of the information contained within this post may be in relation to beta software. Any and all details are subject to change.