private int OpenFileSubClass
        (
            IntPtr hWnd,
            uint uMsg,
            IntPtr wParam,
            IntPtr lParam,
            IntPtr uIdSubclass,
            uint dwRefData
        )
        {
            switch (uMsg)
            {
            case InteropUtil.WM_PARENTNOTIFY:
            {
                unchecked
                {
                    int id = InteropUtil.GetDlgCtrlID(lParam);

                    if (LOW((uint)wParam) == InteropUtil.WM_CREATE &&
                        (id == InteropUtil.ID_FileList || id == 0))
                    {
                        InteropUtil.SetWindowSubclass(lParam, m_defViewSubClassDelegate, 0, 0);
                    }
                }
                break;
            }
            }
            return(InteropUtil.DefSubclassProc(hWnd, uMsg, wParam, lParam));
        }
        private void ResizeCustomControl(IntPtr hWnd, InteropUtil.RECT rect, params IntPtr[] buttons)
        {
            InteropUtil.Assume(buttons != null && buttons.Length > 0);

            InteropUtil.AssumeNonZero(hWnd);

            InteropUtil.WINDOWPLACEMENT wndLoc = InteropUtil.GetWindowPlacement(hWnd);

            wndLoc.Right = rect.right;
            InteropUtil.SetWindowPlacement(hWnd, ref wndLoc);

            foreach (IntPtr hBtn in buttons)
            {
                int btnRight, btnWidth;

                m_calcPosMap[InteropUtil.GetDlgCtrlID(hBtn)](this, rect.right, out btnRight, out btnWidth);

                PositionButton(hBtn, btnRight, btnWidth);
            }

            //see bug # 844
            //We clip hWnd to only draw in the rectangle around our custom buttons.
            //When we supply a custom dialog template to GetOpenFileName(), it adds
            //an extra HWND to the open file dialog, and then sticks all the controls
            //in the dialog //template inside the HWND. It then resizes the control
            //to stretch from the top of the open file dialog to the bottom of the
            //window, extending the bottom of the window large enough to include the
            //additional height of the dialog template. This ends up sticking our custom
            //buttons at the bottom of the window, which is what we want.
            //
            //However, the fact that the parent window extends from the top of the open
            //file dialog was causing some painting problems on Windows XP SP 3 systems.
            //Basically, because the window was covering the predefined controls on the
            //open file dialog, they were not getting painted. This results in a blank
            //window. I tried setting an extended WS_EX_TRANSPARENT style on the dialog,
            //but that didn't help.
            //
            //So, to fix the problem I setup a window region for the synthetic HWND.
            //This clips the drawing of the window to only within the region containing
            //the custom buttons, and thus avoids the problem.
            //
            //I'm not sure why this wasn't an issue on Vista.
            IntPtr hRgn = InteropUtil.CreateRectRgnIndirect(ref rect);

            try
            {
                if (InteropUtil.SetWindowRgn(hWnd, hRgn, true) == 0)
                {
                    //setting the region failed, so we need to delete the region we created above.
                    InteropUtil.DeleteObject(hRgn);
                }
            }
            catch
            {
                if (hRgn != IntPtr.Zero)
                {
                    InteropUtil.DeleteObject(hRgn);
                }
            }
        }
        private void ResizeCustomControl(IntPtr hWnd)
        {
            if (hWnd == m_hWnd)
            {
                IntPtr hSelectButton =
                    InteropUtil.AssumeNonZero(InteropUtil.GetDlgItem(InteropUtil.AssumeNonZero(hWnd),
                                                                     InteropUtil.ID_SELECT));
                IntPtr hOkButton =
                    InteropUtil.AssumeNonZero(InteropUtil.GetDlgItem(InteropUtil.AssumeNonZero(hWnd),
                                                                     InteropUtil.ID_CUSTOM_CANCEL));

                IntPtr hParent  = InteropUtil.AssumeNonZero(InteropUtil.GetParent(hWnd));
                IntPtr fileName =
                    InteropUtil.AssumeNonZero(InteropUtil.GetDlgItem(hParent, InteropUtil.ID_FileNameCombo));

                /*var right = fileName.GetWindowPlacement().Right;
                 * var top = hSelectButton.GetWindowPlacement().Top;*/

                var rect = new InteropUtil.RECT();
                InteropUtil.WINDOWPLACEMENT selectRect = InteropUtil.GetWindowPlacement(hSelectButton);

                rect.top    = selectRect.Top;
                rect.bottom = selectRect.Bottom;
                rect.right  = InteropUtil.GetWindowPlacement(fileName).Right;
                rect.left   = rect.right - (m_cancelWidth + m_buttonGap + m_selectWidth);

                ResizeCustomControl(hWnd, rect, hOkButton, hSelectButton);
            }
        }
        private bool ProcessSelection(IntPtr handle, bool preferSelection)
        {
            IntPtr shelldll_defview = InteropUtil.GetDlgItem(handle,
                                                             InteropUtil.ID_FileList);
            IntPtr listview = InteropUtil.GetDlgItem(shelldll_defview, 1);
            IntPtr focus    = InteropUtil.GetFocus();

            if (listview == focus || preferSelection)
            {
                return(AddSelectedItemsFromSelection(listview));
            }
            else
            {
                //check the content of the file combobox
                IntPtr hFileName = InteropUtil.GetDlgItem(handle,
                                                          InteropUtil.ID_FileNameCombo);
                string currentText = (InteropUtil.GetWindowTextW(hFileName) ?? "").Trim();
                if (!String.IsNullOrEmpty(currentText))
                {
                    try
                    {
                        if (System.IO.Path.IsPathRooted(currentText))
                        {
                            if (Directory.Exists(currentText) || File.Exists(currentText))
                            {
                                //the contents of the text box are a rooted path, that points to an existing directory.
                                //we interpret that to mean that the user wants to select that directory.
                                _selected.Add(currentText);
                                return(true);
                            }
                        }
                        else if (!String.IsNullOrEmpty(m_currentFolder))
                        {
                            string combined = System.IO.Path.Combine(m_currentFolder,
                                                                     currentText);
                            if (Directory.Exists(combined) || File.Exists(combined))
                            {
                                //the contents of the text box are a relative path, that points to a
                                //an existing directory. We interpret the users intent to mean that they wanted
                                //to select the existing path.
                                _selected.Add(combined);
                                return(true);
                            }
                        }
                    }
                    catch (Exception)
                    {
                        //try to add the selection
                        if (AddSelectedItemsFromSelection(listview))
                        {
                            return(true);
                        }
                    }
                }
                //forward all wrong inputs to the standard mechanism
                return(false);
            }
        }
        private string GetFileNameFromSelectedItem(IntPtr hListView, int selectedIndex)
        {
            if (selectedIndex >= 0)
            {
                var lvitem = new InteropUtil.LVITEM();
                lvitem.mask = InteropUtil.LVIF_TEXT;
                IntPtr nativeBuffer = Marshal.AllocCoTaskMem(InteropUtil.NumberOfFileChars * 2);
                for (int i = 0; i < InteropUtil.NumberOfFileChars; ++i)
                {
                    Marshal.WriteInt16(nativeBuffer, i * 2, '\0');
                }
                string name;

                try
                {
                    Marshal.WriteInt16(nativeBuffer, 0);
                    lvitem.pszText    = nativeBuffer;
                    lvitem.cchTextMax = InteropUtil.NumberOfFileChars;
                    uint length = InteropUtil.SendListViewMessageInt(hListView, InteropUtil.LVM_GETITEMTEXT,
                                                                     selectedIndex, ref lvitem);
                    name = Marshal.PtrToStringUni(lvitem.pszText, (int)length);
                }
                finally
                {
                    Marshal.FreeCoTaskMem(nativeBuffer);
                }

                if (name != null && m_currentFolder != null)
                {
                    try
                    {
                        string path = System.IO.Path.Combine(m_currentFolder, name);

                        return(path);

                        if (Directory.Exists(path))
                        {
                            //hFNCombo.SetWindowTextW(name);
                        }
                    }
                    catch (Exception)
                    {
                    }
                }


                return(name);
            }
            return(string.Empty);
        }
        private void PositionButton(IntPtr hWnd, int right, int width)
        {
            InteropUtil.AssumeNonZero(hWnd);
            int id = InteropUtil.GetDlgCtrlID(hWnd);

            //hWnd.BringWindowToTop();

            InteropUtil.WINDOWPLACEMENT buttonLoc = InteropUtil.GetWindowPlacement(hWnd);

            buttonLoc.Right = right;
            buttonLoc.Left  = buttonLoc.Right - width;
            InteropUtil.SetWindowPlacement(hWnd, ref buttonLoc);
            InteropUtil.InvalidateRect(hWnd, IntPtr.Zero, true);
        }
        private int DefViewSubClass
        (
            IntPtr hWnd,
            uint uMsg,
            IntPtr wParam,
            IntPtr lParam,
            IntPtr uIdSubclass,
            uint dwRefData
        )
        {
            if (uMsg == InteropUtil.WM_NOTIFY)
            {
                var header = (InteropUtil.NMHDR)Marshal.PtrToStructure(lParam, typeof(InteropUtil.NMHDR));
                if (header.code == InteropUtil.LVN_ITEMCHANGED && header.hwndFrom != IntPtr.Zero && header.idFrom == 1)
                {
                    var nmListView =
                        (InteropUtil.NMLISTVIEW)Marshal.PtrToStructure(lParam, typeof(InteropUtil.NMLISTVIEW));
                    bool oldSelected = (nmListView.uOldState & InteropUtil.LVIS_SELECTED) != 0;
                    bool newSelected = (nmListView.uNewState & InteropUtil.LVIS_SELECTED) != 0;
                    if (!oldSelected && newSelected)
                    {
                        if (!m_suppressSelectionChange)
                        {
                            //the item went from not selected to being selected
                            //so we want to look and see if the selected item is a folder, and if so
                            //change the text of the item box to be the item on the folder. But, before we do that
                            //we want to make sure that the box isn't currently focused.
                            IntPtr hParent    = InteropUtil.GetParent(hWnd);
                            IntPtr hFNCombo   = InteropUtil.GetDlgItem(hParent, InteropUtil.ID_FileNameCombo);
                            IntPtr hFNEditBox = InteropUtil.GetDlgItem(hParent, InteropUtil.ID_FileNameTextBox);
                            IntPtr hFocus     = InteropUtil.GetFocus();

                            if
                            (
                                (hFNCombo == IntPtr.Zero || hFNCombo != hFocus) &&
                                (hFNEditBox == IntPtr.Zero || hFNEditBox != hFocus)
                            )
                            {
                                SetFileNameToSelectedItem(header.hwndFrom, hFNCombo, nmListView.iItem);
                            }
                        }
                        m_suppressSelectionChange = false;
                    }
                }
            }
            return(InteropUtil.DefSubclassProc(hWnd, uMsg, wParam, lParam));
        }
        private bool AddSelectedItemsFromSelection(IntPtr listview)
        {
            uint count = InteropUtil.SendMessage(listview,
                                                 InteropUtil.LVM_GETSELECTEDCOUNT, 0, 0);

            //if there is at least one item selected we always return these ones
            if (count > 0)
            {
                int ind = -1;
                for (int i = 0; i < count; i++)
                {
                    ind = InteropUtil.SendMessageInt(listview, InteropUtil.LVM_GETNEXTITEM,
                                                     ind,
                                                     InteropUtil.LVNI_SELECTED);
                    //with the index we can get the item's text
                    string item = GetFileNameFromSelectedItem(listview, ind);
                    _selected.Add(item);
                }
                return(true);
            }
            return(false);
        }
        private string GetTextFromCommonDialog(IntPtr hWnd, uint msg)
        {
            string str    = null;
            IntPtr buffer = Marshal.AllocCoTaskMem(2 * InteropUtil.NumberOfFileChars);

            try
            {
                InteropUtil.SendMessageIntPtr(hWnd, msg, new IntPtr(InteropUtil.NumberOfFileChars), buffer);
                var chars = new char[InteropUtil.NumberOfFileChars];
                Marshal.Copy(buffer, chars, 0, chars.Length);
                int firstZeroTerm = ((IList)chars).IndexOf('\0');

                if (firstZeroTerm >= 0 && firstZeroTerm <= chars.Length - 1)
                {
                    str = new string(chars, 0, firstZeroTerm);
                }
            }
            finally
            {
                Marshal.FreeCoTaskMem(buffer);
            }
            return(str);
        }
        private int ProcessNotifyMessage(IntPtr hWnd, InteropUtil.OFNOTIFY notifyData)
        {
            switch (notifyData.hdr_code)
            {
            case InteropUtil.CDN_FOLDERCHANGE:
            {
                //CDM_GETFOLDERPATH returns garbage for some standard folders like 'Libraries'
                //var newFolder = GetTextFromCommonDialog(InteropUtil.AssumeNonZero(InteropUtil.GetParent(hWnd)),
                //                  InteropUtil.CDM_GETFOLDERPATH);
                string newFolder =
                    GetTextFromCommonDialog(InteropUtil.AssumeNonZero(InteropUtil.GetParent(hWnd)),
                                            InteropUtil.CDM_GETFILEPATH);

                /*
                 * if (m_currentFolder != null && newFolder != null &&
                 *  Util.PathContains(newFolder, m_currentFolder))
                 * {
                 *  m_suppressSelectionChange = true;
                 * }
                 */

                m_currentFolder = newFolder;

                /* #5841 On Windows XP when changing the folder 'newFolder' contains the selected directory twice (e.g. c:\temp\i386\i386)
                 * HACK
                 */
                if (!Directory.Exists(newFolder))
                {
                    try
                    {
                        String lastPart   = System.IO.Path.GetFileName(newFolder);
                        String parent     = Directory.GetParent(newFolder).FullName;
                        String parentFile = System.IO.Path.GetFileName(parent);
                        if (lastPart.Equals(parentFile))
                        {
                            m_currentFolder = parent;
                        }
                    }
                    catch (Exception)
                    {
                        //ignore
                    }
                }
                IntPtr fileNameCombo =
                    InteropUtil.AssumeNonZero(
                        InteropUtil.GetDlgItem(InteropUtil.AssumeNonZero(InteropUtil.GetParent(hWnd)),
                                               InteropUtil.ID_FileNameCombo));
                if (m_hasDirChangeFired)
                {
                    InteropUtil.SetWindowTextW(fileNameCombo, String.Empty);
                }
                m_hasDirChangeFired = true;

                //refresh the file list to make sure that the extension is shown properly
                IntPtr hParent = InteropUtil.AssumeNonZero(InteropUtil.GetParent(hWnd));
                SetForegroundWindow(hParent);
                SendKeys.SendWait("{F5}");

                break;
            }

            case InteropUtil.CDN_FILEOK:
            {
                if (!AcceptFiles)
                {
                    return(1);
                }

                IntPtr hParent = InteropUtil.AssumeNonZero(InteropUtil.GetParent(hWnd));
                ProcessSelection(hParent, false);

                break;
            }

            case InteropUtil.CDN_INITDONE:
            {
                IntPtr hParent = InteropUtil.GetParent(hWnd);
                IntPtr hFile   =
                    InteropUtil.AssumeNonZero(InteropUtil.GetDlgItem(InteropUtil.AssumeNonZero(hParent),
                                                                     InteropUtil.ID_FileNameCombo));
                InteropUtil.SetFocus(hFile);
                break;
            }
            }
            return(0);
        }
        private void InitDialog(IntPtr hWnd)
        {
            m_hWnd = hWnd;

            IntPtr hParent = InteropUtil.AssumeNonZero(InteropUtil.GetParent(hWnd));

            InteropUtil.SetWindowSubclass(hParent, m_openFileSubClassDelegate, 0, 0);

            //disable and hide the filter combo box
            IntPtr hFilterCombo = InteropUtil.AssumeNonZero(InteropUtil.GetDlgItem(hParent, InteropUtil.ID_FilterCombo));

            InteropUtil.EnableWindow(hFilterCombo, false);
            InteropUtil.SendMessage(hParent, InteropUtil.CDM_HIDECONTROL, InteropUtil.ID_FilterCombo, 0);
            InteropUtil.SendMessage(hParent, InteropUtil.CDM_HIDECONTROL, InteropUtil.ID_FilterLabel, 0);

            //update the file name label
            IntPtr hFileNameLabel =
                InteropUtil.AssumeNonZero(InteropUtil.GetDlgItem(hParent, InteropUtil.ID_FileNameLabel));

            if (FileNameLabel != String.Empty)
            {
                InteropUtil.SendMessageString(hFileNameLabel, InteropUtil.WM_SETTEXT, 0, FileNameLabel);
            }

            //find the button controls in the parent
            IntPtr hOkButton     = InteropUtil.AssumeNonZero(InteropUtil.GetDlgItem(hParent, InteropUtil.IDOK));
            IntPtr hCancelButton = InteropUtil.AssumeNonZero(InteropUtil.GetDlgItem(hParent, InteropUtil.IDCANCEL));

            //We don't want the accelerator keys for the ok and cancel buttons to work, because
            //they are not shown on the dialog. However, we still want the buttons enabled
            //so that "esc" and "enter" have the behavior they used to. So, we just
            //clear out their text instead.
            InteropUtil.SetWindowTextW(hOkButton, String.Empty);
            InteropUtil.SetWindowTextW(hCancelButton, String.Empty);

            //find our button controls
            IntPtr hSelectButton       = InteropUtil.AssumeNonZero(InteropUtil.GetDlgItem(hWnd, InteropUtil.ID_SELECT));
            IntPtr hCustomCancelButton =
                InteropUtil.AssumeNonZero(InteropUtil.GetDlgItem(hWnd, InteropUtil.ID_CUSTOM_CANCEL));

            if (!String.IsNullOrEmpty(SelectLabel))
            {
                InteropUtil.SetWindowTextW(hSelectButton, SelectLabel);
            }
            if (!String.IsNullOrEmpty(CancelLabel))
            {
                InteropUtil.SetWindowTextW(hCustomCancelButton, CancelLabel);
            }

            //copy the font from the parent's buttons
            InteropUtil.LoadFontFrom(hSelectButton, hOkButton);
            InteropUtil.LoadFontFrom(hCustomCancelButton, hCancelButton);

            InteropUtil.WINDOWPLACEMENT cancelLoc = InteropUtil.GetWindowPlacement(hCancelButton);

            //hide the ok and cancel buttons
            InteropUtil.SendMessage(hParent, InteropUtil.CDM_HIDECONTROL, InteropUtil.IDOK, 0);
            InteropUtil.SendMessage(hParent, InteropUtil.CDM_HIDECONTROL, InteropUtil.IDCANCEL, 0);

            //expand the file name combo to take up the space left by the OK and cancel buttons.
            IntPtr hFileName = InteropUtil.AssumeNonZero(InteropUtil.GetDlgItem(hParent, InteropUtil.ID_FileNameCombo));

            InteropUtil.WINDOWPLACEMENT fileNameLoc = InteropUtil.GetWindowPlacement(hFileName);
            fileNameLoc.Right = InteropUtil.GetWindowPlacement(hOkButton).Right;
            InteropUtil.SetWindowPlacement(hFileName, ref fileNameLoc);

            InteropUtil.WINDOWPLACEMENT parentLoc = InteropUtil.GetWindowPlacement(hParent);

            //subtract the height of the missing cancel button
            parentLoc.Bottom -= (cancelLoc.Bottom - cancelLoc.Top);
            InteropUtil.SetWindowPlacement(hParent, ref parentLoc);

            //move the select and custom cancel buttons to the right hand side of the window:

            InteropUtil.WINDOWPLACEMENT selectLoc       = InteropUtil.GetWindowPlacement(hSelectButton);
            InteropUtil.WINDOWPLACEMENT customCancelLoc = InteropUtil.GetWindowPlacement(hCustomCancelButton);
            m_cancelWidth = customCancelLoc.Right - customCancelLoc.Left;
            m_selectWidth = selectLoc.Right - selectLoc.Left;
            m_buttonGap   = customCancelLoc.Left - selectLoc.Right;

            InteropUtil.WINDOWPLACEMENT ctrlLoc = InteropUtil.GetWindowPlacement(hWnd);
            ctrlLoc.Right = fileNameLoc.Right;

            //ResizeCustomControl(hWnd, fileNameLoc.Right, hCustomCancelButton, hSelectButton);
            ResizeCustomControl(hWnd);
        }
        /// <summary>
        /// Defines the common dialog box hook procedure that is overridden to add specific functionality to a common dialog box.
        /// </summary>
        /// <returns>
        /// A zero value if the default dialog box procedure processes the message; a nonzero value if the default dialog box procedure ignores the message.
        /// </returns>
        /// <param name="hWnd">The handle to the dialog box window. </param><param name="msg">The message being received. </param><param name="wparam">Additional information about the message. </param><param name="lparam">Additional information about the message. </param>
        protected override IntPtr HookProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lparam)
        {
            switch (unchecked ((uint)msg))
            {
            case InteropUtil.WM_INITDIALOG:
            {
                InitDialog(hWnd);
                break;
            }

            case InteropUtil.WM_NOTIFY:
            {
                var notifyData =
                    (InteropUtil.OFNOTIFY)Marshal.PtrToStructure(lparam, typeof(InteropUtil.OFNOTIFY));
                int results = ProcessNotifyMessage(hWnd, notifyData);
                if (results != 0)
                {
                    InteropUtil.SetWindowLongW(hWnd, InteropUtil.DWL_MSGRESULT, results);
                    return((IntPtr)results);
                }
                break;
            }

            case InteropUtil.WM_SIZE:
            {
                ResizeCustomControl(hWnd);
                break;
            }

            case (InteropUtil.BN_CLICKED << 16) | InteropUtil.IDOK:
            {
                break;
            }

            case InteropUtil.WM_COMMAND:
            {
                unchecked
                {
                    IntPtr hParent = InteropUtil.AssumeNonZero(InteropUtil.GetParent(hWnd));
                    uint   code    = HIGH((uint)wParam);
                    uint   id      = LOW((uint)wParam);
                    if (code == InteropUtil.BN_CLICKED)
                    {
                        switch (id)
                        {
                        case InteropUtil.ID_CUSTOM_CANCEL:
                        {
                            //The user clicked our custom cancel button. Close the dialog.
                            InteropUtil.SendMessage(hParent, InteropUtil.WM_CLOSE, 0, 0);
                            break;
                        }

                        case InteropUtil.ID_SELECT:
                        {
                            if (ProcessSelection(hParent, true))
                            {
                                InteropUtil.SendMessage(hParent, InteropUtil.WM_CLOSE, 0, 0);
                                break;
                            }
                            //The user has not selected an existing folder.
                            //So we translate a click of our "Select" button into the OK button and forward the request to the
                            //open file dialog.
                            InteropUtil.SendMessage
                                (hParent,
                                InteropUtil.WM_COMMAND,
                                (InteropUtil.BN_CLICKED << 16) | InteropUtil.IDOK,
                                unchecked ((uint)InteropUtil.GetDlgItem(hParent, InteropUtil.IDOK))
                                );


                            break;
                        }
                        }
                    }
                }
                break;
            }
            }
            return(base.HookProc(hWnd, msg, wParam, lparam));
        }
        protected override bool RunDialog(IntPtr hwndOwner)
        {
            InteropUtil.Assume(Marshal.SystemDefaultCharSize == 2, "The character size should be 2");

            IntPtr nativeBuffer = Marshal.AllocCoTaskMem(InteropUtil.NumberOfFileChars * 2);
            IntPtr filterBuffer = IntPtr.Zero;

            _selected = new List <string>();

            try
            {
                var openFileName = new InteropUtil.OpenFileName();
                openFileName.Initialize();
                openFileName.hwndOwner = hwndOwner;

                var chars = new char[InteropUtil.NumberOfFileChars];

                try
                {
                    if (File.Exists(Path))
                    {
                        if (AcceptFiles)
                        {
                            string fileName = System.IO.Path.GetFileName(Path);
                            int    length   = Math.Min(fileName.Length, InteropUtil.NumberOfFileChars);
                            fileName.CopyTo(0, chars, 0, length);
                            openFileName.lpstrInitialDir = System.IO.Path.GetDirectoryName(Path);
                        }
                        else
                        {
                            openFileName.lpstrInitialDir = System.IO.Path.GetDirectoryName(Path);
                        }
                    }
                    else if (Directory.Exists(Path))
                    {
                        openFileName.lpstrInitialDir = Path;
                    }
                    else
                    {
                        //the path does not exist.
                        //We don't just want to throw it away, however.
                        //The initial path we get is most likely provided by the user in some way.
                        //It could be what they typed into a text box before clicking a browse button,
                        //or it could be a value they had entered previously that used to be valid, but now no longer exists.
                        //In any case, we don't want to throw out the user's text. So, we find the first parent
                        //directory of Path that exists on disk.
                        //We will set the initial directory to that path, and then set the initial file to
                        //the rest of the path. The user will get an error if the click "OK"m saying that the selected path
                        //doesn't exist, but that's ok. If we didn't do this, and showed the path, if they clicked
                        //OK without making changes we would actually change the selected path, which would be bad.
                        //This way, if the users want's to change the folder, he actually has to change something.
                        string pathToShow;
                        InitializePathDNE(Path, out openFileName.lpstrInitialDir, out pathToShow);
                        pathToShow = pathToShow ?? String.Empty;
                        int length = Math.Min(pathToShow.Length, InteropUtil.NumberOfFileChars);
                        pathToShow.CopyTo(0, chars, 0, length);
                    }
                }
                catch
                {
                }

                Marshal.Copy(chars, 0, nativeBuffer, chars.Length);

                openFileName.lpstrFile = nativeBuffer;

                if (!AcceptFiles)
                {
                    string str = string.Format("Folders\0*.{0}-{1}\0\0", Guid.NewGuid().ToString("N"),
                                               Guid.NewGuid().ToString("N"));
                    filterBuffer = openFileName.lpstrFilter = Marshal.StringToCoTaskMemUni(str);
                }
                else
                {
                    openFileName.lpstrFilter = IntPtr.Zero;
                }

                openFileName.nMaxCustFilter = 0;
                openFileName.nFilterIndex   = 0;
                openFileName.nMaxFile       = InteropUtil.NumberOfFileChars;
                openFileName.nMaxFileTitle  = 0;
                openFileName.lpstrTitle     = Title;
                openFileName.lpfnHook       = m_hookDelegate;
                openFileName.templateID     = InteropUtil.IDD_CustomOpenDialog;
                openFileName.hInstance      = Marshal.GetHINSTANCE(typeof(SelectFileAndFolderDialog).Module);
                openFileName.Flags          =
                    InteropUtil.OFN_DONTADDTORECENT |
                    InteropUtil.OFN_ENABLEHOOK |
                    InteropUtil.OFN_ENABLESIZING |
                    InteropUtil.OFN_NOTESTFILECREATE |
                    InteropUtil.OFN_ALLOWMULTISELECT |
                    InteropUtil.OFN_EXPLORER |
                    InteropUtil.OFN_FILEMUSTEXIST |
                    InteropUtil.OFN_PATHMUSTEXIST |
                    InteropUtil.OFN_NODEREFERENCELINKS |
                    InteropUtil.OFN_ENABLETEMPLATE |
                    (ShowReadOnly ? 0 : InteropUtil.OFN_HIDEREADONLY);

                m_useCurrentDir = false;
                bool hideFileExtSettingChanged = false;

                try
                {
                    if (GetHideFileExtensionSetting())
                    {
                        HideFileExtension(false);
                        hideFileExtSettingChanged = true;
                    }

                    bool ret = false;
                    try
                    {
                        ret = InteropUtil.GetOpenFileNameW(ref openFileName);
                    }
                    catch (Exception e)
                    {
                        IntPtr hParent = InteropUtil.AssumeNonZero(InteropUtil.GetParent(m_hWnd));
                        InteropUtil.SendMessage(hParent, InteropUtil.WM_CLOSE, 0, 0);
                        throw e;
                    }
                    //var extErrpr = InteropUtil.CommDlgExtendedError();
                    //InteropUtil.CheckForWin32Error();

                    if (m_useCurrentDir)
                    {
                        Path = m_currentFolder;
                        return(true);
                    }
                    else if (ret)
                    {
                        Marshal.Copy(nativeBuffer, chars, 0, chars.Length);
                        int firstZeroTerm = ((IList)chars).IndexOf('\0');
                        if (firstZeroTerm >= 0 && firstZeroTerm <= chars.Length - 1)
                        {
                            Path = new string(chars, 0, firstZeroTerm);
                        }
                    }
                    return(ret);
                }
                finally
                {
                    //revert registry setting
                    if (hideFileExtSettingChanged)
                    {
                        HideFileExtension(true);
                    }
                }
            }
            finally
            {
                Marshal.FreeCoTaskMem(nativeBuffer);
                if (filterBuffer != IntPtr.Zero)
                {
                    Marshal.FreeCoTaskMem(filterBuffer);
                }
            }
        }
