First attempt at a DIY windows message pump.

This commit is contained in:
Eugene Wang
2018-11-20 18:43:48 -05:00
parent cb1fbebc0a
commit f196f605c5
20 changed files with 2154 additions and 178 deletions

View File

@@ -8,6 +8,7 @@ namespace ConsoleApp
{
static void Main(string[] args)
{
TwainSession session = null;
try
{
var config = new TwainConfigBuilder()
@@ -18,42 +19,41 @@ namespace ConsoleApp
Console.WriteLine($"Platform = {config.Platform}");
Console.WriteLine();
using (var session = new TwainSession(config))
session = new TwainSession(config);
session.PropertyChanged += Session_PropertyChanged;
session.SourceDisabled += Session_SourceDisabled;
if (session.Open(IntPtr.Zero) == NTwain.Data.ReturnCode.Success)
{
session.PropertyChanged += Session_PropertyChanged;
session.SourceDisabled += Session_SourceDisabled;
Console.WriteLine("Available data sources:");
if (session.Open(IntPtr.Zero) == NTwain.Data.ReturnCode.Success)
DataSource firstSrc = null;
foreach (var src in session.GetSources())
{
Console.WriteLine("Available data sources:");
if (firstSrc == null) firstSrc = src;
Console.WriteLine($"\t{src}");
}
Console.WriteLine();
DataSource firstSrc = null;
foreach (var src in session.GetSources())
{
if (firstSrc == null) firstSrc = src;
Console.WriteLine($"\t{src}");
}
var defaultSrc = session.DefaultSource;
Console.WriteLine($"Default data source = {defaultSrc}");
Console.WriteLine();
var selectSrc = session.ShowSourceSelector();
Console.WriteLine($"Selected data source = {selectSrc}");
Console.WriteLine();
var targetSrc = selectSrc ?? defaultSrc ?? firstSrc;
if (targetSrc != null)
{
TestThisSource(session, targetSrc);
}
else
{
Console.WriteLine("No data source to test.");
Console.WriteLine();
var defaultSrc = session.DefaultSource;
Console.WriteLine($"Default data source = {defaultSrc}");
Console.WriteLine();
var selectSrc = session.ShowSourceSelector();
Console.WriteLine($"Selected data source = {selectSrc}");
Console.WriteLine();
var targetSrc = selectSrc ?? defaultSrc ?? firstSrc;
if (targetSrc != null)
{
TestThisSource(session, targetSrc);
}
else
{
Console.WriteLine("No data source to test.");
Console.WriteLine();
}
}
}
@@ -63,9 +63,16 @@ namespace ConsoleApp
Console.WriteLine("ERROR: " + ex.ToString());
}
Console.WriteLine("----------------------------------");
Console.WriteLine("Test ended, press Enter to exit...");
Console.WriteLine("------------------------------------------------");
Console.WriteLine("Test in progress, press Enter to stop testing...");
Console.WriteLine("------------------------------------------------");
Console.ReadLine();
var rc = session.StepDown(NTwain.Data.TwainState.S1);
Console.WriteLine("StepDown RC=" + rc);
Console.ReadLine();
Console.WriteLine("----------------------");
Console.WriteLine("Press Enter to exit...");
Console.WriteLine("----------------------");
}
private static void Session_SourceDisabled(object sender, EventArgs e)

View File

@@ -0,0 +1,14 @@
using System.Runtime.InteropServices;
namespace NTwain.Data.Win32
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct BITMAPFILEHEADER
{
public ushort bfType;
public uint bfSize;
public ushort bfReserved1;
public ushort bfReserved2;
public uint bfOffBits;
}
}

View File

@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace NTwain.Data.Win32
{
// this is a good read
// http://atlc.sourceforge.net/bmp.html
/// <summary>
/// Defines the dimensions and color information for a DIB.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
struct BITMAPINFO
{
/// <summary>
/// Structure that contains information about the dimensions of color format.
/// </summary>
public BITMAPINFOHEADER bmiHeader;
/// <summary>
/// This contains one of the following:
/// 1. An array of RGBQUAD. The elements of the array that make up the color table.
/// 2. An array of 16-bit unsigned integers that specifies indexes into the currently realized logical palette. This use of bmiColors is allowed for functions that use DIBs.
/// The number of entries in the array depends on the values of the biBitCount and biClrUsed members of the BITMAPINFOHEADER structure.
/// </summary>
public IntPtr bmiColors;
};
}

View File

@@ -0,0 +1,306 @@
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace NTwain.Data.Win32
{
/// <summary>
/// Structure that contains information about the dimensions and color format of a DIB.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
struct BITMAPINFOHEADER
{
#region fields
/// <summary>
/// The number of bytes required by the structure.
/// </summary>
public uint biSize;
/// <summary>
/// The width of the bitmap, in pixels.
/// If Compression is JPEG or PNG, the Width member specifies the width of the decompressed
/// JPEG or PNG image file, respectively.
/// </summary>
public int biWidth;
/// <summary>
/// The height of the bitmap, in pixels. If Height is positive,
/// the bitmap is a bottom-up DIB and its origin is the lower-left corner.
/// If Height is negative, the bitmap is a top-down DIB and its origin is the upper-left corner.
/// If Height is negative, indicating a top-down DIB, Compression must be either RGB or BITFIELDS. Top-down DIBs cannot be compressed.
/// If Compression is JPEG or PNG, the Height member specifies the height of the decompressed JPEG or PNG image file, respectively.
/// </summary>
public int biHeight;
/// <summary>
/// The number of planes for the target device. This value must be set to 1.
/// </summary>
public ushort biPlanes;
/// <summary>
/// The number of bits-per-pixel. The BitCount member
/// determines the number of bits that define each pixel and the maximum number of colors in the bitmap.
/// </summary>
public ushort biBitCount;
/// <summary>
/// The type of compression for a compressed bottom-up bitmap (top-down DIBs cannot be compressed).
/// </summary>
public CompressionType biCompression;
/// <summary>
/// The size, in bytes, of the image. This may be set to zero for RGB bitmaps.
/// If Compression is JPEG or PNG, SizeImage indicates the size of the JPEG or PNG image buffer, respectively.
/// </summary>
public uint biSizeImage;
/// <summary>
/// The horizontal resolution, in pixels-per-meter, of the target device for the bitmap.
/// An application can use this value to select a bitmap from a resource group that
/// best matches the characteristics of the current device.
/// </summary>
public int biXPelsPerMeter;
/// <summary>
/// The vertical resolution, in pixels-per-meter, of the target device for the bitmap.
/// </summary>
public int biYPelsPerMeter;
/// <summary>
/// The number of color indexes in the color table that are actually used by the bitmap.
/// If this value is zero, the bitmap uses the maximum number of colors corresponding to
/// the value of the BitCount member for the compression mode specified by Compression.
/// </summary>
public uint biClrUsed;
/// <summary>
/// The number of color indexes that are required for displaying the bitmap.
/// If this value is zero, all colors are required.
/// </summary>
public uint biClrImportant;
#endregion
#region utilities
const double METER_INCH_RATIO = 39.3700787;
/// <summary>
/// Gets the horizontal dpi of the bitmap.
/// </summary>
/// <returns></returns>
public float GetXDpi()
{
return (float)Math.Round(biXPelsPerMeter / METER_INCH_RATIO, 0);
}
/// <summary>
/// Gets the vertical dpi of the bitmap.
/// </summary>
/// <returns></returns>
public float GetYDpi()
{
return (float)Math.Round(biYPelsPerMeter / METER_INCH_RATIO, 0);
}
/// <summary>
/// Gets the size of the structure.
/// </summary>
/// <returns></returns>
public static uint GetByteSize()
{
return (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADER));
}
/// <summary>
/// Checks to see if this structure contain valid data.
/// It also fills in any missing pieces if possible.
/// </summary>
/// <returns></returns>
public bool Validate()
{
if (biHeight != 0 && biWidth != 0 && biBitCount != 0)
{
if (biSize == 0)
{
biSize = GetByteSize();
}
if (biClrUsed == 0)
{
switch (biBitCount)
{
case 1:
biClrUsed = 2;
break;
case 4:
biClrUsed = 16;
break;
case 8:
biClrUsed = 256;
break;
}
}
if (biSizeImage == 0)
{
biSizeImage = (uint)((((
biWidth * biBitCount) + 31) & ~31) >> 3) * (uint)Math.Abs(biHeight);
}
return true;
}
return false;
}
/// <summary>
/// Gets the pointer to scan0 given the header pointer.
/// </summary>
/// <param name="headerPtr">The header PTR.</param>
/// <returns></returns>
public IntPtr GetScan0(IntPtr headerPtr)
{
int p = (int)biClrUsed;
if ((p == 0) && (biBitCount <= 8))
{
p = 1 << biBitCount;
}
p = (p * 4) + (int)biSize + headerPtr.ToInt32();
return new IntPtr(p);
}
/// <summary>
/// Gets whether the bitmap is bottom-up or top-down format.
/// </summary>
/// <value>
/// <c>true</c> if this instance is bottom up image; otherwise, <c>false</c>.
/// </value>
/// <returns></returns>
public bool IsBottomUpImage
{
get
{
return biHeight > 0;
}
}
///// <summary>
///// Gets the System.Drawing pixel format of current structure.
///// </summary>
///// <returns></returns>
//public PixelFormat GetDrawingPixelFormat()
//{
// switch (biBitCount)
// {
// case 1:
// return PixelFormat.Format1bppIndexed;
// case 4:
// return PixelFormat.Format4bppIndexed;
// case 8:
// return PixelFormat.Format8bppIndexed;
// case 16:
// return PixelFormat.Format16bppRgb565;
// case 24:
// return PixelFormat.Format24bppRgb;
// case 32:
// return PixelFormat.Format32bppRgb;
// case 48:
// return PixelFormat.Format48bppRgb;
// }
// return PixelFormat.DontCare;
//}
///// <summary>
///// Gets the color palette that's contained in the header.
///// Note not all images will have palette, so check if the return value
///// is null before using it.
///// </summary>
///// <returns></returns>
//public ColorPalette GetDrawingPalette(IntPtr headerPtr)
//{
// //if (format == PixelFormat.Format8bppIndexed)
// //{
// // // update color palette to grayscale version
// // ColorPalette grayPallet = bitmap.Palette;
// // for (int i = 0; i < grayPallet.Entries.Length; i++)
// // {
// // grayPallet.Entries[i] = Color.FromArgb(i, i, i);
// // }
// // bitmap.Palette = grayPallet; // this is what makes the gray pallet take effect
// //}
// if (biClrUsed > 0)
// {
// byte[] data = new byte[biClrUsed * 4];
// Marshal.Copy(new IntPtr(headerPtr.ToInt32() + biSize), data, 0, data.Length);
// var dummy = new System.Drawing.Bitmap(1, 1, GetDrawingPixelFormat());
// ColorPalette pal = dummy.Palette;
// dummy.Dispose();
// int index = 0;
// int setCount = data.Length / 4;
// for (int i = 0; i < setCount; i++)
// {
// index = i * 4;
// pal.Entries[i] = Color.FromArgb(data[index + 2], data[index + 1], data[index]);
// }
// return pal;
// }
// return null;
//}
/// <summary>
/// Gets the stride size of this bitmap.
/// </summary>
/// <returns></returns>
public int GetStrideSize()
{
int bitsPerRow = (biBitCount * biWidth);
int strideTest = bitsPerRow / 8 + (bitsPerRow % 8 != 0 ? 1 : 0);
int overage = strideTest % 4;
if (overage > 0)
{
strideTest += (4 - overage);
}
return strideTest;
}
/// <summary>
/// Returns a <see cref="System.String" /> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String" /> that represents this instance.
/// </returns>
public override string ToString()
{
return new StringBuilder().Append("BitmapInfoHeader:")
.Append("\r\n\tSize = " + biSize)
.Append("\r\n\tWidth = " + biWidth)
.Append("\r\n\tHeight = " + biHeight)
.Append("\r\n\tPlanes = " + biPlanes)
.Append("\r\n\tBitCount = " + biBitCount)
.Append("\r\n\tCompression = " + biCompression)
.Append("\r\n\tSizeImage = " + biSizeImage)
.Append("\r\n\tXPixelsPerMeter = " + biXPelsPerMeter)
.Append("\r\n\tYPixelsPerMeter = " + biYPelsPerMeter)
.Append("\r\n\tColorUsed = " + biClrUsed)
.Append("\r\n\tColorImportant = " + biClrImportant).ToString();
}
#endregion
/// <summary>
/// Indicates the bitmap compression of <seealso cref="BITMAPINFOHEADER"/>.
/// </summary>
public enum CompressionType : uint
{
/// <summary>
/// An uncompressed format.
/// </summary>
BI_RGB = 0,
/// <summary>
/// A run-length encoded (RLE) format for bitmaps with 8 bpp. The compression format is a 2-byte format consisting of a count byte followed by a byte containing a color index. For more information, see Bitmap Compression.
/// </summary>
BI_RLE8 = 1,
/// <summary>
/// An RLE, format for bitmaps with 4 bpp. The compression format is a 2-byte format consisting of a count byte followed by two word-length color indexes. For more information, see Bitmap Compression.
/// </summary>
BI_RLE4 = 2,
/// <summary>
/// Specifies that the bitmap is not compressed and that the color table consists of three DWORD color masks that specify the red, green, and blue components of each pixel.
/// This is valid when used with 16- and 32-bpp bitmaps.
/// </summary>
BI_BITFIELDS = 3,
/// <summary>
/// Indicates that the image is a JPEG image.
/// </summary>
BI_JPEG = 4,
/// <summary>
/// Indicates that the image is a PNG image.
/// </summary>
BI_PNG = 5
}
};
}

