/// <include file='doc\FolderBrowserDialog.uex' path='docs/doc[@for="FolderBrowserDialog.RunDialog"]/*' /> /// <devdoc> /// Implements running of a folder browser dialog. /// </devdoc> protected override bool RunDialog(IntPtr hWndOwner) { IntPtr pidlRoot = IntPtr.Zero; bool returnValue = false; UnsafeNativeMethods.Shell32.SHGetSpecialFolderLocation(hWndOwner, (int)rootFolder, ref pidlRoot); if (pidlRoot == IntPtr.Zero) { UnsafeNativeMethods.Shell32.SHGetSpecialFolderLocation(hWndOwner, NativeMethods.CSIDL_DESKTOP, ref pidlRoot); if (pidlRoot == IntPtr.Zero) { throw new InvalidOperationException(SR.GetString(SR.FolderBrowserDialogNoRootFolder)); } } int mergedOptions = unchecked ((int)(long)UnsafeNativeMethods.BrowseInfos.NewDialogStyle); if (!showNewFolderButton) { mergedOptions += unchecked ((int)(long)UnsafeNativeMethods.BrowseInfos.HideNewFolderButton); } // The SHBrowserForFolder dialog is OLE/COM based, and documented as only being safe to use under the STA // threading model if the BIF_NEWDIALOGSTYLE flag has been requested (which we always do in mergedOptions // above). So make sure OLE is initialized, and throw an exception if caller attempts to invoke dialog // under the MTA threading model (...dialog does appear under MTA, but is totally non-functional). if (Control.CheckForIllegalCrossThreadCalls && Application.OleRequired() != System.Threading.ApartmentState.STA) { throw new System.Threading.ThreadStateException(SR.GetString(SR.DebuggingExceptionOnly, SR.GetString(SR.ThreadMustBeSTA))); } IntPtr pidlRet = IntPtr.Zero; IntPtr pszDisplayName = IntPtr.Zero; IntPtr pszSelectedPath = IntPtr.Zero; try { // Construct a BROWSEINFO UnsafeNativeMethods.BROWSEINFO bi = new UnsafeNativeMethods.BROWSEINFO(); pszDisplayName = Marshal.AllocHGlobal(NativeMethods.MAX_PATH * Marshal.SystemDefaultCharSize); pszSelectedPath = Marshal.AllocHGlobal((NativeMethods.MAX_PATH + 1) * Marshal.SystemDefaultCharSize); this.callback = new UnsafeNativeMethods.BrowseCallbackProc(this.FolderBrowserDialog_BrowseCallbackProc); bi.pidlRoot = pidlRoot; bi.hwndOwner = hWndOwner; bi.pszDisplayName = pszDisplayName; bi.lpszTitle = descriptionText; bi.ulFlags = mergedOptions; bi.lpfn = callback; bi.lParam = IntPtr.Zero; bi.iImage = 0; // And show the dialog pidlRet = UnsafeNativeMethods.Shell32.SHBrowseForFolder(bi); if (pidlRet != IntPtr.Zero) { // Then retrieve the path from the IDList UnsafeNativeMethods.Shell32.SHGetPathFromIDListLongPath(pidlRet, ref pszSelectedPath); // set the flag to True before selectedPath is set to // assure security check and avoid bogus race condition selectedPathNeedsCheck = true; // Convert to a string selectedPath = Marshal.PtrToStringAuto(pszSelectedPath); returnValue = true; } } finally { UnsafeNativeMethods.CoTaskMemFree(pidlRoot); if (pidlRet != IntPtr.Zero) { UnsafeNativeMethods.CoTaskMemFree(pidlRet); } // Then free all the stuff we've allocated or the SH API gave us if (pszSelectedPath != IntPtr.Zero) { Marshal.FreeHGlobal(pszSelectedPath); } if (pszDisplayName != IntPtr.Zero) { Marshal.FreeHGlobal(pszDisplayName); } this.callback = null; } return(returnValue); }
/// <include file='doc\FolderBrowserDialog.uex' path='docs/doc[@for="FolderBrowserDialog.RunDialog"]/*' /> /// <devdoc> /// Implements running of a folder browser dialog. /// </devdoc> protected override bool RunDialog(IntPtr hWndOwner) { IntPtr pidlRoot = IntPtr.Zero; bool returnValue = false; UnsafeNativeMethods.Shell32.SHGetSpecialFolderLocation(hWndOwner, (int)rootFolder, ref pidlRoot); if (pidlRoot == IntPtr.Zero) { UnsafeNativeMethods.Shell32.SHGetSpecialFolderLocation(hWndOwner, NativeMethods.CSIDL_DESKTOP, ref pidlRoot); if (pidlRoot == IntPtr.Zero) { throw new Exception(SR.GetString(SR.FolderBrowserDialogNoRootFolder)); } } int mergedOptions = (int)UnsafeNativeMethods.BrowseInfos.NewDialogStyle; if (!showNewFolderButton) { mergedOptions += (int)UnsafeNativeMethods.BrowseInfos.HideNewFolderButton; } Application.OleRequired(); IntPtr pidlRet = IntPtr.Zero; try { // Construct a BROWSEINFO UnsafeNativeMethods.BROWSEINFO bi = new UnsafeNativeMethods.BROWSEINFO(); IntPtr pszDisplayName = Marshal.AllocHGlobal(NativeMethods.MAX_PATH); IntPtr pszSelectedPath = Marshal.AllocHGlobal(NativeMethods.MAX_PATH); UnsafeNativeMethods.BrowseCallbackProc callback = new UnsafeNativeMethods.BrowseCallbackProc(this.FolderBrowserDialog_BrowseCallbackProc); bi.pidlRoot = pidlRoot; bi.hwndOwner = hWndOwner; bi.pszDisplayName = pszDisplayName; bi.lpszTitle = descriptionText; bi.ulFlags = mergedOptions; bi.lpfn = callback; bi.lParam = IntPtr.Zero; bi.iImage = 0; // And show the dialog pidlRet = UnsafeNativeMethods.Shell32.SHBrowseForFolder(bi); if (pidlRet != IntPtr.Zero) { // Then retrieve the path from the IDList UnsafeNativeMethods.Shell32.SHGetPathFromIDList(pidlRet, pszSelectedPath); // set the flag to True before selectedPath is set to // assure security check and avoid bogus race condition selectedPathNeedsCheck = true; // Convert to a string selectedPath = Marshal.PtrToStringAuto(pszSelectedPath); // Then free all the stuff we've allocated or the SH API gave us Marshal.FreeHGlobal(pszSelectedPath); Marshal.FreeHGlobal(pszDisplayName); returnValue = true; } } finally { UnsafeNativeMethods.IMalloc malloc = GetSHMalloc(); malloc.Free(pidlRoot); if (pidlRet != IntPtr.Zero) { malloc.Free(pidlRet); } } return(returnValue); }