source: liacs/MIR2010/SourceCode/XBrowseForFolder.h@ 329

Last change on this file since 329 was 95, checked in by Rick van der Zwet, 15 years ago

Bad boy, improper move of directory

File size: 8.0 KB
Line 
1// XBrowseForFolder.h Version 1.0
2//
3// Author: Hans Dietrich
4// hdietrich2@hotmail.com
5//
6// Description:
7// XBrowseForFolder.cpp implements XBrowseForFolder(), a function that
8// wraps SHBrowseForFolder().
9//
10// History
11// Version 1.0 - 2003 September 25
12// - Initial public release
13//
14// This software is released into the public domain. You are free to use it
15// in any way you like.
16//
17// This software is provided "as is" with no expressed or implied warranty.
18// I accept no liability for any damage or loss of business that this software
19// may cause.
20//
21///////////////////////////////////////////////////////////////////////////////
22
23#include <assert.h>
24#include <io.h>
25#include <shlobj.h>
26#include <shellapi.h>
27
28///////////////////////////////////////////////////////////////////////////////
29// ScreenToClientX - helper function
30static void ScreenToClientX(HWND hWnd, LPRECT lpRect)
31{
32 assert(::IsWindow(hWnd));
33 ::ScreenToClient(hWnd, (LPPOINT)lpRect);
34 ::ScreenToClient(hWnd, ((LPPOINT)lpRect)+1);
35}
36
37///////////////////////////////////////////////////////////////////////////////
38// MoveWindowX - helper function
39static void MoveWindowX(HWND hWnd, RECT& rect, BOOL bRepaint)
40{
41 assert(::IsWindow(hWnd));
42 ::MoveWindow(hWnd, rect.left, rect.top,
43 rect.right-rect.left, rect.bottom-rect.top, bRepaint);
44}
45
46///////////////////////////////////////////////////////////////////////////////
47// XBROWSE_FOLDERINFO - structure to pass folder properties to the dialog
48struct XBROWSE_FOLDERINFO
49{
50 LPCSTR lpszInitialFolder;
51 LPCSTR lpszCaption;
52};
53
54///////////////////////////////////////////////////////////////////////////////
55// BrowseCallbackProc - SHBrowseForFolder callback function
56static int CALLBACK BrowseCallbackProc(HWND hwnd, // Window handle to the browse dialog box
57 UINT uMsg, // Value identifying the event
58 LPARAM lParam, // Value dependent upon the message
59 LPARAM lpData) // Application-defined value that was
60 // specified in the lParam member of the
61 // BROWSEINFO structure
62{
63 switch (uMsg)
64 {
65 case BFFM_INITIALIZED: // sent when the browse dialog box has finished initializing.
66 {
67 // remove context help button from dialog caption
68 LONG lStyle = ::GetWindowLong(hwnd, GWL_STYLE);
69 lStyle &= ~DS_CONTEXTHELP;
70 ::SetWindowLong(hwnd, GWL_STYLE, lStyle);
71 lStyle = ::GetWindowLong(hwnd, GWL_EXSTYLE);
72 lStyle &= ~WS_EX_CONTEXTHELP;
73 ::SetWindowLong(hwnd, GWL_EXSTYLE, lStyle);
74
75 // extract folder properties
76 XBROWSE_FOLDERINFO *xinfo = (XBROWSE_FOLDERINFO *)lpData;
77 // set caption
78 if (xinfo->lpszCaption)
79 ::SetWindowText(hwnd, xinfo->lpszCaption);
80 // set initial directory
81 if (xinfo->lpszInitialFolder)
82 ::SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)xinfo->lpszInitialFolder);
83
84 // find the folder tree and make dialog larger
85 HWND hwndTree = FindWindowEx(hwnd, NULL, "SysTreeView32", NULL);
86 if (hwndTree)
87 {
88 // make the dialog larger
89 RECT rectDlg;
90 ::GetWindowRect(hwnd, &rectDlg);
91 rectDlg.right += 40;
92 rectDlg.bottom += 30;
93 MoveWindowX(hwnd, rectDlg, TRUE);
94 ::GetClientRect(hwnd, &rectDlg);
95
96 // move the Cancel button
97 RECT rectCancel = {0};
98 HWND hwndCancel = ::GetDlgItem(hwnd, IDCANCEL);
99 if (hwndCancel)
100 ::GetWindowRect(hwndCancel, &rectCancel);
101 ScreenToClientX(hwnd, &rectCancel);
102 int w = rectCancel.right-rectCancel.left;
103 int h = rectCancel.bottom-rectCancel.top;
104 rectCancel.bottom = rectDlg.bottom - 5;
105 rectCancel.top = rectCancel.bottom - h;
106 rectCancel.right = rectDlg.right - 5;
107 rectCancel.left = rectCancel.right - w;
108 if (hwndCancel)
109 MoveWindowX(hwndCancel, rectCancel, FALSE);
110
111 // move the OK button
112 RECT rectOK = {0};
113 HWND hwndOK = ::GetDlgItem(hwnd, IDOK);
114 if (hwndOK)
115 ::GetWindowRect(hwndOK, &rectOK);
116 ScreenToClientX(hwnd, &rectOK);
117 rectOK.bottom = rectDlg.bottom - 5;
118 rectOK.top = rectOK.bottom - h;
119 rectOK.right = rectCancel.left - 10;
120 rectOK.left = rectOK.right - w;
121 if (hwndOK)
122 MoveWindowX(hwndOK, rectOK, FALSE);
123
124 // expand the folder tree to fill the dialog
125 RECT rectTree;
126 ::GetWindowRect(hwndTree, &rectTree);
127 ScreenToClientX(hwnd, &rectTree);
128 rectTree.top = 5;
129 rectTree.left= 5;
130 rectTree.bottom = rectOK.top - 5;
131 rectTree.right = rectDlg.right - 5;
132 MoveWindowX(hwndTree, rectTree, FALSE);
133 }
134 else
135 {
136 ::OutputDebugString("ERROR - tree control not found.\n");
137 assert(hwndTree);
138 }
139 }
140 break;
141
142 case BFFM_SELCHANGED: // sent when the selection has changed
143 {
144 char szDir[_MAX_PATH] = { 0 };
145
146 // fail if non-filesystem
147 BOOL bRet = SHGetPathFromIDList((LPITEMIDLIST) lParam, szDir);
148 if (bRet)
149 {
150 // fail if folder not accessible
151 if (_access(szDir, 00) != 0)
152 {
153 bRet = FALSE;
154 }
155 else
156 {
157 SHFILEINFO sfi;
158 ::SHGetFileInfo((LPCTSTR)lParam, 0, &sfi, sizeof(sfi),
159 SHGFI_PIDL | SHGFI_ATTRIBUTES);
160 //::OutputDebugString("dwAttributes=0x%08X\n", sfi.dwAttributes);
161
162 // fail if pidl is a link
163 if (sfi.dwAttributes & SFGAO_LINK)
164 {
165 //::OutputDebugString("SFGAO_LINK\n");
166 bRet = FALSE;
167 }
168 }
169 }
170
171 // if invalid selection, disable the OK button
172 if (!bRet)
173 {
174 ::EnableWindow(GetDlgItem(hwnd, IDOK), FALSE);
175 }
176
177 //::OutputDebugString("szDir=%s\n", szDir);
178 }
179 break;
180 }
181
182 return 0;
183}
184
185///////////////////////////////////////////////////////////////////////////////
186//
187// XBrowseForFolder()
188//
189// Purpose: Invoke the SHBrowseForFolder API. If lpszInitialFolder is
190// supplied, it will be the folder initially selected in the tree
191// folder list. Otherwise, the initial folder will be set to the
192// current directory. The selected folder will be returned in
193// lpszBuf.
194//
195// Parameters: hWnd - handle to the owner window for the dialog
196// lpszCaption - text in title bar
197// lpszInitialFolder - initial folder in tree; if NULL, the initial
198// folder will be the current directory.
199// lpszBuf - buffer for the returned folder path
200// dwBufSize - size of lpszBuf in chars
201//
202// Returns: BOOL - TRUE = success; FALSE = user hit Cancel
203//
204BOOL XBrowseForFolder(HWND hWnd,
205 LPCSTR lpszCaption,
206 LPCSTR lpszInitialFolder,
207 LPSTR lpszBuf,
208 DWORD dwBufSize)
209{
210 assert(lpszBuf);
211 assert(dwBufSize >= MAX_PATH);
212
213 if (lpszBuf == NULL || dwBufSize < MAX_PATH)
214 return FALSE;
215
216 lpszBuf[0] = '\0';
217
218 char szInitialPath[_MAX_PATH];
219 ZeroMemory(szInitialPath, sizeof(szInitialPath));
220
221 if (lpszInitialFolder && lpszInitialFolder[0] != '\0')
222 strncpy(szInitialPath, lpszInitialFolder, sizeof(szInitialPath) - 1);
223 else
224 {
225 // no initial folder, set to current directory
226 ::GetCurrentDirectory(sizeof(szInitialPath) - 1, szInitialPath);
227 }
228
229 // set folder properties
230 XBROWSE_FOLDERINFO xinfo;
231 xinfo.lpszInitialFolder = szInitialPath;
232 xinfo.lpszCaption = lpszCaption;
233
234 BROWSEINFO bi;
235 ZeroMemory(&bi, sizeof(BROWSEINFO));
236
237 bi.hwndOwner = hWnd;
238 bi.ulFlags = BIF_RETURNONLYFSDIRS; // do NOT use BIF_NEWDIALOGSTYLE,
239 // BIF_EDITBOX, or BIF_STATUSTEXT
240 bi.lpfn = BrowseCallbackProc;
241 bi.lParam = (LPARAM) &xinfo;
242
243 LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
244
245 BOOL bRet = FALSE;
246
247 if (pidl)
248 {
249 char szBuffer[_MAX_PATH];
250 szBuffer[0] = '\0';
251
252 if (SHGetPathFromIDList(pidl, szBuffer))
253 {
254 ZeroMemory(lpszBuf, dwBufSize);
255 strncpy(lpszBuf, szBuffer, dwBufSize-1);
256 bRet = TRUE;
257 }
258 else
259 {
260 ::OutputDebugString("SHGetPathFromIDList failed\n");
261 }
262
263 IMalloc *pMalloc = NULL;
264 if (SUCCEEDED(SHGetMalloc(&pMalloc)) && pMalloc)
265 {
266 pMalloc->Free(pidl);
267 pMalloc->Release();
268 }
269 }
270
271 return bRet;
272}
Note: See TracBrowser for help on using the repository browser.