View File

@@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NTwain.Data.Win32
{
/// <summary>
/// Class style flags for a window.
/// </summary>
[Flags]
enum ClassStyles : uint
{
/// <summary>
/// Redraws the entire window if a movement or size adjustment changes the height of the client area.
/// </summary>
CS_VREDRAW = 0x0001,
/// <summary>
/// Redraws the entire window if a movement or size adjustment changes the width of the client area.
/// </summary>
CS_HREDRAW = 0x0002,
/// <summary>
/// Sends a double-click message to the window procedure when the user double-clicks the mouse while the cursor is within a window belonging to the class.
/// </summary>
CS_DBLCLKS = 0x0008,
/// <summary>
/// Allocates a unique device context for each window in the class.
/// </summary>
CS_OWNDC = 0x0020,
/// <summary>
/// Allocates one device context to be shared by all windows in the class.
/// </summary>
CS_CLASSDC = 0x0040,
/// <summary>
/// Sets the clipping rectangle of the child window to that of the parent window so that the child can draw on the parent.
/// </summary>
CS_PARENTDC = 0x0080,
/// <summary>
/// Disables Close on the window menu.
/// </summary>
CS_NOCLOSE = 0x0200,
/// <summary>
/// Saves, as a bitmap, the portion of the screen image obscured by a window of this class. When the window is removed, the system uses the saved bitmap to restore the screen image, including other windows that were obscured.
/// </summary>
CS_SAVEBITS = 0x0800,
/// <summary>
/// Aligns the window's client area on a byte boundary (in the x direction). This style affects the width of the window and its horizontal placement on the display.
/// </summary>
CS_BYTEALIGNCLIENT = 0x1000,
/// <summary>
/// Aligns the window on a byte boundary (in the x direction). This style affects the width of the window and its horizontal placement on the display.
/// </summary>
CS_BYTEALIGNWINDOW = 0x2000,
/// <summary>
/// Indicates that the window class is an application global class.
/// </summary>
CS_GLOBALCLASS = 0x4000,
CS_IME = 0x10000,
/// <summary>
/// Enables the drop shadow effect on a window. The effect is turned on and off through SPI_SETDROPSHADOW.
/// </summary>
CS_DROPSHADOW = 0x20000,
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace NTwain.Data.Win32
{
/// <summary>
/// The MSG structure in Windows for TWAIN use.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
struct MSG
{
public IntPtr hwnd;
public int message;
public IntPtr wParam;
public IntPtr lParam;
int time;
int x;
int y;
}
}

View File

@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace NTwain.Data.Win32
{
/// <summary>
/// Describes a color consisting of relative intensities of red, green, and blue.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
struct RGBQUAD
{
/// <summary>
/// The intensity of blue in the color.
/// </summary>
public byte rgbBlue;
/// <summary>
/// The intensity of green in the color.
/// </summary>
public byte rgbGreen;
/// <summary>
/// The intensity of red in the color.
/// </summary>
public byte rgbRed;
/// <summary>
/// This member is reserved and must be zero.
/// </summary>
byte rgbReserved;
};
}

View File

@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace NTwain.Data.Win32
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct WNDCLASSEX
{
[MarshalAs(UnmanagedType.U4)]
public int cbSize;
[MarshalAs(UnmanagedType.U4)]
public ClassStyles style;
public IntPtr lpfnWndProc; // not WndProc -- careful
public int cbClsExtra;
public int cbWndExtra;
public IntPtr hInstance;
public IntPtr hIcon;
public IntPtr hCursor;
public IntPtr hbrBackground;
public string lpszMenuName;
public string lpszClassName;
public IntPtr hIconSm;
}
delegate IntPtr WndProcDelegate(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
}

View File

@@ -0,0 +1,945 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NTwain.Data.Win32
{
/// <summary>
/// Enumerated values of window messages.
/// </summary>
enum WindowMessage
{
/// <summary>
/// Performs no operation. An application sends the WM_NULL message if it wants to post a message that the recipient window will ignore.
/// </summary>
WM_NULL = 0x0000,
/// <summary>
/// Sent when an application requests that a window be created by calling the CreateWindowEx or CreateWindow function. (The message is sent before the function returns.) The window procedure of the new window receives this message after the window is created, but before the window becomes visible.
/// </summary>
WM_CREATE = 0x0001,
/// <summary>
/// Sent when a window is being destroyed. It is sent to the window procedure of the window being destroyed after the window is removed from the screen.
/// This message is sent first to the window being destroyed and then to the child windows (if any) as they are destroyed. During the processing of the message, it can be assumed that all child windows still exist.
/// </summary>
WM_DESTROY = 0x0002,
/// <summary>
/// Sent after a window has been moved.
/// </summary>
WM_MOVE = 0x0003,
/// <summary>
/// Sent to a window after its size has changed.
/// </summary>
WM_SIZE = 0x0005,
/// <summary>
/// Sent to both the window being activated and the window being deactivated. If the windows use the same input queue, the message is sent synchronously, first to the window procedure of the top-level window being deactivated, then to the window procedure of the top-level window being activated. If the windows use different input queues, the message is sent asynchronously, so the window is activated immediately.
/// </summary>
WM_ACTIVATE = 0x0006,
/// <summary>
/// Sent to a window after it has gained the keyboard focus.
/// </summary>
WM_SETFOCUS = 0x0007,
/// <summary>
/// Sent to a window immediately before it loses the keyboard focus.
/// </summary>
WM_KILLFOCUS = 0x0008,
/// <summary>
/// Sent when an application changes the enabled state of a window. It is sent to the window whose enabled state is changing. This message is sent before the EnableWindow function returns, but after the enabled state (WS_DISABLED style bit) of the window has changed.
/// </summary>
WM_ENABLE = 0x000A,
/// <summary>
/// An application sends the WM_SETREDRAW message to a window to allow changes in that window to be redrawn or to prevent changes in that window from being redrawn.
/// </summary>
WM_SETREDRAW = 0x000B,
/// <summary>
/// Sets the text of a window.
/// </summary>
WM_SETTEXT = 0x000C,
/// <summary>
/// Copies the text that corresponds to a window into a buffer provided by the caller.
/// </summary>
WM_GETTEXT = 0x000D,
/// <summary>
/// Determines the length, in characters, of the text associated with a window.
/// </summary>
WM_GETTEXTLENGTH = 0x000E,
/// <summary>
/// The WM_PAINT message is sent when the system or another application makes a request to paint a portion of an application's window. The message is sent when the UpdateWindow or RedrawWindow function is called, or by the DispatchMessage function when the application obtains a WM_PAINT message by using the GetMessage or PeekMessage function.
/// </summary>
WM_PAINT = 0x000F,
/// <summary>
/// Sent as a signal that a window or an application should terminate.
/// </summary>
WM_CLOSE = 0x0010,
/// <summary>
/// The WM_QUERYENDSESSION message is sent when the user chooses to end the session or when an application calls one of the system shutdown functions. If any application returns zero, the session is not ended. The system stops sending WM_QUERYENDSESSION messages as soon as one application returns zero.
/// After processing this message, the system sends the WM_ENDSESSION message with the wParam parameter set to the results of the WM_QUERYENDSESSION message.
/// </summary>
WM_QUERYENDSESSION = 0x0011,
/// <summary>
/// Indicates a request to terminate an application, and is generated when the application calls the PostQuitMessage function. This message causes the GetMessage function to return zero.
/// </summary>
WM_QUIT = 0x0012,
/// <summary>
/// Sent to an icon when the user requests that the window be restored to its previous size and position.
/// </summary>
WM_QUERYOPEN = 0x0013,
/// <summary>
/// Sent when the window background must be erased (for example, when a window is resized). The message is sent to prepare an invalidated portion of a window for painting.
/// </summary>
WM_ERASEBKGND = 0x0014,
/// <summary>
/// The WM_SYSCOLORCHANGE message is sent to all top-level windows when a change is made to a system color setting.
/// </summary>
WM_SYSCOLORCHANGE = 0x0015,
/// <summary>
/// The WM_ENDSESSION message is sent to an application after the system processes the results of the WM_QUERYENDSESSION message. The WM_ENDSESSION message informs the application whether the session is ending.
/// </summary>
WM_ENDSESSION = 0x0016,
/// <summary>
/// Sent to a window when the window is about to be hidden or shown.
/// </summary>
WM_SHOWWINDOW = 0x0018,
/// <summary>
/// The WM_CTLCOLOR message is used in 16-bit versions of Windows to change the color scheme of list boxes, the list boxes of combo boxes, message boxes, button controls, edit controls, static controls, and dialog boxes.
/// </summary>
WM_CTLCOLOR = 0x0019,
[EditorBrowsable(EditorBrowsableState.Never)]
WM_WININICHANGE = 0x001A,
/// <summary>
/// A message that is sent to all top-level windows when the SystemParametersInfo function changes a system-wide setting or when policy settings have changed.
/// Applications should send WM_SETTINGCHANGE to all top-level windows when they make changes to system parameters. (This message cannot be sent directly to a window.) To send the WM_SETTINGCHANGE message to all top-level windows, use the SendMessageTimeout function with the hwnd parameter set to HWND_BROADCAST.
/// </summary>
WM_SETTINGCHANGE = WM_WININICHANGE,
/// <summary>
/// The WM_DEVMODECHANGE message is sent to all top-level windows whenever the user changes device-mode settings.
/// </summary>
WM_DEVMODECHANGE = 0x001B,
/// <summary>
/// Sent when a window belonging to a different application than the active window is about to be activated. The message is sent to the application whose window is being activated and to the application whose window is being deactivated.
/// </summary>
WM_ACTIVATEAPP = 0x001C,
/// <summary>
/// An application sends the WM_FONTCHANGE message to all top-level windows in the system after changing the pool of font resources.
/// </summary>
WM_FONTCHANGE = 0x001D,
/// <summary>
/// A message that is sent whenever there is a change in the system time.
/// </summary>
WM_TIMECHANGE = 0x001E,
/// <summary>
/// Sent to cancel certain modes, such as mouse capture. For example, the system sends this message to the active window when a dialog box or message box is displayed. Certain functions also send this message explicitly to the specified window regardless of whether it is the active window. For example, the EnableWindow function sends this message when disabling the specified window.
/// </summary>
WM_CANCELMODE = 0x001F,
/// <summary>
/// Sent to a window if the mouse causes the cursor to move within a window and mouse input is not captured.
/// </summary>
WM_SETCURSOR = 0x0020,
/// <summary>
/// Sent when the cursor is in an inactive window and the user presses a mouse button. The parent window receives this message only if the child window passes it to the DefWindowProc function.
/// </summary>
WM_MOUSEACTIVATE = 0x0021,
/// <summary>
/// Sent to a child window when the user clicks the window's title bar or when the window is activated, moved, or sized.
/// </summary>
WM_CHILDACTIVATE = 0x0022,
/// <summary>
/// Sent by a computer-based training (CBT) application to separate user-input messages from other messages sent through the WH_JOURNALPLAYBACK procedure.
/// </summary>
WM_QUEUESYNC = 0x0023,
/// <summary>
/// Sent to a window when the size or position of the window is about to change. An application can use this message to override the window's default maximized size and position, or its default minimum or maximum tracking size.
/// </summary>
WM_GETMINMAXINFO = 0x24,
WM_PAINTICON = 0x0026,
WM_ICONERASEBKGND = 0x0027,
/// <summary>
/// Sent to a dialog box procedure to set the keyboard focus to a different control in the dialog box.
/// </summary>
WM_NEXTDLGCTL = 0x0028,
/// <summary>
/// The WM_SPOOLERSTATUS message is sent from Print Manager whenever a job is added to or removed from the Print Manager queue.
/// </summary>
WM_SPOOLERSTATUS = 0x002A,
/// <summary>
/// Sent to the parent window of an owner-drawn button, combo box, list box, or menu when a visual aspect of the button, combo box, list box, or menu has changed.
/// </summary>
WM_DRAWITEM = 0x002B,
/// <summary>
/// Sent to the owner window of a combo box, list box, list view control, or menu item when the control or menu is created.
/// </summary>
WM_MEASUREITEM = 0x002C,
/// <summary>
/// Sent to the owner of a list box or combo box when the list box or combo box is destroyed or when items are removed by the LB_DELETESTRING, LB_RESETCONTENT, CB_DELETESTRING, or CB_RESETCONTENT message. The system sends a WM_DELETEITEM message for each deleted item. The system sends the WM_DELETEITEM message for any deleted list box or combo box item with nonzero item data.
/// </summary>
WM_DELETEITEM = 0x002D,
/// <summary>
/// Sent by a list box with the LBS_WANTKEYBOARDINPUT style to its owner in response to a WM_KEYDOWN message.
/// </summary>
WM_VKEYTOITEM = 0x002E,
/// <summary>
/// Sent by a list box with the LBS_WANTKEYBOARDINPUT style to its owner in response to a WM_CHAR message.
/// </summary>
WM_CHARTOITEM = 0x002F,
/// <summary>
/// Sets the font that a control is to use when drawing text.
/// </summary>
WM_SETFONT = 0x30,
/// <summary>
/// Retrieves the font with which the control is currently drawing its text.
/// </summary>
WM_GETFONT = 0x31,
/// <summary>
/// Sent to a window to associate a hot key with the window. When the user presses the hot key, the system activates the window.
/// </summary>
WM_SETHOTKEY = 0x0032,
/// <summary>
/// Sent to determine the hot key associated with a window.
/// </summary>
WM_GETHOTKEY = 0x0033,
/// <summary>
/// Sent to a minimized (iconic) window. The window is about to be dragged by the user but does not have an icon defined for its class. An application can return a handle to an icon or cursor. The system displays this cursor or icon while the user drags the icon.
/// </summary>
WM_QUERYDRAGICON = 0x37,
/// <summary>
/// Sent to determine the relative position of a new item in the sorted list of an owner-drawn combo box or list box. Whenever the application adds a new item, the system sends this message to the owner of a combo box or list box created with the CBS_SORT or LBS_SORT style.
/// </summary>
WM_COMPAREITEM = 0x0039,
/// <summary>
/// Sent by both Microsoft Active Accessibility and Microsoft UI Automation to obtain information about an accessible object contained in a server application.
/// Applications never send this message directly. Microsoft Active Accessibility sends this message in response to calls to AccessibleObjectFromPoint, AccessibleObjectFromEvent, or AccessibleObjectFromWindow. However, server applications handle this message. UI Automation sends this message in response to calls to IUIAutomation::ElementFromHandle, ElementFromPoint, and GetFocusedElement, and when handling events for which a client has registered.
/// </summary>
WM_GETOBJECT = 0x003D,
/// <summary>
/// Sent to all top-level windows when the system detects more than 12.5 percent of system time over a 30- to 60-second interval is being spent compacting memory. This indicates that system memory is low.
/// </summary>
WM_COMPACTING = 0x0041,
//WM_COMMNOTIFY = 0x0044,
/// <summary>
/// Sent to a window whose size, position, or place in the Z order is about to change as a result of a call to the SetWindowPos function or another window-management function.
/// </summary>
WM_WINDOWPOSCHANGING = 0x0046,
/// <summary>
/// Sent to a window whose size, position, or place in the Z order has changed as a result of a call to the SetWindowPos function or another window-management function.
/// </summary>
WM_WINDOWPOSCHANGED = 0x0047,
WM_POWER = 0x0048,
/// <summary>
/// An application sends the WM_COPYDATA message to pass data to another application.
/// </summary>
WM_COPYDATA = 0x004A,
/// <summary>
/// Posted to an application when a user cancels the application's journaling activities. The message is posted with a NULL window handle.
/// </summary>
WM_CANCELJOURNAL = 0x004B,
/// <summary>
/// Sent by a common control to its parent window when an event has occurred or the control requires some information.
/// </summary>
WM_NOTIFY = 0x004E,
/// <summary>
/// Posted to the window with the focus when the user chooses a new input language, either with the hotkey (specified in the Keyboard control panel application) or from the indicator on the system taskbar. An application can accept the change by passing the message to the DefWindowProc function or reject the change (and prevent it from taking place) by returning immediately.
/// </summary>
WM_INPUTLANGCHANGEREQUEST = 0x0050,
/// <summary>
/// Sent to the topmost affected window after an application's input language has been changed. You should make any application-specific settings and pass the message to the DefWindowProc function, which passes the message to all first-level child windows. These child windows can pass the message to DefWindowProc to have it pass the message to their child windows, and so on.
/// </summary>
WM_INPUTLANGCHANGE = 0x0051,
/// <summary>
/// Sent to an application that has initiated a training card with Windows Help. The message informs the application when the user clicks an authorable button. An application initiates a training card by specifying the HELP_TCARD command in a call to the WinHelp function.
/// </summary>
WM_TCARD = 0x0052,
/// <summary>
/// Indicates that the user pressed the F1 key. If a menu is active when F1 is pressed, WM_HELP is sent to the window associated with the menu; otherwise, WM_HELP is sent to the window that has the keyboard focus. If no window has the keyboard focus, WM_HELP is sent to the currently active window.
/// </summary>
WM_HELP = 0x0053,
/// <summary>
/// Sent to all windows after the user has logged on or off. When the user logs on or off, the system updates the user-specific settings. The system sends this message immediately after updating the settings.
/// </summary>
WM_USERCHANGED = 0x0054,
/// <summary>
/// Determines if a window accepts ANSI or Unicode structures in the WM_NOTIFY notification message. WM_NOTIFYFORMAT messages are sent from a common control to its parent window and from the parent window to the common control.
/// </summary>
WM_NOTIFYFORMAT = 0x0055,
/// <summary>
/// Notifies a window that the user clicked the right mouse button (right-clicked) in the window.
/// </summary>
WM_CONTEXTMENU = 0x007B,
/// <summary>
/// Sent to a window when the SetWindowLong function is about to change one or more of the window's styles.
/// </summary>
WM_STYLECHANGING = 0x007C,
/// <summary>
/// Sent to a window after the SetWindowLong function has changed one or more of the window's styles.
/// </summary>
WM_STYLECHANGED = 0x007D,
/// <summary>
/// The WM_DISPLAYCHANGE message is sent to all windows when the display resolution has changed.
/// </summary>
WM_DISPLAYCHANGE = 0x007E,
/// <summary>
/// Sent to a window to retrieve a handle to the large or small icon associated with a window. The system displays the large icon in the ALT+TAB dialog, and the small icon in the window caption.
/// </summary>
WM_GETICON = 0x007F,
/// <summary>
/// Associates a new large or small icon with a window. The system displays the large icon in the ALT+TAB dialog box, and the small icon in the window caption.
/// </summary>
WM_SETICON = 0x0080,
// non client area
/// <summary>
/// Sent prior to the WM_CREATE message when a window is first created.
/// </summary>
WM_NCCREATE = 0x0081,
/// <summary>
/// Notifies a window that its nonclient area is being destroyed. The DestroyWindow function sends the WM_NCDESTROY message to the window following the WM_DESTROY message.WM_DESTROY is used to free the allocated memory object associated with the window.
/// The WM_NCDESTROY message is sent after the child windows have been destroyed. In contrast, WM_DESTROY is sent before the child windows are destroyed.
/// </summary>
WM_NCDESTROY = 0x0082,
/// <summary>
/// Sent when the size and position of a window's client area must be calculated. By processing this message, an application can control the content of the window's client area when the size or position of the window changes.
/// </summary>
WM_NCCALCSIZE = 0x0083,
/// <summary>
/// Sent to a window in order to determine what part of the window corresponds to a particular screen coordinate. This can happen, for example, when the cursor moves, when a mouse button is pressed or released, or in response to a call to a function such as WindowFromPoint. If the mouse is not captured, the message is sent to the window beneath the cursor. Otherwise, the message is sent to the window that has captured the mouse.
/// </summary>
WM_NCHITTEST = 0x84,
/// <summary>
/// The WM_NCPAINT message is sent to a window when its frame must be painted.
/// </summary>
WM_NCPAINT = 0x0085,
/// <summary>
/// Sent to a window when its nonclient area needs to be changed to indicate an active or inactive state.
/// </summary>
WM_NCACTIVATE = 0x0086,
/// <summary>
/// Sent to the window procedure associated with a control. By default, the system handles all keyboard input to the control; the system interprets certain types of keyboard input as dialog box navigation keys. To override this default behavior, the control can respond to the WM_GETDLGCODE message to indicate the types of input it wants to process itself.
/// </summary>
WM_GETDLGCODE = 0x0087,
/// <summary>
/// The WM_SYNCPAINT message is used to synchronize painting while avoiding linking independent GUI threads.
/// </summary>
WM_SYNCPAINT = 0x0088,
// non client mouse
/// <summary>
/// Posted to a window when the cursor is moved within the nonclient area of the window. This message is posted to the window that contains the cursor. If a window has captured the mouse, this message is not posted.
/// </summary>
WM_NCMOUSEMOVE = 0x00A0,
/// <summary>
/// Posted when the user presses the left mouse button while the cursor is within the nonclient area of a window. This message is posted to the window that contains the cursor. If a window has captured the mouse, this message is not posted.
/// </summary>
WM_NCLBUTTONDOWN = 0x00A1,
/// <summary>
/// Posted when the user releases the left mouse button while the cursor is within the nonclient area of a window. This message is posted to the window that contains the cursor. If a window has captured the mouse, this message is not posted.
/// </summary>
WM_NCLBUTTONUP = 0x00A2,
/// <summary>
/// Posted when the user double-clicks the left mouse button while the cursor is within the nonclient area of a window. This message is posted to the window that contains the cursor. If a window has captured the mouse, this message is not posted.
/// </summary>
WM_NCLBUTTONDBLCLK = 0x00A3,
/// <summary>
/// Posted when the user presses the right mouse button while the cursor is within the nonclient area of a window. This message is posted to the window that contains the cursor. If a window has captured the mouse, this message is not posted.
/// </summary>
WM_NCRBUTTONDOWN = 0x00A4,
/// <summary>
/// Posted when the user releases the right mouse button while the cursor is within the nonclient area of a window. This message is posted to the window that contains the cursor. If a window has captured the mouse, this message is not posted.
/// </summary>
WM_NCRBUTTONUP = 0x00A5,
/// <summary>
/// Posted when the user double-clicks the right mouse button while the cursor is within the nonclient area of a window. This message is posted to the window that contains the cursor. If a window has captured the mouse, this message is not posted.
/// </summary>
WM_NCRBUTTONDBLCLK = 0x00A6,
/// <summary>
/// Posted when the user presses the middle mouse button while the cursor is within the nonclient area of a window. This message is posted to the window that contains the cursor. If a window has captured the mouse, this message is not posted.
/// </summary>
WM_NCMBUTTONDOWN = 0x00A7,
/// <summary>
/// Posted when the user releases the middle mouse button while the cursor is within the nonclient area of a window. This message is posted to the window that contains the cursor. If a window has captured the mouse, this message is not posted.
/// </summary>
WM_NCMBUTTONUP = 0x00A8,
/// <summary>
/// Posted when the user double-clicks the middle mouse button while the cursor is within the nonclient area of a window. This message is posted to the window that contains the cursor. If a window has captured the mouse, this message is not posted.
/// </summary>
WM_NCMBUTTONDBLCLK = 0x00A9,
/// <summary>
/// Posted when the user presses the first or second X button while the cursor is in the nonclient area of a window. This message is posted to the window that contains the cursor. If a window has captured the mouse, this message is not posted.
/// </summary>
WM_NCXBUTTONDOWN = 0x00AB,
/// <summary>
/// Posted when the user releases the first or second X button while the cursor is in the nonclient area of a window. This message is posted to the window that contains the cursor. If a window has captured the mouse, this message is not posted.
/// </summary>
WM_NCXBUTTONUP = 0x00AC,
/// <summary>
/// Posted when the user double-clicks the first or second X button while the cursor is in the nonclient area of a window. This message is posted to the window that contains the cursor. If a window has captured the mouse, this message is not posted.
/// </summary>
WM_NCXBUTTONDBLCLK = 0x00AD,
WM_INPUT_DEVICE_CHANGE = 0x00FE,
WM_INPUT = 0x00FF,
/// <summary>
/// Undocumented value that needs to be suppressed in custom
/// drawn form.
/// </summary>
WM_NCUAHDRAWCAPTION = 0x00ae,
/// <summary>
/// Undocumented value that needs to be suppressed in custom
/// drawn form.
/// </summary>
WM_NCUAHDRAWFRAME = 0x00af,
// keyboard
/// <summary>
/// Posted to the window with the keyboard focus when a nonsystem key is pressed. A nonsystem key is a key that is pressed when the ALT key is not pressed.
/// </summary>
WM_KEYDOWN = 0x0100,
/// <summary>
/// Posted to the window with the keyboard focus when a nonsystem key is released. A nonsystem key is a key that is pressed when the ALT key is not pressed, or a keyboard key that is pressed when a window has the keyboard focus.
/// </summary>
WM_KEYUP = 0x0101,
/// <summary>
/// Posted to the window with the keyboard focus when a WM_KEYDOWN message is translated by the TranslateMessage function. The WM_CHAR message contains the character code of the key that was pressed.
/// </summary>
WM_CHAR = 0x0102,
/// <summary>
/// Posted to the window with the keyboard focus when a WM_KEYUP message is translated by the TranslateMessage function. WM_DEADCHAR specifies a character code generated by a dead key. A dead key is a key that generates a character, such as the umlaut (double-dot), that is combined with another character to form a composite character. For example, the umlaut-O character (Ö) is generated by typing the dead key for the umlaut character, and then typing the O key.
/// </summary>
WM_DEADCHAR = 0x0103,
/// <summary>
/// Posted to the window with the keyboard focus when the user presses the F10 key (which activates the menu bar) or holds down the ALT key and then presses another key. It also occurs when no window currently has the keyboard focus; in this case, the WM_SYSKEYDOWN message is sent to the active window. The window that receives the message can distinguish between these two contexts by checking the context code in the lParam parameter.
/// </summary>
WM_SYSKEYDOWN = 0x0104,
/// <summary>
/// Posted to the window with the keyboard focus when the user releases a key that was pressed while the ALT key was held down. It also occurs when no window currently has the keyboard focus; in this case, the WM_SYSKEYUP message is sent to the active window. The window that receives the message can distinguish between these two contexts by checking the context code in the lParam parameter.
/// </summary>
WM_SYSKEYUP = 0x0105,
/// <summary>
/// Posted to the window with the keyboard focus when a WM_SYSKEYDOWN message is translated by the TranslateMessage function. It specifies the character code of a system character key — that is, a character key that is pressed while the ALT key is down.
/// </summary>
WM_SYSCHAR = 0x0106,
/// <summary>
/// Sent to the window with the keyboard focus when a WM_SYSKEYDOWN message is translated by the TranslateMessage function. WM_SYSDEADCHAR specifies the character code of a system dead key — that is, a dead key that is pressed while holding down the ALT key.
/// </summary>
WM_SYSDEADCHAR = 0x0107,
//WM_KEYLAST = 0x0108,
/// <summary>
/// Posted to the window with the keyboard focus when a WM_KEYDOWN message is translated by the TranslateMessage function. The WM_UNICHAR message contains the character code of the key that was pressed.
/// The WM_UNICHAR message is equivalent to WM_CHAR, but it uses Unicode Transformation Format (UTF)-32, whereas WM_CHAR uses UTF-16. It is designed to send or post Unicode characters to ANSI windows and it can can handle Unicode Supplementary Plane characters.
/// </summary>
WM_UNICHAR = 0x0109,
/// <summary>
/// Sent immediately before the IME generates the composition string as a result of a keystroke.
/// </summary>
WM_IME_STARTCOMPOSITION = 0x010D,
/// <summary>
/// Sent to an application when the IME ends composition.
/// </summary>
WM_IME_ENDCOMPOSITION = 0x010E,
/// <summary>
/// Sent to an application when the IME changes composition status as a result of a keystroke.
/// </summary>
WM_IME_COMPOSITION = 0x010F,
//WM_IME_KEYLAST = 0x010F,
/// <summary>
/// Sent to the dialog box procedure immediately before a dialog box is displayed. Dialog box procedures typically use this message to initialize controls and carry out any other initialization tasks that affect the appearance of the dialog box.
/// </summary>
WM_INITDIALOG = 0x0110,
/// <summary>
/// Sent when the user selects a command item from a menu, when a control sends a notification message to its parent window, or when an accelerator keystroke is translated.
/// </summary>
WM_COMMAND = 0x0111,
/// <summary>
/// A window receives this message when the user chooses a command from the Window menu (formerly known as the system or control menu) or when the user chooses the maximize button, minimize button, restore button, or close button.
/// </summary>
WM_SYSCOMMAND = 0x0112,
/// <summary>
/// Posted to the installing thread's message queue when a timer expires.
/// </summary>
WM_TIMER = 0x0113,
/// <summary>
/// The WM_HSCROLL message is sent to a window when a scroll event occurs in the window's standard horizontal scroll bar. This message is also sent to the owner of a horizontal scroll bar control when a scroll event occurs in the control.
/// </summary>
WM_HSCROLL = 0x0114,
/// <summary>
/// The WM_VSCROLL message is sent to a window when a scroll event occurs in the window's standard vertical scroll bar. This message is also sent to the owner of a vertical scroll bar control when a scroll event occurs in the control.
/// </summary>
WM_VSCROLL = 0x0115,
// menu
/// <summary>
/// Sent when a menu is about to become active. It occurs when the user clicks an item on the menu bar or presses a menu key. This allows the application to modify the menu before it is displayed.
/// </summary>
WM_INITMENU = 0x0116,
/// <summary>
/// Sent when a drop-down menu or submenu is about to become active. This allows an application to modify the menu before it is displayed, without changing the entire menu.
/// </summary>
WM_INITMENUPOPUP = 0x0117,
WM_GESTURE = 0x0119,
WM_GESTURENOTIFY = 0x011A,
/// <summary>
/// Sent to a menu's owner window when the user selects a menu item.
/// </summary>
WM_MENUSELECT = 0x011F,
/// <summary>
/// Sent when a menu is active and the user presses a key that does not correspond to any mnemonic or accelerator key. This message is sent to the window that owns the menu.
/// </summary>
WM_MENUCHAR = 0x0120,
/// <summary>
/// Sent to the owner window of a modal dialog box or menu that is entering an idle state. A modal dialog box or menu enters an idle state when no messages are waiting in its queue after it has processed one or more previous messages.
/// </summary>
WM_ENTERIDLE = 0x0121,
/// <summary>
/// Sent when the user releases the right mouse button while the cursor is on a menu item.
/// </summary>
WM_MENURBUTTONUP = 0x0122,
/// <summary>
/// Sent to the owner of a drag-and-drop menu when the user drags a menu item.
/// </summary>
WM_MENUDRAG = 0x0123,
/// <summary>
/// Sent to the owner of a drag-and-drop menu when the mouse cursor enters a menu item or moves from the center of the item to the top or bottom of the item.
/// </summary>
WM_MENUGETOBJECT = 0x0124,
/// <summary>
/// Sent when a drop-down menu or submenu has been destroyed.
/// </summary>
WM_UNINITMENUPOPUP = 0x0125,
/// <summary>
/// Sent when the user makes a selection from a menu.
/// </summary>
WM_MENUCOMMAND = 0x0126,
/// <summary>
/// An application sends the WM_CHANGEUISTATE message to indicate that the UI state should be changed.
/// </summary>
WM_CHANGEUISTATE = 0x0127,
/// <summary>
/// An application sends the WM_UPDATEUISTATE message to change the UI state for the specified window and all its child windows.
/// </summary>
WM_UPDATEUISTATE = 0x0128,
/// <summary>
/// An application sends the WM_QUERYUISTATE message to retrieve the UI state for a window.
/// </summary>
WM_QUERYUISTATE = 0x0129,
// others
WM_CTLCOLORMSGBOX = 0x0132,
/// <summary>
/// An edit control that is not read-only or disabled sends the WM_CTLCOLOREDIT message to its parent window when the control is about to be drawn. By responding to this message, the parent window can use the specified device context handle to set the text and background colors of the edit control.
/// </summary>
WM_CTLCOLOREDIT = 0x133,
/// <summary>
/// Sent to the parent window of a list box before the system draws the list box. By responding to this message, the parent window can set the text and background colors of the list box by using the specified display device context handle.
/// </summary>
WM_CTLCOLORLISTBOX = 0x0134,
/// <summary>
/// The WM_CTLCOLORBTN message is sent to the parent window of a button before drawing the button. The parent window can change the button's text and background colors. However, only owner-drawn buttons respond to the parent window processing this message.
/// </summary>
WM_CTLCOLORBTN = 0x0135,
/// <summary>
/// Sent to a dialog box before the system draws the dialog box. By responding to this message, the dialog box can set its text and background colors using the specified display device context handle.
/// </summary>
WM_CTLCOLORDLG = 0x0136,
/// <summary>
/// The WM_CTLCOLORSCROLLBAR message is sent to the parent window of a scroll bar control when the control is about to be drawn. By responding to this message, the parent window can use the display context handle to set the background color of the scroll bar control.
/// </summary>
WM_CTLCOLORSCROLLBAR = 0x0137,
/// <summary>
/// A static control, or an edit control that is read-only or disabled, sends the WM_CTLCOLORSTATIC message to its parent window when the control is about to be drawn. By responding to this message, the parent window can use the specified device context handle to set the text and background colors of the static control.
/// </summary>
WM_CTLCOLORSTATIC = 0x0138,
// mouse
//WM_MOUSEFIRST = 0x0200,
/// <summary>
/// Posted to a window when the cursor moves. If the mouse is not captured, the message is posted to the window that contains the cursor. Otherwise, the message is posted to the window that has captured the mouse.
/// </summary>
WM_MOUSEMOVE = 0x0200,
/// <summary>
/// Posted when the user presses the left mouse button while the cursor is in the client area of a window. If the mouse is not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has captured the mouse.
/// </summary>
WM_LBUTTONDOWN = 0x0201,
/// <summary>
/// Posted when the user releases the left mouse button while the cursor is in the client area of a window. If the mouse is not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has captured the mouse.
/// </summary>
WM_LBUTTONUP = 0x0202,
/// <summary>
/// Posted when the user double-clicks the left mouse button while the cursor is in the client area of a window. If the mouse is not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has captured the mouse.
/// </summary>
WM_LBUTTONDBLCLK = 0x0203,
/// <summary>
/// Posted when the user presses the right mouse button while the cursor is in the client area of a window. If the mouse is not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has captured the mouse.
/// </summary>
WM_RBUTTONDOWN = 0x0204,
/// <summary>
/// Posted when the user releases the right mouse button while the cursor is in the client area of a window. If the mouse is not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has captured the mouse.
/// </summary>
WM_RBUTTONUP = 0x0205,
/// <summary>
/// Posted when the user double-clicks the right mouse button while the cursor is in the client area of a window. If the mouse is not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has captured the mouse.
/// </summary>
WM_RBUTTONDBLCLK = 0x0206,
/// <summary>
/// Posted when the user presses the middle mouse button while the cursor is in the client area of a window. If the mouse is not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has captured the mouse.
/// </summary>
WM_MBUTTONDOWN = 0x0207,
/// <summary>
/// Posted when the user releases the middle mouse button while the cursor is in the client area of a window. If the mouse is not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has captured the mouse.
/// </summary>
WM_MBUTTONUP = 0x0208,
/// <summary>
/// Posted when the user double-clicks the middle mouse button while the cursor is in the client area of a window. If the mouse is not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has captured the mouse.
/// </summary>
WM_MBUTTONDBLCLK = 0x0209,
/// <summary>
/// Sent to the focus window when the mouse wheel is rotated. The DefWindowProc function propagates the message to the window's parent. There should be no internal forwarding of the message, since DefWindowProc propagates it up the parent chain until it finds a window that processes it.
/// </summary>
WM_MOUSEWHEEL = 0x020A,
/// <summary>
/// Posted when the user presses the first or second X button while the cursor is in the client area of a window. If the mouse is not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has captured the mouse.
/// </summary>
WM_XBUTTONDOWN = 0x020B,
/// <summary>
/// Posted when the user releases the first or second X button while the cursor is in the client area of a window. If the mouse is not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has captured the mouse.
/// </summary>
WM_XBUTTONUP = 0x020C,
/// <summary>
/// Posted when the user double-clicks the first or second X button while the cursor is in the client area of a window. If the mouse is not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has captured the mouse.
/// </summary>
WM_XBUTTONDBLCLK = 0x020D,
//WM_MOUSELAST = 0x020D,
/// <summary>
/// Sent to the active window when the mouse's horizontal scroll wheel is tilted or rotated. The DefWindowProc function propagates the message to the window's parent. There should be no internal forwarding of the message, since DefWindowProc propagates it up the parent chain until it finds a window that processes it.
/// </summary>
WM_MOUSEHWHEEL = 0x020e,
/// <summary>
/// Sent to the parent of a child window when the child window is created or destroyed, or when the user clicks a mouse button while the cursor is over the child window. When the child window is being created, the system sends WM_PARENTNOTIFY just before the CreateWindow or CreateWindowEx function that creates the window returns. When the child window is being destroyed, the system sends the message before any processing to destroy the window takes place.
/// </summary>
WM_PARENTNOTIFY = 0x0210,
/// <summary>
/// Notifies an application's main window procedure that a menu modal loop has been entered.
/// </summary>
WM_ENTERMENULOOP = 0x0211,
/// <summary>
/// Notifies an application's main window procedure that a menu modal loop has been entered.
/// </summary>
WM_EXITMENULOOP = 0x0212,
/// <summary>
/// Sent to an application when the right or left arrow key is used to switch between the menu bar and the system menu.
/// </summary>
WM_NEXTMENU = 0x0213,
/// <summary>
/// Sent to a window that the user is resizing. By processing this message, an application can monitor the size and position of the drag rectangle and, if needed, change its size or position.
/// </summary>
WM_SIZING = 0x0214,
/// <summary>
/// Sent to the window that is losing the mouse capture.
/// </summary>
WM_CAPTURECHANGED = 0x0215,
/// <summary>
/// Sent to a window that the user is moving. By processing this message, an application can monitor the position of the drag rectangle and, if needed, change its position.
/// </summary>
WM_MOVING = 0x0216,
/// <summary>
/// Notifies applications that a power-management event has occurred.
/// </summary>
WM_POWERBROADCAST = 0x0218,
/// <summary>
/// Notifies an application of a change to the hardware configuration of a device or the computer.
/// </summary>
WM_DEVICECHANGE = 0x0219,
/// <summary>
/// An application sends the WM_MDICREATE message to a multiple-document interface (MDI) client window to create an MDI child window.
/// </summary>
WM_MDICREATE = 0x0220,
/// <summary>
/// An application sends the WM_MDIDESTROY message to a multiple-document interface (MDI) client window to close an MDI child window.
/// </summary>
WM_MDIDESTROY = 0x0221,
/// <summary>
/// An application sends the WM_MDIACTIVATE message to a multiple-document interface (MDI) client window to instruct the client window to activate a different MDI child window.
/// </summary>
WM_MDIACTIVATE = 0x0222,
/// <summary>
/// An application sends the WM_MDIRESTORE message to a multiple-document interface (MDI) client window to restore an MDI child window from maximized or minimized size.
/// </summary>
WM_MDIRESTORE = 0x0223,
/// <summary>
/// An application sends the WM_MDINEXT message to a multiple-document interface (MDI) client window to activate the next or previous child window.
/// </summary>
WM_MDINEXT = 0x0224,
/// <summary>
/// An application sends the WM_MDIMAXIMIZE message to a multiple-document interface (MDI) client window to maximize an MDI child window. The system resizes the child window to make its client area fill the client window. The system places the child window's window menu icon in the rightmost position of the frame window's menu bar, and places the child window's restore icon in the leftmost position. The system also appends the title bar text of the child window to that of the frame window.
/// </summary>
WM_MDIMAXIMIZE = 0x0225,
/// <summary>
/// An application sends the WM_MDITILE message to a multiple-document interface (MDI) client window to arrange all of its MDI child windows in a tile format.
/// </summary>
WM_MDITILE = 0x0226,
/// <summary>
/// An application sends the WM_MDICASCADE message to a multiple-document interface (MDI) client window to arrange all its child windows in a cascade format.
/// </summary>
WM_MDICASCADE = 0x0227,
/// <summary>
/// An application sends the WM_MDIICONARRANGE message to a multiple-document interface (MDI) client window to arrange all minimized MDI child windows. It does not affect child windows that are not minimized.
/// </summary>
WM_MDIICONARRANGE = 0x0228,
/// <summary>
/// An application sends the WM_MDIGETACTIVE message to a multiple-document interface (MDI) client window to retrieve the handle to the active MDI child window.
/// </summary>
WM_MDIGETACTIVE = 0x0229,
/// <summary>
/// An application sends the WM_MDISETMENU message to a multiple-document interface (MDI) client window to replace the entire menu of an MDI frame window, to replace the window menu of the frame window, or both.
/// </summary>
WM_MDISETMENU = 0x0230,
/// <summary>
/// Sent one time to a window after it enters the moving or sizing modal loop. The window enters the moving or sizing modal loop when the user clicks the window's title bar or sizing border, or when the window passes the WM_SYSCOMMAND message to the DefWindowProc function and the wParam parameter of the message specifies the SC_MOVE or SC_SIZE value. The operation is complete when DefWindowProc returns.
/// The system sends the WM_ENTERSIZEMOVE message regardless of whether the dragging of full windows is enabled.
/// </summary>
WM_ENTERSIZEMOVE = 0x0231,
/// <summary>
/// Sent one time to a window, after it has exited the moving or sizing modal loop. The window enters the moving or sizing modal loop when the user clicks the window's title bar or sizing border, or when the window passes the WM_SYSCOMMAND message to the DefWindowProc function and the wParam parameter of the message specifies the SC_MOVE or SC_SIZE value. The operation is complete when DefWindowProc returns.
/// </summary>
WM_EXITSIZEMOVE = 0x0232,
/// <summary>
/// Sent when the user drops a file on the window of an application that has registered itself as a recipient of dropped files.
/// </summary>
WM_DROPFILES = 0x0233,
/// <summary>
/// An application sends the WM_MDIREFRESHMENU message to a multiple-document interface (MDI) client window to refresh the window menu of the MDI frame window.
/// </summary>
WM_MDIREFRESHMENU = 0x0234,
WM_POINTERDEVICECHANGE = 0x238,
WM_POINTERDEVICEINRANGE = 0x239,
WM_POINTERDEVICEOUTOFRANGE = 0x23A,
WM_TOUCH = 0x0240,
WM_NCPOINTERUPDATE = 0x0241,
WM_NCPOINTERDOWN = 0x0242,
WM_NCPOINTERUP = 0x0243,
WM_POINTERUPDATE = 0x0245,
WM_POINTERDOWN = 0x0246,
WM_POINTERUP = 0x0247,
WM_POINTERENTER = 0x0249,
WM_POINTERLEAVE = 0x024A,
WM_POINTERACTIVATE = 0x024B,
WM_POINTERCAPTURECHANGED = 0x024C,
WM_TOUCHHITTESTING = 0x024D,
WM_POINTERWHEEL = 0x024E,
WM_POINTERHWHEEL = 0x024F,
WM_IME_SETCONTEXT = 0x0281,
/// <summary>
/// Sent to an application to notify it of changes to the IME window.
/// </summary>
WM_IME_NOTIFY = 0x0282,
/// <summary>
/// Sent by an application to direct the IME window to carry out the requested command. The application uses this message to control the IME window that it has created. To send this message, the application calls the SendMessage function with the following parameters.
/// </summary>
WM_IME_CONTROL = 0x0283,
/// <summary>
/// Sent to an application when the IME window finds no space to extend the area for the composition window.
/// </summary>
WM_IME_COMPOSITIONFULL = 0x0284,
/// <summary>
/// Sent to an application when the operating system is about to change the current IME.
/// </summary>
WM_IME_SELECT = 0x0285,
/// <summary>
/// Sent to an application when the IME gets a character of the conversion result.
/// </summary>
WM_IME_CHAR = 0x0286,
/// <summary>
/// Sent to an application to provide commands and request information.
/// </summary>
WM_IME_REQUEST = 0x0288,
/// <summary>
/// Sent to an application by the IME to notify the application of a key press and to keep message order.
/// </summary>
WM_IME_KEYDOWN = 0x0290,
/// <summary>
/// Sent to an application by the IME to notify the application of a key release and to keep message order.
/// </summary>
WM_IME_KEYUP = 0x0291,
/// <summary>
/// Posted to a window when the cursor hovers over the nonclient area of the window for the period of time specified in a prior call to TrackMouseEvent.
/// </summary>
WM_NCMOUSEHOVER = 0x02A0,
/// <summary>
/// Posted to a window when the cursor hovers over the client area of the window for the period of time specified in a prior call to TrackMouseEvent.
/// </summary>
WM_MOUSEHOVER = 0x02A1,
/// <summary>
/// Posted to a window when the cursor leaves the nonclient area of the window specified in a prior call to TrackMouseEvent.
/// </summary>
WM_NCMOUSELEAVE = 0x02A2,
/// <summary>
/// Posted to a window when the cursor leaves the client area of the window specified in a prior call to TrackMouseEvent.
/// </summary>
WM_MOUSELEAVE = 0x02A3,
WM_WTSSESSION_CHANGE = 0x02B1,
/// <summary>
/// Sent when a window's position changes such that most of its area intersects a monitor with a dots per inch (dpi) that is different from the DPI before the position change.
/// </summary>
WM_DPICHANGED = 0x02E0,
/// <summary>
/// An application sends a WM_CUT message to an edit control or combo box to delete (cut) the current selection, if any, in the edit control and copy the deleted text to the clipboard in CF_TEXT format.
/// </summary>
WM_CUT = 0x0300,
/// <summary>
/// An application sends the WM_COPY message to an edit control or combo box to copy the current selection to the clipboard in CF_TEXT format.
/// </summary>
WM_COPY = 0x0301,
/// <summary>
/// An application sends a WM_PASTE message to an edit control or combo box to copy the current content of the clipboard to the edit control at the current caret position. Data is inserted only if the clipboard contains data in CF_TEXT format.
/// </summary>
WM_PASTE = 0x0302,
/// <summary>
/// An application sends a WM_CLEAR message to an edit control or combo box to delete (clear) the current selection, if any, from the edit control.
/// </summary>
WM_CLEAR = 0x0303,
/// <summary>
/// An application sends a WM_UNDO message to an edit control to undo the last operation. When this message is sent to an edit control, the previously deleted text is restored or the previously added text is deleted.
/// </summary>
WM_UNDO = 0x0304,
/// <summary>
/// Sent to the clipboard owner if it has delayed rendering a specific clipboard format and if an application has requested data in that format. The clipboard owner must render data in the specified format and place it on the clipboard by calling the SetClipboardData function.
/// </summary>
WM_RENDERFORMAT = 0x0305,
/// <summary>
/// Sent to the clipboard owner before it is destroyed, if the clipboard owner has delayed rendering one or more clipboard formats. For the content of the clipboard to remain available to other applications, the clipboard owner must render data in all the formats it is capable of generating, and place the data on the clipboard by calling the SetClipboardData function.
/// </summary>
WM_RENDERALLFORMATS = 0x0306,
/// <summary>
/// ent to the clipboard owner when a call to the EmptyClipboard function empties the clipboard.
/// </summary>
WM_DESTROYCLIPBOARD = 0x0307,
/// <summary>
/// Sent to the first window in the clipboard viewer chain when the content of the clipboard changes. This enables a clipboard viewer window to display the new content of the clipboard.
/// </summary>
WM_DRAWCLIPBOARD = 0x0308,
/// <summary>
/// Sent to the clipboard owner by a clipboard viewer window when the clipboard contains data in the CF_OWNERDISPLAY format and the clipboard viewer's client area needs repainting.
/// </summary>
WM_PAINTCLIPBOARD = 0x0309,
/// <summary>
/// Sent to the clipboard owner by a clipboard viewer window when the clipboard contains data in the CF_OWNERDISPLAY format and an event occurs in the clipboard viewer's vertical scroll bar. The owner should scroll the clipboard image and update the scroll bar values.
/// </summary>
WM_VSCROLLCLIPBOARD = 0x030A,
/// <summary>
/// Sent to the clipboard owner by a clipboard viewer window when the clipboard contains data in the CF_OWNERDISPLAY format and the clipboard viewer's client area has changed size.
/// </summary>
WM_SIZECLIPBOARD = 0x030B,
/// <summary>
/// Sent to the clipboard owner by a clipboard viewer window to request the name of a CF_OWNERDISPLAY clipboard format.
/// </summary>
WM_ASKCBFORMATNAME = 0x030C,
/// <summary>
/// Sent to the first window in the clipboard viewer chain when a window is being removed from the chain.
/// </summary>
WM_CHANGECBCHAIN = 0x030D,
/// <summary>
/// Sent to the clipboard owner by a clipboard viewer window. This occurs when the clipboard contains data in the CF_OWNERDISPLAY format and an event occurs in the clipboard viewer's horizontal scroll bar. The owner should scroll the clipboard image and update the scroll bar values.
/// </summary>
WM_HSCROLLCLIPBOARD = 0x030E,
/// <summary>
/// The WM_QUERYNEWPALETTE message informs a window that it is about to receive the keyboard focus, giving the window the opportunity to realize its logical palette when it receives the focus.
/// </summary>
WM_QUERYNEWPALETTE = 0x030F,
/// <summary>
/// The WM_PALETTEISCHANGING message informs applications that an application is going to realize its logical palette.
/// </summary>
WM_PALETTEISCHANGING = 0x0310,
/// <summary>
/// The WM_PALETTECHANGED message is sent to all top-level and overlapped windows after the window with the keyboard focus has realized its logical palette, thereby changing the system palette. This message enables a window that uses a color palette but does not have the keyboard focus to realize its logical palette and update its client area.
/// </summary>
WM_PALETTECHANGED = 0x0311,
/// <summary>
/// Posted when the user presses a hot key registered by the RegisterHotKey function. The message is placed at the top of the message queue associated with the thread that registered the hot key.
/// </summary>
WM_HOTKEY = 0x0312,
/// <summary>
/// Undocumented message to show system menu.
/// </summary>
WM_POPUPSYSTEMMENU = 0x313,
/// <summary>
/// The WM_PRINT message is sent to a window to request that it draw itself in the specified device context, most commonly in a printer device context.
/// </summary>
WM_PRINT = 0x0317,
/// <summary>
/// The WM_PRINTCLIENT message is sent to a window to request that it draw its client area in the specified device context, most commonly in a printer device context.
/// Unlike WM_PRINT, WM_PRINTCLIENT is not processed by DefWindowProc. A window should process the WM_PRINTCLIENT message through an application-defined WindowProc function for it to be used properly.
/// </summary>
WM_PRINTCLIENT = 0x0318,
/// <summary>
/// Notifies a window that the user generated an application command event, for example, by clicking an application command button using the mouse or typing an application command key on the keyboard.
/// </summary>
WM_APPCOMMAND = 0x0319,
/// <summary>
/// Broadcast to every window following a theme change event. Examples of theme change events are the activation of a theme, the deactivation of a theme, or a transition from one theme to another.
/// </summary>
WM_THEMECHANGED = 0x31a,
/// <summary>
/// Sent when the contents of the clipboard have changed.
/// </summary>
WM_CLIPBOARDUPDATE = 0x031D,
#region dwm values
/// <summary>
/// Sent to all top-level windows when Desktop Window Manager (DWM) composition has been enabled or disabled.
/// </summary>
WM_DWMCOMPOSITIONCHANGED = 0x031E,
/// <summary>
/// Sent when the non-client area rendering policy has changed. DwmGetWindowAttribute and DwmSetWindowAttribute are used to get or set the non-client rendering policy specified by the DWMNCRENDERINGPOLICY enumeration.
/// </summary>
WM_DWMNCRENDERINGCHANGED = 0x031F,
/// <summary>
/// Sent to all top-level windows when the colorization color has changed.
/// </summary>
WM_DWMCOLORIZATIONCOLORCHANGED = 0x0320,
/// <summary>
/// Sent when a Desktop Window Manager (DWM) composed window is maximized.
/// </summary>
WM_DWMWINDOWMAXIMIZEDCHANGE = 0x0321,
WM_DWMSENDICONICTHUMBNAIL = 0x323,
WM_DWMSENDICONICLIVEPREVIEWBITMAP = 0x326,
#endregion
/// <summary>
/// Sent to request extended title bar information.
/// </summary>
WM_GETTITLEBARINFOEX = 0x033F,
//WM_HANDHELDFIRST = 0x0358,
//WM_HANDHELDLAST = 0x035F,
//WM_AFXFIRST = 0x0360,
//WM_AFXLAST = 0x037F,
//WM_PENWINFIRST = 0x0380,
//WM_PENWINLAST = 0x038F,
WM_APP = 0x8000,
WM_USER = 0x0400,
//WM_REFLECT = WM_USER + 0x1c00,
//WM_TABLET_ADDED = 0x2c8,
//WM_TABLET_DEFBASE = 0x2c0,
//WM_TABLET_DELETED = 0x2c9,
//WM_TABLET_FLICK = 0x2cb,
//WM_TABLET_QUERYSYSTEMGESTURESTATUS = 0x2cc,
//WM_TRAYMOUSEMESSAGE = 0x800,
//OCM_COMMAND = 0x2111,
}
}

View File

@@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NTwain.Data.Win32
{
/// <summary>
/// Style flags for a window.
/// </summary>
[Flags]
enum WindowStyles : uint
{
/// <summary>
/// Creates an overlapped window. An overlapped window usually has a caption and a border.
/// </summary>
WS_OVERLAPPED = 0,
/// <summary>
/// Creates a pop-up window. Cannot be used with the WS_CHILD style.
/// </summary>
WS_POPUP = 0x80000000,
/// <summary>
/// Creates a child window. Cannot be used with the WS_POPUP style.
/// </summary>
WS_CHILD = 0x40000000,
/// <summary>
/// Creates a window that is initially minimized. For use with the WS_OVERLAPPED style only.
/// </summary>
WS_MINIMIZE = 0x20000000,
/// <summary>
/// Creates a window that is initially visible.
/// </summary>
WS_VISIBLE = 0x10000000,
/// <summary>
/// Creates a window that is initially disabled.
/// </summary>
WS_DISABLED = 0x8000000,
/// <summary>
/// Clips child windows relative to each other; that is, when a particular child window receives a paint message, the WS_CLIPSIBLINGS style clips all other overlapped child windows out of the region of the child window to be updated. (If WS_CLIPSIBLINGS is not given and child windows overlap, when you draw within the client area of a child window, it is possible to draw within the client area of a neighboring child window.) For use with the WS_CHILD style only.
/// </summary>
WS_CLIPSIBLINGS = 0x4000000,
/// <summary>
/// Excludes the area occupied by child windows when you draw within the parent window. Used when you create the parent window.
/// </summary>
WS_CLIPCHILDREN = 0x2000000,
/// <summary>
/// Creates a window of maximum size.
/// </summary>
WS_MAXIMIZE = 0x1000000,
/// <summary>
/// Creates a window that has a title bar (implies the WS_BORDER style). Cannot be used with the WS_DLGFRAME style.
/// </summary>
WS_CAPTION = 0xc00000,
/// <summary>
/// Creates a window that has a border.
/// </summary>
WS_BORDER = 0x800000,
/// <summary>
/// Creates a window with a double border but no title.
/// </summary>
WS_DLGFRAME = 0x400000,
/// <summary>
/// Creates a window that has a vertical scroll bar.
/// </summary>
WS_VSCROLL = 0x200000,
/// <summary>
/// Creates a window that has a horizontal scroll bar.
/// </summary>
WS_HSCROLL = 0x100000,
/// <summary>
/// Creates a window that has a Control-menu box in its title bar. Used only for windows with title bars.
/// </summary>
WS_SYSMENU = 0x80000,
/// <summary>
/// Creates a window with a thick frame that can be used to size the window.
/// </summary>
WS_THICKFRAME = 0x40000,
/// <summary>
/// Specifies the first control of a group of controls in which the user can move from one control to the next with the arrow keys. All controls defined with the WS_GROUP style FALSE after the first control belong to the same group. The next control with the WS_GROUP style starts the next group (that is, one group ends where the next begins).
/// </summary>
WS_GROUP = 0x20000,
/// <summary>
/// Specifies one of any number of controls through which the user can move by using the TAB key. The TAB key moves the user to the next control specified by the WS_TABSTOP style.
/// </summary>
WS_TABSTOP = 0x10000,
/// <summary>
/// Creates a window that has a Minimize button.
/// </summary>
WS_MINIMIZEBOX = 0x20000,
/// <summary>
/// Creates a window that has a Maximize button.
/// </summary>
WS_MAXIMIZEBOX = 0x10000,
/// <summary>
/// Creates an overlapped window. An overlapped window has a title bar and a border. Same as the WS_OVERLAPPED style.
/// </summary>
WS_TILED = 0,
/// <summary>
/// Creates a window that is initially minimized. Same as the WS_MINIMIZE style.
/// </summary>
WS_ICONIC = 0x20000000,
/// <summary>
/// Creates a window that has a sizing border. Same as the WS_THICKFRAME style.
/// </summary>
WS_SIZEBOX = 0x40000,
/// <summary>
/// Creates an overlapped window with the WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, WS_THICKFRAME, WS_MINIMIZEBOX, and WS_MAXIMIZEBOX styles. Same as the WS_OVERLAPPEDWINDOW style.
/// </summary>
WS_TILEDWINDOW = 0xcf0000,
/// <summary>
/// Creates an overlapped window with the WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, WS_THICKFRAME, WS_MINIMIZEBOX, and WS_MAXIMIZEBOX styles.
/// </summary>
WS_OVERLAPPEDWINDOW = 0xcf0000,
/// <summary>
/// Creates a pop-up window with the WS_BORDER, WS_POPUP, and WS_SYSMENU styles. The WS_CAPTION style must be combined with the WS_POPUPWINDOW style to make the Control menu visible.
/// </summary>
WS_POPUPWINDOW = 0x80880000,
/// <summary>
/// Same as the WS_CHILD style.
/// </summary>
WS_CHILDWINDOW = 0x40000000,
}
}

View File

@@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NTwain.Data.Win32
{
/// <summary>
/// Extended style flags for a window.
/// </summary>
[Flags]
enum WindowStylesEx : uint
{
/// <summary>
/// Designates a window with a double border that may (optionally) be created with a title bar when you specify the WS_CAPTION style flag in the dwStyle parameter.
/// </summary>
WS_EX_DLGMODALFRAME = 1,
/// <summary>
/// Specifies that a child window created with this style will not send the WM_PARENTNOTIFY message to its parent window when the child window is created or destroyed.
/// </summary>
WS_EX_NOPARENTNOTIFY = 4,
/// <summary>
/// Specifies that a window created with this style should be placed above all nontopmost windows and stay above them even when the window is deactivated. An application can use the SetWindowPos member function to add or remove this attribute.
/// </summary>
WS_EX_TOPMOST = 8,
/// <summary>
/// Specifies that a window created with this style accepts drag-and-drop files.
/// </summary>
WS_EX_ACCEPTFILES = 0x10,
/// <summary>
/// Specifies that a window created with this style is to be transparent. That is, any windows that are beneath the window are not obscured by the window. A window created with this style receives WM_PAINT messages only after all sibling windows beneath it have been updated.
/// </summary>
WS_EX_TRANSPARENT = 0x20,
/// <summary>
/// Creates an MDI child window.
/// </summary>
WS_EX_MDICHILD = 0x40,
/// <summary>
/// Creates a tool window, which is a window intended to be used as a floating toolbar. A tool window has a title bar that is shorter than a normal title bar, and the window title is drawn using a smaller font. A tool window does not appear in the task bar or in the window that appears when the user presses ALT+TAB.
/// </summary>
WS_EX_TOOLWINDOW = 0x80,
/// <summary>
/// Specifies that a window has a border with a raised edge.
/// </summary>
WS_EX_WINDOWEDGE = 0x100,
/// <summary>
/// Specifies that a window has a 3D look — that is, a border with a sunken edge.
/// </summary>
WS_EX_CLIENTEDGE = 0x200,
/// <summary>
/// Includes a question mark in the title bar of the window. When the user clicks the question mark, the cursor changes to a question mark with a pointer. If the user then clicks a child window, the child receives a WM_HELP message.
/// </summary>
WS_EX_CONTEXTHELP = 0x400,
/// <summary>
/// Gives a window generic right-aligned properties. This depends on the window class.
/// </summary>
WS_EX_RIGHT = 0x1000,
/// <summary>
/// Gives window generic left-aligned properties. This is the default.
/// </summary>
WS_EX_LEFT = 0,
/// <summary>
/// Displays the window text using right-to-left reading order properties.
/// </summary>
WS_EX_RTLREADING = 0x2000,
/// <summary>
/// Displays the window text using left-to-right reading order properties. This is the default.
/// </summary>
WS_EX_LTRREADING = 0,
/// <summary>
/// Places a vertical scroll bar to the left of the client area.
/// </summary>
WS_EX_LEFTSCROLLBAR = 0x4000,
/// <summary>
/// Places a vertical scroll bar (if present) to the right of the client area. This is the default.
/// </summary>
WS_EX_RIGHTSCROLLBAR = 0,
/// <summary>
/// Allows the user to navigate among the child windows of the window by using the TAB key.
/// </summary>
WS_EX_CONTROLPARENT = 0x10000,
/// <summary>
/// Creates a window with a three-dimensional border style intended to be used for items that do not accept user input.
/// </summary>
WS_EX_STATICEDGE = 0x20000,
/// <summary>
/// Forces a top-level window onto the taskbar when the window is visible.
/// </summary>
WS_EX_APPWINDOW = 0x40000,
/// <summary>
/// Combines the WS_EX_CLIENTEDGE and WS_EX_WINDOWEDGE styles
/// </summary>
WS_EX_OVERLAPPEDWINDOW = 0x300,
/// <summary>
/// Combines the WS_EX_WINDOWEDGE and WS_EX_TOPMOST styles.
/// </summary>
WS_EX_PALETTEWINDOW = 0x188,
WS_EX_LAYERED = 0x80000,
WS_EX_NOINHERITLAYOUT = 0x100000,
WS_EX_NOREDIRECTIONBITMAP = 0x00200000,
WS_EX_LAYOUTRTL = 0x400000,
WS_EX_COMPOSITED = 0x2000000,
WS_EX_NOACTIVATE = 0x8000000,
}
}

View File

@@ -43,18 +43,22 @@ namespace NTwain
/// <returns></returns>
public ReturnCode ShowUI(IntPtr windowHandle, bool modal = false)
{
var ui = new TW_USERINTERFACE
var rc = ReturnCode.Failure;
Session.Invoke(() =>
{
ShowUI = 1,
ModalUI = (ushort)(modal ? 1 : 0),
hParent = windowHandle
};
Session._disableDSNow = false;
var rc = Session.DGControl.UserInterface.EnableDSUIOnly(ref ui);
if (rc == ReturnCode.Success)
{
Session._lastEnableUI = ui;
}
var ui = new TW_USERINTERFACE
{
ShowUI = 1,
ModalUI = (ushort)(modal ? 1 : 0),
hParent = windowHandle
};
Session._disableDSNow = false;
rc = Session.DGControl.UserInterface.EnableDSUIOnly(ref ui);
if (rc == ReturnCode.Success)
{
Session._lastEnableUI = ui;
}
});
return rc;
}
@@ -67,18 +71,22 @@ namespace NTwain
/// <returns></returns>
public ReturnCode Enable(bool showUI, IntPtr windowHandle, bool modal = false)
{
var ui = new TW_USERINTERFACE
var rc = ReturnCode.Failure;
Session.Invoke(() =>
{
ShowUI = (ushort)(showUI ? 1 : 0),
ModalUI = (ushort)(modal ? 1 : 0),
hParent = windowHandle
};
Session._disableDSNow = false;
var rc = Session.DGControl.UserInterface.EnableDS(ref ui);
if (rc == ReturnCode.Success)
{
Session._lastEnableUI = ui;
}
var ui = new TW_USERINTERFACE
{
ShowUI = (ushort)(showUI ? 1 : 0),
ModalUI = (ushort)(modal ? 1 : 0),
hParent = windowHandle
};
Session._disableDSNow = false;
rc = Session.DGControl.UserInterface.EnableDS(ref ui);
if (rc == ReturnCode.Success)
{
Session._lastEnableUI = ui;
}
});
return rc;
}

