зеркало из https://github.com/dotnet/winforms.git
Centralise lifetime management of native ImageList
Move calls to Create, Duplicate and Destroy into NativeImageList to reduce a chance of interleaved calls to Win32 API.
This commit is contained in:
Родитель
33ac99ea6f
Коммит
9647c6b0b3
|
@ -14,13 +14,6 @@ internal partial class Interop
|
|||
{
|
||||
[DllImport(Libraries.Comctl32, ExactSpelling = true, EntryPoint = "ImageList_Duplicate")]
|
||||
public static extern IntPtr Duplicate(IntPtr himl);
|
||||
|
||||
public static IntPtr Duplicate(IHandle himl)
|
||||
{
|
||||
IntPtr result = Duplicate(himl.Handle);
|
||||
GC.KeepAlive(himl);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3344,6 +3344,9 @@ Stack trace where the illegal operation occurred was:
|
|||
<data name="ImageListCreateFailed" xml:space="preserve">
|
||||
<value>Creation of the ImageList handle did not succeed.</value>
|
||||
</data>
|
||||
<data name="ImageListDuplicateFailed" xml:space="preserve">
|
||||
<value>Duplication of the ImageList handle did not succeed.</value>
|
||||
</data>
|
||||
<data name="ImageListEntryType" xml:space="preserve">
|
||||
<value>Image added to an ImageList must either derive from Image or be an Icon.</value>
|
||||
</data>
|
||||
|
|
|
@ -5556,6 +5556,11 @@ Trasování zásobníku, kde došlo k neplatné operaci:
|
|||
<target state="translated">Vytvoření popisovače ImageList se nezdařilo.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ImageListDuplicateFailed">
|
||||
<source>Duplication of the ImageList handle did not succeed.</source>
|
||||
<target state="new">Duplication of the ImageList handle did not succeed.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ImageListEntryType">
|
||||
<source>Image added to an ImageList must either derive from Image or be an Icon.</source>
|
||||
<target state="translated">Obrázek přidaný do seznamu ImageList musí být buď odvozen od objektu Image, nebo musí být objektem Icon.</target>
|
||||
|
|
|
@ -5556,6 +5556,11 @@ Stapelüberwachung, in der der unzulässige Vorgang auftrat:
|
|||
<target state="translated">Fehler beim Erstellen des ImageList-Handles.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ImageListDuplicateFailed">
|
||||
<source>Duplication of the ImageList handle did not succeed.</source>
|
||||
<target state="new">Duplication of the ImageList handle did not succeed.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ImageListEntryType">
|
||||
<source>Image added to an ImageList must either derive from Image or be an Icon.</source>
|
||||
<target state="translated">Das zu einer ImageList hinzugefügte Bild muss von "Image" abgeleitet oder ein Symbol sein.</target>
|
||||
|
|
|
@ -5556,6 +5556,11 @@ El seguimiento de la pila donde tuvo lugar la operación no válida fue:
|
|||
<target state="translated">Error al crear el identificador de ImageList.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ImageListDuplicateFailed">
|
||||
<source>Duplication of the ImageList handle did not succeed.</source>
|
||||
<target state="new">Duplication of the ImageList handle did not succeed.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ImageListEntryType">
|
||||
<source>Image added to an ImageList must either derive from Image or be an Icon.</source>
|
||||
<target state="translated">Las imágenes que se agreguen a ImageList deben derivar de una imagen o ser un icono.</target>
|
||||
|
|
|
@ -5556,6 +5556,11 @@ Cette opération non conforme s'est produite sur la trace de la pile :
|
|||
<target state="translated">Échec de la création du handle ImageList.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ImageListDuplicateFailed">
|
||||
<source>Duplication of the ImageList handle did not succeed.</source>
|
||||
<target state="new">Duplication of the ImageList handle did not succeed.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ImageListEntryType">
|
||||
<source>Image added to an ImageList must either derive from Image or be an Icon.</source>
|
||||
<target state="translated">Une image ajoutée à ImageList doit dériver de Image ou être un Icon.</target>
|
||||
|
|
|
@ -5556,6 +5556,11 @@ Traccia dello stack da cui si è verificata l'operazione non valida:
|
|||
<target state="translated">Creazione dell'handle di ImageList non riuscita.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ImageListDuplicateFailed">
|
||||
<source>Duplication of the ImageList handle did not succeed.</source>
|
||||
<target state="new">Duplication of the ImageList handle did not succeed.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ImageListEntryType">
|
||||
<source>Image added to an ImageList must either derive from Image or be an Icon.</source>
|
||||
<target state="translated">Un'immagine aggiunta a ImageList deve essere un'icona o derivare da Image.</target>
|
||||
|
|
|
@ -5556,6 +5556,11 @@ Stack trace where the illegal operation occurred was:
|
|||
<target state="translated">ImageList ハンドルを作成できませんでした。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ImageListDuplicateFailed">
|
||||
<source>Duplication of the ImageList handle did not succeed.</source>
|
||||
<target state="new">Duplication of the ImageList handle did not succeed.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ImageListEntryType">
|
||||
<source>Image added to an ImageList must either derive from Image or be an Icon.</source>
|
||||
<target state="translated">ImageList に追加されるイメージは Image から派生しているか、またはアイコンでなければなりません。</target>
|
||||
|
|
|
@ -5556,6 +5556,11 @@ Stack trace where the illegal operation occurred was:
|
|||
<target state="translated">ImageList 핸들을 만들지 못했습니다.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ImageListDuplicateFailed">
|
||||
<source>Duplication of the ImageList handle did not succeed.</source>
|
||||
<target state="new">Duplication of the ImageList handle did not succeed.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ImageListEntryType">
|
||||
<source>Image added to an ImageList must either derive from Image or be an Icon.</source>
|
||||
<target state="translated">ImageList에 추가하는 이미지는 이미지에서 파생되거나 아이콘이어야 합니다.</target>
|
||||
|
|
|
@ -5556,6 +5556,11 @@ Stos śledzenia, w którym wystąpiła zabroniona operacja:
|
|||
<target state="translated">Nie można utworzyć uchwytu elementu ImageList.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ImageListDuplicateFailed">
|
||||
<source>Duplication of the ImageList handle did not succeed.</source>
|
||||
<target state="new">Duplication of the ImageList handle did not succeed.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ImageListEntryType">
|
||||
<source>Image added to an ImageList must either derive from Image or be an Icon.</source>
|
||||
<target state="translated">Obraz dodany do listy ImageList musi dziedziczyć po elemencie Image lub musi być elementem Icon.</target>
|
||||
|
|
|
@ -5556,6 +5556,11 @@ Rastreamento de pilha em que a operação ilegal ocorreu:
|
|||
<target state="translated">A criação do identificador de ImageList não teve êxito.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ImageListDuplicateFailed">
|
||||
<source>Duplication of the ImageList handle did not succeed.</source>
|
||||
<target state="new">Duplication of the ImageList handle did not succeed.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ImageListEntryType">
|
||||
<source>Image added to an ImageList must either derive from Image or be an Icon.</source>
|
||||
<target state="translated">A imagem adicionada a ImageList deve derivar de Image ou ser um Ícone.</target>
|
||||
|
|
|
@ -5557,6 +5557,11 @@ Stack trace where the illegal operation occurred was:
|
|||
<target state="translated">Не удалось создать дескриптор ImageList.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ImageListDuplicateFailed">
|
||||
<source>Duplication of the ImageList handle did not succeed.</source>
|
||||
<target state="new">Duplication of the ImageList handle did not succeed.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ImageListEntryType">
|
||||
<source>Image added to an ImageList must either derive from Image or be an Icon.</source>
|
||||
<target state="translated">Изображение, добавляемое к ImageList, должно иметь тип, производный от Image, либо тип Icon.</target>
|
||||
|
|
|
@ -5556,6 +5556,11 @@ Geçersiz işlemin gerçekleştiği yığın izi:
|
|||
<target state="translated">ImageList işleyicisi oluşturulamadı.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ImageListDuplicateFailed">
|
||||
<source>Duplication of the ImageList handle did not succeed.</source>
|
||||
<target state="new">Duplication of the ImageList handle did not succeed.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ImageListEntryType">
|
||||
<source>Image added to an ImageList must either derive from Image or be an Icon.</source>
|
||||
<target state="translated">ImageList'e eklenen resim Image'den türetilmeli veya Icon olmalıdır.</target>
|
||||
|
|
|
@ -5556,6 +5556,11 @@ Stack trace where the illegal operation occurred was:
|
|||
<target state="translated">创建 ImageList 句柄失败。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ImageListDuplicateFailed">
|
||||
<source>Duplication of the ImageList handle did not succeed.</source>
|
||||
<target state="new">Duplication of the ImageList handle did not succeed.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ImageListEntryType">
|
||||
<source>Image added to an ImageList must either derive from Image or be an Icon.</source>
|
||||
<target state="translated">添加到 ImageList 的图像必须从 Image 派生或者为 Icon。</target>
|
||||
|
|
|
@ -5556,6 +5556,11 @@ Stack trace where the illegal operation occurred was:
|
|||
<target state="translated">建立 ImageList 控制代碼失敗。</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ImageListDuplicateFailed">
|
||||
<source>Duplication of the ImageList handle did not succeed.</source>
|
||||
<target state="new">Duplication of the ImageList handle did not succeed.</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ImageListEntryType">
|
||||
<source>Image added to an ImageList must either derive from Image or be an Icon.</source>
|
||||
<target state="translated">只有衍生自 Image 或本身為 Icon 的影像才可以加入至 ImageList 中。</target>
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using static Interop;
|
||||
using static Interop.ComCtl32;
|
||||
|
||||
namespace System.Windows.Forms
|
||||
{
|
||||
|
@ -11,30 +13,61 @@ namespace System.Windows.Forms
|
|||
{
|
||||
internal class NativeImageList : IDisposable, IHandle
|
||||
{
|
||||
#if DEBUG
|
||||
private readonly string _callStack;
|
||||
#endif
|
||||
private const int GrowBy = 4;
|
||||
private const int InitialCapacity = 4;
|
||||
|
||||
internal NativeImageList(IntPtr himl)
|
||||
private static readonly object s_syncLock = new object();
|
||||
|
||||
public NativeImageList(Ole32.IStream pstm)
|
||||
{
|
||||
IntPtr himl;
|
||||
lock (s_syncLock)
|
||||
{
|
||||
himl = ComCtl32.ImageList.Read(pstm);
|
||||
Init(himl);
|
||||
}
|
||||
}
|
||||
|
||||
public NativeImageList(Size imageSize, ILC flags)
|
||||
{
|
||||
IntPtr himl;
|
||||
lock (s_syncLock)
|
||||
{
|
||||
himl = ComCtl32.ImageList.Create(imageSize.Width, imageSize.Height, flags, InitialCapacity, GrowBy);
|
||||
Init(himl);
|
||||
}
|
||||
}
|
||||
|
||||
private NativeImageList(IntPtr himl)
|
||||
{
|
||||
Handle = himl;
|
||||
}
|
||||
|
||||
private void Init(IntPtr himl)
|
||||
{
|
||||
if (himl != IntPtr.Zero)
|
||||
{
|
||||
Handle = himl;
|
||||
return;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
_callStack = Environment.StackTrace;
|
||||
Debug.Fail($"{nameof(NativeImageList)} could not be created. Originating stack:\n{_callStack}");
|
||||
#endif
|
||||
throw new InvalidOperationException(SR.ImageListCreateFailed);
|
||||
}
|
||||
|
||||
public IntPtr Handle { get; private set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
lock (s_syncLock)
|
||||
{
|
||||
if (Handle == IntPtr.Zero)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public void Dispose(bool disposing)
|
||||
{
|
||||
if (Handle != IntPtr.Zero)
|
||||
{
|
||||
ComCtl32.ImageList.Destroy(Handle);
|
||||
Handle = IntPtr.Zero;
|
||||
}
|
||||
|
@ -44,13 +77,35 @@ namespace System.Windows.Forms
|
|||
#endif
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
private readonly string _callStack = new StackTrace().ToString();
|
||||
|
||||
~NativeImageList()
|
||||
{
|
||||
#if DEBUG
|
||||
Debug.Fail($"{nameof(NativeImageList)} was not disposed properly. Originating stack:\n{_callStack}");
|
||||
|
||||
// We can't do anything with the fields when we're on the finalizer as they're all classes. If any of
|
||||
// them become structs they'll be a part of this instance and possible to clean up. Ideally we fix
|
||||
// the leaks and never come in on the finalizer.
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
Dispose(false);
|
||||
internal NativeImageList Duplicate()
|
||||
{
|
||||
lock (s_syncLock)
|
||||
{
|
||||
IntPtr himl = ComCtl32.ImageList.Duplicate(Handle);
|
||||
if (himl != IntPtr.Zero)
|
||||
{
|
||||
return new NativeImageList(himl);
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
Debug.Fail($"{nameof(NativeImageList)} could not be duplicated. Originating stack:\n{_callStack}");
|
||||
#endif
|
||||
throw new InvalidOperationException(SR.ImageListDuplicateFailed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,9 +33,6 @@ namespace System.Windows.Forms
|
|||
private static readonly Color s_fakeTransparencyColor = Color.FromArgb(0x0d, 0x0b, 0x0c);
|
||||
private static readonly Size s_defaultImageSize = new Size(16, 16);
|
||||
|
||||
private const int InitialCapacity = 4;
|
||||
private const int GrowBy = 4;
|
||||
|
||||
private const int MaxDimension = 256;
|
||||
private static int s_maxImageWidth = MaxDimension;
|
||||
private static int s_maxImageHeight = MaxDimension;
|
||||
|
@ -235,7 +232,7 @@ namespace System.Windows.Forms
|
|||
bool recreatingHandle = HandleCreated; // We only need to fire RecreateHandle if there was a previous handle
|
||||
DestroyHandle();
|
||||
_originals = null;
|
||||
_nativeImageList = new NativeImageList(ComCtl32.ImageList.Duplicate(himl));
|
||||
_nativeImageList = himl.Duplicate();
|
||||
if (ComCtl32.ImageList.GetIconSize(new HandleRef(this, _nativeImageList.Handle), out int x, out int y).IsTrue())
|
||||
{
|
||||
_imageSize = new Size(x, y);
|
||||
|
@ -460,18 +457,20 @@ namespace System.Windows.Forms
|
|||
try
|
||||
{
|
||||
ComCtl32.InitCommonControls();
|
||||
_nativeImageList = new NativeImageList(ComCtl32.ImageList.Create(_imageSize.Width, _imageSize.Height, flags, InitialCapacity, GrowBy));
|
||||
|
||||
if (_nativeImageList != null)
|
||||
{
|
||||
_nativeImageList.Dispose();
|
||||
_nativeImageList = null;
|
||||
}
|
||||
|
||||
_nativeImageList = new NativeImageList(_imageSize, flags);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ThemingScope.Deactivate(userCookie);
|
||||
}
|
||||
|
||||
if (Handle == IntPtr.Zero)
|
||||
{
|
||||
throw new InvalidOperationException(SR.ImageListCreateFailed);
|
||||
}
|
||||
|
||||
ComCtl32.ImageList.SetBkColor(this, ComCtl32.CLR.NONE);
|
||||
|
||||
Debug.Assert(_originals != null, "Handle not yet created, yet original images are gone");
|
||||
|
|
|
@ -54,12 +54,11 @@ namespace System.Windows.Forms
|
|||
|
||||
try
|
||||
{
|
||||
MemoryStream ms = new MemoryStream(Decompress(dat));
|
||||
|
||||
using MemoryStream ms = new MemoryStream(Decompress(dat));
|
||||
lock (internalSyncObject)
|
||||
{
|
||||
ComCtl32.InitCommonControls();
|
||||
nativeImageList = new ImageList.NativeImageList(ComCtl32.ImageList.Read(new Ole32.GPStream(ms)));
|
||||
nativeImageList = new ImageList.NativeImageList(new Ole32.GPStream(ms));
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
|
Загрузка…
Ссылка в новой задаче