Skip to content

Commit

Permalink
Restructure DataObject
Browse files Browse the repository at this point in the history
  • Loading branch information
lonitra committed Jan 16, 2025
1 parent 194388c commit 1feda3d
Show file tree
Hide file tree
Showing 67 changed files with 2,900 additions and 1,235 deletions.
7 changes: 7 additions & 0 deletions src/System.Private.Windows.Core/src/GlobalSuppressions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

[assembly: SuppressMessage("Usage", "CA2201:Do not raise reserved exception types", Justification = "Compat", Scope = "member", Target = "~M:System.Private.Windows.Core.OLE.DesktopDataObject.Composition.NativeToDesktopAdapter.ReadByteStreamFromHGLOBAL(Windows.Win32.Foundation.HGLOBAL,System.Boolean@)~System.IO.MemoryStream")]
[assembly: SuppressMessage("Usage", "CA2201:Do not raise reserved exception types", Justification = "Compat", Scope = "member", Target = "~M:System.Private.Windows.Core.OLE.DesktopDataObject.Composition.NativeToRuntimeAdapter.System#Runtime#InteropServices#ComTypes#IDataObject#EnumFormatEtc(System.Runtime.InteropServices.ComTypes.DATADIR)~System.Runtime.InteropServices.ComTypes.IEnumFORMATETC")]
[assembly: SuppressMessage("Usage", "CA2201:Do not raise reserved exception types", Justification = "Compat", Scope = "member", Target = "~M:System.Private.Windows.Core.OLE.DesktopClipboard.SetDataObject(System.Object,System.Boolean,System.Int32,System.Int32)")]
[assembly: SuppressMessage("Usage", "CA2201:Do not raise reserved exception types", Justification = "Compat", Scope = "member", Target = "~M:System.Private.Windows.Core.OLE.DesktopClipboard.GetDataObject~System.Private.Windows.Core.OLE.IDataObjectDesktop")]
17 changes: 17 additions & 0 deletions src/System.Private.Windows.Core/src/NativeMethods.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ BeginPaint
BI_COMPRESSION
BitBlt
BOOL
CFSTR_DROPDESCRIPTION
CFSTR_INDRAGLOOP
CLIPBRD_E_BAD_DATA
CLR_*
CallWindowProc
CoCreateInstance
CombineRgn
CopyImage
CP_ACP
CreateBitmap
CreateCompatibleBitmap
CreateCompatibleDC
Expand Down Expand Up @@ -50,7 +53,11 @@ DRAGDROP_S_CANCEL
DRAGDROP_S_DROP
DRAGDROP_S_USEDEFAULTCURSORS
DrawIconEx
DragQueryFile
DROPDESCRIPTION
DROPFILES
DV_E_*
DVASPECT
E_ABORT
E_ACCESSDENIED
E_FAIL
Expand Down Expand Up @@ -78,6 +85,7 @@ GetWindowText
GetWindowTextLength
GET_CLASS_LONG_INDEX
GetClientRect
GetClipboardFormatName
GetClipRgn
GetDC
GetDCEx
Expand Down Expand Up @@ -119,7 +127,9 @@ HPROPSHEETPAGE
HRGN
HWND
HWND_*
IDataObject
IDI_*
IDragSourceHelper2
IEnumUnknown
IGlobalInterfaceTable
ImageLockMode
Expand Down Expand Up @@ -162,6 +172,10 @@ OLE_E_INVALIDRECT
OLE_E_NOCONNECTION
OLE_E_PROMPTSAVECANCELLED
OleCreatePictureIndirect
OleDuplicateData
OleFlushClipboard
OleGetClipboard
OleSetClipboard
PeekMessage
PostMessage
POINTS
Expand All @@ -171,7 +185,9 @@ PWSTR
RealizePalette
RECT
REGDB_E_CLASSNOTREG
RegisterClipboardFormat
ReleaseDC
ReleaseStgMedium
RestoreDC
RPC_E_CHANGED_MODE
RPC_E_DISCONNECTED
Expand Down Expand Up @@ -215,6 +231,7 @@ SystemParametersInfoForDpi
TYPE_E_BADMODULEKIND
UNICODE_STRING_MAX_CHARS
VIEW_E_DRAW
WideCharToMultiByte
WIN32_ERROR
WINCODEC_ERR_*
WINDOW_LONG_PTR_INDEX
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System.Private.Windows.Core.OLE;

/// <summary>
/// Translates between WinForms text-based <see cref="DesktopClipboard"/>
/// formats and Win32 32-bit signed integer-based clipboard
/// formats. Provides <see langword="static"/> methods to create new
/// <see cref="DesktopClipboard"/> formats and add them to the Windows Registry.
/// </summary>
internal static partial class DesktopDataFormats
{
/// <summary>
/// Represents a format type.
/// </summary>
public class Format
{
/// <summary>
/// Initializes a new instance of the <see cref="Format"/> class and
/// specifies whether a Win32 handle is expected with this format.
/// </summary>
public Format(string name, int id)
{
Name = name;
Id = id;
}

/// <summary>
/// Specifies the name of this format.
/// </summary>
public string Name { get; }

/// <summary>
/// Specifies the ID number for this format.
/// </summary>
public int Id { get; }
}
}
193 changes: 193 additions & 0 deletions src/System.Private.Windows.Core/src/OLE/DesktopDataFormats.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.ComponentModel;
using System.Private.Windows.Core.Resources;
using System.Runtime.InteropServices;
using Windows.Win32;
using Windows.Win32.System.Ole;

namespace System.Private.Windows.Core.OLE;

/// <summary>
/// Translates between WinForms text-based <see cref="DesktopClipboard"/>
/// formats and Win32 32-bit signed integer-based clipboard
/// formats. Provides <see langword="static"/> methods to create new
/// <see cref="DesktopClipboard"/> formats and add them to the Windows Registry.
/// </summary>
internal static partial class DesktopDataFormats
{
internal const string TextConstant = "Text";
internal const string UnicodeTextConstant = "UnicodeText";
internal const string DibConstant = "DeviceIndependentBitmap";
internal const string BitmapConstant = "Bitmap";
internal const string EmfConstant = "EnhancedMetafile";
internal const string WmfConstant = "MetaFilePict";
internal const string SymbolicLinkConstant = "SymbolicLink";
internal const string DifConstant = "DataInterchangeFormat";
internal const string TiffConstant = "TaggedImageFileFormat";
internal const string OemTextConstant = "OEMText";
internal const string PaletteConstant = "Palette";
internal const string PenDataConstant = "PenData";
internal const string RiffConstant = "RiffAudio";
internal const string WaveAudioConstant = "WaveAudio";
internal const string FileDropConstant = "FileDrop";
internal const string LocaleConstant = "Locale";
internal const string HtmlConstant = "HTML Format";
internal const string RtfConstant = "Rich Text Format";
internal const string CsvConstant = "Csv";
internal const string StringConstant = "System.String";
internal const string SerializableConstant = "WindowsForms10PersistentObject";

private static Format[]? s_formatList;

private static int s_formatCount;

#if NET9_0_OR_GREATER
private static readonly Lock s_internalSyncObject = new();
#else
private static readonly object s_internalSyncObject = new();
#endif

/// <summary>
/// Gets a <see cref="Format"/> with the Windows Clipboard numeric ID and name for the specified format.
/// </summary>
public static Format GetFormat(string format)
{
ArgumentException.ThrowIfNullOrWhiteSpace(format);

lock (s_internalSyncObject)
{
EnsurePredefined();

// It is much faster to do a case sensitive search here.
// So do the case sensitive compare first, then the expensive one.
for (int n = 0; n < s_formatCount; n++)
{
if (s_formatList[n].Name.Equals(format))
{
return s_formatList[n];
}
}

for (int n = 0; n < s_formatCount; n++)
{
if (string.Equals(s_formatList[n].Name, format, StringComparison.OrdinalIgnoreCase))
{
return s_formatList[n];
}
}

// Need to add this format string
uint formatId = PInvokeCore.RegisterClipboardFormat(format);
if (formatId == 0)
{
throw new Win32Exception(Marshal.GetLastWin32Error(), SR.RegisterCFFailed);
}

EnsureFormatSpace(1);
s_formatList[s_formatCount] = new Format(format, (int)formatId);
return s_formatList[s_formatCount++];
}
}

/// <summary>
/// Gets a <see cref="Format"/> with the Windows Clipboard numeric ID and name for the specified ID.
/// </summary>
internal static unsafe Format GetFormat(ushort id)
{
lock (s_internalSyncObject)
{
EnsurePredefined();

for (int n = 0; n < s_formatCount; n++)
{
if (s_formatList[n].Id == id)
{
return s_formatList[n];
}
}

string? name = null;

// The max length of the name of clipboard formats is equal to the max length
// of a Win32 Atom of 255 chars. An additional null terminator character is added,
// giving a required capacity of 256 chars.
Span<char> formatName = stackalloc char[256];
fixed (char* pFormatName = formatName)
{
int length = PInvokeCore.GetClipboardFormatName(id, pFormatName, 256);
if (length != 0)
{
name = formatName[..length].ToString();
}
}

// This can happen if windows adds a standard format that we don't know about,
// so we should play it safe.
name ??= $"Format{id}";

EnsureFormatSpace(1);
s_formatList[s_formatCount] = new Format(name, id);
return s_formatList[s_formatCount++];
}
}

/// <summary>
/// Ensures that we have enough room in our format list
/// </summary>
[MemberNotNull(nameof(s_formatList))]
private static void EnsureFormatSpace(int size)
{
if (s_formatList is null || s_formatList.Length <= s_formatCount + size)
{
int newSize = s_formatCount + 20;

Format[] newList = new Format[newSize];
for (int n = 0; n < s_formatCount; n++)
{
newList[n] = s_formatList![n];
}

s_formatList = newList;
}
}

/// <summary>
/// Ensures that the Win32 predefined formats are setup in our format list.
/// This is called anytime we need to search the list
/// </summary>
[MemberNotNull(nameof(s_formatList))]
private static void EnsurePredefined()
{
if (s_formatCount == 0)
{
s_formatList =
[
// Text name Win32 format ID
new(UnicodeTextConstant, (int)CLIPBOARD_FORMAT.CF_UNICODETEXT),
new(TextConstant, (int)CLIPBOARD_FORMAT.CF_TEXT),
new(BitmapConstant, (int)CLIPBOARD_FORMAT.CF_BITMAP),
new(WmfConstant, (int)CLIPBOARD_FORMAT.CF_METAFILEPICT),
new(EmfConstant, (int)CLIPBOARD_FORMAT.CF_ENHMETAFILE),
new(DifConstant, (int)CLIPBOARD_FORMAT.CF_DIF),
new(TiffConstant, (int)CLIPBOARD_FORMAT.CF_TIFF),
new(OemTextConstant, (int)CLIPBOARD_FORMAT.CF_OEMTEXT),
new(DibConstant, (int)CLIPBOARD_FORMAT.CF_DIB),
new(PaletteConstant, (int)CLIPBOARD_FORMAT.CF_PALETTE),
new(PenDataConstant, (int)CLIPBOARD_FORMAT.CF_PENDATA),
new(RiffConstant, (int)CLIPBOARD_FORMAT.CF_RIFF),
new(WaveAudioConstant, (int)CLIPBOARD_FORMAT.CF_WAVE),
new(SymbolicLinkConstant, (int)CLIPBOARD_FORMAT.CF_SYLK),
new(FileDropConstant, (int)CLIPBOARD_FORMAT.CF_HDROP),
new(LocaleConstant, (int)CLIPBOARD_FORMAT.CF_LOCALE)
];

s_formatCount = s_formatList.Length;
}
else
{
s_formatList ??= [];
}
}
}
Loading

0 comments on commit 1feda3d

Please sign in to comment.