View File

@@ -1,34 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace NTwain.Internals
{
/// <summary>
/// The MSG structure in Windows for TWAIN use.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
struct MSG
{
public MSG(IntPtr hwnd, int message, IntPtr wParam, IntPtr lParam)
{
_hwnd = hwnd;
_message = (uint)message;
_wParam = wParam;
_lParam = lParam;
_time = 0;
_x = 0;
_y = 0;
}
IntPtr _hwnd;
uint _message;
IntPtr _wParam;
IntPtr _lParam;
uint _time;
int _x;
int _y;
}
}

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net35;net40;net461;netstandard2.0</TargetFrameworks>
<TargetFrameworks>net40;net461;netstandard2.0</TargetFrameworks>
<PackageLicenseUrl>https://github.com/soukoku/ntwain/blob/master/LICENSE.txt</PackageLicenseUrl>
<PackageProjectUrl>https://github.com/soukoku/ntwain</PackageProjectUrl>
<PackageIconUrl>https://github.com/soukoku/ntwain/blob/master/Scanner-Icon.png?raw=true</PackageIconUrl>

View File

@@ -0,0 +1,34 @@
using System;
using System.Threading;
namespace NTwain.Threading
{
internal class ActionItem
{
private ManualResetEventSlim waiter;
private Action action;
public ActionItem(Action action)
{
this.action = action;
}
public ActionItem(ManualResetEventSlim waiter, Action action)
{
this.waiter = waiter;
this.action = action;
}
public void DoAction()
{
try
{
action();
}
finally
{
waiter?.Set();
}
}
}
}

