Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restructure DataObject #12792

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft

Restructure DataObject #12792

wants to merge 3 commits into from

Conversation

lonitra
Copy link
Member

@lonitra lonitra commented Jan 16, 2025

DO NOT MERGE

Related: #12179

Restructure DataObject and move to System.Private.Windows.Core assembly so that implementation can be shared with WPF as our implementations are largely similar. The goal is to move it to the shared assembly while preserving important history of DataObject and Clipboard.

Microsoft Reviewers: Open in CodeFlow

/// <param name="resolver"></param>
/// <param name="legacyMode">Indicates whether this was called from legacy method family <see cref="IDataObjectDesktop.GetData(string)"/></param>
/// <returns>The object of type T if successfully read. Otherwise, <see langword="null"/>.</returns>
internal abstract object? ReadObjectFromStream<T>(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation we have for this method and below likely we want to share, however, this was made abstract due to Binder being abstract. Binder needs to be abstract because it is where we indicate additional supported types that are not common between applications e.g. ImageListStreamer. We can probably find a way to largely share the implementation, but dealing with extension methods may also be tricky.

/// before method ends.
/// </para>
/// </remarks>
public abstract Composition PopulateFromRuntimeDataObject(ComTypes.IDataObject runtimeDataObject);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also likely want to largely share this implementation, but this needed to be made abstract due to DesktopToNativeAdapter and NativeToDesktopAdapter being abstract.

/// <inheritdoc cref="DataObject(object)"/>
internal DataObject(Com.IDataObject* data) => _innerData = Composition.CreateFromNativeDataObject(data);
/// <inheritdoc cref="DesktopDataObject(object, Composition)"/>
internal DesktopDataObject(Com.IDataObject* data, Composition composition) => _innerData = composition.PopulateFromNativeDataObject(data);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to pass Composition here now because Composition is abstract. It would be nice if we did not need to do this as we are not programmatically enforcing that Composition is properly populated and instead rely that the Composition implementation calls Composition.Populate.

/// <summary>
/// Extension methods for data objects.
/// </summary>
internal static class DesktopDataObjectExtensions
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the same as DataObjectExtensions. DataObjectExtensions cannot be moved because it is public, but perhaps we can potentially reduce duplication. It is tricky though due to this one referring to IDataObjectDesktop and the other is referring to IDataObject.

Comment on lines 125 to 127
private static Format[]? s_formatList;

private static int s_formatCount;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We actually test that calling GetFormat gives back the same DataFormat instance which is why the public version has its own s_formatList. Because of this, there are some duplicated work around managing the list that perhaps could be better.

@@ -19,32 +21,6 @@ namespace System.Windows.Forms;
/// </summary>
internal static unsafe class DragDropHelper
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this change we have an internal and public DragDropHelper. We should probably move this class entirely to the shared assembly after working out any references to WinForms specific types.

Comment on lines +75 to +88
internal override bool TryGetDataCore<[DynamicallyAccessedMembers((DynamicallyAccessedMemberTypes)(-1))] T>(string format, Func<TypeName, Type>? resolver, bool autoConvert, [MaybeNullWhen(false), NotNullWhen(true)] out T data)
{
if (!_haveCheckedOverride && _dataObject is not null && _dataObject.GetType() != typeof(DataObject))
{
// TryGetDataCore could be overridden. Call the potential overridden version and flag that it's been called so that
// we don't end up in an infinite loop if it hasn't been overridden.
_haveCheckedOverride = true;
bool result = _dataObject.TryGetDataCoreInternal(format, resolver, autoConvert, out data);
_haveCheckedOverride = false;
return result;
}

return base.TryGetDataCore(format, resolver, autoConvert, out data);
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue here is that we are calling this method (among other methods I missed in current changeset such as SetText, SetAudio, GetText) internally in DesktopDataObject. If the user has overridden this method then we won't call their override version. We need to bridge the gap so that those overrides get called hence the need for WinFormsDataObject to have a reference to DataObject. We also need to watch out for infinite loops occurring if the user has not overridden the method hence _haveCheckedOverride. Though we need a better way of working around this problem because as it currently stands their override method is called more times than expected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
draft draft PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant