| File: System\Windows\Forms\ComponentModel\COM2Interop\COM2PictureConverter.cs | Web Access |
| Project: src\winforms\src\System.Windows.Forms\System.Windows.Forms.csproj (System.Windows.Forms) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Drawing; using Windows.Win32.Graphics.GdiPlus; using Windows.Win32.System.Com; using Windows.Win32.System.Ole; using Windows.Win32.System.Variant; namespace System.Windows.Forms.ComponentModel.Com2Interop; /// <summary> /// This class maps an IPicture to a System.Drawing.Image. /// </summary> internal sealed unsafe class Com2PictureConverter : Com2DataTypeToManagedDataTypeConverter { private object? _lastManaged; private OLE_HANDLE _lastNativeHandle; private Type _pictureType = typeof(Bitmap); public Com2PictureConverter(Com2PropertyDescriptor property) { if (property.DISPID == PInvokeCore.DISPID_MOUSEICON || property.Name.Contains("Icon")) { _pictureType = typeof(Icon); } } public override Type ManagedType => _pictureType; public override object? ConvertNativeToManaged(VARIANT nativeValue, Com2PropertyDescriptor property) { if (nativeValue.Type != VARENUM.VT_UNKNOWN) { Debug.Assert(nativeValue.IsEmpty, $"Expected IUnknown, got {nativeValue.Type}"); return null; } using var picture = ComScope<IPicture>.TryQueryFrom((IUnknown*)nativeValue, out HRESULT hr); if (hr.Failed) { Debug.Fail($"Failed to get IPicture: {hr}"); return null; } picture.Value->get_Handle(out OLE_HANDLE handle).ThrowOnFailure(); if (_lastManaged is not null && handle == _lastNativeHandle) { return _lastManaged; } if (handle != 0) { // GDI handles are sign extended 32 bit values. // We need to first cast to int so sign extension happens correctly. nint extendedHandle = (int)handle.Value; picture.Value->get_Type(out PICTYPE type).ThrowOnFailure(); switch (type) { case PICTYPE.PICTYPE_ICON: _pictureType = typeof(Icon); _lastManaged = Icon.FromHandle(extendedHandle); break; case PICTYPE.PICTYPE_BITMAP: _pictureType = typeof(Bitmap); _lastManaged = Image.FromHbitmap(extendedHandle); break; default: Debug.Fail("Unknown picture type"); return null; } _lastNativeHandle = handle; } else { _lastManaged = null; } return _lastManaged; } public override VARIANT ConvertManagedToNative(object? managedValue, Com2PropertyDescriptor property, ref bool cancelSet) { if (managedValue is not null && managedValue == _lastManaged) { // There should be no point in setting the same object back for this property. cancelSet = true; return VARIANT.Empty; } cancelSet = false; // Build the IPicture. if (managedValue is not null) { BOOL own = false; PICTDESC pictdesc; if (managedValue is Icon icon) { pictdesc = icon.CreatePICTDESC(copy: false); } else if (managedValue is Bitmap bitmap) { pictdesc = bitmap.CreatePICTDESC(); own = true; } else { Debug.Fail($"Unknown Image type: {managedValue.GetType().Name}"); return VARIANT.Empty; } using ComScope<IPicture> picture = new(null); PInvokeCore.OleCreatePictureIndirect(&pictdesc, IID.Get<IPicture>(), own, picture).ThrowOnFailure(); _lastManaged = managedValue; picture.Value->get_Handle(out _lastNativeHandle).ThrowOnFailure(); IUnknown* unknown; picture.Value->QueryInterface(IID.Get<IUnknown>(), (void**)&unknown).ThrowOnFailure(); return (VARIANT)unknown; } else { _lastManaged = null; _lastNativeHandle = default; return VARIANT.Empty; } } }