diff --git a/src/Common/src/Interop/User32/Interop.SetParent.cs b/src/Common/src/Interop/User32/Interop.SetParent.cs
index 0643cfe52bc..0fe148de583 100644
--- a/src/Common/src/Interop/User32/Interop.SetParent.cs
+++ b/src/Common/src/Interop/User32/Interop.SetParent.cs
@@ -9,7 +9,7 @@ internal static partial class Interop
{
internal static partial class User32
{
- [DllImport(Libraries.User32, ExactSpelling = true)]
+ [DllImport(Libraries.User32, ExactSpelling = true, SetLastError = true)]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndChildNewParent);
public static IntPtr SetParent(IntPtr hWndChild, HandleRef hWndChildNewParent)
diff --git a/src/System.Windows.Forms/src/Resources/SR.resx b/src/System.Windows.Forms/src/Resources/SR.resx
index aa10b110981..78ecc5d77e8 100644
--- a/src/System.Windows.Forms/src/Resources/SR.resx
+++ b/src/System.Windows.Forms/src/Resources/SR.resx
@@ -4513,7 +4513,7 @@ Stack trace where the illegal operation occurred was:
Print preview
-
+
PrintDocument to be previewed.
@@ -6653,4 +6653,7 @@ Stack trace where the illegal operation occurred was:
UpDown
+
+ Failed to set Win32 parent window of the Control.
+
diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.cs.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.cs.xlf
index 32a5c2cbf05..c2e6adbaf85 100644
--- a/src/System.Windows.Forms/src/Resources/xlf/SR.cs.xlf
+++ b/src/System.Windows.Forms/src/Resources/xlf/SR.cs.xlf
@@ -10881,6 +10881,11 @@ Trasování zásobníku, kde došlo k neplatné operaci:
Šířka musí být větší než hodnota MinWidth.
+
+
+ Failed to set Win32 parent window of the Control.
+
+ Před vytvořením prvního objektu IWin32Window v aplikaci je nutné volat metodu SetCompatibleTextRenderingDefault.
diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.de.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.de.xlf
index f100f1b05c3..91e176a8caf 100644
--- a/src/System.Windows.Forms/src/Resources/xlf/SR.de.xlf
+++ b/src/System.Windows.Forms/src/Resources/xlf/SR.de.xlf
@@ -10881,6 +10881,11 @@ Stapelüberwachung, in der der unzulässige Vorgang auftrat:
"Width" muss größer als MinWidth sein.
+
+
+ Failed to set Win32 parent window of the Control.
+
+ SetCompatibleTextRenderingDefault muss aufgerufen werden, bevor das erste IWin32Window-Objekt in der Anwendung erstellt wird.
diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.es.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.es.xlf
index eeacf250dc7..b3f55e0882b 100644
--- a/src/System.Windows.Forms/src/Resources/xlf/SR.es.xlf
+++ b/src/System.Windows.Forms/src/Resources/xlf/SR.es.xlf
@@ -10881,6 +10881,11 @@ El seguimiento de la pila donde tuvo lugar la operación no válida fue:
El ancho debe ser mayor que MinWidth.
+
+
+ Failed to set Win32 parent window of the Control.
+
+ SetCompatibleTextRenderingDefault se debe llamar antes de crear el primer objeto IWin32Window en la aplicación.
diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.fr.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.fr.xlf
index c7d31c428db..edbd41e6a57 100644
--- a/src/System.Windows.Forms/src/Resources/xlf/SR.fr.xlf
+++ b/src/System.Windows.Forms/src/Resources/xlf/SR.fr.xlf
@@ -10881,6 +10881,11 @@ Cette opération non conforme s'est produite sur la trace de la pile :
La largeur doit être supérieure à MinWidth.
+
+
+ Failed to set Win32 parent window of the Control.
+
+ SetCompatibleTextRenderingDefault doit être appelé avant la création du premier objet IWin32Window dans l'application.
diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.it.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.it.xlf
index 8ca0e05cbdb..d01f189cc28 100644
--- a/src/System.Windows.Forms/src/Resources/xlf/SR.it.xlf
+++ b/src/System.Windows.Forms/src/Resources/xlf/SR.it.xlf
@@ -10881,6 +10881,11 @@ Traccia dello stack da cui si è verificata l'operazione non valida:
Width deve essere maggiore di MinWidth.
+
+
+ Failed to set Win32 parent window of the Control.
+
+ SetCompatibleTextRenderingDefault deve essere chiamato prima della creazione del primo oggetto IWin32Window nell'applicazione.
diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.ja.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.ja.xlf
index 21268309ed3..12d0c4e1460 100644
--- a/src/System.Windows.Forms/src/Resources/xlf/SR.ja.xlf
+++ b/src/System.Windows.Forms/src/Resources/xlf/SR.ja.xlf
@@ -10881,6 +10881,11 @@ Stack trace where the illegal operation occurred was:
幅は MinWidth より大きくなければなりません。
+
+
+ Failed to set Win32 parent window of the Control.
+
+ 最初の IWin32Window オブジェクトがアプリケーションで作成される前に、SetCompatibleTextRenderingDefault が呼び出されなければなりません。
diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.ko.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.ko.xlf
index 40d3e6176e0..9e95799e86e 100644
--- a/src/System.Windows.Forms/src/Resources/xlf/SR.ko.xlf
+++ b/src/System.Windows.Forms/src/Resources/xlf/SR.ko.xlf
@@ -10881,6 +10881,11 @@ Stack trace where the illegal operation occurred was:
Width는 MinWidth보다 커야 합니다.
+
+
+ Failed to set Win32 parent window of the Control.
+
+ SetCompatibleTextRenderingDefault는 응용 프로그램에 첫 번째 IWin32Window 개체가 만들어지기 전에 호출해야 합니다.
diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.pl.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.pl.xlf
index 4d360b9152e..4217e380b78 100644
--- a/src/System.Windows.Forms/src/Resources/xlf/SR.pl.xlf
+++ b/src/System.Windows.Forms/src/Resources/xlf/SR.pl.xlf
@@ -10881,6 +10881,11 @@ Stos śledzenia, w którym wystąpiła zabroniona operacja:
Szerokość musi być większa od wartości elementu MinWidth.
+
+
+ Failed to set Win32 parent window of the Control.
+
+ Należy wywołać element SetCompatibleTextRenderingDefault, aby pierwszy obiekt IWin32Window został utworzony w aplikacji.
diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.pt-BR.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.pt-BR.xlf
index 5412d8a708c..70d6e49d224 100644
--- a/src/System.Windows.Forms/src/Resources/xlf/SR.pt-BR.xlf
+++ b/src/System.Windows.Forms/src/Resources/xlf/SR.pt-BR.xlf
@@ -10881,6 +10881,11 @@ Rastreamento de pilha em que a operação ilegal ocorreu:
A largura deve ser maior que MinWidth.
+
+
+ Failed to set Win32 parent window of the Control.
+
+ É necessário chamar SetCompatibleTextRenderingDefault antes da criação do primeiro objeto IWin32Window no aplicativo.
diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.ru.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.ru.xlf
index 134a960ca19..0ae416ddf4f 100644
--- a/src/System.Windows.Forms/src/Resources/xlf/SR.ru.xlf
+++ b/src/System.Windows.Forms/src/Resources/xlf/SR.ru.xlf
@@ -10882,6 +10882,11 @@ Stack trace where the illegal operation occurred was:
Значение ширины должно быть больше MinWidth.
+
+
+ Failed to set Win32 parent window of the Control.
+
+ До создания первого объекта IWin32Window в приложении необходимо вызвать SetCompatibleTextRenderingDefault.
diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.tr.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.tr.xlf
index 8a19a2b62a4..d12838be314 100644
--- a/src/System.Windows.Forms/src/Resources/xlf/SR.tr.xlf
+++ b/src/System.Windows.Forms/src/Resources/xlf/SR.tr.xlf
@@ -10881,6 +10881,11 @@ Geçersiz işlemin gerçekleştiği yığın izi:
Width değeri MinWidth değerinden büyük olmalı.
+
+
+ Failed to set Win32 parent window of the Control.
+
+ Uygulamada ilk IWin32Window nesnesi oluşturulmadan önce SetCompatibleTextRenderingDefault çağrılmalıdır.
diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.zh-Hans.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.zh-Hans.xlf
index 72a5109a63d..717a07c9d00 100644
--- a/src/System.Windows.Forms/src/Resources/xlf/SR.zh-Hans.xlf
+++ b/src/System.Windows.Forms/src/Resources/xlf/SR.zh-Hans.xlf
@@ -10881,6 +10881,11 @@ Stack trace where the illegal operation occurred was:
宽度必须大于 MinWidth。
+
+
+ Failed to set Win32 parent window of the Control.
+
+ 在应用程序中创建第一个 IWin32Window 对象之前,必须调用 SetCompatibleTextRenderingDefault。
diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.zh-Hant.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.zh-Hant.xlf
index 60f7b43f321..4acd436fc62 100644
--- a/src/System.Windows.Forms/src/Resources/xlf/SR.zh-Hant.xlf
+++ b/src/System.Windows.Forms/src/Resources/xlf/SR.zh-Hant.xlf
@@ -10881,6 +10881,11 @@ Stack trace where the illegal operation occurred was:
寬度必須大於 MinWidth。
+
+
+ Failed to set Win32 parent window of the Control.
+
+ 在應用程式中建立第一個 IWin32Window 物件之前,必須先呼叫 SetCompatibleTextRenderingDefault。
diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Control.ActiveXImpl.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Control.ActiveXImpl.cs
index b68134c086e..da76ca44413 100644
--- a/src/System.Windows.Forms/src/System/Windows/Forms/Control.ActiveXImpl.cs
+++ b/src/System.Windows.Forms/src/System/Windows/Forms/Control.ActiveXImpl.cs
@@ -918,7 +918,10 @@ internal unsafe void InPlaceActivate(Ole32.OLEIVERB verb)
// If it doesn't, that means that the host
// won't reflect messages back to us.
HWNDParent = hwndParent;
- User32.SetParent(new HandleRef(_control, _control.Handle), hwndParent);
+ if (User32.SetParent(new HandleRef(_control, _control.Handle), hwndParent) == IntPtr.Zero)
+ {
+ throw new Win32Exception(Marshal.GetLastWin32Error(), SR.Win32SetParentFailed);
+ }
// Now create our handle if it hasn't already been done.
_control.CreateControl();
diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs
index 3c916a918f1..93337cb2f58 100644
--- a/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs
+++ b/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs
@@ -7497,7 +7497,10 @@ internal virtual void OnParentHandleRecreated()
{
if (IsHandleCreated)
{
- User32.SetParent(new HandleRef(this, Handle), new HandleRef(parent, parent.Handle));
+ if (User32.SetParent(new HandleRef(this, Handle), new HandleRef(parent, parent.Handle)) == IntPtr.Zero)
+ {
+ throw new Win32Exception(Marshal.GetLastWin32Error(), SR.Win32SetParentFailed);
+ }
UpdateZOrder();
}
}
@@ -9755,118 +9758,154 @@ protected void RecreateHandle()
internal virtual void RecreateHandleCore()
{
- //
lock (this)
{
- if (IsHandleCreated)
+ if (!IsHandleCreated)
{
+ // Do nothing if the handle is not created yet.
+ return;
+ }
- bool focused = ContainsFocus;
+ bool focused = ContainsFocus;
#if DEBUG
- if (CoreSwitches.PerfTrack.Enabled)
- {
- Debug.Write("RecreateHandle: ");
- Debug.Write(GetType().FullName);
- Debug.Write(" [Text=");
- Debug.Write(Text);
- Debug.Write("]");
- Debug.WriteLine("");
- }
+ if (CoreSwitches.PerfTrack.Enabled)
+ {
+ Debug.Write("RecreateHandle: ");
+ Debug.Write(GetType().FullName);
+ Debug.Write(" [Text=");
+ Debug.Write(Text);
+ Debug.Write("]");
+ Debug.WriteLine("");
+ }
#endif
- bool created = (_state & States.Created) != 0;
- if (GetState(States.TrackingMouseEvent))
- {
- SetState(States.MouseEnterPending, true);
- UnhookMouseEvent();
- }
+ bool created = GetState(States.Created);
+ if (GetState(States.TrackingMouseEvent))
+ {
+ SetState(States.MouseEnterPending, true);
+ UnhookMouseEvent();
+ }
- HandleRef parentHandle = new HandleRef(this, User32.GetParent(this));
+ HandleRef parentHandle = new HandleRef(this, User32.GetParent(this));
- try
- {
- Control[] controlSnapshot = null;
- _state |= States.Recreate;
+ Control[] controlSnapshot = null;
+ SetState(States.Recreate, true);
- try
- {
- // Inform child controls that their parent is recreating handle.
+ try
+ {
+ // Inform child controls that their parent is recreating handle.
- // The default behavior is to now SetParent to parking window, then
- // SetParent back after the parent's handle has been recreated.
- // This behavior can be overridden in OnParentHandleRecreat* and is in ListView.
+ // The default behavior is to now SetParent to parking window, then
+ // SetParent back after the parent's handle has been recreated.
+ // This behavior can be overridden in OnParentHandleRecreat* and is in ListView.
- //fish out control collection w/o demand creating one.
- ControlCollection controlsCollection = (ControlCollection)Properties.GetObject(s_controlsCollectionProperty);
- if (controlsCollection != null && controlsCollection.Count > 0)
+ //fish out control collection w/o demand creating one.
+ ControlCollection controlsCollection = (ControlCollection)Properties.GetObject(s_controlsCollectionProperty);
+ if (controlsCollection != null && controlsCollection.Count > 0)
+ {
+ controlSnapshot = new Control[controlsCollection.Count];
+ for (int i = 0; i < controlsCollection.Count; i++)
+ {
+ Control childControl = controlsCollection[i];
+ if (childControl != null && childControl.IsHandleCreated)
{
- controlSnapshot = new Control[controlsCollection.Count];
- for (int i = 0; i < controlsCollection.Count; i++)
- {
- Control childControl = controlsCollection[i];
- if (childControl != null && childControl.IsHandleCreated)
- {
- // SetParent to parking window
- childControl.OnParentHandleRecreating();
+ // SetParent to parking window
+ childControl.OnParentHandleRecreating();
- // if we were successful, remember this control
- // so we can raise OnParentHandleRecreated
- controlSnapshot[i] = childControl;
- }
- else
- {
- // put in a null slot which we'll skip over later.
- controlSnapshot[i] = null;
- }
- }
+ // if we were successful, remember this control
+ // so we can raise OnParentHandleRecreated
+ controlSnapshot[i] = childControl;
}
-
- // do the main work of recreating the handle
- DestroyHandle();
- CreateHandle();
- }
- finally
- {
- _state &= ~States.Recreate;
-
- // inform children that their parent's handle has recreated
- if (controlSnapshot != null)
+ else
{
- for (int i = 0; i < controlSnapshot.Length; i++)
- {
- Control childControl = controlSnapshot[i];
- if (childControl != null && childControl.IsHandleCreated)
- {
- // SetParent back to the new Parent handle
- childControl.OnParentHandleRecreated();
- }
- }
+ // put in a null slot which we'll skip over later.
+ controlSnapshot[i] = null;
}
}
- if (created)
- {
- CreateControl();
- }
}
- finally
+
+ // do the main work of recreating the handle
+ DestroyHandle();
+
+ // Note that CreateHandle --> _window.CreateHandle may fail due to DPI awareness setting.
+ // By carefully choosing the correct parking window / keeping this and this.Parent DPI awareness untouched,
+ // the call shouldn't fail.
+ // However, it could fail if this.CreateParams.Parent is changed outside our control.
+ CreateHandle();
+ }
+ catch (Exception)
+ {
+ // this.DestroyHandle succeeded, but CreateHandle failed.
+ // The control is actually destroyed.
+ if (_window.Handle == IntPtr.Zero)
{
- if (parentHandle.Handle != IntPtr.Zero // the parent was not null
- && (FromHandle(parentHandle.Handle) == null || _parent == null) // but wasnt a windows forms window
- && UnsafeNativeMethods.IsWindow(parentHandle))
- { // and still is a window
- // correctly parent back up to where we were before.
- // if we were parented to a proper windows forms control, CreateControl would have properly parented
- // us back.
- User32.SetParent(new HandleRef(this, Handle), parentHandle);
+ SetState(States.Created, false);
+ }
+
+ throw;
+ }
+ finally
+ {
+ SetState(States.Recreate, false);
+
+ // Inform children their parent's handle has been created.
+ // This means
+ // an Exception gets thrown before/during the invocation of DestroyHandle.
+ // In this case, GetState(States.Created) == true.
+ // We will restore the Parent value of the (visited) child controls.
+ // - or -
+ // an Exception gets thrown in CreateHandle.
+ // In this case, _window.Handle will be IntPtr.Zero,
+ // and we should have GetState(States.Created) == false.
+ // Do not go through this if CreateHandle fails (and an Exception is probably on its way bubbling up).
+ // - or -
+ // CreateHandle is successful.
+ // We will move the child controls to the new parent.
+ if (controlSnapshot != null && GetState(States.Created))
+ {
+ for (int i = 0; i < controlSnapshot.Length; i++)
+ {
+ Control childControl = controlSnapshot[i];
+ if (childControl != null && childControl.IsHandleCreated)
+ {
+ // Re-parent the control.
+ // If the control fails to re-parent itself,
+ // It and its next siblings will keep States.ParentRecreating state,
+ // parked in ParkingWindow.
+ // We let the error bubble up immediately.
+ childControl.OnParentHandleRecreated();
+ }
}
}
+ }
- // Restore control focus
- if (focused)
+ if (created)
+ {
+ CreateControl();
+ }
+
+ if (// The window has a parent Win32 window before re-creation
+ parentHandle.Handle != IntPtr.Zero
+ // But the parent is not a managed WinForm Control, or this.Parent == null
+ && (FromHandle(parentHandle.Handle) == null || _parent == null)
+ // Still, parentHandle is a valid native Win32 window handle, e.g. the desktop window.
+ && UnsafeNativeMethods.IsWindow(parentHandle))
+ {
+ // correctly parent back up to where we were before.
+ // if we were parented to a proper windows forms control, CreateControl would have properly parented
+ // us back.
+ if (User32.SetParent(new HandleRef(this, Handle), parentHandle) == IntPtr.Zero)
{
- Focus();
+ // Somehow we failed to SetParent due to, e.g., different DPI awareness setting.
+ throw new Win32Exception(Marshal.GetLastWin32Error(), SR.Win32SetParentFailed);
}
}
+
+ // Restore control focus
+ if (focused)
+ {
+ Focus();
+ }
}
}
@@ -10918,7 +10957,13 @@ private void SetParentHandle(IntPtr value)
}
else
{
- User32.SetParent(new HandleRef(_window, Handle), value);
+ if (User32.SetParent(new HandleRef(_window, Handle), value) == IntPtr.Zero)
+ {
+ // Somehow we failed to SetParent, e.g. due to different DPI awareness setting.
+ // Throwing exception will keep the handle parked inside ParkingWindow if recreate == true.
+ throw new Win32Exception(Marshal.GetLastWin32Error(), SR.Win32SetParentFailed);
+ }
+
if (_parent != null)
{
_parent.UpdateChildZOrder(this);
@@ -10932,7 +10977,11 @@ private void SetParentHandle(IntPtr value)
// The handle was previously parented to the parking window. Its TopLevel property was
// then changed to true so the above call to GetParent returns null even though the parent of the control is
// not null. We need to explicitly set the parent to null.
- User32.SetParent(new HandleRef(_window, Handle), IntPtr.Zero);
+ if (User32.SetParent(new HandleRef(_window, Handle), IntPtr.Zero) == IntPtr.Zero)
+ {
+ throw new Win32Exception(Marshal.GetLastWin32Error(), SR.Win32SetParentFailed);
+ }
+
Application.UnparkHandle(new HandleRef(_window, Handle), _window.DpiAwarenessContext);
}
}
diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/NativeWindow.cs b/src/System.Windows.Forms/src/System/Windows/Forms/NativeWindow.cs
index 8a2285eb63c..b51a0ce13b8 100644
--- a/src/System.Windows.Forms/src/System/Windows/Forms/NativeWindow.cs
+++ b/src/System.Windows.Forms/src/System/Windows/Forms/NativeWindow.cs
@@ -438,8 +438,8 @@ public virtual void CreateHandle(CreateParams cp)
IntPtr createResult = IntPtr.Zero;
int lastWin32Error = 0;
- // Parking window dpi awarness context need to match with dpi awarenss context of control being
- // parented to this parkign window. Otherwise, reparenting of control will fail.
+ // Parking window dpi awareness context need to match with dpi awareness context of control being
+ // parented to this parking window. Otherwise, reparenting of control will fail.
using (DpiHelper.EnterDpiAwarenessScope(DpiAwarenessContext))
{
IntPtr modHandle = Kernel32.GetModuleHandleW(null);