Beispiel #14
0
        private int ProcessNotifyMessage(IntPtr hWnd, InteropUtil.OFNOTIFY notifyData)
        {
            switch (notifyData.hdr_code)
            {
            case InteropUtil.CDN_FOLDERCHANGE:
            {
                //CDM_GETFOLDERPATH returns garbage for some standard folders like 'Libraries'
                //var newFolder = GetTextFromCommonDialog(InteropUtil.AssumeNonZero(InteropUtil.GetParent(hWnd)),
                //                  InteropUtil.CDM_GETFOLDERPATH);
                var newFolder = GetTextFromCommonDialog(InteropUtil.AssumeNonZero(InteropUtil.GetParent(hWnd)),
                                                        InteropUtil.CDM_GETFILEPATH);

                /*
                 * if (m_currentFolder != null && newFolder != null &&
                 *  Util.PathContains(newFolder, m_currentFolder))
                 * {
                 *  m_suppressSelectionChange = true;
                 * }
                 */

                m_currentFolder = newFolder;
                var fileNameCombo =
                    InteropUtil.AssumeNonZero(
                        InteropUtil.GetDlgItem(InteropUtil.AssumeNonZero(InteropUtil.GetParent(hWnd)),
                                               InteropUtil.ID_FileNameCombo));
                if (m_hasDirChangeFired)
                {
                    InteropUtil.SetWindowTextW(fileNameCombo, "");
                }
                m_hasDirChangeFired = true;

                //refresh the file list to make sure that the extension is shown properly
                var hParent = InteropUtil.AssumeNonZero(InteropUtil.GetParent(hWnd));
                SetForegroundWindow(hParent);
                SendKeys.SendWait("{F5}");

                break;
            }

            case InteropUtil.CDN_FILEOK:
            {
                if (!AcceptFiles)
                {
                    return(1);
                }

                var hParent = InteropUtil.AssumeNonZero(InteropUtil.GetParent(hWnd));
                ProcessSelection(hParent, false);

                break;
            }

            case InteropUtil.CDN_INITDONE:
            {
                var hParent = InteropUtil.GetParent(hWnd);
                var hFile   =
                    InteropUtil.AssumeNonZero(InteropUtil.GetDlgItem(InteropUtil.AssumeNonZero(hParent),
                                                                     InteropUtil.ID_FileNameCombo));
                InteropUtil.SetFocus(hFile);
                break;
            }
            }
            return(0);
        }