Mercurial > dwindows
view win/XBrowseForFolder.cpp @ 1362:412af8059331
Attempt to get it building with Mingw again... builds but crashes.
Fix building DLL without HTML widget support... Mingw is missing required headers.
Moved wrapper functions into the main source file so it will export the APIs even if unsupported.
Removed debugging code from XBrowseForFolder.cpp because Mingw does not support it.
author | bsmith@81767d24-ef19-dc11-ae90-00e081727c95 |
---|---|
date | Fri, 18 Nov 2011 18:56:40 +0000 |
parents | bf3a6d596cd4 |
children | f8d1da63fb77 |
line wrap: on
line source
// XBrowseForFolder.cpp Version 1.2 // // Author: Hans Dietrich // hdietrich@gmail.com // // Description: // XBrowseForFolder.cpp implements XBrowseForFolder(), a function that // wraps SHBrowseForFolder(). // // History // Version 1.2 - 2008 February 29 // - Changed API to allow for initial CSIDL. // - Added option to set dialog caption, suggested by SimpleDivX. // - Added option to set root, suggested by Jean-Michel Reghem. // // Version 1.1 - 2003 September 29 (not released) // - Added support for edit box // // Version 1.0 - 2003 September 25 // - Initial public release // // License: // This software is released into the public domain. You are free to use // it in any way you like, except that you may not sell this source code. // // This software is provided "as is" with no expressed or implied warranty. // I accept no liability for any damage or loss of business that this // software may cause. // /////////////////////////////////////////////////////////////////////////////// /* Make sure we get the right version */ #define _WIN32_IE 0x0500 #ifndef __AFX_H__ #include "windows.h" #include "tchar.h" #endif #include "Shlobj.h" #include "io.h" #include "XBrowseForFolder.h" #ifndef __MINGW32__ #pragma warning(disable: 4127) // conditional expression is constant (_ASSERTE) #pragma warning(disable : 4996) // disable bogus deprecation warning #endif /* MingW does not have this */ #if !defined(BIF_NONEWFOLDERBUTTON) # define BIF_NONEWFOLDERBUTTON 0x200 #endif //============================================================================= // struct to pass to callback function //============================================================================= struct FOLDER_PROPS { LPCTSTR lpszTitle; LPCTSTR lpszInitialFolder; UINT ulFlags; }; #ifndef __AFX_H__ /////////////////////////////////////////////////////////////////////////////// // CRect - a minimal CRect class class CRect : public tagRECT { public: //CRect() { } CRect(int l = 0, int t = 0, int r = 0, int b = 0) { left = l; top = t; right = r; bottom = b; } int Width() const { return right - left; } int Height() const { return bottom - top; } void SwapLeftRight() { SwapLeftRight(LPRECT(this)); } static void SwapLeftRight(LPRECT lpRect) { LONG temp = lpRect->left; lpRect->left = lpRect->right; lpRect->right = temp; } operator LPRECT() { return this; } }; #endif /////////////////////////////////////////////////////////////////////////////// // ScreenToClientX - helper function in case non-MFC static void ScreenToClientX(HWND hWnd, LPRECT lpRect) { ::ScreenToClient(hWnd, (LPPOINT)lpRect); ::ScreenToClient(hWnd, ((LPPOINT)lpRect)+1); } /////////////////////////////////////////////////////////////////////////////// // MoveWindowX - helper function in case non-MFC static void MoveWindowX(HWND hWnd, CRect& rect, BOOL bRepaint) { ::MoveWindow(hWnd, rect.left, rect.top, rect.Width(), rect.Height(), bRepaint); } /////////////////////////////////////////////////////////////////////////////// // SizeBrowseDialog - resize dialog, move controls static void SizeBrowseDialog(HWND hWnd, FOLDER_PROPS *fp) { // find the folder tree and make dialog larger HWND hwndTree = FindWindowEx(hWnd, NULL, _T("SysTreeView32"), NULL); if (!hwndTree) { // ... this usually means that BIF_NEWDIALOGSTYLE is enabled. // Then the class name is as used in the code below. hwndTree = FindWindowEx(hWnd, NULL, _T("SHBrowseForFolder ShellNameSpace Control"), NULL); } CRect rectDlg; if (hwndTree) { // check if edit box int nEditHeight = 0; HWND hwndEdit = FindWindowEx(hWnd, NULL, _T("Edit"), NULL); CRect rectEdit; if (hwndEdit && (fp->ulFlags & BIF_EDITBOX)) { ::GetWindowRect(hwndEdit, &rectEdit); ScreenToClientX(hWnd, &rectEdit); nEditHeight = rectEdit.Height(); } else if (hwndEdit) { ::MoveWindow(hwndEdit, 20000, 20000, 10, 10, FALSE); ::ShowWindow(hwndEdit, SW_HIDE); hwndEdit = 0; } // make the dialog larger ::GetWindowRect(hWnd, &rectDlg); rectDlg.right += 40; rectDlg.bottom += 30; if (hwndEdit) rectDlg.bottom += nEditHeight + 5; MoveWindowX(hWnd, rectDlg, TRUE); ::GetClientRect(hWnd, &rectDlg); int hMargin = 10; int vMargin = 10; // check if new dialog style - this means that there will be a resizing // grabber in lower right corner if (fp->ulFlags & BIF_NEWDIALOGSTYLE) hMargin = ::GetSystemMetrics(SM_CXVSCROLL); // move the Cancel button CRect rectCancel; HWND hwndCancel = ::GetDlgItem(hWnd, IDCANCEL); if (hwndCancel) ::GetWindowRect(hwndCancel, &rectCancel); ScreenToClientX(hWnd, &rectCancel); int h = rectCancel.Height(); int w = rectCancel.Width(); rectCancel.bottom = rectDlg.bottom - vMargin;//nMargin; rectCancel.top = rectCancel.bottom - h; rectCancel.right = rectDlg.right - hMargin; //(scrollWidth + 2*borderWidth); rectCancel.left = rectCancel.right - w; if (hwndCancel) { MoveWindowX(hwndCancel, rectCancel, FALSE); } // move the OK button CRect rectOK(0, 0, 0, 0); HWND hwndOK = ::GetDlgItem(hWnd, IDOK); if (hwndOK) ::GetWindowRect(hwndOK, &rectOK); ScreenToClientX(hWnd, &rectOK); rectOK.bottom = rectCancel.bottom; rectOK.top = rectCancel.top; rectOK.right = rectCancel.left - 10; rectOK.left = rectOK.right - w; if (hwndOK) { MoveWindowX(hwndOK, rectOK, FALSE); } // expand the folder tree to fill the dialog CRect rectTree; ::GetWindowRect(hwndTree, &rectTree); ScreenToClientX(hWnd, &rectTree); if (hwndEdit) { rectEdit.left = hMargin; rectEdit.right = rectDlg.right - hMargin; rectEdit.top = vMargin; rectEdit.bottom = rectEdit.top + nEditHeight; MoveWindowX(hwndEdit, rectEdit, FALSE); rectTree.top = rectEdit.bottom + 5; } else { rectTree.top = vMargin; } rectTree.left = hMargin; rectTree.bottom = rectOK.top - 10;//nMargin; rectTree.right = rectDlg.right - hMargin; MoveWindowX(hwndTree, rectTree, FALSE); } } /////////////////////////////////////////////////////////////////////////////// // BrowseCallbackProc - SHBrowseForFolder callback function static int CALLBACK BrowseCallbackProc(HWND hWnd, // Window handle to the browse dialog box UINT uMsg, // Value identifying the event LPARAM lParam, // Value dependent upon the message LPARAM lpData) // Application-defined value that was // specified in the lParam member of the // BROWSEINFO structure { switch (uMsg) { case BFFM_INITIALIZED: // sent when the browse dialog box has finished initializing. { // remove context help button from dialog caption LONG lStyle = ::GetWindowLong(hWnd, GWL_STYLE); lStyle &= ~DS_CONTEXTHELP; ::SetWindowLong(hWnd, GWL_STYLE, lStyle); lStyle = ::GetWindowLong(hWnd, GWL_EXSTYLE); lStyle &= ~WS_EX_CONTEXTHELP; ::SetWindowLong(hWnd, GWL_EXSTYLE, lStyle); FOLDER_PROPS *fp = (FOLDER_PROPS *) lpData; if (fp) { if (fp->lpszInitialFolder && (fp->lpszInitialFolder[0] != _T('\0'))) { // set initial directory ::SendMessage(hWnd, BFFM_SETSELECTION, TRUE, (LPARAM)fp->lpszInitialFolder); } if (fp->lpszTitle && (fp->lpszTitle[0] != _T('\0'))) { // set window caption ::SetWindowText(hWnd, fp->lpszTitle); } } SizeBrowseDialog(hWnd, fp); } break; case BFFM_SELCHANGED: // sent when the selection has changed { TCHAR szDir[MAX_PATH*2] = { 0 }; // fail if non-filesystem BOOL bRet = SHGetPathFromIDList((LPITEMIDLIST) lParam, szDir); if (bRet) { // fail if folder not accessible if (_taccess(szDir, 00) != 0) { bRet = FALSE; } else { SHFILEINFO sfi; ::SHGetFileInfo((LPCTSTR)lParam, 0, &sfi, sizeof(sfi), SHGFI_PIDL | SHGFI_ATTRIBUTES); // fail if pidl is a link if (sfi.dwAttributes & SFGAO_LINK) { bRet = FALSE; } } } // if invalid selection, disable the OK button if (!bRet) { ::EnableWindow(GetDlgItem(hWnd, IDOK), FALSE); } } break; } return 0; } /////////////////////////////////////////////////////////////////////////////// // // XBrowseForFolder() // // Purpose: Invoke the SHBrowseForFolder API. If lpszInitialFolder is // supplied, it will be the folder initially selected in the tree // folder list. Otherwise, the initial folder will be set to the // current directory. The selected folder will be returned in // lpszBuf. // // Parameters: hWnd - handle to the owner window for the dialog // lpszInitialFolder - initial folder in tree; if NULL, the initial // folder will be the current directory; if // if this is a CSIDL, must be a real folder. // nRootFolder - optional CSIDL of root folder for tree; // -1 = use default. // lpszCaption - optional caption for folder dialog // lpszBuf - buffer for the returned folder path // dwBufSize - size of lpszBuf in TCHARs // bEditBox - TRUE = include edit box in dialog // // Returns: BOOL - TRUE = success; FALSE = user hit Cancel // BOOL _cdecl XBrowseForFolder(HWND hWnd, LPCTSTR lpszInitialFolder, int nRootFolder, LPCTSTR lpszCaption, LPTSTR lpszBuf, DWORD dwBufSize, BOOL bEditBox /*= FALSE*/) { if (lpszBuf == NULL || dwBufSize < MAX_PATH) return FALSE; ZeroMemory(lpszBuf, dwBufSize*sizeof(TCHAR)); BROWSEINFO bi = { 0 }; // check if there is a special root folder LPITEMIDLIST pidlRoot = NULL; if (nRootFolder != -1) { if (SUCCEEDED(SHGetSpecialFolderLocation(hWnd, nRootFolder, &pidlRoot))) bi.pidlRoot = pidlRoot; } TCHAR szInitialPath[MAX_PATH*2] = { _T('\0') }; if (lpszInitialFolder) { // is this a folder path string or a csidl? if (HIWORD(lpszInitialFolder) == 0) { // csidl int nFolder = LOWORD((UINT)(UINT_PTR)lpszInitialFolder); SHGetSpecialFolderPath(hWnd, szInitialPath, nFolder, FALSE); } else { // string _tcsncpy(szInitialPath, lpszInitialFolder, sizeof(szInitialPath)/sizeof(TCHAR)-2); } } if ((szInitialPath[0] == _T('\0')) && (bi.pidlRoot == NULL)) { // no initial folder and no root, set to current directory ::GetCurrentDirectory(sizeof(szInitialPath)/sizeof(TCHAR)-2, szInitialPath); } FOLDER_PROPS fp; bi.hwndOwner = hWnd; bi.ulFlags = BIF_RETURNONLYFSDIRS; // do NOT use BIF_NEWDIALOGSTYLE, // or BIF_STATUSTEXT if (bEditBox) bi.ulFlags |= BIF_EDITBOX; bi.ulFlags |= BIF_NONEWFOLDERBUTTON; bi.lpfn = BrowseCallbackProc; bi.lParam = (LPARAM) &fp; fp.lpszInitialFolder = szInitialPath; fp.lpszTitle = lpszCaption; fp.ulFlags = bi.ulFlags; BOOL bRet = FALSE; LPITEMIDLIST pidlFolder = SHBrowseForFolder(&bi); if (pidlFolder) { TCHAR szBuffer[MAX_PATH*2] = { _T('\0') }; if (SHGetPathFromIDList(pidlFolder, szBuffer)) { _tcsncpy(lpszBuf, szBuffer, dwBufSize-1); bRet = TRUE; } } // free up pidls IMalloc *pMalloc = NULL; if (SUCCEEDED(SHGetMalloc(&pMalloc)) && pMalloc) { if (pidlFolder) pMalloc->Free(pidlFolder); if (pidlRoot) pMalloc->Free(pidlRoot); pMalloc->Release(); } return bRet; }