/// <summary> /// Creates, displays, and operates a task dialog. The task dialog contains application-defined messages, title, /// verification check box, command links and push buttons, plus any combination of predefined icons and push buttons /// as specified on the other members of the class before calling Show. /// </summary> /// <param name="hwndOwner">Owner window the task Dialog will modal to.</param> /// <param name="verificationFlagChecked">Returns true if the verification checkbox was checked when the dialog /// was dismissed.</param> /// <param name="radioButtonResult">The radio botton selected by the user.</param> /// <returns>The result of the dialog, either a DialogResult value for common push buttons set in the CommonButtons /// member or the ButtonID from a TaskDialogButton structure set on the Buttons member.</returns> private int PrivateShow(IntPtr hwndOwner, out bool verificationFlagChecked, out int radioButtonResult) { verificationFlagChecked = false; radioButtonResult = 0; int result; UnsafeNativeMethods.TASKDIALOGCONFIG config = new UnsafeNativeMethods.TASKDIALOGCONFIG(); try { config.cbSize = (uint)UnsafeNativeMethods.TASKDIALOGCONFIG.SizeOf; config.hwndParent = hwndOwner; config.dwFlags = this.flags; config.dwCommonButtons = this.commonButtons; if (!string.IsNullOrEmpty(this.windowTitle)) { config.pszWindowTitle = this.windowTitle; } config.MainIcon = (IntPtr)this.mainIcon; if (this.customMainIcon != null) { config.dwFlags |= UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_USE_HICON_MAIN; config.MainIcon = this.customMainIcon.Handle; } if (!string.IsNullOrEmpty(this.mainInstruction)) { config.pszMainInstruction = this.mainInstruction; } if (!string.IsNullOrEmpty(this.content)) { config.pszContent = this.content; } TaskDialogButton[] customButtons = this.buttons; if (customButtons.Length > 0) { // Hand marshal the buttons array. int elementSize = TaskDialogButton.SizeOf; config.pButtons = MemoryAlloc.PrivateHeap.Allocate(elementSize * customButtons.Length); for (int i = 0; i < customButtons.Length; i++) { unsafe // Unsafe because of pointer arithmatic. { byte* p = (byte*)config.pButtons; Marshal.StructureToPtr(customButtons[i], (IntPtr)(p + (elementSize * i)), false); } config.cButtons++; } } TaskDialogButton[] customRadioButtons = this.radioButtons; if (customRadioButtons.Length > 0) { // Hand marshal the buttons array. int elementSize = TaskDialogButton.SizeOf; config.pRadioButtons = MemoryAlloc.PrivateHeap.Allocate(elementSize * customRadioButtons.Length); for (int i = 0; i < customRadioButtons.Length; i++) { unsafe // Unsafe because of pointer arithmatic. { byte* p = (byte*)config.pRadioButtons; Marshal.StructureToPtr(customRadioButtons[i], (IntPtr)(p + (elementSize * i)), false); } config.cRadioButtons++; } } config.nDefaultButton = this.defaultButton; config.nDefaultRadioButton = this.defaultRadioButton; if (!string.IsNullOrEmpty(this.verificationText)) { config.pszVerificationText = this.verificationText; } if (!string.IsNullOrEmpty(this.expandedInformation)) { config.pszExpandedInformation = this.expandedInformation; } if (!string.IsNullOrEmpty(this.expandedControlText)) { config.pszExpandedControlText = this.expandedControlText; } if (!string.IsNullOrEmpty(this.collapsedControlText)) { config.pszCollapsedControlText = this.CollapsedControlText; } config.FooterIcon = (IntPtr)this.footerIcon; if (this.customFooterIcon != null) { config.dwFlags |= UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_USE_HICON_FOOTER; config.FooterIcon = this.customFooterIcon.Handle; } if (!string.IsNullOrEmpty(this.footer)) { config.pszFooter = this.footer; } // If our user has asked for a callback then we need to ask for one to // translate to the friendly version. if (this.callback != null) { config.pfCallback = this.PrivateCallback; } ////config.lpCallbackData = this.callbackData; // How do you do this? Need to pin the ref? config.cxWidth = this.width; // The call all this mucking about is here for. UnsafeNativeMethods.TaskDialogIndirect(ref config, out result, out radioButtonResult, out verificationFlagChecked); } finally { // Free the unmanged memory needed for the button arrays. // There is the possiblity of leaking memory if the app-domain is destroyed in a non clean way // and the hosting OS process is kept alive but fixing this would require using hardening techniques // that are not required for the users of this class. if (config.pButtons != IntPtr.Zero) { int elementSize = TaskDialogButton.SizeOf; for (int i = 0; i < config.cButtons; i++) { unsafe { byte* p = (byte*)config.pButtons; Marshal.DestroyStructure((IntPtr)(p + (elementSize * i)), typeof(TaskDialogButton)); } } MemoryAlloc.PrivateHeap.Free(config.pButtons); } if (config.pRadioButtons != IntPtr.Zero) { int elementSize = TaskDialogButton.SizeOf; for (int i = 0; i < config.cRadioButtons; i++) { unsafe { byte* p = (byte*)config.pRadioButtons; Marshal.DestroyStructure((IntPtr)(p + (elementSize * i)), typeof(TaskDialogButton)); } } MemoryAlloc.PrivateHeap.Free(config.pRadioButtons); } } return result; }
private int PrivateShow(IntPtr hwndOwner, out bool verificationFlagChecked, out int radioButtonResult) { verificationFlagChecked = false; radioButtonResult = 0; int result = 0; UnsafeNativeMethods.TASKDIALOGCONFIG config = new UnsafeNativeMethods.TASKDIALOGCONFIG(); try { config.cbSize = (uint)Marshal.SizeOf(typeof(UnsafeNativeMethods.TASKDIALOGCONFIG)); config.hwndParent = hwndOwner; config.dwFlags = this.flags; config.dwCommonButtons = this.commonButtons; if (!string.IsNullOrEmpty(this.windowTitle)) { config.pszWindowTitle = this.windowTitle; } config.MainIcon = (IntPtr)this.mainIcon; if (this.customMainIcon != null) { config.dwFlags |= UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_USE_HICON_MAIN; config.MainIcon = this.customMainIcon.Handle; } if (!string.IsNullOrEmpty(this.mainInstruction)) { config.pszMainInstruction = this.mainInstruction; } if (!string.IsNullOrEmpty(this.content)) { config.pszContent = this.content; } TaskDialogButton[] customButtons = this.buttons; if (customButtons.Length > 0) { int elementSize = Marshal.SizeOf(typeof(TaskDialogButton)); config.pButtons = Marshal.AllocHGlobal(elementSize * (int)customButtons.Length); for (int i = 0; i < customButtons.Length; i++) { unsafe { byte* p = (byte*)config.pButtons; Marshal.StructureToPtr(customButtons[i], (IntPtr)(p + (elementSize * i)), false); } config.cButtons++; } } TaskDialogButton[] customRadioButtons = this.radioButtons; if (customRadioButtons.Length > 0) { int elementSize = Marshal.SizeOf(typeof(TaskDialogButton)); config.pRadioButtons = Marshal.AllocHGlobal(elementSize * (int)customRadioButtons.Length); for (int i = 0; i < customRadioButtons.Length; i++) { unsafe { byte* p = (byte*)config.pRadioButtons; Marshal.StructureToPtr(customRadioButtons[i], (IntPtr)(p + (elementSize * i)), false); } config.cRadioButtons++; } } config.nDefaultButton = this.defaultButton; config.nDefaultRadioButton = this.defaultRadioButton; if (!string.IsNullOrEmpty(this.verificationText)) { config.pszVerificationText = this.verificationText; } if (!string.IsNullOrEmpty(this.expandedInformation)) { config.pszExpandedInformation = this.expandedInformation; } if (!string.IsNullOrEmpty(this.expandedControlText)) { config.pszExpandedControlText = this.expandedControlText; } if (!string.IsNullOrEmpty(this.collapsedControlText)) { config.pszCollapsedControlText = this.CollapsedControlText; } config.FooterIcon = (IntPtr)this.footerIcon; if (this.customFooterIcon != null) { config.dwFlags |= UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_USE_HICON_FOOTER; config.FooterIcon = this.customFooterIcon.Handle; } if (!string.IsNullOrEmpty(this.footer)) { config.pszFooter = this.footer; } if (this.callback != null) { config.pfCallback = new UnsafeNativeMethods.TaskDialogCallback(this.PrivateCallback); } config.cxWidth = this.width; UnsafeNativeMethods.TaskDialogIndirect(ref config, out result, out radioButtonResult, out verificationFlagChecked); } finally { if (config.pButtons != IntPtr.Zero) { int elementSize = Marshal.SizeOf(typeof(TaskDialogButton)); for (int i = 0; i < config.cButtons; i++) { unsafe { byte* p = (byte*)config.pButtons; Marshal.DestroyStructure((IntPtr)(p + (elementSize * i)), typeof(TaskDialogButton)); } } Marshal.FreeHGlobal(config.pButtons); } if (config.pRadioButtons != IntPtr.Zero) { int elementSize = Marshal.SizeOf(typeof(TaskDialogButton)); for (int i = 0; i < config.cRadioButtons; i++) { unsafe { byte* p = (byte*)config.pRadioButtons; Marshal.DestroyStructure((IntPtr)(p + (elementSize * i)), typeof(TaskDialogButton)); } } Marshal.FreeHGlobal(config.pRadioButtons); } } return result; }