View File

@@ -1,23 +0,0 @@
//using System;
//using System.Collections.Generic;
//using System.Linq;
//using System.Text;
//using System.Threading;
//namespace NTwain.Threading
//{
// /// <summary>
// /// A base thread-marshalling class that does no marshalling.
// /// </summary>
// public class ThreadDispatcher
// {
// /// <summary>
// /// Invokes an action and returns after it's done.
// /// </summary>
// /// <param name="action"></param>
// public virtual void Invoke(Action action)
// {
// action(); SynchronizationContext.Current
// }
// }
//}

View File

@@ -0,0 +1,265 @@
using NTwain.Data.Win32;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using System.Threading;
namespace NTwain.Threading
{
/// <summary>
/// Provides an internal message pump on Windows using a background thread.
/// </summary>
class WinMsgLoop
{
static ushort classAtom;
static IntPtr hInstance;
static readonly int dequeMsg = UnsafeNativeMethods.RegisterWindowMessage("WinMsgLoopQueue");
const int CW_USEDEFAULT = -1;
static IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
Debug.WriteLine($"Dummy window got msg {(WindowMessage)msg}.");
switch ((WindowMessage)msg)
{
case WindowMessage.WM_DESTROY:
UnsafeNativeMethods.PostQuitMessage(0);
return IntPtr.Zero;
}
return UnsafeNativeMethods.DefWindowProc(hWnd, msg, wParam, lParam);
}
static void InitGlobal()
{
if (classAtom == 0)
{
hInstance = UnsafeNativeMethods.GetModuleHandle(null);
var wc = new WNDCLASSEX();
wc.cbSize = Marshal.SizeOf(wc);
wc.style = ClassStyles.CS_VREDRAW | ClassStyles.CS_HREDRAW;
var procPtr = Marshal.GetFunctionPointerForDelegate(new WndProcDelegate(WndProc));
wc.lpfnWndProc = procPtr;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = IntPtr.Zero;
wc.hCursor = IntPtr.Zero;
wc.hbrBackground = IntPtr.Zero;
wc.lpszMenuName = null;
wc.lpszClassName = Guid.NewGuid().ToString("n");
wc.hIconSm = IntPtr.Zero;
classAtom = UnsafeNativeMethods.RegisterClassEx(ref wc);
if (classAtom == 0)
{
throw new Win32Exception();
}
}
}
readonly TwainSession session;
readonly ConcurrentQueue<ActionItem> actionQueue;
Thread loopThread;
bool stop;
IntPtr hWnd;
public WinMsgLoop(TwainSession session)
{
this.session = session;
actionQueue = new ConcurrentQueue<ActionItem>();
}
public void Start()
{
if (stop || loopThread != null || hWnd != IntPtr.Zero) return;
Debug.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId}: {nameof(WinMsgLoop)}.{nameof(Start)}()");
InitGlobal();
Win32Exception startErr = null;
// startWaiter ensures thread is running before this method returns
using (var startWaiter = new ManualResetEventSlim())
{
stop = false;
loopThread = new Thread(new ThreadStart(() =>
{
Debug.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId}: starting msg pump...");
hWnd = UnsafeNativeMethods.CreateWindowEx(WindowStylesEx.WS_EX_LEFT, classAtom, Guid.NewGuid().ToString(),
WindowStyles.WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
IntPtr.Zero, IntPtr.Zero, hInstance, IntPtr.Zero);
if (hWnd == IntPtr.Zero)
{
startErr = new Win32Exception();
// clear queue
while (actionQueue.TryDequeue(out ActionItem dummy)) { }
loopThread = null;
stop = false;
startWaiter.Set();
}
else
{
startWaiter.Set();
MSG msg = default;
while (!stop && UnsafeNativeMethods.GetMessage(ref msg, IntPtr.Zero, 0, 0))
{
UnsafeNativeMethods.TranslateMessage(ref msg);
if (!session.HandleWindowsMessage(ref msg))
{
if (msg.message == dequeMsg)
{
if (actionQueue.TryDequeue(out ActionItem work))
{
work.DoAction();
if (stop) break;
}
}
else
{
UnsafeNativeMethods.DispatchMessage(ref msg);
}
}
}
// clear queue
while (actionQueue.TryDequeue(out ActionItem dummy)) { }
loopThread = null;
hWnd = IntPtr.Zero;
stop = false;
}
}));
loopThread.IsBackground = true;
loopThread.SetApartmentState(ApartmentState.STA);
loopThread.Start();
startWaiter.Wait();
if (startErr != null) throw startErr;
}
}
public void Stop()
{
if (stop) return;
stop = true;
if (hWnd != IntPtr.Zero)
{
Debug.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId}: calling destroy window...");
BeginInvoke(() =>
{
if (UnsafeNativeMethods.DestroyWindow(hWnd))
{
hWnd = IntPtr.Zero;
}
else
{
Debug.WriteLine("Failed to destroy window: " + new Win32Exception().Message);
}
});
}
}
bool IsSameThread()
{
return loopThread == Thread.CurrentThread || loopThread == null;
}
/// <summary>
/// Runs the action synchronously on the internal message pump thread.
/// </summary>
/// <param name="action"></param>
public void Invoke(Action action)
{
if (IsSameThread())
{
// ok
action();
}
else
{
// queue up work
using (var waiter = new ManualResetEventSlim())
{
actionQueue.Enqueue(new ActionItem(waiter, action));
UnsafeNativeMethods.PostMessage(hWnd, dequeMsg, IntPtr.Zero, IntPtr.Zero);
waiter.Wait();
}
}
}
/// <summary>
/// Runs the action asynchronously on the internal message pump thread.
/// </summary>
/// <param name="action"></param>
public void BeginInvoke(Action action)
{
if (hWnd == IntPtr.Zero) action();
else
{
actionQueue.Enqueue(new ActionItem(action));
UnsafeNativeMethods.PostMessage(hWnd, dequeMsg, IntPtr.Zero, IntPtr.Zero);
}
}
[SuppressUnmanagedCodeSecurity]
internal static class UnsafeNativeMethods
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true, ThrowOnUnmappableChar = true, BestFitMapping = false)]
public static extern IntPtr GetModuleHandle(string modName);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetMessage([In, Out] ref MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern bool TranslateMessage([In, Out] ref MSG lpMsg);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr DispatchMessage([In] ref MSG lpmsg);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int PostMessage(IntPtr hWnd, int msg, IntPtr wparam, IntPtr lparam);
[DllImport("user32.dll")]
public static extern void PostQuitMessage(int nExitCode);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr DefWindowProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, BestFitMapping = false)]
public static extern int RegisterWindowMessage(string msg);
[DllImport("user32.dll", SetLastError = true)]
public static extern ushort RegisterClassEx([In] ref WNDCLASSEX lpwcx);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true, BestFitMapping = false)]
public static extern IntPtr CreateWindowEx(WindowStylesEx dwExStyle,
ushort lpszClassName,
[MarshalAs(UnmanagedType.LPStr)] string lpszWindowName,
WindowStyles style,
int x, int y, int width, int height,
IntPtr hWndParent, IntPtr hMenu, IntPtr hInst, IntPtr lpParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool DestroyWindow(IntPtr hWnd);
}
}
}

