Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

lboxctl3.c

Go to the documentation of this file.
00001 /****************************************************************************\ 00002 * 00003 * LBOXCTL3.C - 00004 * 00005 * Copyright (c) 1985 - 1999, Microsoft Corporation 00006 * 00007 * Directory List Box Routines 00008 * 00009 * ??-???-???? ianja Ported from Win 3.0 sources 00010 * 14-Feb-1991 mikeke Added Revalidation code 00011 \****************************************************************************/ 00012 00013 #define CTLMGR 00014 #define LSTRING 00015 00016 #include "precomp.h" 00017 #pragma hdrstop 00018 00019 #define DATESEPARATOR TEXT('-') 00020 #define TIMESEPARATOR TEXT(':') 00021 #define TABCHAR TEXT('\t') 00022 00023 #define MAXDIGITSINSIZE 9 00024 00025 void LB_CreateLBLine(LPWIN32_FIND_DATA, LPWSTR); 00026 00027 #define DDL_PRIVILEGES (DDL_READONLY | DDL_HIDDEN | DDL_SYSTEM | DDL_ARCHIVE) 00028 #define DDL_TYPE (DDL_DRIVES | DDL_DIRECTORY | DDL_POSTMSGS) 00029 00030 /***************************************************************************\ 00031 * ChopText 00032 * 00033 * Chops the given path at 'lpchBuffer' + CCH_CHOPTEXT_EXTRA to fit in the 00034 * field of the static control with id 'idStatic' in the dialog box 'hwndDlg'. 00035 * If the path is too long, an ellipsis prefix is added to the beginning of the 00036 * chopped text ("x:\...\") 00037 * 00038 * If the supplied path does not fit and the last directory appended to 00039 * ellipsis (i.e. "c:\...\eee" in the case of "c:\aaa\bbb\ccc\ddd\eee") 00040 * does not fit, then "x:\..." is returned. 00041 * 00042 * Pathological case: 00043 * "c:\SW\MW\R2\LIB\SERVICES\NT" almost fits into static control, while 00044 * "c:\...\MW\R2\LIB\SERVICES\NT" does fit - although it is more characters. 00045 * In this case, ChopText substitutes the first 'n' characters of the path with 00046 * a prefix containing MORE than 'n' characters! The extra characters will 00047 * be put in front of lpch, so there must be space reserved for them or they 00048 * will trash the stack. lpch contains CCH_CHOPTEXT_EXTRA chars followed by 00049 * the path. 00050 * 00051 * History: 00052 \***************************************************************************/ 00053 00054 /* 00055 * In practice CCH_CHOPTEXT_EXTRA probably never has to be more than 1 or 2, 00056 * but in case the font is weird, set it to the number of chars in the prefix. 00057 * This guarantees enough space to prepend the prefix. 00058 */ 00059 #define CCH_CHOPTEXT_EXTRA 7 00060 00061 LPWSTR ChopText( 00062 PWND pwndDlg, 00063 int idStatic, 00064 LPWSTR lpchBuffer) 00065 { 00066 #define AWCHLEN(a) ((sizeof(a)/sizeof(a[0])) - 1) 00067 00068 /* 00069 * Declaring szPrefix this way ensures CCH_CHOPTEXT_EXTRA is big enough 00070 */ 00071 WCHAR szPrefix[CCH_CHOPTEXT_EXTRA + 1] = L"x:\\...\\"; 00072 int cxField; 00073 RECT rc; 00074 SIZE size; 00075 PWND pwndStatic; 00076 PSTAT pstat; 00077 HDC hdc; 00078 HFONT hOldFont; 00079 int cchPath; 00080 PWCHAR lpch; 00081 PWCHAR lpchPath; 00082 00083 /* 00084 * Get length of static field. 00085 */ 00086 pwndStatic = _GetDlgItem(pwndDlg, idStatic); 00087 if (pwndStatic == NULL) 00088 return NULL; 00089 00090 _GetClientRect(pwndStatic, &rc); 00091 cxField = rc.right - rc.left; 00092 00093 /* 00094 * Set up DC appropriately for the static control. 00095 */ 00096 hdc = NtUserGetDC(HWq(pwndStatic)); 00097 00098 /* 00099 * Only assume this is a static window if this window uses the static 00100 * window wndproc. 00101 */ 00102 hOldFont = NULL; 00103 if (GETFNID(pwndStatic) == FNID_STATIC) { 00104 pstat = ((PSTATWND)pwndStatic)->pstat; 00105 if (pstat != NULL && pstat != (PSTAT)-1 && pstat->hFont) 00106 hOldFont = SelectObject(hdc, pstat->hFont); 00107 } 00108 00109 /* 00110 * Check horizontal extent of string. 00111 */ 00112 lpch = lpchPath = lpchBuffer + CCH_CHOPTEXT_EXTRA; 00113 cchPath = wcslen(lpchPath); 00114 GetTextExtentPoint(hdc, lpchPath, cchPath, &size); 00115 if (size.cx > cxField) { 00116 00117 /* 00118 * String is too long to fit in the static control; chop it. 00119 * Set up new prefix and determine remaining space in control. 00120 */ 00121 szPrefix[0] = *lpchPath; 00122 GetTextExtentPoint(hdc, szPrefix, AWCHLEN(szPrefix), &size); 00123 00124 /* 00125 * If the field is too small to display all of the prefix, 00126 * copy only the prefix. 00127 */ 00128 if (cxField < size.cx) { 00129 RtlCopyMemory(lpch, szPrefix, sizeof(szPrefix)); 00130 goto DoneChop; 00131 } else 00132 cxField -= size.cx; 00133 00134 /* 00135 * Advance a directory at a time until the remainder of the 00136 * string fits into the static control after the "x:\...\" prefix. 00137 */ 00138 while (TRUE) { 00139 int cchT; 00140 while (*lpch && (*lpch++ != L'\\')) { 00141 ; 00142 } 00143 cchT = cchPath - (int)(lpch - lpchPath); 00144 GetTextExtentPoint(hdc, lpch, cchT, &size); 00145 if (*lpch == 0 || size.cx <= cxField) { 00146 00147 if (*lpch == 0) { 00148 00149 /* 00150 * Nothing could fit after the prefix; remove the 00151 * final "\" from the prefix 00152 */ 00153 szPrefix[AWCHLEN(szPrefix) - 1] = 0; 00154 } 00155 00156 /* 00157 * rest of string fits -- back up and stick prefix on front 00158 * We are guaranteed to have at least CCH_CHOPTEXT_EXTRA chars 00159 * backing up space, so we won't trash any stack. #26453 00160 */ 00161 lpch -= AWCHLEN(szPrefix); 00162 00163 UserAssert(lpch >= lpchBuffer); 00164 00165 RtlCopyMemory(lpch, szPrefix, sizeof(szPrefix) - sizeof(WCHAR)); 00166 goto DoneChop; 00167 } 00168 } 00169 } 00170 00171 DoneChop: 00172 if (hOldFont) 00173 SelectObject(hdc, hOldFont); 00174 00175 ReleaseDC(HWq(pwndStatic), hdc); 00176 00177 return lpch; 00178 } 00179 00180 00181 /***************************************************************************\ 00182 * xxxDlgDirListHelper 00183 * 00184 * NOTE: If idStaticPath is < 0, then that parameter contains the details 00185 * about what should be in each line of the list box 00186 * 00187 * History: 00188 \***************************************************************************/ 00189 00190 BOOL xxxDlgDirListHelper( 00191 PWND pwndDlg, 00192 LPWSTR lpszPathSpec, 00193 LPBYTE lpszPathSpecClient, 00194 int idListBox, 00195 int idStaticPath, 00196 UINT attrib, 00197 BOOL fListBox) /* Listbox or ComboBox? */ 00198 { 00199 PWND pwndLB; 00200 TL tlpwndLB; 00201 BOOL fDir = TRUE; 00202 BOOL fRoot, bRet; 00203 BOOL fPostIt; 00204 INT cch; 00205 WCHAR ch; 00206 WCHAR szStaticPath[CCH_CHOPTEXT_EXTRA + MAX_PATH]; 00207 PWCHAR pszCurrentDir; 00208 UINT wDirMsg; 00209 LPWSTR lpchFile; 00210 LPWSTR lpchDirectory; 00211 PLBIV plb; 00212 BOOL fWasVisible = FALSE; 00213 BOOL fWin40Compat; 00214 PCBOX pcbox; 00215 00216 CheckLock(pwndDlg); 00217 00218 /* 00219 * Strip the private bit DDL_NOFILES out - KidPix passes it in my mistake! 00220 */ 00221 if (attrib & ~DDL_VALID) { 00222 RIPERR2(ERROR_INVALID_FLAGS, RIP_WARNING, "Invalid flags, %x & ~%x != 0", 00223 attrib, DDL_VALID); 00224 return FALSE; 00225 } 00226 00227 if (attrib & DDL_NOFILES) { 00228 RIPMSG0(RIP_WARNING, "DlgDirListHelper: stripping DDL_NOFILES"); 00229 attrib &= ~DDL_NOFILES; 00230 } 00231 00232 /* 00233 * Case:Works is an app that calls DlgDirList with a NULL has hwndDlg; 00234 * This is allowed because he uses NULL for idStaticPath and idListBox. 00235 * So, the validation layer has been modified to allow a NULL for hwndDlg. 00236 * But, we catch the bad apps with the following check. 00237 * Fix for Bug #11864 --SANKAR-- 08/22/91 -- 00238 */ 00239 if (!pwndDlg && (idStaticPath || idListBox)) { 00240 RIPERR0(ERROR_INVALID_PARAMETER, RIP_VERBOSE, ""); 00241 return FALSE; 00242 } 00243 00244 plb = NULL; 00245 00246 /* 00247 * Do we need to add date, time, size or attribute info? 00248 * Windows checks the Atom but misses if the class has been sub-classed 00249 * as in VB. 00250 */ 00251 if (pwndLB = (PWND)_GetDlgItem(pwndDlg, idListBox)) { 00252 WORD fnid = GETFNID(pwndLB); 00253 00254 if ((fnid == FNID_LISTBOX && fListBox) || 00255 (fnid == FNID_COMBOBOX && !fListBox) || 00256 (fnid == FNID_COMBOLISTBOX && fListBox)) { 00257 if (fListBox) { 00258 plb = ((PLBWND)pwndLB)->pLBIV; 00259 } else { 00260 00261 pcbox = ((PCOMBOWND)pwndLB)->pcbox; 00262 plb = ((PLBWND)(pcbox->spwndList))->pLBIV; 00263 } 00264 } else { 00265 RIPERR0(ERROR_LISTBOX_ID_NOT_FOUND, RIP_VERBOSE, ""); 00266 } 00267 } else if (idListBox != 0) { 00268 00269 /* 00270 * Yell if the app passed an invalid list box id and keep from using a 00271 * bogus plb. PLB is NULLed above. 00272 */ 00273 RIPERR0(ERROR_LISTBOX_ID_NOT_FOUND, RIP_VERBOSE, ""); 00274 } 00275 00276 if (idStaticPath < 0 && plb != NULL) { 00277 00278 /* 00279 * Clear idStaticPath because its purpose is over. 00280 */ 00281 idStaticPath = 0; 00282 00283 } 00284 00285 fPostIt = (attrib & DDL_POSTMSGS); 00286 00287 if (lpszPathSpec) { 00288 cch = lstrlenW(lpszPathSpec); 00289 if (!cch) { 00290 if (lpszPathSpecClient != (LPBYTE)lpszPathSpec) { 00291 lpszPathSpecClient = achSlashStar; 00292 } 00293 lpszPathSpec = awchSlashStar; 00294 } else { 00295 /* 00296 * Make sure we won't overflow our buffers... 00297 */ 00298 if (cch > CCHFILEMAX) 00299 return FALSE; 00300 00301 /* 00302 * Convert lpszPathSpec into an upper case, OEM string. 00303 */ 00304 CharUpper(lpszPathSpec); 00305 lpchDirectory = lpszPathSpec; 00306 00307 lpchFile = szSLASHSTARDOTSTAR + 1; 00308 00309 if (*lpchDirectory) { 00310 00311 cch = wcslen(lpchDirectory); 00312 00313 /* 00314 * If the directory name has a * or ? in it, don't bother trying 00315 * the (slow) SetCurrentDirectory. 00316 */ 00317 if (((INT)FindCharPosition(lpchDirectory, TEXT('*')) != cch) || 00318 ((INT)FindCharPosition(lpchDirectory, TEXT('?')) != cch) || 00319 !SetCurrentDirectory(lpchDirectory)) { 00320 00321 /* 00322 * Set 'fDir' and 'fRoot' accordingly. 00323 */ 00324 lpchFile = lpchDirectory + cch; 00325 fDir = *(lpchFile - 1) == TEXT('\\'); 00326 fRoot = 0; 00327 while (cch--) { 00328 ch = *(lpchFile - 1); 00329 if (ch == TEXT('*') || ch == TEXT('?')) 00330 fDir = TRUE; 00331 00332 if (ch == TEXT('\\') || ch == TEXT('/') || ch == TEXT(':')) { 00333 fRoot = (cch == 0 || *(lpchFile - 2) == TEXT(':') || 00334 (ch == TEXT(':'))); 00335 break; 00336 } 00337 lpchFile--; 00338 } 00339 00340 /* 00341 * To remove Bug #16, the following error return is to be removed. 00342 * In order to prevent the existing apps from breaking up, it is 00343 * decided that the bug will not be fixed and will be mentioned 00344 * in the documentation. 00345 * --SANKAR-- Sep 21 00346 */ 00347 00348 /* 00349 * If no wildcard characters, return error. 00350 */ 00351 if (!fDir) { 00352 RIPERR0(ERROR_NO_WILDCARD_CHARACTERS, RIP_VERBOSE, ""); 00353 return FALSE; 00354 } 00355 00356 /* 00357 * Special case for lpchDirectory == "\" 00358 */ 00359 if (fRoot) 00360 lpchFile++; 00361 00362 /* 00363 * Do we need to change directories? 00364 */ 00365 if (fRoot || cch >= 0) { 00366 00367 /* 00368 * Replace the Filename's first char with a nul. 00369 */ 00370 ch = *--lpchFile; 00371 *lpchFile = TEXT('\0'); 00372 00373 /* 00374 * Change the current directory. 00375 */ 00376 if (*lpchDirectory) { 00377 bRet = SetCurrentDirectory(lpchDirectory); 00378 if (!bRet) { 00379 00380 /* 00381 * Restore the filename before we return... 00382 */ 00383 *((LPWSTR)lpchFile)++ = ch; 00384 return FALSE; 00385 } 00386 } 00387 00388 /* 00389 * Restore the filename's first character. 00390 */ 00391 *lpchFile++ = ch; 00392 } 00393 00394 /* 00395 * Undo damage caused by special case above. 00396 */ 00397 if (fRoot) { 00398 lpchFile--; 00399 } 00400 } 00401 } 00402 00403 /* 00404 * This is copying on top of the data the client passed us! Since 00405 * the LB_DIR or CB_DIR could be posted, and since we need to 00406 * pass a client side string pointer when we do that, we need 00407 * to copy this new data back to the client! 00408 */ 00409 if (fPostIt && lpszPathSpecClient != (LPBYTE)lpszPathSpec) { 00410 WCSToMB(lpchFile, -1, &lpszPathSpecClient, MAXLONG, FALSE); 00411 } 00412 wcscpy(lpszPathSpec, lpchFile); 00413 } 00414 } 00415 /* 00416 * In some cases, the ChopText requires extra space ahead of the path: 00417 * Give it CCH_CHOPTEXT_EXTRA extra spaces. (See ChopText() above). 00418 */ 00419 pszCurrentDir = szStaticPath + CCH_CHOPTEXT_EXTRA; 00420 GetCurrentDirectory( 00421 sizeof(szStaticPath)/sizeof(WCHAR) - CCH_CHOPTEXT_EXTRA, 00422 pszCurrentDir); 00423 00424 /* 00425 * If we have a listbox, lock it down 00426 */ 00427 if (pwndLB != NULL) { 00428 ThreadLockAlways(pwndLB, &tlpwndLB); 00429 } 00430 00431 /* 00432 * Fill in the static path item. 00433 */ 00434 if (idStaticPath) { 00435 00436 /* 00437 * To fix a bug OemToAnsi() call is inserted; SANKAR--Sep 16th 00438 */ 00439 // OemToChar(szCurrentDir, szCurrentDir); 00440 CharLower(pszCurrentDir); 00441 SetDlgItemText(HWq(pwndDlg), idStaticPath, ChopText(pwndDlg, idStaticPath, szStaticPath)); 00442 } 00443 00444 /* 00445 * Fill in the directory List/ComboBox if it exists. 00446 */ 00447 if (idListBox && pwndLB != NULL) { 00448 00449 HWND hwndLB = HWq(pwndLB); 00450 00451 wDirMsg = (UINT)(fListBox ? LB_RESETCONTENT : CB_RESETCONTENT); 00452 00453 if (fPostIt) { 00454 PostMessage(hwndLB, wDirMsg, 0, 0L); 00455 } else { 00456 if (plb != NULL && (fWasVisible = IsLBoxVisible(plb))) { 00457 SendMessage(hwndLB, WM_SETREDRAW, FALSE, 0L); 00458 } 00459 SendMessage(hwndLB, wDirMsg, 0, 0L); 00460 } 00461 00462 wDirMsg = (UINT)(fListBox ? LB_DIR : CB_DIR); 00463 00464 if (attrib == DDL_DRIVES) 00465 attrib |= DDL_EXCLUSIVE; 00466 00467 // 00468 // Hack for DDL_EXCLUSIVE to REALLY work. 00469 // 00470 fWin40Compat = TestWF(pwndLB, WFWIN40COMPAT); 00471 00472 // 00473 // BACKWARDS COMPATIBILITY HACK 00474 // 00475 // We want DDL_EXCLUSIVE to _really_ work for new apps. I.E., we 00476 // want apps to be able to specify DDL_DRIVES/DDL_VOLUMES with 00477 // DDL_EXCLUSIVE and privilege bits -- and have only those items 00478 // matching show up, w/out files. 00479 // 00480 if (attrib & DDL_EXCLUSIVE) 00481 { 00482 if (fWin40Compat) 00483 { 00484 if (attrib & (DDL_DRIVES | DDL_DIRECTORY)) 00485 attrib |= DDL_NOFILES; 00486 } 00487 else 00488 { 00489 if (attrib == (DDL_DRIVES | DDL_EXCLUSIVE)) 00490 attrib |= DDL_NOFILES; 00491 } 00492 } 00493 00494 if (!(attrib & DDL_NOFILES)) { 00495 00496 /* 00497 * Add everything except the subdirectories and disk drives. 00498 */ 00499 if (fPostIt) { 00500 /* 00501 * Post lpszPathSpecClient, the client side pointer. 00502 */ 00503 #ifdef WASWIN31 00504 PostMessage(hwndLB, wDirMsg, attrib & 00505 ~(DDL_DIRECTORY | DDL_DRIVES | DDL_POSTMSGS), 00506 (LPARAM)lpszPathSpecClient); 00507 #else 00508 /* 00509 * On NT, keep DDL_POSTMSGS in wParam because we need to know 00510 * in the wndproc whether the pointer is clientside or server 00511 * side. 00512 */ 00513 PostMessage(hwndLB, wDirMsg, 00514 attrib & ~(DDL_DIRECTORY | DDL_DRIVES), 00515 (LPARAM)lpszPathSpecClient); 00516 #endif 00517 00518 } else { 00519 00520 /* 00521 * IanJa: #ifndef WIN16 (32-bit Windows), attrib gets extended 00522 * to LONG wParam automatically by the compiler 00523 */ 00524 SendMessage(hwndLB, wDirMsg, 00525 attrib & ~(DDL_DIRECTORY | DDL_DRIVES), 00526 (LPARAM)lpszPathSpec); 00527 } 00528 00529 #ifdef WASWIN31 00530 /* 00531 * Strip out just the subdirectory and drive bits. 00532 */ 00533 attrib &= (DDL_DIRECTORY | DDL_DRIVES); 00534 #else 00535 // 00536 // B#1433 00537 // The old code stripped out read-only, hidden, system, and archive 00538 // information for subdirectories, making it impossible to have 00539 // a listbox w/ hidden directories! 00540 // 00541 00542 /* 00543 * Strip out just the subdirectory and drive bits. ON NT, keep 00544 * the DDL_POSTMSG bit so we know how to thunk this message. 00545 */ 00546 if (!fWin40Compat) 00547 attrib &= DDL_TYPE; 00548 else 00549 { 00550 attrib &= (DDL_TYPE | (attrib & DDL_PRIVILEGES)); 00551 attrib |= DDL_NOFILES; 00552 } 00553 // attrib &= (DDL_DIRECTORY | DDL_DRIVES | DDL_POSTMSGS); 00554 #endif 00555 } 00556 00557 // 00558 // Add directories and volumes to the listbox. 00559 // 00560 if (attrib & DDL_TYPE) { 00561 00562 /* 00563 * Add the subdirectories and disk drives. 00564 */ 00565 lpszPathSpec = szSLASHSTARDOTSTAR + 1; 00566 00567 attrib |= DDL_EXCLUSIVE; 00568 00569 if (fPostIt) { 00570 /* 00571 * Post lpszPathSpecClient, the client side pointer (see text 00572 * above). 00573 */ 00574 PostMessage(hwndLB, wDirMsg, attrib, (LPARAM)lpszPathSpecClient); 00575 } else { 00576 SendMessage(hwndLB, wDirMsg, attrib, (LPARAM)lpszPathSpec); 00577 } 00578 } 00579 00580 if (!fPostIt && fWasVisible) { 00581 SendMessage(hwndLB, WM_SETREDRAW, TRUE, 0L); 00582 NtUserInvalidateRect(hwndLB, NULL, TRUE); 00583 } 00584 } 00585 00586 if (pwndLB != NULL) { 00587 ThreadUnlock(&tlpwndLB); 00588 } 00589 00590 return TRUE; 00591 } 00592 00593 00594 /***************************************************************************\ 00595 * xxxDlgDirList 00596 * 00597 * History: 00598 \***************************************************************************/ 00599 00600 BOOL DlgDirListA( 00601 HWND hwndDlg, 00602 LPSTR lpszPathSpecClient, 00603 int idListBox, 00604 int idStaticPath, 00605 UINT attrib) 00606 { 00607 LPWSTR lpszPathSpec; 00608 PWND pwndDlg; 00609 TL tlpwndDlg; 00610 BOOL fRet; 00611 00612 pwndDlg = ValidateHwnd(hwndDlg); 00613 00614 if (pwndDlg == NULL) 00615 return FALSE; 00616 00617 lpszPathSpec = NULL; 00618 if (lpszPathSpecClient) { 00619 if (!MBToWCS(lpszPathSpecClient, -1, &lpszPathSpec, -1, TRUE)) 00620 return FALSE; 00621 } 00622 00623 /* 00624 * The last parameter is TRUE to indicate ListBox (not ComboBox) 00625 */ 00626 ThreadLock(pwndDlg, &tlpwndDlg); 00627 fRet = xxxDlgDirListHelper(pwndDlg, lpszPathSpec, lpszPathSpecClient, 00628 idListBox, idStaticPath, attrib, TRUE); 00629 ThreadUnlock(&tlpwndDlg); 00630 00631 if (lpszPathSpec) { 00632 if (fRet) { 00633 /* 00634 * Non-zero retval means some text to copy out. Copy out up to 00635 * the nul terminator (buffer will be big enough). 00636 */ 00637 WCSToMB(lpszPathSpec, -1, &lpszPathSpecClient, MAXLONG, FALSE); 00638 } 00639 UserLocalFree(lpszPathSpec); 00640 } 00641 00642 return fRet; 00643 } 00644 00645 BOOL DlgDirListW( 00646 HWND hwndDlg, 00647 LPWSTR lpszPathSpecClient, 00648 int idListBox, 00649 int idStaticPath, 00650 UINT attrib) 00651 { 00652 LPWSTR lpszPathSpec; 00653 PWND pwndDlg; 00654 TL tlpwndDlg; 00655 BOOL fRet; 00656 00657 pwndDlg = ValidateHwnd(hwndDlg); 00658 00659 if (pwndDlg == NULL) 00660 return FALSE; 00661 00662 lpszPathSpec = lpszPathSpecClient; 00663 00664 /* 00665 * The last parameter is TRUE to indicate ListBox (not ComboBox) 00666 */ 00667 ThreadLock(pwndDlg, &tlpwndDlg); 00668 fRet = xxxDlgDirListHelper(pwndDlg, lpszPathSpec, (LPBYTE)lpszPathSpecClient, 00669 idListBox, idStaticPath, attrib, TRUE); 00670 ThreadUnlock(&tlpwndDlg); 00671 00672 return fRet; 00673 } 00674 00675 00676 /***************************************************************************\ 00677 * DlgDirSelectHelper 00678 * 00679 * History: 00680 \***************************************************************************/ 00681 00682 BOOL DlgDirSelectHelper( 00683 LPWSTR lpszPathSpec, 00684 int chCount, 00685 HWND hwndListBox) 00686 { 00687 INT cch; 00688 LPWSTR lpchFile; 00689 BOOL fDir; 00690 INT sItem; 00691 LPWSTR lpchT; 00692 WCHAR rgch[CCHFILEMAX + 2]; 00693 int cchT; 00694 LARGE_UNICODE_STRING str; 00695 00696 /* 00697 * Callers such as DlgDirSelectEx do not validate the existance 00698 * of hwndListBox 00699 */ 00700 if (hwndListBox == NULL) { 00701 RIPERR0(ERROR_CONTROL_ID_NOT_FOUND, RIP_VERBOSE, ""); 00702 return 0; 00703 } 00704 00705 sItem = (INT)SendMessage(hwndListBox, LB_GETCURSEL, 0, 0L); 00706 if (sItem < 0) 00707 return FALSE; 00708 00709 cchT = (INT)SendMessage(hwndListBox, LB_GETTEXT, sItem, (LPARAM)rgch); 00710 UserAssert(cchT < (sizeof(rgch)/sizeof(rgch[0]))); 00711 00712 lpchFile = rgch; 00713 fDir = (*rgch == TEXT('[')); 00714 00715 /* 00716 * Check if all details along with file name are to be returned. Make sure 00717 * we can find the listbox because with drop down combo boxes, the 00718 * GetDlgItem will fail. 00719 * 00720 * Make sure this window has been using the listbox window proc because 00721 * we store some data as a window long. 00722 */ 00723 00724 /* 00725 * Only the file name is to be returned. Find the end of the filename. 00726 */ 00727 lpchT = lpchFile; 00728 while ((*lpchT) && (*lpchT != TABCHAR)) 00729 lpchT++; 00730 *lpchT = TEXT('\0'); 00731 00732 cch = wcslen(lpchFile); 00733 00734 /* 00735 * Selection is drive or directory. 00736 */ 00737 if (fDir) { 00738 lpchFile++; 00739 cch--; 00740 *(lpchFile + cch - 1) = TEXT('\\'); 00741 00742 /* 00743 * Selection is drive 00744 */ 00745 if (rgch[1] == TEXT('-')) { 00746 lpchFile++; 00747 cch--; 00748 *(lpchFile + 1) = TEXT(':'); 00749 *(lpchFile + 2) = 0; 00750 } 00751 } else { 00752 00753 /* 00754 * Selection is file. If filename has no extension, append '.' 00755 */ 00756 lpchT = lpchFile; 00757 for (; (cch > 0) && (*lpchT != TABCHAR); 00758 cch--, lpchT++) { 00759 if (*lpchT == TEXT('.')) 00760 goto Exit; 00761 } 00762 if (*lpchT == TABCHAR) { 00763 memmove(lpchT + 1, lpchT, CHARSTOBYTES(cch + 1)); 00764 *lpchT = TEXT('.'); 00765 } else { 00766 *lpchT++ = TEXT('.'); 00767 *lpchT = 0; 00768 } 00769 } 00770 00771 Exit: 00772 RtlInitLargeUnicodeString(&str, lpchFile, (UINT)-1); 00773 TextCopy(&str, lpszPathSpec, (UINT)chCount); 00774 return fDir; 00775 } 00776 00777 00778 /***************************************************************************\ 00779 * DlgDirSelectEx 00780 * 00781 * History: 00782 \***************************************************************************/ 00783 00784 BOOL DlgDirSelectExA( 00785 HWND hwndDlg, 00786 LPSTR lpszPathSpec, 00787 int chCount, 00788 int idListBox) 00789 { 00790 LPWSTR lpwsz; 00791 BOOL fRet; 00792 00793 lpwsz = (LPWSTR)UserLocalAlloc(HEAP_ZERO_MEMORY, chCount * sizeof(WCHAR)); 00794 if (!lpwsz) { 00795 return FALSE; 00796 } 00797 00798 fRet = DlgDirSelectHelper(lpwsz, chCount, GetDlgItem(hwndDlg, idListBox)); 00799 00800 WCSToMB(lpwsz, -1, &lpszPathSpec, chCount, FALSE); 00801 00802 UserLocalFree(lpwsz); 00803 00804 return fRet; 00805 } 00806 00807 BOOL DlgDirSelectExW( 00808 HWND hwndDlg, 00809 LPWSTR lpszPathSpec, 00810 int chCount, 00811 int idListBox) 00812 { 00813 return DlgDirSelectHelper(lpszPathSpec, chCount, GetDlgItem(hwndDlg, idListBox)); 00814 } 00815 00816 00817 /***************************************************************************\ 00818 * xxxLbDir 00819 * 00820 * History: 00821 \***************************************************************************/ 00822 00823 /* 00824 * Note that these FILE_ATTRIBUTE_* values map directly with 00825 * their DDL_* counterparts, with the exception of FILE_ATTRIBUTE_NORMAL. 00826 */ 00827 #define FIND_ATTR ( \ 00828 FILE_ATTRIBUTE_NORMAL | \ 00829 FILE_ATTRIBUTE_DIRECTORY | \ 00830 FILE_ATTRIBUTE_HIDDEN | \ 00831 FILE_ATTRIBUTE_SYSTEM | \ 00832 FILE_ATTRIBUTE_ARCHIVE | \ 00833 FILE_ATTRIBUTE_READONLY ) 00834 #define EXCLUDE_ATTR ( \ 00835 FILE_ATTRIBUTE_DIRECTORY | \ 00836 FILE_ATTRIBUTE_HIDDEN | \ 00837 FILE_ATTRIBUTE_SYSTEM ) 00838 00839 INT xxxLbDir( 00840 PLBIV plb, 00841 UINT attrib, 00842 LPWSTR lhszFileSpec) 00843 { 00844 INT result; 00845 BOOL fWasVisible, bRet; 00846 WCHAR Buffer[CCHFILEMAX + 1]; 00847 WCHAR Buffer2[CCHFILEMAX + 1]; 00848 HANDLE hFind; 00849 WIN32_FIND_DATA ffd; 00850 UINT attribFile; 00851 DWORD mDrives; 00852 INT cDrive; 00853 UINT attribInclMask, attribExclMask; 00854 00855 CheckLock(plb->spwnd); 00856 00857 /* 00858 * Make sure the buffer is valid and copy it onto the stack. Why? Because 00859 * there is a chance that lhszFileSpec is pointing to an invalid string 00860 * because some app posted a CB_DIR or LB_DIR without the DDL_POSTMSGS 00861 * bit set. 00862 */ 00863 try { 00864 wcscpy(Buffer2, lhszFileSpec); 00865 lhszFileSpec = Buffer2; 00866 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 00867 return -1; 00868 } 00869 00870 result = -1; 00871 00872 #ifndef UNICODE 00873 CharToOem(lhszFileSpec, lhszFileSpec); 00874 #endif 00875 00876 if (fWasVisible = IsLBoxVisible(plb)) { 00877 SendMessage(HWq(plb->spwnd), WM_SETREDRAW, FALSE, 0); 00878 } 00879 00880 /* 00881 * First we add the files then the directories and drives. 00882 * If they only wanted drives then skip the file query 00883 * Also under Windows specifing only 0x8000 (DDL_EXCLUSIVE) adds no files). 00884 */ 00885 00886 00887 // if ((attrib != (DDL_EXCLUSIVE | DDL_DRIVES)) && (attrib != DDL_EXCLUSIVE) && 00888 if (attrib != (DDL_EXCLUSIVE | DDL_DRIVES | DDL_NOFILES)) { 00889 hFind = FindFirstFile(lhszFileSpec, &ffd); 00890 00891 if (hFind != INVALID_HANDLE_VALUE) { 00892 00893 /* 00894 * If this is not an exclusive search, include normal files. 00895 */ 00896 attribInclMask = attrib & FIND_ATTR; 00897 if (!(attrib & DDL_EXCLUSIVE)) 00898 attribInclMask |= FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_READONLY | 00899 FILE_ATTRIBUTE_ARCHIVE; 00900 00901 /* 00902 * Make a mask of the attributes to be excluded from 00903 * the search. 00904 */ 00905 attribExclMask = ~attrib & EXCLUDE_ATTR; 00906 00907 // LATER BUG - scottlu 00908 // Win3 assumes doing a LoadCursor here will return the same wait cursor that 00909 // has already been created, whereas calling ServerLoadCursor creates a new 00910 // one every time! 00911 // hCursorT = NtUserSetCursor(ServerLoadCursor(NULL, IDC_WAIT)); 00912 00913 00914 // FindFirst/Next works different in NT then DOS. Under DOS you passed in 00915 // a set of attributes under NT you get back a set of attributes and have 00916 // to test for those attributes (Dos input attributes were Hidden, System 00917 // and Directoy) the dos find first always returned ReadOnly and archive files 00918 00919 // we are going to select a file in one of two cases. 00920 // 1) if any of the attrib bits are set on the file. 00921 // 2) if we want normal files and the file is a notmal file (the file attrib 00922 // bits don't contain any NOEXCLBITS 00923 00924 do { 00925 attribFile = (UINT)ffd.dwFileAttributes; 00926 if (attribFile == FILE_ATTRIBUTE_COMPRESSED) { 00927 attribFile = FILE_ATTRIBUTE_NORMAL; 00928 } 00929 attribFile &= ~FILE_ATTRIBUTE_COMPRESSED; 00930 00931 /* 00932 * Accept those files that have only the 00933 * attributes that we are looking for. 00934 */ 00935 if ((attribFile & attribInclMask) != 0 && 00936 (attribFile & attribExclMask) == 0) { 00937 if (attribFile & DDL_DIRECTORY) { 00938 00939 /* 00940 * Don't include '.' (current directory) in list. 00941 */ 00942 if (*((LPDWORD)&ffd.cFileName[0]) == 0x0000002E) 00943 goto cfnf; 00944 00945 /* 00946 * If we're not looking for dirs, ignore it 00947 */ 00948 if (!(attrib & DDL_DIRECTORY)) 00949 goto cfnf; 00950 00951 } else if (attrib & DDL_NOFILES) { 00952 /* 00953 * Don't include files if DDL_NOFILES is set. 00954 */ 00955 goto cfnf; 00956 } 00957 00958 LB_CreateLBLine(&ffd, 00959 Buffer); 00960 result = xxxLBInsertItem(plb, Buffer, 0, MSGFLAG_SPECIAL_THUNK | LBI_ADD); 00961 } 00962 cfnf: 00963 bRet = FindNextFile(hFind, &ffd); 00964 00965 } while (result >= -1 && bRet); 00966 FindClose(hFind); 00967 00968 // LATER see above comment 00969 // NtUserSetCursor(hCursorT); 00970 } 00971 } 00972 00973 /* 00974 * If drive bit set, include drives in the list. 00975 */ 00976 if (result != LB_ERRSPACE && (attrib & DDL_DRIVES)) { 00977 ffd.cFileName[0] = TEXT('['); 00978 ffd.cFileName[1] = ffd.cFileName[3] = TEXT('-'); 00979 ffd.cFileName[4] = TEXT(']'); 00980 ffd.cFileName[5] = 0; 00981 mDrives = GetLogicalDrives(); 00982 for (cDrive = 0; mDrives; mDrives >>= 1, cDrive++) { 00983 if (mDrives & 1) { 00984 ffd.cFileName[2] = (WCHAR)(TEXT('A') + cDrive); 00985 00986 /* 00987 * We have to set the SPECIAL_THUNK bit because we are 00988 * adding a server side string to a list box that may not 00989 * be HASSTRINGS so we have to force the server-client 00990 * string thunk. 00991 */ 00992 if ((result = xxxLBInsertItem(plb, CharLower(ffd.cFileName), -1, 00993 MSGFLAG_SPECIAL_THUNK)) < 0) { 00994 break; 00995 } 00996 } 00997 } 00998 } 00999 01000 if (result == LB_ERRSPACE) { 01001 xxxNotifyOwner(plb, LB_ERRSPACE); 01002 } 01003 01004 if (fWasVisible) { 01005 SendMessage(HWq(plb->spwnd), WM_SETREDRAW, TRUE, 0); 01006 } 01007 01008 xxxLBShowHideScrollBars(plb); 01009 01010 xxxCheckRedraw(plb, FALSE, 0); 01011 01012 if (result != LB_ERRSPACE) { 01013 01014 /* 01015 * Return index of last item in the listbox. We can't just return 01016 * result because that is the index of the last item added which may 01017 * be in the middle somewhere if the LBS_SORT style is on. 01018 */ 01019 return plb->cMac - 1; 01020 } else { 01021 return result; 01022 } 01023 } 01024 01025 /***************************************************************************\ 01026 * xxxLbInsertFile 01027 * 01028 * Yet another CraigC shell hack... This responds to LB_ADDFILE messages 01029 * sent to directory windows in the file system as a response to the 01030 * WM_FILESYSCHANGE message. That way, we don't reread the whole 01031 * directory when we copy files. 01032 * 01033 * History: 01034 \***************************************************************************/ 01035 01036 INT xxxLbInsertFile( 01037 PLBIV plb, 01038 LPWSTR lpFile) 01039 { 01040 WCHAR chBuffer[CCHFILEMAX + 1]; 01041 INT result = -1; 01042 HANDLE hFind; 01043 WIN32_FIND_DATA ffd; 01044 01045 CheckLock(plb->spwnd); 01046 01047 hFind = FindFirstFile(lpFile, &ffd); 01048 if (hFind != INVALID_HANDLE_VALUE) { 01049 FindClose(hFind); 01050 LB_CreateLBLine(&ffd, chBuffer); 01051 result = xxxLBInsertItem(plb, chBuffer, 0, MSGFLAG_SPECIAL_THUNK | LBI_ADD); 01052 } 01053 01054 if (result == LB_ERRSPACE) { 01055 xxxNotifyOwner(plb, result); 01056 } 01057 01058 xxxCheckRedraw(plb, FALSE, 0); 01059 return result; 01060 } 01061 01062 /***************************************************************************\ 01063 * LB_CreateLBLine 01064 * 01065 * This creates a character string that contains all the required 01066 * details of a file;( Name) 01067 * 01068 * History: 01069 \***************************************************************************/ 01070 01071 void LB_CreateLBLine( 01072 PWIN32_FIND_DATA pffd, 01073 LPWSTR lpBuffer) 01074 { 01075 BYTE bAttribute; 01076 LPWSTR lpch; 01077 01078 lpch = lpBuffer; 01079 01080 bAttribute = (BYTE)pffd->dwFileAttributes; 01081 if (bAttribute & DDL_DIRECTORY) /* Is it a directory */ 01082 *lpch++ = TEXT('['); 01083 01084 /* 01085 * Copy the file name 01086 * 01087 * If we are running from wow, check if the shortname exists 01088 */ 01089 if (GetClientInfo()->dwTIFlags & TIF_16BIT) { 01090 UNICODE_STRING Name; 01091 BOOLEAN fSpace = FALSE; 01092 01093 RtlInitUnicodeString(&Name, pffd->cFileName); 01094 if (RtlIsNameLegalDOS8Dot3(&Name, NULL, &fSpace) && !fSpace) { 01095 /* 01096 * Legal 8.3 name and no spaces, so use the principal 01097 * file name. 01098 */ 01099 wcscpy(lpch, pffd->cFileName); 01100 } else { 01101 if (pffd->cAlternateFileName[0] == 0) 01102 wcscpy(lpch, pffd->cFileName); 01103 else 01104 /* 01105 * Use the alternate file name. 01106 */ 01107 wcscpy(lpch, pffd->cAlternateFileName); 01108 } 01109 /* 01110 * Make filename lower-case for 16-bit apps. Some Corel apps 01111 * require this. 01112 */ 01113 CharLower(lpch); 01114 01115 } 01116 else 01117 wcscpy(lpch, pffd->cFileName); 01118 01119 lpch = (LPWSTR)(lpch + wcslen(lpch)); 01120 01121 if (bAttribute & DDL_DIRECTORY) /* Is it a directory */ 01122 *lpch++ = TEXT(']'); 01123 01124 *lpch = TEXT('\0'); 01125 01126 #ifndef UNICODE 01127 OemToChar(lpBuffer, lpBuffer); 01128 #endif 01129 01130 *lpch = TEXT('\0'); /* Null terminate */ 01131 }

Generated on Sat May 15 19:40:37 2004 for test by doxygen 1.3.7