public static extern int SHGetSpecialFolderLocation(IntPtr hwnd, int csidl, out CoTaskMemSafeHandle ppidl);
private static extern HResult PropVariantToStringVectorAlloc(PropVariantSafeHandle propvar, out CoTaskMemSafeHandle pprgsz, out uint pcElem);
private unsafe bool RunDialogOld(IntPtr hWndOwner) { CoTaskMemSafeHandle listHandle; Interop.Shell32.SHGetSpecialFolderLocation(hWndOwner, (int)rootFolder, out listHandle); if (listHandle.IsInvalid) { Interop.Shell32.SHGetSpecialFolderLocation(hWndOwner, (int)Environment.SpecialFolder.Desktop, out listHandle); if (listHandle.IsInvalid) { throw new InvalidOperationException(SR.FolderBrowserDialogNoRootFolder); } } using (listHandle) { uint mergedOptions = Interop.Shell32.BrowseInfoFlags.BIF_NEWDIALOGSTYLE; if (!showNewFolderButton) { mergedOptions |= Interop.Shell32.BrowseInfoFlags.BIF_NONEWFOLDERBUTTON; } // 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(string.Format(SR.DebuggingExceptionOnly, SR.ThreadMustBeSTA)); } var callback = new Interop.Shell32.BrowseCallbackProc(FolderBrowserDialog_BrowseCallbackProc); char[] displayName = ArrayPool <char> .Shared.Rent(Interop.Kernel32.MAX_PATH + 1); try { fixed(char *pDisplayName = displayName) { var bi = new Interop.Shell32.BROWSEINFO(); bi.pidlRoot = listHandle; bi.hwndOwner = hWndOwner; bi.pszDisplayName = pDisplayName; bi.lpszTitle = descriptionText; bi.ulFlags = mergedOptions; bi.lpfn = callback; bi.lParam = IntPtr.Zero; bi.iImage = 0; // Show the dialog using (CoTaskMemSafeHandle browseHandle = Interop.Shell32.SHBrowseForFolderW(ref bi)) { if (browseHandle.IsInvalid) { return(false); } // Retrieve the path from the IDList. Interop.Shell32.SHGetPathFromIDListLongPath(browseHandle.DangerousGetHandle(), out selectedPath); GC.KeepAlive(callback); return(true); } } } finally { ArrayPool <char> .Shared.Return(displayName); } } }