Ejemplo n.º 1
0
        /// <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);
        }