View File

@@ -1,52 +1,52 @@
using NTwain.Data;
using NTwain.Triplets;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
//using NTwain.Data;
//using NTwain.Triplets;
//using System;
//using System.Collections.Generic;
//using System.ComponentModel;
//using System.Linq;
//using System.Text;
namespace NTwain
{
partial class TwainSession : IDisposable
{
private bool disposedValue = false; // To detect redundant calls
//namespace NTwain
//{
// partial class TwainSession : IDisposable
// {
// private bool disposedValue = false; // To detect redundant calls
/// <summary>
/// Handles actual disposal logic.
/// </summary>
/// <param name="disposing"></param>
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
StepDown(TwainState.DsmLoaded);
// TODO: dispose managed state (managed objects).
}
// /// <summary>
// /// Handles actual disposal logic.
// /// </summary>
// /// <param name="disposing"></param>
// protected virtual void Dispose(bool disposing)
// {
// if (!disposedValue)
// {
// if (disposing)
// {
// StepDown(TwainState.DsmLoaded);
// // TODO: dispose managed state (managed objects).
// }
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
// TODO: set large fields to null.
// // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
// // TODO: set large fields to null.
disposedValue = true;
}
}
// disposedValue = true;
// }
// }
// TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
// ~TwainSession() {
// // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
// Dispose(false);
// }
// // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
// // ~TwainSession() {
// // // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
// // Dispose(false);
// // }
/// <summary>
/// Closes any open TWAIN objects.
/// </summary>
public void Dispose()
{
Dispose(true);
// TODO: uncomment the following line if the finalizer is overridden above.
// GC.SuppressFinalize(this);
}
}
}
// /// <summary>
// /// Closes any open TWAIN objects.
// /// </summary>
// public void Dispose()
// {
// Dispose(true);
// // TODO: uncomment the following line if the finalizer is overridden above.
// // GC.SuppressFinalize(this);
// }
// }
//}

