public DialogResult ShowDialog(out object objResult, object objConstructParam) { objResult = null; ProcessMessagesEx(); // Creating a window on the new desktop spawns a CtfMon.exe child // process by default. On Windows Vista, this process is terminated // correctly when the desktop is closed. However, on Windows 7 it // isn't terminated (probably a bug); creating multiple desktops // accumulates CtfMon.exe child processes. ChildProcessesSnapshot cpsCtfMons = new ChildProcessesSnapshot( "CtfMon.exe"); ClipboardEventChainBlocker ccb = new ClipboardEventChainBlocker(); byte[] pbClipHash = ClipboardUtil.ComputeHash(); SecureThreadInfo stp = new SecureThreadInfo(); foreach (Screen sc in Screen.AllScreens) { Bitmap bmpBack = UIUtil.CreateScreenshot(sc); if (bmpBack != null) { UIUtil.DimImage(bmpBack); } stp.BackgroundBitmaps.Add(bmpBack); } DialogResult dr = DialogResult.None; try { uint uOrgThreadId = NativeMethods.GetCurrentThreadId(); IntPtr pOrgDesktop = NativeMethods.GetThreadDesktop(uOrgThreadId); string strName = "D" + Convert.ToBase64String( CryptoRandom.Instance.GetRandomBytes(16), Base64FormattingOptions.None); strName = strName.Replace(@"+", string.Empty); strName = strName.Replace(@"/", string.Empty); strName = strName.Replace(@"=", string.Empty); if (strName.Length > 15) { strName = strName.Substring(0, 15); } NativeMethods.DesktopFlags deskFlags = (NativeMethods.DesktopFlags.CreateMenu | NativeMethods.DesktopFlags.CreateWindow | NativeMethods.DesktopFlags.ReadObjects | NativeMethods.DesktopFlags.WriteObjects | NativeMethods.DesktopFlags.SwitchDesktop); IntPtr pNewDesktop = NativeMethods.CreateDesktop(strName, null, IntPtr.Zero, 0, deskFlags, IntPtr.Zero); if (pNewDesktop == IntPtr.Zero) { throw new InvalidOperationException(); } bool bNameSupported = NativeMethods.DesktopNameContains(pNewDesktop, strName).GetValueOrDefault(false); Debug.Assert(bNameSupported); stp.ThreadDesktop = pNewDesktop; stp.FormConstructParam = objConstructParam; Thread th = new Thread(this.SecureDialogThread); th.CurrentCulture = Thread.CurrentThread.CurrentCulture; th.CurrentUICulture = Thread.CurrentThread.CurrentUICulture; th.Start(stp); SecureThreadState st = SecureThreadState.None; while (st != SecureThreadState.Terminated) { th.Join(150); lock (stp) { st = stp.State; } if ((st == SecureThreadState.ShowingDialog) && bNameSupported) { IntPtr hCurDesk = NativeMethods.OpenInputDesktop(0, false, NativeMethods.DesktopFlags.ReadObjects); if (hCurDesk == IntPtr.Zero) { Debug.Assert(false); continue; } if (hCurDesk == pNewDesktop) { if (!NativeMethods.CloseDesktop(hCurDesk)) { Debug.Assert(false); } continue; } bool?obOnSec = NativeMethods.DesktopNameContains(hCurDesk, strName); if (!NativeMethods.CloseDesktop(hCurDesk)) { Debug.Assert(false); } lock (stp) { st = stp.State; } // Update; might have changed if (obOnSec.HasValue && !obOnSec.Value && (st == SecureThreadState.ShowingDialog)) { HandleUnexpectedDesktopSwitch(pOrgDesktop, pNewDesktop, stp); } } } if (!NativeMethods.SwitchDesktop(pOrgDesktop)) { Debug.Assert(false); } NativeMethods.SetThreadDesktop(pOrgDesktop); th.Join(); // Ensure thread terminated before closing desktop if (!NativeMethods.CloseDesktop(pNewDesktop)) { Debug.Assert(false); } NativeMethods.CloseDesktop(pOrgDesktop); // Optional dr = stp.DialogResult; objResult = stp.ResultObject; } catch (Exception) { Debug.Assert(false); } byte[] pbNewClipHash = ClipboardUtil.ComputeHash(); if ((pbClipHash != null) && (pbNewClipHash != null) && !MemUtil.ArraysEqual(pbClipHash, pbNewClipHash)) { ClipboardUtil.Clear(); } ccb.Dispose(); foreach (Bitmap bmpBack in stp.BackgroundBitmaps) { if (bmpBack != null) { bmpBack.Dispose(); } } stp.BackgroundBitmaps.Clear(); cpsCtfMons.TerminateNewChildsAsync(4100); // If something failed, show the dialog on the normal desktop if (dr == DialogResult.None) { Form f = m_fnConstruct(objConstructParam); dr = f.ShowDialog(); objResult = m_fnResultBuilder(f); UIUtil.DestroyForm(f); } return(dr); }
public DialogResult ShowDialog(out object objResult, object objConstructParam) { objResult = null; ProcessMessagesEx(); ClipboardEventChainBlocker ccb = new ClipboardEventChainBlocker(); byte[] pbClipHash = ClipboardUtil.ComputeHash(); Bitmap bmpBack = UIUtil.CreateScreenshot(); if (bmpBack != null) { UIUtil.DimImage(bmpBack); } DialogResult dr = DialogResult.None; try { uint uOrgThreadId = NativeMethods.GetCurrentThreadId(); IntPtr pOrgDesktop = NativeMethods.GetThreadDesktop(uOrgThreadId); string strName = "D" + Convert.ToBase64String( Guid.NewGuid().ToByteArray(), Base64FormattingOptions.None); strName = strName.Replace(@"+", string.Empty); strName = strName.Replace(@"/", string.Empty); strName = strName.Replace(@"=", string.Empty); NativeMethods.DesktopFlags deskFlags = NativeMethods.DesktopFlags.CreateMenu | NativeMethods.DesktopFlags.CreateWindow | NativeMethods.DesktopFlags.ReadObjects | NativeMethods.DesktopFlags.WriteObjects | NativeMethods.DesktopFlags.SwitchDesktop; IntPtr pNewDesktop = NativeMethods.CreateDesktop(strName, null, IntPtr.Zero, 0, deskFlags, IntPtr.Zero); if (pNewDesktop == IntPtr.Zero) { throw new InvalidOperationException(); } SecureThreadParams stp = new SecureThreadParams(); stp.BackgroundBitmap = bmpBack; stp.ThreadDesktop = pNewDesktop; stp.FormConstructParam = objConstructParam; Thread th = new Thread(this.SecureDialogThread); th.CurrentCulture = Thread.CurrentThread.CurrentCulture; th.CurrentUICulture = Thread.CurrentThread.CurrentUICulture; th.Start(stp); th.Join(); if (!NativeMethods.SwitchDesktop(pOrgDesktop)) { Debug.Assert(false); } NativeMethods.SetThreadDesktop(pOrgDesktop); if (!NativeMethods.CloseDesktop(pNewDesktop)) { Debug.Assert(false); } NativeMethods.CloseDesktop(pOrgDesktop); dr = stp.DialogResult; objResult = stp.ResultObject; } catch (Exception) { Debug.Assert(false); } byte[] pbNewClipHash = ClipboardUtil.ComputeHash(); if ((pbClipHash != null) && (pbNewClipHash != null) && !MemUtil.ArraysEqual(pbClipHash, pbNewClipHash)) { ClipboardUtil.Clear(); } ccb.Release(); if (bmpBack != null) { bmpBack.Dispose(); } // If something failed, show the dialog on the normal desktop if (dr == DialogResult.None) { Form f = m_fnConstruct(objConstructParam); dr = f.ShowDialog(); objResult = m_fnResultBuilder(f); UIUtil.DestroyForm(f); } return(dr); }