Merge pull request #75 from soukoku/Win32-native-experiments

Win32 native experiments
This commit is contained in:
Eugene Wang
2025-11-12 08:25:50 -05:00
committed by GitHub
16 changed files with 666 additions and 714 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework> <TargetFramework>net10.0-windows7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms> <UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
+6 -6
View File
@@ -127,13 +127,13 @@ namespace WinConsole32
} }
static int xferCount = 0; static int xferCount = 0;
static Stopwatch watch; static Stopwatch watch = new Stopwatch();
private static void Session_Transferred(TwainAppSession twain, TransferredEventArgs e) private static void Session_Transferred(TwainAppSession twain, TransferredEventArgs e)
{ {
if (e.Data != null) if (e.Data != null)
{ {
var saveFile = $"twain_{DateTime.Now:yyyyMMdd_HHmmss}_{xferCount}"; var saveFile = $"twain_{DateTime.Now:yyyyMMdd_HHmmss}_{xferCount}";
Console.WriteLine("SUCCESS! Got twain memory data #{0} on thread {1}, saving to {saveFile}.", ++xferCount, Environment.CurrentManagedThreadId, saveFile); Console.WriteLine($"SUCCESS! Got twain memory data #{++xferCount} on thread {Environment.CurrentManagedThreadId}, saving to {saveFile}.");
using (var img = new ImageMagick.MagickImage(e.Data.AsStream())) using (var img = new ImageMagick.MagickImage(e.Data.AsStream()))
{ {
@@ -157,11 +157,11 @@ namespace WinConsole32
else if (e.FileInfo != null) else if (e.FileInfo != null)
{ {
var fi = e.FileInfo.Value; var fi = e.FileInfo.Value;
Console.WriteLine("SUCCESS! Got twain file data #{0} on thread {1} as {saveFile}.", ++xferCount, Environment.CurrentManagedThreadId, fi.FileName); Console.WriteLine($"SUCCESS! Got twain file data #{++xferCount} on thread {Environment.CurrentManagedThreadId} as {fi.FileName}.");
} }
else else
{ {
Console.WriteLine("BUMMER! No twain data #{0} on thread {1}.", ++xferCount, Environment.CurrentManagedThreadId); Console.WriteLine($"BUMMER! No twain data #{++xferCount} on thread {Environment.CurrentManagedThreadId}.");
} }
e.Dispose(); e.Dispose();
} }
@@ -199,10 +199,10 @@ namespace WinConsole32
twain.Caps.ICAP_PIXELTYPE.Set(TWPT.RGB); twain.Caps.ICAP_PIXELTYPE.Set(TWPT.RGB);
twain.Caps.ICAP_XRESOLUTION.Set(300f); twain.Caps.ICAP_XRESOLUTION.Set(300f);
twain.Caps.ICAP_YRESOLUTION.Set(300f); twain.Caps.ICAP_YRESOLUTION.Set(300f);
twain.Caps.CAP_XFERCOUNT.Set(100); twain.Caps.CAP_XFERCOUNT.Set(4);
xferCount = 0; xferCount = 0;
watch = Stopwatch.StartNew(); watch.Restart();
var rc = twain.EnableSource(true, false); var rc = twain.EnableSource(true, false);
} }
} }
+1 -1
View File
@@ -11,7 +11,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Magick.NET-Q8-AnyCPU" Version="14.0.0" /> <PackageReference Include="Magick.NET-Q8-AnyCPU" Version="14.9.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
+1 -1
View File
@@ -202,7 +202,7 @@ namespace WinFormSample
// color // color
saveFile += ".jpg"; saveFile += ".jpg";
format = ImageMagick.MagickFormat.Jpeg; format = ImageMagick.MagickFormat.Jpeg;
img.Quality = _jpegQuality; img.Quality = (uint)_jpegQuality;
} }
if (_saveDisk) img.Write(saveFile); if (_saveDisk) img.Write(saveFile);
else img.Write(new NoOpStream(), format); else img.Write(new NoOpStream(), format);
+2 -2
View File
@@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework> <TargetFramework>net10.0-windows7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms> <UseWindowsForms>true</UseWindowsForms>
<PlatformTarget>x86</PlatformTarget> <PlatformTarget>x86</PlatformTarget>
@@ -10,7 +10,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Magick.NET-Q8-x86" Version="13.9.1" /> <PackageReference Include="Magick.NET-Q8-x86" Version="14.9.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
+2 -2
View File
@@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework> <TargetFramework>net10.0-windows7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms> <UseWindowsForms>true</UseWindowsForms>
<PlatformTarget>x64</PlatformTarget> <PlatformTarget>x64</PlatformTarget>
@@ -14,7 +14,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Magick.NET-Q8-x64" Version="13.9.1" /> <PackageReference Include="Magick.NET-Q8-x64" Version="14.9.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
+1 -1
View File
@@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<!--change these in each release--> <!--change these in each release-->
<VersionPrefix>4.0.0.0</VersionPrefix> <VersionPrefix>4.0.0.0</VersionPrefix>
<VersionSuffix>alpha.13</VersionSuffix> <VersionSuffix>alpha.14</VersionSuffix>
<!--keep it the same until major # changes--> <!--keep it the same until major # changes-->
<AssemblyVersion>4.0.0.0</AssemblyVersion> <AssemblyVersion>4.0.0.0</AssemblyVersion>
+53 -46
View File
@@ -1,52 +1,59 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<PackageId>NTwain</PackageId> <PackageId>NTwain</PackageId>
<Description>Library containing the TWAIN API for dotnet.</Description> <Description>Library containing the TWAIN API for dotnet.</Description>
<TargetFrameworks>net8.0;net8.0-windows;net9.0;net9.0-windows;net462;</TargetFrameworks> <TargetFrameworks>net8.0;net8.0-windows;net9.0;net9.0-windows;net10.0;net10.0-windows;net472;</TargetFrameworks>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'net462' OR $(TargetFramework.EndsWith('windows'))"> <PropertyGroup Condition=" '$(TargetFramework)' == 'net472' OR $(TargetFramework.EndsWith('windows'))">
<UseWindowsForms>true</UseWindowsForms> <UseWindowsForms>true</UseWindowsForms>
<UseWPF>true</UseWPF> <UseWPF>true</UseWPF>
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net462'"> <ItemGroup Condition=" '$(TargetFramework)' == 'net472'">
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" /> <PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<!--<PackageReference Include="System.Buffers" Version="4.5.1" />--> <!--<PackageReference Include="System.Buffers" Version="4.5.1" />-->
<PackageReference Include="System.Memory" Version="4.5.5" /> <PackageReference Include="System.Memory" Version="4.6.3" />
</ItemGroup> <PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.1.2" />
<ItemGroup Condition=" '$(TargetFramework)' != 'net462'"> </ItemGroup>
<PackageReference Include="System.Text.Encoding.CodePages" Version="8.0.0" /> <ItemGroup Condition=" '$(TargetFramework)' != 'net472'">
</ItemGroup> <PackageReference Include="System.Text.Encoding.CodePages" Version="10.0.0" />
<ItemGroup Condition="'$(Configuration)'!='Release'"> </ItemGroup>
<None Remove="runtimes\win-x64\native\TWAINDSM.dll" /> <ItemGroup Condition="'$(Configuration)'!='Release'">
<None Remove="runtimes\win-x86\native\TWAINDSM.dll" /> <None Remove="runtimes\win-x64\native\TWAINDSM.dll" />
</ItemGroup> <None Remove="runtimes\win-x86\native\TWAINDSM.dll" />
<ItemGroup Condition="'$(Configuration)'!='Release'"> </ItemGroup>
<Content Include="runtimes\win-x64\native\TWAINDSM.dll"> <ItemGroup Condition="'$(Configuration)'!='Release'">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <Content Include="runtimes\win-x64\native\TWAINDSM.dll">
</Content> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Content Include="runtimes\win-x86\native\TWAINDSM.dll"> </Content>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <Content Include="runtimes\win-x86\native\TWAINDSM.dll">
</Content> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</ItemGroup> </Content>
</ItemGroup>
<ItemGroup> <ItemGroup>
<None Update="DSM\DSMGenerator.dummy"> <PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.242">
<DesignTime>True</DesignTime> <PrivateAssets>all</PrivateAssets>
<AutoGen>True</AutoGen> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<DependentUpon>DSMGenerator.tt</DependentUpon> </PackageReference>
</None> </ItemGroup>
<None Update="DSM\DSMGenerator.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>DSMGenerator.dummy</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup> <ItemGroup>
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" /> <None Update="DSM\DSMGenerator.dummy">
</ItemGroup> <DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>DSMGenerator.tt</DependentUpon>
</None>
<None Update="DSM\DSMGenerator.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>DSMGenerator.dummy</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
</ItemGroup>
</Project> </Project>
+234 -320
View File
@@ -2,339 +2,253 @@
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
namespace NTwain.Native namespace Windows.Win32.Graphics.Gdi
{ {
// this is a good read // this is a good read
// http://atlc.sourceforge.net/bmp.html // 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;
}; partial struct BITMAPINFOHEADER
/// <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); const double METER_INCH_RATIO = 39.3700787;
}
/// <summary> /// <summary>
/// Gets the vertical dpi of the bitmap. /// Gets the horizontal dpi of the bitmap.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public float GetYDpi() public float GetXDpi()
{
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(); return (float)Math.Round(biXPelsPerMeter / METER_INCH_RATIO, 0);
} }
if (biClrUsed == 0) /// <summary>
/// Gets the vertical dpi of the bitmap.
/// </summary>
/// <returns></returns>
public float GetYDpi()
{ {
switch (biBitCount) return (float)Math.Round(biYPelsPerMeter / METER_INCH_RATIO, 0);
{
case 1:
biClrUsed = 2;
break;
case 4:
biClrUsed = 16;
break;
case 8:
biClrUsed = 256;
break;
}
} }
if (biSizeImage == 0) /// <summary>
/// Gets the size of the structure.
/// </summary>
/// <returns></returns>
public static uint GetByteSize()
{ {
biSizeImage = (uint)(((( return (uint)Marshal.SizeOf<BITMAPINFOHEADER>();
biWidth * biBitCount) + 31) & ~31) >> 3) * (uint)Math.Abs(biHeight); }
/// <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;
} }
return true; /// <summary>
} /// Gets the pointer to scan0 given the header pointer.
return false; /// </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 GetStride()
{
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;
}
/// <inheritdoc/>
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 = " + Compression)
.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();
}
/// <summary>
/// Gets the bitmap compression type.
/// </summary>
public CompressionType Compression { get { return (CompressionType)biCompression; } }
/// <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
}
} }
/// <summary> //[StructLayout(LayoutKind.Sequential, Pack = 1)]
/// Gets the pointer to scan0 given the header pointer. //struct BITMAPFILEHEADER
/// </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) // public ushort bfType;
// { // public uint bfSize;
// case 1: // public ushort bfReserved1;
// return PixelFormat.Format1bppIndexed; // public ushort bfReserved2;
// case 4: // public uint bfOffBits;
// 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 GetStride()
{
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
}
};
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct BITMAPFILEHEADER
{
public ushort bfType;
public uint bfSize;
public ushort bfReserved1;
public ushort bfReserved2;
public uint bfOffBits;
}
} }
+129 -128
View File
@@ -1,145 +1,146 @@
using NTwain.Data; using NTwain.Data;
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Windows.Win32.Graphics.Gdi;
namespace NTwain.Native namespace NTwain.Native
{ {
static class ImageTools static class ImageTools
{
// this is modified from twain cs sample
// http://sourceforge.net/projects/twainforcsharp/?source=typ_redirect
public static bool IsDib(IntPtr data)
{ {
// a quick check not guaranteed correct, // this is modified from twain cs sample
// compare first 2 bytes to size of struct (which is also the first field) // http://sourceforge.net/projects/twainforcsharp/?source=typ_redirect
var test = Marshal.ReadInt16(data);
// should be 40
return test == BITMAPINFOHEADER.GetByteSize();
}
public static bool IsTiff(IntPtr data)
{
var test = Marshal.ReadInt16(data);
// should be II
return test == 0x4949;
}
public static unsafe BufferedData? GetBitmapData(IntPtr data) public static bool IsDib(IntPtr data)
{
var infoHeader = Marshal.PtrToStructure<BITMAPINFOHEADER>(data);
if (infoHeader.Validate())
{
var fileHeaderSize = Marshal.SizeOf(typeof(BITMAPFILEHEADER));
var fileHeader = new BITMAPFILEHEADER
{ {
bfType = 0x4D42, // "BM" // a quick check not guaranteed correct,
bfOffBits = (uint)fileHeaderSize + // compare first 2 bytes to size of struct (which is also the first field)
infoHeader.biSize + var test = Marshal.ReadInt16(data);
(infoHeader.biClrUsed * 4) // should be 40
}; return test == BITMAPINFOHEADER.GetByteSize();
fileHeader.bfSize = fileHeader.bfOffBits + infoHeader.biSizeImage; }
public static bool IsTiff(IntPtr data)
var dataCopy = BufferedData.MemPool.Rent((int)fileHeader.bfSize); // new byte[fileHeader.bfSize];
// TODO: run benchmark on which one is faster
// write file header
//IntPtr tempPtr = Marshal.AllocHGlobal(fileHeaderSize);
//Marshal.StructureToPtr(fileHeader, tempPtr, true);
//Marshal.Copy(tempPtr, dataCopy, 0, fileHeaderSize);
//Marshal.FreeHGlobal(tempPtr);
// would this be faster?
fixed (byte* p = dataCopy)
{ {
Marshal.StructureToPtr(fileHeader, (IntPtr)p, false); var test = Marshal.ReadInt16(data);
// should be II
return test == 0x4949;
} }
// write image public static unsafe BufferedData? GetBitmapData(IntPtr data)
Marshal.Copy(data, dataCopy, fileHeaderSize, (int)fileHeader.bfSize - fileHeaderSize);
return new BufferedData(dataCopy, (int)fileHeader.bfSize, true);
}
return default;
}
public static BufferedData? GetTiffData(IntPtr data)
{
// Find the size of the image so we can turn it into a memory stream...
var headerSize = Marshal.SizeOf(typeof(TIFFHEADER));
var tagSize = Marshal.SizeOf(typeof(TIFFTAG));
var tiffSize = 0;
var tagPtr = data.ToInt64() + headerSize;
for (int i = 0; i < 999; i++)
{
tagPtr += (tagSize * i);
var tag = Marshal.PtrToStructure<TIFFTAG>((IntPtr)tagPtr);
switch (tag.u16Tag)
{ {
case 273: // StripOffsets... var infoHeader = Marshal.PtrToStructure<BITMAPINFOHEADER>(data);
case 279: // StripByteCounts... if (infoHeader.Validate())
tiffSize += (int)tag.u32Value; {
break; var fileHeaderSize = Marshal.SizeOf<BITMAPFILEHEADER>();
var fileHeader = new BITMAPFILEHEADER
{
bfType = 0x4D42, // "BM"
bfOffBits = (uint)fileHeaderSize +
infoHeader.biSize +
(infoHeader.biClrUsed * 4)
};
fileHeader.bfSize = fileHeader.bfOffBits + infoHeader.biSizeImage;
var dataCopy = BufferedData.MemPool.Rent((int)fileHeader.bfSize); // new byte[fileHeader.bfSize];
// TODO: run benchmark on which one is faster
// write file header
//IntPtr tempPtr = Marshal.AllocHGlobal(fileHeaderSize);
//Marshal.StructureToPtr(fileHeader, tempPtr, true);
//Marshal.Copy(tempPtr, dataCopy, 0, fileHeaderSize);
//Marshal.FreeHGlobal(tempPtr);
// would this be faster?
fixed (byte* p = dataCopy)
{
Marshal.StructureToPtr(fileHeader, (IntPtr)p, false);
}
// write image
Marshal.Copy(data, dataCopy, fileHeaderSize, (int)fileHeader.bfSize - fileHeaderSize);
return new BufferedData(dataCopy, (int)fileHeader.bfSize, true);
}
return default;
} }
}
if (tiffSize > 0) public static BufferedData? GetTiffData(IntPtr data)
{ {
var dataCopy = BufferedData.MemPool.Rent(tiffSize);// new byte[tiffSize]; // Find the size of the image so we can turn it into a memory stream...
Marshal.Copy(data, dataCopy, 0, tiffSize); var headerSize = Marshal.SizeOf<TIFFHEADER>();
return new BufferedData(dataCopy, tiffSize, true); var tagSize = Marshal.SizeOf<TIFFTAG>();
} var tiffSize = 0;
return default; var tagPtr = data.ToInt64() + headerSize;
for (int i = 0; i < 999; i++)
{
tagPtr += (tagSize * i);
var tag = Marshal.PtrToStructure<TIFFTAG>((IntPtr)tagPtr);
switch (tag.u16Tag)
{
case 273: // StripOffsets...
case 279: // StripByteCounts...
tiffSize += (int)tag.u32Value;
break;
}
}
if (tiffSize > 0)
{
var dataCopy = BufferedData.MemPool.Rent(tiffSize);// new byte[tiffSize];
Marshal.Copy(data, dataCopy, 0, tiffSize);
return new BufferedData(dataCopy, tiffSize, true);
}
return default;
}
//internal static Bitmap ReadBitmapImage(IntPtr data)
//{
// Bitmap finalImg = null;
// Bitmap tempImg = null;
// try
// {
// var header = (BITMAPINFOHEADER)Marshal.PtrToStructure(data, typeof(BITMAPINFOHEADER));
// if (header.Validate())
// {
// PixelFormat format = header.GetDrawingPixelFormat();
// tempImg = new Bitmap(header.biWidth, Math.Abs(header.biHeight), header.GetStride(), format, header.GetScan0(data));
// ColorPalette pal = header.GetDrawingPalette(data);
// if (pal != null)
// {
// tempImg.Palette = pal;
// }
// float xdpi = header.GetXDpi();
// float ydpi = header.GetYDpi();
// if (xdpi != 0 && ydpi == 0)
// {
// ydpi = xdpi;
// }
// else if (ydpi != 0 && xdpi == 0)
// {
// xdpi = ydpi;
// }
// if (xdpi != 0)
// {
// tempImg.SetResolution(xdpi, ydpi);
// }
// if (header.IsBottomUpImage)
// {
// tempImg.RotateFlip(RotateFlipType.RotateNoneFlipY);
// }
// finalImg = tempImg;
// tempImg = null;
// }
// }
// finally
// {
// if (tempImg != null)
// {
// tempImg.Dispose();
// }
// }
// return finalImg;
//}
} }
//internal static Bitmap ReadBitmapImage(IntPtr data)
//{
// Bitmap finalImg = null;
// Bitmap tempImg = null;
// try
// {
// var header = (BITMAPINFOHEADER)Marshal.PtrToStructure(data, typeof(BITMAPINFOHEADER));
// if (header.Validate())
// {
// PixelFormat format = header.GetDrawingPixelFormat();
// tempImg = new Bitmap(header.biWidth, Math.Abs(header.biHeight), header.GetStride(), format, header.GetScan0(data));
// ColorPalette pal = header.GetDrawingPalette(data);
// if (pal != null)
// {
// tempImg.Palette = pal;
// }
// float xdpi = header.GetXDpi();
// float ydpi = header.GetYDpi();
// if (xdpi != 0 && ydpi == 0)
// {
// ydpi = xdpi;
// }
// else if (ydpi != 0 && xdpi == 0)
// {
// xdpi = ydpi;
// }
// if (xdpi != 0)
// {
// tempImg.SetResolution(xdpi, ydpi);
// }
// if (header.IsBottomUpImage)
// {
// tempImg.RotateFlip(RotateFlipType.RotateNoneFlipY);
// }
// finalImg = tempImg;
// tempImg = null;
// }
// }
// finally
// {
// if (tempImg != null)
// {
// tempImg.Dispose();
// }
// }
// return finalImg;
//}
}
} }
+20 -20
View File
@@ -1,21 +1,21 @@
using System; //using System;
using System.Runtime.InteropServices; //using System.Runtime.InteropServices;
namespace NTwain.Native //namespace NTwain.Native
{ //{
/// <summary> // /// <summary>
/// The MSG structure in Windows for TWAIN use. // /// The MSG structure in Windows for TWAIN use.
/// </summary> // /// </summary>
[StructLayout(LayoutKind.Sequential)] // [StructLayout(LayoutKind.Sequential)]
struct WIN_MESSAGE // struct WIN_MESSAGE
{ // {
public IntPtr hwnd; // public IntPtr hwnd;
public uint message; // public uint message;
public IntPtr wParam; // public IntPtr wParam;
public IntPtr lParam; // public IntPtr lParam;
uint _time; // uint _time;
int _x; // int _x;
int _y; // int _y;
uint lprivate; // uint lprivate;
} // }
} //}
+79 -79
View File
@@ -1,97 +1,97 @@
using System; //using System;
using System.Runtime.InteropServices; //using System.Runtime.InteropServices;
namespace NTwain.Native //namespace NTwain.Native
{ //{
/// <summary> // /// <summary>
/// Native methods for windows. // /// Native methods for windows.
/// </summary> // /// </summary>
static partial class WinNativeMethods // static partial class WinNativeMethods
{ // {
#if NET7_0_OR_GREATER //#if NET7_0_OR_GREATER
[LibraryImport("kernel32", SetLastError = true)] // [LibraryImport("kernel32", SetLastError = true)]
public static partial IntPtr GlobalAlloc(AllocFlag uFlags, UIntPtr dwBytes); // public static partial IntPtr GlobalAlloc(AllocFlag uFlags, UIntPtr dwBytes);
[LibraryImport("kernel32", SetLastError = true)] // [LibraryImport("kernel32", SetLastError = true)]
public static partial IntPtr GlobalFree(IntPtr hMem); // public static partial IntPtr GlobalFree(IntPtr hMem);
[LibraryImport("kernel32", SetLastError = true)] // [LibraryImport("kernel32", SetLastError = true)]
public static partial IntPtr GlobalLock(IntPtr handle); // public static partial IntPtr GlobalLock(IntPtr handle);
[LibraryImport("kernel32", SetLastError = true)] // [LibraryImport("kernel32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)] // [return: MarshalAs(UnmanagedType.Bool)]
public static partial bool GlobalUnlock(IntPtr handle); // public static partial bool GlobalUnlock(IntPtr handle);
#else //#else
[DllImport("kernel32", SetLastError = true)] // [DllImport("kernel32", SetLastError = true)]
public static extern IntPtr GlobalAlloc(AllocFlag uFlags, UIntPtr dwBytes); // public static extern IntPtr GlobalAlloc(AllocFlag uFlags, UIntPtr dwBytes);
[DllImport("kernel32", SetLastError = true)] // [DllImport("kernel32", SetLastError = true)]
public static extern IntPtr GlobalFree(IntPtr hMem); // public static extern IntPtr GlobalFree(IntPtr hMem);
[DllImport("kernel32", SetLastError = true)] // [DllImport("kernel32", SetLastError = true)]
public static extern IntPtr GlobalLock(IntPtr handle); // public static extern IntPtr GlobalLock(IntPtr handle);
[DllImport("kernel32", SetLastError = true)] // [DllImport("kernel32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)] // [return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GlobalUnlock(IntPtr handle); // public static extern bool GlobalUnlock(IntPtr handle);
#endif //#endif
[Flags]
public enum AllocFlag : uint
{
/// <summary>
/// Allocates fixed memory. The return value is a pointer.
/// </summary>
GMEM_FIXED = 0,
/// <summary>
/// Allocates movable memory. Memory blocks are never moved in physical memory, but they can be moved within the default heap.
/// The return value is a handle to the memory object. To translate the handle into a pointer, use the GlobalLock function.
/// </summary>
GMEM_MOVEABLE = 2,
/// <summary>
/// Initializes memory contents to zero.
/// </summary>
GMEM_ZEROINIT = 0x40,
GPTR = GMEM_FIXED | GMEM_ZEROINIT,
GHND = GMEM_MOVEABLE | GMEM_ZEROINIT
}
// [Flags] // [Flags]
// public enum PEEK_MESSAGE_REMOVE_TYPE : uint // public enum AllocFlag : uint
// { // {
// PM_NOREMOVE = 0x00000000, // /// <summary>
// PM_REMOVE = 0x00000001, // /// Allocates fixed memory. The return value is a pointer.
// PM_NOYIELD = 0x00000002, // /// </summary>
// PM_QS_INPUT = 0x04070000, // GMEM_FIXED = 0,
// PM_QS_POSTMESSAGE = 0x00980000, // /// <summary>
// PM_QS_PAINT = 0x00200000, // /// Allocates movable memory. Memory blocks are never moved in physical memory, but they can be moved within the default heap.
// PM_QS_SENDMESSAGE = 0x00400000, // /// The return value is a handle to the memory object. To translate the handle into a pointer, use the GlobalLock function.
// /// </summary>
// GMEM_MOVEABLE = 2,
// /// <summary>
// /// Initializes memory contents to zero.
// /// </summary>
// GMEM_ZEROINIT = 0x40,
// GPTR = GMEM_FIXED | GMEM_ZEROINIT,
// GHND = GMEM_MOVEABLE | GMEM_ZEROINIT
// } // }
//#if NET7_0_OR_GREATER //// [Flags]
// [LibraryImport("USER32.dll")] //// public enum PEEK_MESSAGE_REMOVE_TYPE : uint
// public static partial int PeekMessageW(ref WIN_MESSAGE lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax, PEEK_MESSAGE_REMOVE_TYPE wRemoveMsg); //// {
//// PM_NOREMOVE = 0x00000000,
//// PM_REMOVE = 0x00000001,
//// PM_NOYIELD = 0x00000002,
//// PM_QS_INPUT = 0x04070000,
//// PM_QS_POSTMESSAGE = 0x00980000,
//// PM_QS_PAINT = 0x00200000,
//// PM_QS_SENDMESSAGE = 0x00400000,
//// }
// [LibraryImport("USER32.dll", SetLastError = true)] ////#if NET7_0_OR_GREATER
// public static partial int GetMessageW(ref WIN_MESSAGE lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax); //// [LibraryImport("USER32.dll")]
//// public static partial int PeekMessageW(ref WIN_MESSAGE lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax, PEEK_MESSAGE_REMOVE_TYPE wRemoveMsg);
// [LibraryImport("USER32.dll")] //// [LibraryImport("USER32.dll", SetLastError = true)]
// public static partial int TranslateMessage(ref WIN_MESSAGE lpMsg); //// public static partial int GetMessageW(ref WIN_MESSAGE lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax);
// [LibraryImport("USER32.dll")] //// [LibraryImport("USER32.dll")]
// public static partial nint DispatchMessageW(ref WIN_MESSAGE lpMsg); //// public static partial int TranslateMessage(ref WIN_MESSAGE lpMsg);
//#else
// [DllImport("USER32.dll")]
// public static extern int PeekMessageW(ref WIN_MESSAGE lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax, PEEK_MESSAGE_REMOVE_TYPE wRemoveMsg);
// [DllImport("USER32.dll", SetLastError = true)] //// [LibraryImport("USER32.dll")]
// public static extern int GetMessageW(ref WIN_MESSAGE lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax); //// public static partial nint DispatchMessageW(ref WIN_MESSAGE lpMsg);
////#else
//// [DllImport("USER32.dll")]
//// public static extern int PeekMessageW(ref WIN_MESSAGE lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax, PEEK_MESSAGE_REMOVE_TYPE wRemoveMsg);
// [DllImport("USER32.dll")] //// [DllImport("USER32.dll", SetLastError = true)]
// public static extern int TranslateMessage(ref WIN_MESSAGE lpMsg); //// public static extern int GetMessageW(ref WIN_MESSAGE lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax);
// [DllImport("USER32.dll")] //// [DllImport("USER32.dll")]
// public static extern nint DispatchMessageW(ref WIN_MESSAGE lpMsg); //// public static extern int TranslateMessage(ref WIN_MESSAGE lpMsg);
//#endif
} //// [DllImport("USER32.dll")]
} //// public static extern nint DispatchMessageW(ref WIN_MESSAGE lpMsg);
////#endif
// }
//}
+4
View File
@@ -0,0 +1,4 @@
{
"$schema": "https://aka.ms/CsWin32.schema.json",
"allowMarshaling": false
}
+8
View File
@@ -0,0 +1,8 @@
MSG
GlobalAlloc
GlobalFree
GlobalLock
GlobalUnlock
BITMAPINFOHEADER
BITMAPINFO
BITMAPFILEHEADER
+121 -104
View File
@@ -1,114 +1,131 @@
using NTwain.Data; using NTwain.Data;
using NTwain.Native;
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.System.Memory;
namespace NTwain namespace NTwain
{ {
// this file contains memory methods // this file contains memory methods
partial class TwainAppSession : IMemoryManager partial class TwainAppSession : IMemoryManager
{
TW_ENTRYPOINT_DELEGATES _entryPoint;
public IntPtr Alloc(uint size)
{ {
if (_entryPoint.DSM_MemAllocate != null) TW_ENTRYPOINT_DELEGATES _entryPoint;
{
return _entryPoint.DSM_MemAllocate(size); public IntPtr Alloc(uint size)
} {
else if (TWPlatform.IsWindows) if (_entryPoint.DSM_MemAllocate != null)
{ {
return WinNativeMethods.GlobalAlloc(WinNativeMethods.AllocFlag.GHND, (UIntPtr)size); return _entryPoint.DSM_MemAllocate(size);
} }
else if (TWPlatform.IsLinux) else if (TWPlatform.IsWindows)
{ {
return Marshal.AllocHGlobal((int)size); #pragma warning disable CA1416 // Validate platform compatibility
} return PInvoke.GlobalAlloc(GLOBAL_ALLOC_FLAGS.GHND, size);
else if (TWPlatform.IsMacOSX) #pragma warning restore CA1416 // Validate platform compatibility
{ //return WinNativeMethods.GlobalAlloc(WinNativeMethods.AllocFlag.GHND, (UIntPtr)size);
return Marshal.AllocHGlobal((int)size); }
} else if (TWPlatform.IsLinux)
else {
{ return Marshal.AllocHGlobal((int)size);
throw new PlatformNotSupportedException(); }
} else if (TWPlatform.IsMacOSX)
{
return Marshal.AllocHGlobal((int)size);
}
else
{
throw new PlatformNotSupportedException();
}
}
public void Free(IntPtr handle)
{
if (handle == IntPtr.Zero) return;
if (_entryPoint.DSM_MemFree != null)
{
_entryPoint.DSM_MemFree(handle);
}
else if (TWPlatform.IsWindows)
{
#pragma warning disable CA1416 // Validate platform compatibility
PInvoke.GlobalFree((HGLOBAL)handle);
#pragma warning restore CA1416 // Validate platform compatibility
//WinNativeMethods.GlobalFree(handle);
}
else if (TWPlatform.IsLinux)
{
Marshal.FreeHGlobal(handle);
}
else if (TWPlatform.IsMacOSX)
{
Marshal.FreeHGlobal(handle);
}
else
{
throw new PlatformNotSupportedException();
}
}
public IntPtr Lock(IntPtr handle)
{
if (handle == IntPtr.Zero) return IntPtr.Zero;
if (_entryPoint.DSM_MemLock != null)
{
return _entryPoint.DSM_MemLock(handle);
}
else if (TWPlatform.IsWindows)
{
unsafe
{
#pragma warning disable CA1416 // Validate platform compatibility
return (IntPtr)PInvoke.GlobalLock((HGLOBAL)handle);
#pragma warning restore CA1416 // Validate platform compatibility
}
//return WinNativeMethods.GlobalLock(handle);
}
else if (TWPlatform.IsLinux)
{
return handle;
}
else if (TWPlatform.IsMacOSX)
{
return handle;
}
else
{
throw new PlatformNotSupportedException();
}
}
public void Unlock(IntPtr handle)
{
if (handle == IntPtr.Zero) return;
if (_entryPoint.DSM_MemUnlock != null)
{
_entryPoint.DSM_MemUnlock(handle);
}
else if (TWPlatform.IsWindows)
{
#pragma warning disable CA1416 // Validate platform compatibility
PInvoke.GlobalUnlock((HGLOBAL)handle);
#pragma warning restore CA1416 // Validate platform compatibility
//WinNativeMethods.GlobalUnlock(handle);
}
else if (TWPlatform.IsLinux)
{
}
else if (TWPlatform.IsMacOSX)
{
}
else
{
throw new PlatformNotSupportedException();
}
}
} }
public void Free(IntPtr handle)
{
if (handle == IntPtr.Zero) return;
if (_entryPoint.DSM_MemFree != null)
{
_entryPoint.DSM_MemFree(handle);
}
else if (TWPlatform.IsWindows)
{
WinNativeMethods.GlobalFree(handle);
}
else if (TWPlatform.IsLinux)
{
Marshal.FreeHGlobal(handle);
}
else if (TWPlatform.IsMacOSX)
{
Marshal.FreeHGlobal(handle);
}
else
{
throw new PlatformNotSupportedException();
}
}
public IntPtr Lock(IntPtr handle)
{
if (handle == IntPtr.Zero) return IntPtr.Zero;
if (_entryPoint.DSM_MemLock != null)
{
return _entryPoint.DSM_MemLock(handle);
}
else if (TWPlatform.IsWindows)
{
return WinNativeMethods.GlobalLock(handle);
}
else if (TWPlatform.IsLinux)
{
return handle;
}
else if (TWPlatform.IsMacOSX)
{
return handle;
}
else
{
throw new PlatformNotSupportedException();
}
}
public void Unlock(IntPtr handle)
{
if (handle == IntPtr.Zero) return;
if (_entryPoint.DSM_MemUnlock != null)
{
_entryPoint.DSM_MemUnlock(handle);
}
else if (TWPlatform.IsWindows)
{
WinNativeMethods.GlobalUnlock(handle);
}
else if (TWPlatform.IsLinux)
{
}
else if (TWPlatform.IsMacOSX)
{
}
else
{
throw new PlatformNotSupportedException();
}
}
}
} }
+4 -3
View File
@@ -7,6 +7,7 @@ using System.Diagnostics;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Windows.Forms; using System.Windows.Forms;
using System.Windows.Interop; using System.Windows.Interop;
using Windows.Win32.Foundation;
using MSG = NTwain.Data.MSG; using MSG = NTwain.Data.MSG;
namespace NTwain namespace NTwain
@@ -83,11 +84,11 @@ namespace NTwain
bool handled = false; bool handled = false;
if (_state >= STATE.S5) if (_state >= STATE.S5)
{ {
WIN_MESSAGE winMsg = new() Windows.Win32.UI.WindowsAndMessaging.MSG winMsg = new()
{ {
hwnd = hWnd, hwnd = (HWND)hWnd,
message = (uint)msg, message = (uint)msg,
wParam = wParam, wParam = TWPlatform.Is32bit ? new UIntPtr((uint)wParam.ToInt32()) : new UIntPtr((ulong)wParam.ToInt64()),
lParam = lParam lParam = lParam
}; };
// no need to do another lock call when using marshal alloc // no need to do another lock call when using marshal alloc