View File

@@ -1,5 +1,7 @@
using NTwain.Data;
using NTwain.Data.Win32;
using NTwain.Internals;
using NTwain.Threading;
using NTwain.Triplets;
using System;
using System.Collections.Generic;
@@ -21,39 +23,32 @@ namespace NTwain
DataGroups dg, DataArgumentType dat, Message msg, IntPtr data)
{
Debug.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId}: {nameof(Handle32BitCallback)}({dg}, {dat}, {msg}, {data})");
HandleSourceMsg(msg);
BeginInvoke(() =>
{
Debug.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId}: in BeginInvoke {nameof(Handle32BitCallback)}({dg}, {dat}, {msg}, {data})");
HandleSourceMsg(msg);
});
Debug.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId}: after BeginInvoke {nameof(Handle32BitCallback)}({dg}, {dat}, {msg}, {data})");
return ReturnCode.Success;
}
/// <summary>
/// If on Windows pass all messages from WndProc here to handle it
/// for TWAIN-specific things.
/// </summary>
/// <param name="hwnd">The window handle.</param>
/// <param name="msg">The message.</param>
/// <param name="wParam">The w parameter.</param>
/// <param name="lParam">The l parameter.</param>
/// <returns>
/// true if handled by TWAIN.
/// </returns>
public bool HandleWndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam)
internal bool HandleWindowsMessage(ref MSG msg)
{
var handled = false;
if (State > TwainState.S4)
{
var winMsg = new MSG(hwnd, msg, wParam, lParam);
// transform it into a pointer for twain
IntPtr msgPtr = IntPtr.Zero;
try
{
msgPtr = Config.MemoryManager.Allocate((uint)Marshal.SizeOf(winMsg));
msgPtr = Config.MemoryManager.Allocate((uint)Marshal.SizeOf(msg));
IntPtr locked = Config.MemoryManager.Lock(msgPtr);
Marshal.StructureToPtr(winMsg, locked, false);
Marshal.StructureToPtr(msg, locked, false);
TW_EVENT evt = new TW_EVENT { pEvent = locked };
if (handled = DGControl.Event.ProcessEvent(ref evt) == ReturnCode.DSEvent)
{
Debug.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId}: {nameof(HandleWindowsMessage)} with {evt.TWMessage}");
HandleSourceMsg((Message)evt.TWMessage);
}
}
@@ -67,6 +62,7 @@ namespace NTwain
private void HandleSourceMsg(Message msg)
{
Debug.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId}: {nameof(HandleSourceMsg)}({msg})");
switch (msg)
{
case Message.DeviceEvent:

View File

@@ -1,4 +1,5 @@
using NTwain.Data;
using NTwain.Threading;
using NTwain.Triplets;
using System;
using System.Collections.Generic;
@@ -24,6 +25,8 @@ namespace NTwain
// need to keep delegate around to prevent GC?
readonly Callback32 _callback32Delegate;
readonly WinMsgLoop _winMsgLoop;
/// <summary>
/// Constructs a new <see cref="TwainSession"/>.
@@ -37,11 +40,25 @@ namespace NTwain
case PlatformID.MacOSX:
case PlatformID.Unix:
default:
_winMsgLoop = new WinMsgLoop(this);
_callback32Delegate = new Callback32(Handle32BitCallback);
break;
}
}
public void Invoke(Action action)
{
if (_winMsgLoop != null) _winMsgLoop.Invoke(action);
else action();
}
public void BeginInvoke(Action action)
{
if (_winMsgLoop != null) _winMsgLoop.BeginInvoke(action);
else action();
}
/// <summary>
/// Opens the TWAIN session.
/// </summary>
@@ -50,7 +67,26 @@ namespace NTwain
public ReturnCode Open(IntPtr hWnd)
{
_hWnd = hWnd;
return DGControl.Parent.OpenDSM(hWnd);
var rc = DGControl.Parent.OpenDSM(hWnd);
if (rc == ReturnCode.Success)
{
_winMsgLoop?.Start();
}
return rc;
}
/// <summary>
/// Closes the TWAIN session.
/// </summary>
/// <returns></returns>
public ReturnCode Close()
{
var rc = DGControl.Parent.CloseDSM(_hWnd);
if (rc == ReturnCode.Success)
{
_winMsgLoop?.Stop();
}
return rc;
}
/// <summary>
@@ -60,13 +96,20 @@ namespace NTwain
/// <returns></returns>
public ReturnCode StepDown(TwainState targetState)
{
if (targetState == this.State) return ReturnCode.Success;
var rc = ReturnCode.Failure;
while (State > targetState)
{
switch (State)
{
case TwainState.DsmLoaded:
case TwainState.DsmUnloaded:
case TwainState.Invalid:
// can do nothing in these states
return ReturnCode.Success;
case TwainState.DsmOpened:
rc = DGControl.Parent.CloseDSM(_hWnd);
rc = Close();
if (rc != ReturnCode.Success) return rc;
break;
case TwainState.SourceOpened: