CPF/CPF.Windows/ClipboardImpl.cs
2024-01-15 22:53:10 +08:00

1377 lines
58 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Text;
using CPF.Input;
using System.Threading;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.IO;
using CPF.Drawing;
using System.Linq;
namespace CPF.Windows
{
internal class ClipboardImpl : IClipboard
{
static int htmlId;
static int[] Format;
static ClipboardImpl()
{
//CF_BITMAP 位图的句柄HBITMAP
//CF_DIB 包含BITMAPINFO结构和位图位的内存对象。
htmlId = UnmanagedMethods.RegisterClipboardFormat(Html);
Format = new int[] { (int)UnmanagedMethods.ClipboardFormat.CF_UNICODETEXT, htmlId, (int)UnmanagedMethods.ClipboardFormat.CF_DIB, (int)UnmanagedMethods.ClipboardFormat.CF_HDROP, 0 };
}
private void OpenClipboard()
{
while (!UnmanagedMethods.OpenClipboard(IntPtr.Zero))
{
Thread.Sleep(100);
//await Task.Delay(100);
}
}
//public void SetText(string text)
//{
// if (text == null)
// {
// throw new ArgumentNullException(nameof(text));
// }
// OpenClipboard();
// UnmanagedMethods.EmptyClipboard();
// try
// {
// var hGlobal = Marshal.StringToHGlobalUni(text);
// UnmanagedMethods.SetClipboardData(UnmanagedMethods.ClipboardFormat.CF_UNICODETEXT, hGlobal);
// }
// finally
// {
// UnmanagedMethods.CloseClipboard();
// }
//}
public void Clear()
{
OpenClipboard();
try
{
UnmanagedMethods.EmptyClipboard();
}
finally
{
UnmanagedMethods.CloseClipboard();
}
}
//List<IntPtr> intPtrs = new List<IntPtr>();
public void SetData(params ValueTuple<DataFormat, object>[] data)
{
if (data == null)
{
throw new ArgumentNullException(nameof(data));
}
//foreach (var item in intPtrs)
//{
// Marshal.FreeHGlobal(item);
//}
OpenClipboard();
UnmanagedMethods.EmptyClipboard();
try
{
IntPtr hGlobal = IntPtr.Zero;
IntPtr ptr = IntPtr.Zero;
foreach (var item in data)
{
switch (item.Item1)
{
case DataFormat.Text:
hGlobal = Marshal.StringToHGlobalUni(item.Item2.ToString());
UnmanagedMethods.SetClipboardData(UnmanagedMethods.ClipboardFormat.CF_UNICODETEXT, hGlobal);
break;
case DataFormat.Html:
var html = item.Item2.ToString();
Encoding enc = Encoding.UTF8;
string begin = "Version:0.9\r\nStartHTML:{0:000000}\r\nEndHTML:{1:000000}"
+ "\r\nStartFragment:{2:000000}\r\nEndFragment:{3:000000}\r\n";
string html_begin = "<html>\r\n<head>\r\n"
+ "<meta http-equiv=\"Content-Type\""
+ " content=\"text/html; charset=" + enc.WebName + "\">\r\n"
+ "<title>HTML clipboard</title>\r\n</head>\r\n<body>\r\n"
+ "<!--StartFragment-->";
string html_end = "<!--EndFragment-->\r\n</body>\r\n</html>\r\n";
string begin_sample = String.Format(begin, 0, 0, 0, 0);
int count_begin = enc.GetByteCount(begin_sample);
int count_html_begin = enc.GetByteCount(html_begin);
int count_html = enc.GetByteCount(html);
int count_html_end = enc.GetByteCount(html_end);
string html_total = String.Format(
begin
, count_begin
, count_begin + count_html_begin + count_html + count_html_end
, count_begin + count_html_begin
, count_begin + count_html_begin + count_html
) + html_begin + html + html_end;
//var h = Marshal.StringToCoTaskMemUTF8(html_total);
var l = enc.GetByteCount(html_total);
var h = Marshal.AllocHGlobal(l);
//intPtrs.Add(h);
Marshal.Copy(enc.GetBytes(html_total), 0, h, l);
UnmanagedMethods.SetClipboardData(htmlId, h);
//Marshal.FreeHGlobal(h);
break;
case DataFormat.Image:
var img = item.Item2 as Image;
IntPtr screenDC = UnmanagedMethods.GetDC(IntPtr.Zero);
IntPtr memDc = UnmanagedMethods.CreateCompatibleDC(screenDC);
UnmanagedMethods.BITMAPINFOHEADER info = new UnmanagedMethods.BITMAPINFOHEADER();
info.biSize = (uint)Marshal.SizeOf(typeof(UnmanagedMethods.BITMAPINFOHEADER));
info.biBitCount = 24;
info.biHeight = img.Height;
info.biWidth = img.Width;
info.biPlanes = 1;
info.biSizeImage = (uint)(img.Width * img.Height * 3);
var dibHbitmap = UnmanagedMethods.CreateDIBSection(memDc, ref info, 0, out IntPtr ppvBits, IntPtr.Zero, 0);
var oldBits = UnmanagedMethods.SelectObject(memDc, dibHbitmap);
IntPtr hBitmap;
var stream = img.SaveToStream(ImageFormat.Png);
var states = UnmanagedMethods.GdipCreateBitmapFromStream(new GPStream(stream), out IntPtr bitmap);
stream.Dispose();
UnmanagedMethods.GdipCreateHBITMAPFromBitmap(bitmap, out hBitmap, UnmanagedMethods.ToWin32(Color.White));
UnmanagedMethods.GdipDisposeImage(bitmap);
UnmanagedMethods.SetClipboardData(UnmanagedMethods.ClipboardFormat.CF_BITMAP, hBitmap);
IntPtr sdc = UnmanagedMethods.CreateCompatibleDC(screenDC);
var sob = UnmanagedMethods.SelectObject(sdc, hBitmap);
UnmanagedMethods.BitBlt(memDc, 0, 0, img.Width, img.Height, sdc, 0, 0, TernaryRasterOperations.SRCCOPY);
var dib = UnmanagedMethods.GlobalAlloc(UnmanagedMethods.GMEM_MOVEABLE | UnmanagedMethods.GMEM_ZEROINIT, (int)info.biSize + (int)info.biSizeImage);
ptr = UnmanagedMethods.GlobalLock(dib);
Marshal.StructureToPtr(info, ptr, true);
var d = new byte[info.biSizeImage];
Marshal.Copy(ppvBits, d, 0, d.Length);
Marshal.Copy(d, 0, ptr + (int)info.biSize, d.Length);
UnmanagedMethods.SetClipboardData(UnmanagedMethods.ClipboardFormat.CF_DIB, dib);
UnmanagedMethods.GlobalUnlock(dib);
UnmanagedMethods.SelectObject(sdc, sob);
UnmanagedMethods.DeleteDC(sdc);
UnmanagedMethods.SelectObject(memDc, oldBits);
UnmanagedMethods.DeleteDC(memDc);
UnmanagedMethods.ReleaseDC(IntPtr.Zero, screenDC);
//UnmanagedMethods.DeleteObject(hBitmap);
break;
case DataFormat.FileNames:
var files = item.Item2 as IEnumerable<string>;
if (files != null)
{
char[] filesStr = (string.Join("\0", files) + "\0\0").ToCharArray();
_DROPFILES df = new _DROPFILES();
df.fWide = true;
#if Net4
df.pFiles = Marshal.SizeOf(typeof(_DROPFILES));
int required = (filesStr.Length * sizeof(char)) + Marshal.SizeOf(typeof(_DROPFILES));
#else
df.pFiles = Marshal.SizeOf<_DROPFILES>();
int required = (filesStr.Length * sizeof(char)) + Marshal.SizeOf<_DROPFILES>();
#endif
hGlobal = UnmanagedMethods.GlobalAlloc(UnmanagedMethods.GMEM_MOVEABLE | UnmanagedMethods.GMEM_ZEROINIT, required);
long available = UnmanagedMethods.GlobalSize(hGlobal).ToInt64();
if (required > available)
{ break; }
ptr = UnmanagedMethods.GlobalLock(hGlobal);
try
{
Marshal.StructureToPtr(df, ptr, false);
#if Net4
Marshal.Copy(filesStr, 0, ptr + Marshal.SizeOf(typeof(_DROPFILES)), filesStr.Length);
#else
Marshal.Copy(filesStr, 0, ptr + Marshal.SizeOf<_DROPFILES>(), filesStr.Length);
#endif
UnmanagedMethods.SetClipboardData(UnmanagedMethods.ClipboardFormat.CF_HDROP, hGlobal);
}
finally
{
UnmanagedMethods.GlobalUnlock(hGlobal);
}
}
break;
}
}
}
finally
{
UnmanagedMethods.CloseClipboard();
}
}
public bool Contains(DataFormat dataFormat)
{
OpenClipboard();
uint LastRetrievedFormat = 0;
List<uint> list = new List<uint>();
while (0 != (LastRetrievedFormat = UnmanagedMethods.EnumClipboardFormats(LastRetrievedFormat)))
{
list.Add(LastRetrievedFormat);
}
UnmanagedMethods.CloseClipboard();
//var f = Format[(int)dataFormat - 1];
var f = GetFormatId(dataFormat);
if (list.IndexOf((uint)f) < 0)
{
if (dataFormat == DataFormat.Text)
{
if (list.IndexOf((uint)UnmanagedMethods.ClipboardFormat.CF_TEXT) >= 0)
{
return true;
}
if (list.IndexOf((uint)UnmanagedMethods.ClipboardFormat.CF_OEMTEXT) >= 0)
{
return true;
}
}
return false;
}
return true;
}
public static DataFormat GetFormat(int format)
{
ushort f = (ushort)(format & 0xFFFF);
if (format == 2 || format == 8)
{
return DataFormat.Image;
}
for (int i = 0; i < Format.Length; i++)
{
if (Format[i] == f)
{
if (i == 0)
{
return DataFormat.Text;
}
else if (i == 1)
{
return DataFormat.Html;
}
else if (i == 2)
{
return DataFormat.Image;
}
else if (i == 3)
{
return DataFormat.FileNames;
}
}
}
if (format == (ushort)UnmanagedMethods.ClipboardFormat.CF_TEXT || format == (ushort)UnmanagedMethods.ClipboardFormat.CF_OEMTEXT)
{
return DataFormat.Text;
}
return DataFormat.Unknown;
}
public static int GetFormatId(DataFormat dataFormat)
{
//return Format[(int)dataFormat];
switch (dataFormat)
{
case DataFormat.Text:
return Format[0];
case DataFormat.Html:
return Format[1];
case DataFormat.Image:
return Format[2];
case DataFormat.FileNames:
return Format[3];
default:
return 0;
}
}
public static Image ImageFormHBitmap(IntPtr hBitmap)
{
var r = UnmanagedMethods.GdipCreateBitmapFromHBITMAP(hBitmap, IntPtr.Zero, out IntPtr b);
if (r != 0)
{
return null;
}
MemoryStream ms = new MemoryStream();
Guid png = new Guid("{b96b3caf-0728-11d3-9d7b-0000f81ef32e}");
Guid jpg = new Guid("{b96b3cae-0728-11d3-9d7b-0000f81ef32e}");
int numDecoders;
int status = UnmanagedMethods.GdipGetImageDecodersSize(out numDecoders, out int size);
if (status != 0)
{
return null;
}
IntPtr memory = Marshal.AllocHGlobal(size);
status = UnmanagedMethods.GdipGetImageDecoders(numDecoders, size, memory);
int index;
List<ImageCodecInfoPrivate> codes = new List<ImageCodecInfoPrivate>();
for (index = 0; index < numDecoders; index++)
{
IntPtr curcodec = (IntPtr)((long)memory + (int)Marshal.SizeOf(typeof(ImageCodecInfoPrivate)) * index);
ImageCodecInfoPrivate codecp = new ImageCodecInfoPrivate();
Marshal.PtrToStructure(curcodec, codecp);
codes.Add(codecp);
}
var pngCode = codes.Find(a => a.FormatID == png);
UnmanagedMethods.GdipSaveImageToStream(b, new GPStream(ms), ref pngCode.Clsid, IntPtr.Zero);
ms.Position = 0;
var img = new Bitmap(ms);
UnmanagedMethods.GdipDisposeImage(b);
//ms.Position = 0;
//File.WriteAllBytes(Path.Combine(CPF.Platform.Application.StartupPath, "test.png"), ms.ToArray());
ms.Dispose();
return img;
}
public object GetData(DataFormat dataFormat)
{
//if (dataFormat != DataFormat.Image)
{
OpenClipboard();
try
{
int formatId = (int)UnmanagedMethods.ClipboardFormat.CF_UNICODETEXT;
switch (dataFormat)
{
case DataFormat.Text:
uint LastRetrievedFormat = 0;
while (0 != (LastRetrievedFormat = UnmanagedMethods.EnumClipboardFormats(LastRetrievedFormat)))
{
if (LastRetrievedFormat == (uint)UnmanagedMethods.ClipboardFormat.CF_OEMTEXT)
{
formatId = (int)UnmanagedMethods.ClipboardFormat.CF_OEMTEXT;
break;
}
else if (LastRetrievedFormat == (uint)UnmanagedMethods.ClipboardFormat.CF_TEXT)
{
formatId = (int)UnmanagedMethods.ClipboardFormat.CF_TEXT;
break;
}
}
break;
case DataFormat.Html:
formatId = htmlId;
break;
case DataFormat.Image:
formatId = (int)UnmanagedMethods.ClipboardFormat.CF_DIB;
break;
case DataFormat.FileNames:
formatId = (int)UnmanagedMethods.ClipboardFormat.CF_HDROP;
break;
}
IntPtr hText = UnmanagedMethods.GetClipboardData(formatId);
if (hText == IntPtr.Zero)
{
return null;
}
string stringData = null;
int size;
IntPtr ptr = UnmanagedMethods.GlobalLock(hText);
try
{
switch (dataFormat)
{
case DataFormat.Text:
if (formatId == (int)UnmanagedMethods.ClipboardFormat.CF_TEXT)
{
try
{
var rv = Marshal.PtrToStringAnsi(hText);//在Unity 里会报错
return rv;
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(e);
Console.WriteLine(e);
var dwBufSize = (int)UnmanagedMethods.GlobalSize(hText);
//var ss = new String((sbyte*)hText, 0, dwBufSize);
byte[] cc = new byte[dwBufSize];
Marshal.Copy(hText, cc, 0, (int)dwBufSize);
string ss = Encoding.GetEncoding("GBK").GetString(cc).TrimEnd('\0');
return ss;
}
}
else
{
var rv = Marshal.PtrToStringUni(hText);
return rv;
}
case DataFormat.Html:
size = (int)UnmanagedMethods.GlobalSize(hText);
//if (unicode)
//{
//stringData = new string((char*)ptr);
//}
//else
//{
// stringData = new string((sbyte*)ptr);
//}
byte[] bytes = new byte[size];
Marshal.Copy(ptr, bytes, 0, size);
stringData = Encoding.UTF8.GetString(bytes);
var start = stringData.IndexOf("<!--StartFragment");
var end = stringData.IndexOf("<!--EndFragment");
if (start == -1 || end == -1)
{
var s = stringData.IndexOf("StartFragment:");
var e = stringData.IndexOf("EndFragment:");
if (s == -1 || end == -1)
{
}
else
{
start = int.Parse(stringData.Substring(s + 14, 10));
end = int.Parse(stringData.Substring(e + 14, 10));
var by = Encoding.UTF8.GetBytes(stringData);
stringData = Encoding.UTF8.GetString(by, start, end - start);
stringData = stringData.Substring(start, end - start + 1);
}
}
else
{
stringData = stringData.Substring(start + 17, end - start - 17);
stringData = stringData.TrimStart('-', ' ', '>');
}
return stringData;
case DataFormat.Image:
if (formatId == (int)UnmanagedMethods.ClipboardFormat.CF_BITMAP)
{
var img = ImageFormHBitmap(hText);
return img;
}
else
unsafe
{
#if Net4
var bmp = (UnmanagedMethods.BITMAPINFOHEADER)Marshal.PtrToStructure(ptr, typeof(UnmanagedMethods.BITMAPINFOHEADER));
#else
var bmp = Marshal.PtrToStructure<UnmanagedMethods.BITMAPINFOHEADER>(ptr);
#endif
IntPtr screenDC = UnmanagedMethods.GetDC(IntPtr.Zero);
IntPtr memDc = UnmanagedMethods.CreateCompatibleDC(screenDC);
UnmanagedMethods.BITMAPINFOHEADER info = new UnmanagedMethods.BITMAPINFOHEADER();
info.biSize = (uint)Marshal.SizeOf(typeof(UnmanagedMethods.BITMAPINFOHEADER));
info.biBitCount = 32;
info.biHeight = bmp.biHeight;
info.biWidth = bmp.biWidth;
info.biPlanes = 1;
var hBitmap = UnmanagedMethods.CreateDIBSection(memDc, ref info, 0, out IntPtr ppvBits, IntPtr.Zero, 0);
var oldBits = UnmanagedMethods.SelectObject(memDc, hBitmap);//将位图载入上下文
//_ = UnmanagedMethods.GlobalLock(hText);
_ = UnmanagedMethods.StretchDIBits(memDc, 0, 0, bmp.biWidth, Math.Abs(bmp.biHeight), 0, 0, bmp.biWidth, Math.Abs(bmp.biHeight), (ptr + sizeof(UnmanagedMethods.BITMAPINFOHEADER)), ref info, 0, (uint)TernaryRasterOperations.SRCCOPY);
//sizeof(UnmanagedMethods.BITMAPFILEHEADER) +
//var c = sizeof(UnmanagedMethods.BITMAPINFOHEADER);
var img = ImageFormHBitmap(hBitmap);
//var img = new Bitmap(bmp.biWidth, bmp.biHeight, bmp.biWidth * 4, PixelFormat.PRgba, ppvBits).Clone();
UnmanagedMethods.SelectObject(memDc, oldBits);
UnmanagedMethods.ReleaseDC(IntPtr.Zero, screenDC);
UnmanagedMethods.DeleteDC(memDc);
UnmanagedMethods.DeleteObject(hBitmap);
return img;
}
case DataFormat.FileNames:
string[] files = null;
StringBuilder sb = new StringBuilder(260);
int count = UnmanagedMethods.DragQueryFile(hText, unchecked((int)0xFFFFFFFF), null, 0);
if (count > 0)
{
files = new string[count];
for (int i = 0; i < count; i++)
{
int charlen = UnmanagedMethods.DragQueryFileLongPath(hText, i, sb);
if (0 == charlen)
continue;
string s = sb.ToString(0, charlen);
// SECREVIEW : do we really need to do this?
//
//string fullPath = Path.GetFullPath(s);
//Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "FileIO(" + fullPath + ") Demanded");
//new FileIOPermission(FileIOPermissionAccess.PathDiscovery, fullPath).Demand();
files[i] = s;
}
}
return files;
default:
return null;
}
}
finally
{
UnmanagedMethods.GlobalUnlock(hText);
}
}
finally
{
UnmanagedMethods.CloseClipboard();
}
}
//else
//{
// IDataObject dataObject = null;
// int hr, retry = 10;
// do
// {
// hr = UnmanagedMethods.OleGetClipboard(ref dataObject);
// if (hr != 0)
// {
// if (retry == 0)
// {
// //ThrowIfFailed(hr);
// throw new Exception("读取剪贴板失败");
// }
// retry--;
// Thread.Sleep(100 /*ms*/);
// }
// }
// while (hr != 0);
// FORMATETC formatetc = new FORMATETC();
// STGMEDIUM medium = new STGMEDIUM();
// var tymed = TYMED.TYMED_GDI;
// formatetc.cfFormat = (short)UnmanagedMethods.ClipboardFormat.CF_BITMAP;
// formatetc.dwAspect = DVASPECT.DVASPECT_CONTENT;
// formatetc.lindex = -1;
// formatetc.tymed = tymed;
// medium.tymed = tymed;
// Object data = null;
// if (0 == dataObject.QueryGetData(ref formatetc))
// {
// try
// {
// //IntSecurity.UnmanagedCode.Assert();
// try
// {
// dataObject.GetData(ref formatetc, out medium);
// }
// finally
// {
// //CodeAccessPermission.RevertAssert();
// }
// if (medium.unionmember != IntPtr.Zero)
// {
// var r = UnmanagedMethods.GdipCreateBitmapFromHBITMAP(medium.unionmember, IntPtr.Zero, out IntPtr b);
// if (r != 0)
// {
// return null;
// }
// //UnmanagedMethods.BITMAP BITMAP = new UnmanagedMethods.BITMAP();
// //UnmanagedMethods.GetObject(medium.unionmember, Marshal.SizeOf(typeof(UnmanagedMethods.BITMAP)), BITMAP);
// MemoryStream ms = new MemoryStream();
// Guid png = new Guid("{b96b3caf-0728-11d3-9d7b-0000f81ef32e}");
// int numDecoders;
// int size;
// int status = UnmanagedMethods.GdipGetImageDecodersSize(out numDecoders, out size);
// if (status != 0)
// {
// return null;
// }
// IntPtr memory = Marshal.AllocHGlobal(size);
// status = UnmanagedMethods.GdipGetImageDecoders(numDecoders, size, memory);
// int index;
// List<ImageCodecInfoPrivate> codes = new List<ImageCodecInfoPrivate>();
// for (index = 0; index < numDecoders; index++)
// {
// IntPtr curcodec = (IntPtr)((long)memory + (int)Marshal.SizeOf(typeof(ImageCodecInfoPrivate)) * index);
// ImageCodecInfoPrivate codecp = new ImageCodecInfoPrivate();
// Marshal.PtrToStructure(curcodec, codecp);
// codes.Add(codecp);
// }
// var pngCode = codes.Find(a => a.FormatID == png);
// UnmanagedMethods.GdipSaveImageToStream(b, new ComStreamFromDataStream(ms), ref pngCode.Clsid, IntPtr.Zero);
// ms.Position = 0;
// var img = new CPF.Bitmap(ms);
// UnmanagedMethods.GdipDisposeImage(b);
// ms.Dispose();
// return img;
// }
// }
// catch
// {
// }
// }
// return data;
//}
}
/// <para>Specifies the standard ANSI text format. This <see langword='static '/>
/// field is read-only.</para>
/// </devdoc>
public static readonly string Text = "Text";
/// <para>Specifies the standard Windows Unicode text format. This
/// <see langword='static '/>
/// field is read-only.</para>
/// </devdoc>
public static readonly string UnicodeText = "UnicodeText";
/// <para>Specifies the Windows Device Independent Bitmap (DIB)
/// format. This <see langword='static '/>
/// field is read-only.</para>
/// </devdoc>
public static readonly string Dib = "DeviceIndependentBitmap";
/// <devdoc>
/// <para>Specifies a Windows bitmap format. This <see langword='static '/> field is read-only.</para>
/// </devdoc>
public static readonly string Bitmap = "Bitmap";
/// <devdoc>
/// <para>Specifies the Windows enhanced metafile format. This
/// <see langword='static '/> field is read-only.</para>
/// </devdoc>
public static readonly string EnhancedMetafile = "EnhancedMetafile";
/// <devdoc>
/// <para>Specifies the Windows metafile format, which Win Forms
/// does not directly use. This <see langword='static '/>
/// field is read-only.</para>
/// </devdoc>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly")] // Would be a breaking change to rename this
public static readonly string MetafilePict = "MetaFilePict";
/// <devdoc>
/// <para>Specifies the Windows symbolic link format, which Win
/// Forms does not directly use. This <see langword='static '/>
/// field is read-only.</para>
/// </devdoc>
public static readonly string SymbolicLink = "SymbolicLink";
/// <devdoc>
/// <para>Specifies the Windows data interchange format, which Win
/// Forms does not directly use. This <see langword='static '/>
/// field is read-only.</para>
/// </devdoc>
public static readonly string Dif = "DataInterchangeFormat";
/// <devdoc>
/// <para>Specifies the Tagged Image File Format (TIFF), which Win
/// Forms does not directly use. This <see langword='static '/>
/// field is read-only.</para>
/// </devdoc>
public static readonly string Tiff = "TaggedImageFileFormat";
/// <devdoc>
/// <para>Specifies the standard Windows original equipment
/// manufacturer (OEM) text format. This <see langword='static '/> field is read-only.</para>
/// </devdoc>
public static readonly string OemText = "OEMText";
/// <devdoc>
/// <para>Specifies the Windows palette format. This <see langword='static '/>
/// field is read-only.</para>
/// </devdoc>
public static readonly string Palette = "Palette";
/// <devdoc>
/// <para>Specifies the Windows pen data format, which consists of
/// pen strokes for handwriting software; Win Forms does not use this format. This
/// <see langword='static '/>
/// field is read-only.</para>
/// </devdoc>
public static readonly string PenData = "PenData";
/// <devdoc>
/// <para>Specifies the Resource Interchange File Format (RIFF)
/// audio format, which Win Forms does not directly use. This <see langword='static '/> field is read-only.</para>
/// </devdoc>
public static readonly string Riff = "RiffAudio";
/// <devdoc>
/// <para>Specifies the wave audio format, which Win Forms does not
/// directly use. This <see langword='static '/> field is read-only.</para>
/// </devdoc>
public static readonly string WaveAudio = "WaveAudio";
/// <devdoc>
/// <para>Specifies the Windows file drop format, which Win Forms
/// does not directly use. This <see langword='static '/>
/// field is read-only.</para>
/// </devdoc>
public static readonly string FileDrop = "FileDrop";
/// <devdoc>
/// <para>Specifies the Windows culture format, which Win Forms does
/// not directly use. This <see langword='static '/> field is read-only.</para>
/// </devdoc>
public static readonly string Locale = "Locale";
/// <devdoc>
/// <para>Specifies text consisting of HTML data. This
/// <see langword='static '/> field is read-only.</para>
/// </devdoc>
public static readonly string Html = "HTML Format";
/// <devdoc>
/// <para>Specifies text consisting of Rich Text Format (RTF) data. This
/// <see langword='static '/> field is read-only.</para>
/// </devdoc>
public static readonly string Rtf = "Rich Text Format";
/// <devdoc>
/// <para>Specifies a comma-separated value (CSV) format, which is a
/// common interchange format used by spreadsheets. This format is not used directly
/// by Win Forms. This <see langword='static '/>
/// field is read-only.</para>
/// </devdoc>
public static readonly string CommaSeparatedValue = "Csv";
}
//[ComImport()]
//[Guid("0000010E-0000-0000-C000-000000000046")]
//[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
//public interface IDataObject
//{
// /// <devdoc>
// /// Called by a data consumer to obtain data from a source data object.
// /// The GetData method renders the data described in the specified FORMATETC
// /// structure and transfers it through the specified STGMEDIUM structure.
// /// The caller then assumes responsibility for releasing the STGMEDIUM structure.
// /// </devdoc>
// void GetData([In] ref FORMATETC format, out STGMEDIUM medium);
// /// <devdoc>
// /// Called by a data consumer to obtain data from a source data object.
// /// This method differs from the GetData method in that the caller must
// /// allocate and free the specified storage medium.
// /// </devdoc>
// void GetDataHere([In] ref FORMATETC format, ref STGMEDIUM medium);
// /// <devdoc>
// /// Determines whether the data object is capable of rendering the data
// /// described in the FORMATETC structure. Objects attempting a paste or
// /// drop operation can call this method before calling IDataObject::GetData
// /// to get an indication of whether the operation may be successful.
// /// </devdoc>
// [PreserveSig]
// int QueryGetData([In] ref FORMATETC format);
// /// <devdoc>
// /// Provides a standard FORMATETC structure that is logically equivalent to one that is more
// /// complex. You use this method to determine whether two different
// /// FORMATETC structures would return the same data, removing the need
// /// for duplicate rendering.
// /// </devdoc>
// [PreserveSig]
// int GetCanonicalFormatEtc([In] ref FORMATETC formatIn, out FORMATETC formatOut);
// /// <devdoc>
// /// Called by an object containing a data source to transfer data to
// /// the object that implements this method.
// /// </devdoc>
// void SetData([In] ref FORMATETC formatIn, [In] ref STGMEDIUM medium, [MarshalAs(UnmanagedType.Bool)] bool release);
// /// <devdoc>
// /// Creates an object for enumerating the FORMATETC structures for a
// /// data object. These structures are used in calls to IDataObject::GetData
// /// or IDataObject::SetData.
// /// </devdoc>
// IEnumFORMATETC EnumFormatEtc(DATADIR direction);
// /// <devdoc>
// /// Called by an object supporting an advise sink to create a connection between
// /// a data object and the advise sink. This enables the advise sink to be
// /// notified of changes in the data of the object.
// /// </devdoc>
// [PreserveSig]
// int DAdvise([In] ref FORMATETC pFormatetc, ADVF advf, IAdviseSink adviseSink, out int connection);
// /// <devdoc>
// /// Destroys a notification connection that had been previously set up.
// /// </devdoc>
// void DUnadvise(int connection);
// /// <devdoc>
// /// Creates an object that can be used to enumerate the current advisory connections.
// /// </devdoc>
// [PreserveSig]
// int EnumDAdvise(out IEnumSTATDATA enumAdvise);
//}
//public struct FORMATETC
//{
// [MarshalAs(UnmanagedType.U2)]
// public short cfFormat;
// public IntPtr ptd;
// [MarshalAs(UnmanagedType.U4)]
// public DVASPECT dwAspect;
// public int lindex;
// [MarshalAs(UnmanagedType.U4)]
// public TYMED tymed;
//}
//public enum DATADIR
//{
// DATADIR_GET = 1,
// DATADIR_SET = 2
//}
///// <devdoc>
///// The IEnumFORMATETC interface is used to enumerate an array of FORMATETC
///// structures. IEnumFORMATETC has the same methods as all enumerator interfaces:
///// Next, Skip, Reset, and Clone.
///// </devdoc>
//[ComImport()]
//[Guid("00000103-0000-0000-C000-000000000046")]
//[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
//public interface IEnumFORMATETC
//{
// /// <devdoc>
// /// Retrieves the next celt items in the enumeration sequence. If there are
// /// fewer than the requested number of elements left in the sequence, it
// /// retrieves the remaining elements. The number of elements actually
// /// retrieved is returned through pceltFetched (unless the caller passed
// /// in NULL for that parameter).
// /// </devdoc>
// [PreserveSig]
// int Next(int celt, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] FORMATETC[] rgelt, [Out, MarshalAs(UnmanagedType.LPArray)] int[] pceltFetched);
// /// <devdoc>
// /// Skips over the next specified number of elements in the enumeration sequence.
// /// </devdoc>
// [PreserveSig]
// int Skip(int celt);
// /// <devdoc>
// /// Resets the enumeration sequence to the beginning.
// /// </devdoc>
// [PreserveSig]
// int Reset();
// /// <devdoc>
// /// Creates another enumerator that contains the same enumeration state as
// /// the current one. Using this function, a client can record a particular
// /// point in the enumeration sequence and then return to that point at a
// /// later time. The new enumerator supports the same interface as the original one.
// /// </devdoc>
// void Clone(out IEnumFORMATETC newEnum);
//}
//[Flags]
//public enum DVASPECT
//{
// DVASPECT_CONTENT = 1,
// DVASPECT_THUMBNAIL = 2,
// DVASPECT_ICON = 4,
// DVASPECT_DOCPRINT = 8
//}
//[Flags]
//public enum TYMED
//{
// TYMED_HGLOBAL = 1,
// TYMED_FILE = 2,
// TYMED_ISTREAM = 4,
// TYMED_ISTORAGE = 8,
// TYMED_GDI = 16,
// TYMED_MFPICT = 32,
// TYMED_ENHMF = 64,
// TYMED_NULL = 0
//}
//[Flags]
//[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1712:DoNotPrefixEnumValuesWithTypeName")]
//public enum ADVF
//{
// ADVF_NODATA = 1,
// ADVF_PRIMEFIRST = 2,
// ADVF_ONLYONCE = 4,
// ADVF_DATAONSTOP = 64,
// ADVFCACHE_NOHANDLER = 8,
// ADVFCACHE_FORCEBUILTIN = 16,
// ADVFCACHE_ONSAVE = 32
//}
///// <devdoc>
///// The IAdviseSink interface enables containers and other objects to
///// receive notifications of data changes, view changes, and compound-document
///// changes occurring in objects of interest. Container applications, for
///// example, require such notifications to keep cached presentations of their
///// linked and embedded objects up-to-date. Calls to IAdviseSink methods are
///// asynchronous, so the call is sent and then the next instruction is executed
///// without waiting for the call's return.
///// </devdoc>
//[ComImport()]
//[Guid("0000010F-0000-0000-C000-000000000046")]
//[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
//public interface IAdviseSink
//{
// /// <devdoc>
// /// Called by the server to notify a data object's currently registered
// /// advise sinks that data in the object has changed.
// /// </devdoc>
// [PreserveSig]
// void OnDataChange([In] ref FORMATETC format, [In] ref STGMEDIUM stgmedium);
// /// <devdoc>
// /// Notifies an object's registered advise sinks that its view has changed.
// /// </devdoc>
// [PreserveSig]
// void OnViewChange(int aspect, int index);
// /// <devdoc>
// /// Called by the server to notify all registered advisory sinks that
// /// the object has been renamed.
// /// </devdoc>
// [PreserveSig]
// void OnRename(IMoniker moniker);
// /// <devdoc>
// /// Called by the server to notify all registered advisory sinks that
// /// the object has been saved.
// /// </devdoc>
// [PreserveSig]
// void OnSave();
// /// <devdoc>
// /// Called by the server to notify all registered advisory sinks that the
// /// object has changed from the running to the loaded state.
// /// </devdoc>
// [PreserveSig]
// void OnClose();
//}
//public struct STGMEDIUM
//{
// public TYMED tymed;
// public IntPtr unionmember;
// [MarshalAs(UnmanagedType.IUnknown)]
// public object pUnkForRelease;
//}
[StructLayout(LayoutKind.Sequential)]
public struct FILETIME
{
public int dwLowDateTime;
public int dwHighDateTime;
}
//[Guid("0000000f-0000-0000-C000-000000000046")]
//[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
//[ComImport]
//public interface IMoniker
//{
// // IPersist portion
// void GetClassID(out Guid pClassID);
// // IPersistStream portion
// [PreserveSig]
// int IsDirty();
// void Load(IStream pStm);
// void Save(IStream pStm, [MarshalAs(UnmanagedType.Bool)] bool fClearDirty);
// void GetSizeMax(out Int64 pcbSize);
// // IMoniker portion
// void BindToObject(IBindCtx pbc, IMoniker pmkToLeft, [In()] ref Guid riidResult, [MarshalAs(UnmanagedType.Interface)] out Object ppvResult);
// void BindToStorage(IBindCtx pbc, IMoniker pmkToLeft, [In()] ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out Object ppvObj);
// void Reduce(IBindCtx pbc, int dwReduceHowFar, ref IMoniker ppmkToLeft, out IMoniker ppmkReduced);
// void ComposeWith(IMoniker pmkRight, [MarshalAs(UnmanagedType.Bool)] bool fOnlyIfNotGeneric, out IMoniker ppmkComposite);
// void Enum([MarshalAs(UnmanagedType.Bool)] bool fForward, out IEnumMoniker ppenumMoniker);
// [PreserveSig]
// int IsEqual(IMoniker pmkOtherMoniker);
// void Hash(out int pdwHash);
// [PreserveSig]
// int IsRunning(IBindCtx pbc, IMoniker pmkToLeft, IMoniker pmkNewlyRunning);
// void GetTimeOfLastChange(IBindCtx pbc, IMoniker pmkToLeft, out FILETIME pFileTime);
// void Inverse(out IMoniker ppmk);
// void CommonPrefixWith(IMoniker pmkOther, out IMoniker ppmkPrefix);
// void RelativePathTo(IMoniker pmkOther, out IMoniker ppmkRelPath);
// void GetDisplayName(IBindCtx pbc, IMoniker pmkToLeft, [MarshalAs(UnmanagedType.LPWStr)] out String ppszDisplayName);
// void ParseDisplayName(IBindCtx pbc, IMoniker pmkToLeft, [MarshalAs(UnmanagedType.LPWStr)] String pszDisplayName, out int pchEaten, out IMoniker ppmkOut);
// [PreserveSig]
// int IsSystemMoniker(out int pdwMksys);
//}
//[StructLayout(LayoutKind.Sequential)]
//public struct BIND_OPTS
//{
// public int cbStruct;
// public int grfFlags;
// public int grfMode;
// public int dwTickCountDeadline;
//}
//[Guid("0000000e-0000-0000-C000-000000000046")]
//[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
//[ComImport]
//public interface IBindCtx
//{
// void RegisterObjectBound([MarshalAs(UnmanagedType.Interface)] Object punk);
// void RevokeObjectBound([MarshalAs(UnmanagedType.Interface)] Object punk);
// void ReleaseBoundObjects();
// void SetBindOptions([In()] ref BIND_OPTS pbindopts);
// void GetBindOptions(ref BIND_OPTS pbindopts);
// void GetRunningObjectTable(out IRunningObjectTable pprot);
// void RegisterObjectParam([MarshalAs(UnmanagedType.LPWStr)] String pszKey, [MarshalAs(UnmanagedType.Interface)] Object punk);
// void GetObjectParam([MarshalAs(UnmanagedType.LPWStr)] String pszKey, [MarshalAs(UnmanagedType.Interface)] out Object ppunk);
// void EnumObjectParam(out IEnumString ppenum);
// [PreserveSig]
// int RevokeObjectParam([MarshalAs(UnmanagedType.LPWStr)] String pszKey);
//}
//[Guid("00000101-0000-0000-C000-000000000046")]
//[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
//[ComImport]
//public interface IEnumString
//{
// [PreserveSig]
// int Next(int celt, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 0), Out] String[] rgelt, IntPtr pceltFetched);
// [PreserveSig]
// int Skip(int celt);
// void Reset();
// void Clone(out IEnumString ppenum);
//}
//[Guid("00000010-0000-0000-C000-000000000046")]
//[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
//[ComImport]
//public interface IRunningObjectTable
//{
// int Register(int grfFlags, [MarshalAs(UnmanagedType.Interface)] Object punkObject, IMoniker pmkObjectName);
// void Revoke(int dwRegister);
// [PreserveSig]
// int IsRunning(IMoniker pmkObjectName);
// [PreserveSig]
// int GetObject(IMoniker pmkObjectName, [MarshalAs(UnmanagedType.Interface)] out Object ppunkObject);
// void NoteChangeTime(int dwRegister, ref FILETIME pfiletime);
// [PreserveSig]
// int GetTimeOfLastChange(IMoniker pmkObjectName, out FILETIME pfiletime);
// void EnumRunning(out IEnumMoniker ppenumMoniker);
//}
//[Guid("00000102-0000-0000-C000-000000000046")]
//[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
//[ComImport]
//public interface IEnumMoniker
//{
// [PreserveSig]
// int Next(int celt, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0), Out] IMoniker[] rgelt, IntPtr pceltFetched);
// [PreserveSig]
// int Skip(int celt);
// void Reset();
// void Clone(out IEnumMoniker ppenum);
//}
//[ComImport()]
//[Guid("00000103-0000-0000-C000-000000000046")]
//[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
//public interface IEnumSTATDATA
//{
// /// <devdoc>
// /// Retrieves the next celt items in the enumeration sequence. If there are
// /// fewer than the requested number of elements left in the sequence, it
// /// retrieves the remaining elements. The number of elements actually
// /// retrieved is returned through pceltFetched (unless the caller passed
// /// in NULL for that parameter).
// /// </devdoc>
// [PreserveSig]
// int Next(int celt, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] STATDATA[] rgelt, [Out, MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] int[] pceltFetched);
// /// <devdoc>
// /// Skips over the next specified number of elements in the enumeration sequence.
// /// </devdoc>
// [PreserveSig]
// int Skip(int celt);
// /// <devdoc>
// /// Resets the enumeration sequence to the beginning.
// /// </devdoc>
// [PreserveSig]
// int Reset();
// /// <devdoc>
// /// Creates another enumerator that contains the same enumeration state as
// /// the current one. Using this function, a client can record a particular
// /// point in the enumeration sequence and then return to that point at a
// /// later time. The new enumerator supports the same interface as the original one.
// /// </devdoc>
// void Clone(out IEnumSTATDATA newEnum);
//}
//public struct STATDATA
//{
// public FORMATETC formatetc;
// public ADVF advf;
// public IAdviseSink advSink;
// public int connection;
//}
//internal class ComStreamFromDataStream : IStream
//{
// protected Stream dataStream;
// // to support seeking ahead of the stream length...
// long virtualPosition = -1;
// internal ComStreamFromDataStream(Stream dataStream)
// {
// if (dataStream == null) throw new ArgumentNullException("dataStream");
// this.dataStream = dataStream;
// }
// private void ActualizeVirtualPosition()
// {
// if (virtualPosition == -1) return;
// if (virtualPosition > dataStream.Length)
// dataStream.SetLength(virtualPosition);
// dataStream.Position = virtualPosition;
// virtualPosition = -1;
// }
// public virtual IStream Clone()
// {
// NotImplemented();
// return null;
// }
// public virtual void Commit(int grfCommitFlags)
// {
// dataStream.Flush();
// // Extend the length of the file if needed.
// ActualizeVirtualPosition();
// }
// public virtual long CopyTo(IStream pstm, long cb, long[] pcbRead)
// {
// int bufsize = 4096; // one page
// IntPtr buffer = Marshal.AllocHGlobal(bufsize);
// if (buffer == IntPtr.Zero) throw new OutOfMemoryException();
// long written = 0;
// try
// {
// while (written < cb)
// {
// int toRead = bufsize;
// if (written + toRead > cb) toRead = (int)(cb - written);
// int read = Read(buffer, toRead);
// if (read == 0) break;
// if (pstm.Write(buffer, read) != read)
// {
// throw EFail("Wrote an incorrect number of bytes");
// }
// written += read;
// }
// }
// finally
// {
// Marshal.FreeHGlobal(buffer);
// }
// if (pcbRead != null && pcbRead.Length > 0)
// {
// pcbRead[0] = written;
// }
// return written;
// }
// public virtual Stream GetDataStream()
// {
// return dataStream;
// }
// public virtual void LockRegion(long libOffset, long cb, int dwLockType)
// {
// }
// protected static ExternalException EFail(string msg)
// {
// throw new ExternalException(msg);
// }
// protected static void NotImplemented()
// {
// throw new ExternalException("未实现");
// }
// public virtual int Read(IntPtr buf, /* cpr: int offset,*/ int length)
// {
// // System.Text.Out.WriteLine("IStream::Read(" + length + ")");
// byte[] buffer = new byte[length];
// int count = Read(buffer, length);
// Marshal.Copy(buffer, 0, buf, length);
// return count;
// }
// public virtual int Read(byte[] buffer, /* cpr: int offset,*/ int length)
// {
// ActualizeVirtualPosition();
// return dataStream.Read(buffer, 0, length);
// }
// public virtual void Revert()
// {
// NotImplemented();
// }
// public virtual long Seek(long offset, int origin)
// {
// // Console.WriteLine("IStream::Seek("+ offset + ", " + origin + ")");
// long pos = virtualPosition;
// if (virtualPosition == -1)
// {
// pos = dataStream.Position;
// }
// long len = dataStream.Length;
// switch (origin)
// {
// case GPStream.STREAM_SEEK_SET:
// if (offset <= len)
// {
// dataStream.Position = offset;
// virtualPosition = -1;
// }
// else
// {
// virtualPosition = offset;
// }
// break;
// case GPStream.STREAM_SEEK_END:
// if (offset <= 0)
// {
// dataStream.Position = len + offset;
// virtualPosition = -1;
// }
// else
// {
// virtualPosition = len + offset;
// }
// break;
// case GPStream.STREAM_SEEK_CUR:
// if (offset + pos <= len)
// {
// dataStream.Position = pos + offset;
// virtualPosition = -1;
// }
// else
// {
// virtualPosition = offset + pos;
// }
// break;
// }
// if (virtualPosition != -1)
// {
// return virtualPosition;
// }
// else
// {
// return dataStream.Position;
// }
// }
// public virtual void SetSize(long value)
// {
// dataStream.SetLength(value);
// }
// public virtual void Stat(IntPtr pstatstg, int grfStatFlag)
// {
// // GpStream has a partial implementation, but it's so partial rather
// // restrict it to use with GDI+
// NotImplemented();
// }
// public virtual void UnlockRegion(long libOffset, long cb, int dwLockType)
// {
// }
// public virtual int Write(IntPtr buf, /* cpr: int offset,*/ int length)
// {
// byte[] buffer = new byte[length];
// Marshal.Copy(buf, buffer, 0, length);
// return Write(buffer, length);
// }
// public virtual int Write(byte[] buffer, /* cpr: int offset,*/ int length)
// {
// ActualizeVirtualPosition();
// dataStream.Write(buffer, 0, length);
// return length;
// }
//}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
internal class ImageCodecInfoPrivate
{
[MarshalAs(UnmanagedType.Struct)]
public Guid Clsid;
[MarshalAs(UnmanagedType.Struct)]
public Guid FormatID;
public IntPtr CodecName = IntPtr.Zero;
public IntPtr DllName = IntPtr.Zero;
public IntPtr FormatDescription = IntPtr.Zero;
public IntPtr FilenameExtension = IntPtr.Zero;
public IntPtr MimeType = IntPtr.Zero;
public int Flags;
public int Version;
public int SigCount;
public int SigSize;
public IntPtr SigPattern = IntPtr.Zero;
public IntPtr SigMask = IntPtr.Zero;
}
}