1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* ***** BEGIN LICENSE BLOCK ***** 3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 4 * 5 * The contents of this file are subject to the Mozilla Public License Version 6 * 1.1 (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * http://www.mozilla.org/MPL/ 9 * 10 * Software distributed under the License is distributed on an "AS IS" basis, 11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 12 * for the specific language governing rights and limitations under the 13 * License. 14 * 15 * The Original Code is mozilla.org code. 16 * 17 * The Initial Developer of the Original Code is 18 * Netscape Communications Corporation. 19 * Portions created by the Initial Developer are Copyright (C) 1998 20 * the Initial Developer. All Rights Reserved. 21 * 22 * Contributor(s): 23 * 24 * Alternatively, the contents of this file may be used under the terms of 25 * either the GNU General Public License Version 2 or later (the "GPL"), or 26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 27 * in which case the provisions of the GPL or the LGPL are applicable instead 28 * of those above. If you wish to allow use of your version of this file only 29 * under the terms of either the GPL or the LGPL, and not to allow others to 30 * use your version of this file under the terms of the MPL, indicate your 31 * decision by deleting the provisions above and replace them with the notice 32 * and other provisions required by the GPL or the LGPL. If you do not delete 33 * the provisions above, a recipient may use your version of this file under 34 * the terms of any one of the MPL, the GPL or the LGPL. 35 * 36 * ***** END LICENSE BLOCK ***** */ 37 #define _CRT_SECURE_NO_DEPRECATE 38 39 #include <windows.h> 40 #include <windowsx.h> 41 #include <direct.h> 42 #include <stdio.h> 43 44 #include "resource.h" 45 46 extern HINSTANCE hInst; 47 48 #define ITEM_BITMAPWIDTH 16 49 #define ITEM_BITMAPHEIGHT 16 50 #define ITEM_LEFTMARGIN 4 51 #define ITEM_GAP 4 52 53 static HWND hWndDirPicker; 54 static HICON hIconDrives[5]; 55 static HICON hIconFolders[3]; 56 static LPSTR lpszStringToReturn; 57 static char szUNCRoot[256] = ""; 58 59 UINT DriveType(UINT iType); 60 61 static void fillComboBox(HWND hWnd) 62 { 63 HWND hWndCB = GetDlgItem(hWnd, ID_COMBO_DIR); 64 HWND hWndTempLB = GetDlgItem(hWnd, ID_LISTTEMP_DIR); 65 if(hWndCB == NULL) 66 return; 67 ComboBox_ResetContent(hWndCB); 68 ListBox_ResetContent(hWndTempLB); 69 ListBox_Dir(hWndTempLB, DDL_DRIVES|DDL_EXCLUSIVE, (LPSTR)"*"); 70 71 int iDriveCount = ListBox_GetCount(hWndTempLB); 72 int iCurDrive=_getdrive() - 1; 73 74 char szDrive[16]; 75 char szItem[80]; 76 77 for (int i = 0; i < iDriveCount; i++) 78 { 79 ListBox_GetText(hWndTempLB, i, szDrive); 80 CharLower(szDrive); 81 int iDrive = szDrive[2] - 'a'; 82 char szRoot[16]; 83 sprintf(szRoot, "%c:\\", szDrive[2]); 84 85 int iType = DriveType(iDrive); 86 87 if(iType < 2) 88 continue; 89 90 //Start the item string with the drive letter, colon, and two spaces 91 sprintf(szItem, "%c%s", szDrive[2], ": "); 92 93 if((iType == DRIVE_FIXED) || (iType == DRIVE_RAMDISK)) 94 { // get volume ID 95 char szVolumeID[80]; 96 DWORD dwMaxLength; 97 DWORD dwSysFlags; 98 GetVolumeInformation(szRoot, // address of root directory of the file system 99 szVolumeID, // address of name of the volume 100 sizeof(szVolumeID), // length of lpVolumeNameBuffer 101 NULL, // address of volume serial number 102 &dwMaxLength, // address of system's maximum filename length 103 &dwSysFlags, // address of file system flags 104 NULL, // address of name of file system 105 NULL); // length of lpFileSystemNameBuffer 106 107 CharLower(szVolumeID); 108 lstrcat(szItem, szVolumeID); 109 } 110 111 //For network drives, go grab the \\server\share for it. 112 if(DRIVE_REMOTE == iType) 113 { 114 char szNet[64]; 115 szNet[0] = '\0'; 116 DWORD dwSizeOfszNet = sizeof(szNet); 117 118 sprintf(szDrive, "%c:", szDrive[2]); 119 CharUpper(szDrive); 120 WNetGetConnection(szDrive, szNet, &dwSizeOfszNet); 121 CharLower(szNet); 122 lstrcat(szItem, szNet); 123 } 124 125 int index = ComboBox_AddString(hWndCB, szItem); 126 ComboBox_SetItemData(hWndCB, index, MAKELONG(iDrive, iType)); 127 if(iDrive == iCurDrive) 128 ComboBox_SetCurSel(hWndCB, index); 129 if(szUNCRoot[0] != '\0') 130 ComboBox_SetCurSel(hWndCB, -1); 131 } 132 } 133 134 static void fillTempLBWithDirs(HWND hWndTempLB, LPSTR lpszDir) 135 { 136 BOOL bDone = FALSE; 137 WIN32_FIND_DATA ffdataStruct; 138 139 char szPath[_MAX_PATH]; 140 char szFileName[_MAX_PATH]; 141 lstrcpy(szPath, lpszDir); 142 if(szPath[lstrlen(szPath) - 1] == '\\') 143 szPath[lstrlen(szPath) - 1] = '\0'; 144 lstrcpy(szFileName, szPath); 145 lstrcat(szFileName, "\\*"); 146 HANDLE handle = FindFirstFile(szFileName, &ffdataStruct); 147 if(handle == INVALID_HANDLE_VALUE) 148 { 149 FindClose(handle); 150 return; 151 } 152 while(!bDone) 153 { 154 lstrcpy(szFileName, szPath); 155 lstrcat(szFileName, "\\"); 156 lstrcat(szFileName, ffdataStruct.cFileName); 157 if(ffdataStruct. dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 158 { 159 char szStringToAdd[_MAX_PATH + 2]; 160 lstrcpy(szStringToAdd, "["); 161 lstrcat(szStringToAdd, ffdataStruct.cFileName); 162 lstrcat(szStringToAdd, "]"); 163 CharLower(szStringToAdd); 164 ListBox_AddString(hWndTempLB, szStringToAdd); 165 } 166 bDone = !FindNextFile(handle, &ffdataStruct); 167 } 168 FindClose(handle); 169 } 170 171 static void fillListBox(HWND hWnd, LPSTR lpszDir) 172 { 173 HWND hWndLB = GetDlgItem(hWnd, ID_LIST_DIR); 174 HWND hWndTempLB = GetDlgItem(hWnd, ID_LISTTEMP_DIR); 175 HWND hWndEdit = GetDlgItem(hWnd, ID_EDIT_DIR); 176 if((hWndLB == NULL) || (lpszDir == NULL)) 177 return; 178 179 int iLastChar = lstrlen(lpszDir); 180 if(lpszDir[iLastChar - 1] == '\\') 181 lpszDir[iLastChar - 1] = '\0'; 182 183 SetWindowRedraw(hWndLB, FALSE); 184 ListBox_ResetContent(hWndLB); 185 ListBox_ResetContent(hWndTempLB); 186 187 LPSTR lpszLast; 188 lpszLast = CharLower(lpszDir); 189 190 SetWindowText(hWndLB, lpszDir); 191 192 char szDir[_MAX_DIR]; 193 char szFullDir[_MAX_DIR]; 194 sprintf(szFullDir, "%s", lpszDir); 195 sprintf(szDir, "%s\\*.*", lpszDir); 196 197 BOOL bFirst = TRUE; 198 char ch; 199 int index; 200 while (TRUE) 201 { 202 LPSTR lpsz; 203 if((lpszDir[0] == '\\') && (lpszDir[1] == '\\') && bFirst) 204 lpsz = strchr(lpszLast + lstrlen(szUNCRoot), '\\'); 205 else 206 lpsz = strchr(lpszLast, '\\'); 207 if(lpsz != NULL) { 208 if (bFirst) 209 ch = *(++lpsz); 210 else 211 ch = *lpsz; 212 *lpsz = 0; 213 } 214 else 215 { 216 //If we're looking at a drive only, then append a backslash 217 if (lpszLast == lpszDir && bFirst) 218 lstrcat(lpszLast, "\\"); 219 } 220 //Add the drive string--includes the last one where lpsz == NULL 221 index = ListBox_AddString(hWndLB, lpszLast); 222 223 UINT i = (NULL != lpsz) ? ID_ICON_FOLDEROPEN : ID_ICON_OPENSELECT; 224 ListBox_SetItemData(hWndLB, index, MAKELONG(index, i)); 225 226 if(NULL == lpsz) 227 break; 228 229 //Restore last character. 230 *lpsz = ch; 231 lpsz += (bFirst) ? 0 : 1; 232 233 bFirst=FALSE; 234 lpszLast = lpsz; 235 } 236 int indent = index + 1; 237 238 //Get available directories 239 fillTempLBWithDirs(hWndTempLB, lpszDir); 240 241 int itemCount = ListBox_GetCount(hWndTempLB); 242 243 int i=0; 244 for (i = 0; i < itemCount; i++) { 245 index = ListBox_GetText(hWndTempLB, i, lpszDir); 246 //Skip directories beginning with . (skipping . and ..) 247 if(lpszDir[1] == '.') 248 continue; 249 //Remove the ending ']' 250 iLastChar = lstrlen(lpszDir); 251 lpszDir[iLastChar - 1] = '\0'; 252 //Add the string to the real directory list. 253 index = ListBox_AddString(hWndLB, lpszDir + 1); 254 ListBox_SetItemData(hWndLB, index, MAKELONG(indent, ID_ICON_FOLDERCLOSED)); 255 } 256 //Force a listbox repaint. 257 SetWindowRedraw(hWndLB, TRUE); 258 InvalidateRect(hWndLB, NULL, TRUE); 259 260 if(szFullDir[lstrlen(szFullDir) - 1] == ':') 261 lstrcat(szFullDir, "\\"); 262 Edit_SetText(hWndEdit, szFullDir); 263 264 GetScrollRange(hWndLB, SB_VERT, (LPINT)&i, (LPINT)&index); 265 266 if(!(i == 0 && index == 0)) 267 ListBox_SetTopIndex(hWndLB, max((int)(index - 2), 0)); 268 269 ListBox_SetCurSel(hWndLB, indent - 1); 270 } 271 272 static void onDrawItem(LPDRAWITEMSTRUCT lpdis, BOOL bDrive) 273 { 274 if((int)lpdis->itemID < 0) 275 return; 276 277 char szItem[_MAX_DIR]; 278 DWORD dwItemData; 279 280 if(bDrive) 281 { 282 dwItemData = ComboBox_GetItemData(lpdis->hwndItem, lpdis->itemID); 283 ComboBox_GetLBText(lpdis->hwndItem, lpdis->itemID, szItem); 284 } 285 else 286 { 287 dwItemData = ListBox_GetItemData(lpdis->hwndItem, lpdis->itemID); 288 ListBox_GetText(lpdis->hwndItem, lpdis->itemID, szItem); 289 } 290 291 if(lpdis->itemAction & (ODA_DRAWENTIRE | ODA_SELECT)) 292 { 293 COLORREF colorText; 294 COLORREF colorBack; 295 if(lpdis->itemState & ODS_SELECTED) 296 { 297 colorText = SetTextColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); 298 colorBack = SetBkColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHT)); 299 } 300 HICON hIcon; 301 int indent = 0; 302 if(bDrive) 303 { 304 int iType=(int)HIWORD(dwItemData); 305 switch (iType) 306 { 307 case DRIVE_REMOVABLE: 308 hIcon = hIconDrives[0]; 309 break; 310 case DRIVE_FIXED: 311 hIcon = hIconDrives[1]; 312 break; 313 case DRIVE_REMOTE: 314 hIcon = hIconDrives[2]; 315 break; 316 case DRIVE_CDROM: 317 hIcon = hIconDrives[3]; 318 break; 319 case DRIVE_RAMDISK: 320 hIcon = hIconDrives[4]; 321 break; 322 } 323 324 } 325 else 326 { 327 int iconID = (int)HIWORD(lpdis->itemData); 328 switch (iconID) 329 { 330 case ID_ICON_FOLDERCLOSED: 331 hIcon = hIconFolders[0]; 332 break; 333 case ID_ICON_FOLDEROPEN: 334 hIcon = hIconFolders[1]; 335 break; 336 case ID_ICON_OPENSELECT: 337 hIcon = hIconFolders[2]; 338 break; 339 } 340 indent = 4 * (1 + LOWORD(lpdis->itemData)); 341 } 342 343 ExtTextOut(lpdis->hDC, 344 lpdis->rcItem.left + ITEM_LEFTMARGIN + ITEM_BITMAPWIDTH + ITEM_GAP + indent, 345 lpdis->rcItem.top, 346 ETO_OPAQUE | ETO_CLIPPED, 347 &lpdis->rcItem, 348 szItem, 349 lstrlen(szItem), 350 NULL); 351 352 BOOL res = DrawIcon(lpdis->hDC, 353 lpdis->rcItem.left + ITEM_LEFTMARGIN + indent, 354 lpdis->rcItem.top, 355 hIcon); 356 357 if(lpdis->itemState & ODS_SELECTED) 358 { 359 SetTextColor(lpdis->hDC, colorText); 360 SetBkColor(lpdis->hDC, colorBack); 361 } 362 } 363 if((lpdis->itemAction & ODA_FOCUS) || (lpdis->itemState & ODS_FOCUS)) 364 DrawFocusRect(lpdis->hDC, &lpdis->rcItem); 365 } 366 367 static void fillUNCRootArray(LPSTR lpsz) 368 { 369 char szCurDir[_MAX_PATH]; 370 _getcwd(szCurDir, sizeof(szCurDir)); 371 lstrcpy(szUNCRoot, lpsz); 372 if(szUNCRoot[lstrlen(szUNCRoot) - 1] == '\\') 373 szUNCRoot[lstrlen(szUNCRoot) - 1] = '\0'; 374 for(;;) 375 { 376 LPSTR lptemp = strrchr(szUNCRoot, '\\'); 377 if(lptemp == NULL) 378 break; 379 *lptemp = '\0'; 380 if(_chdir(szUNCRoot) == -1) 381 { 382 *lptemp = '\\'; 383 break; 384 } 385 } 386 _chdir(szCurDir); 387 } 388 389 static void onInitDialog(HWND hWnd, LPSTR lpsz) 390 { 391 hWndDirPicker = hWnd; 392 lpszStringToReturn = lpsz; 393 394 hIconDrives[0] = LoadIcon(hInst, MAKEINTRESOURCE(ID_ICON_DRIVEFLOPPY)); 395 hIconDrives[1] = LoadIcon(hInst, MAKEINTRESOURCE(ID_ICON_DRIVEHARD)); 396 hIconDrives[2] = LoadIcon(hInst, MAKEINTRESOURCE(ID_ICON_DRIVENETWORK)); 397 hIconDrives[3] = LoadIcon(hInst, MAKEINTRESOURCE(ID_ICON_DRIVECDROM)); 398 hIconDrives[4] = LoadIcon(hInst, MAKEINTRESOURCE(ID_ICON_DRIVERAM)); 399 400 hIconFolders[0] = LoadIcon(hInst, MAKEINTRESOURCE(ID_ICON_FOLDERCLOSED)); 401 hIconFolders[1] = LoadIcon(hInst, MAKEINTRESOURCE(ID_ICON_FOLDEROPEN)); 402 hIconFolders[2] = LoadIcon(hInst, MAKEINTRESOURCE(ID_ICON_OPENSELECT)); 403 404 if(lpsz[0] == '\0') 405 _getcwd(lpsz, _MAX_PATH); 406 else if(lpsz[lstrlen(lpsz) - 1] == ':') 407 lstrcat(lpsz, "\\"); 408 409 int ret = _chdir(lpsz); 410 if(ret == -1) 411 { 412 char szText[_MAX_PATH + 80]; 413 sprintf(szText, "The specified directory %s\ncannot be found", lpsz); 414 MessageBox(GetParent(hWnd), szText, "Choose Directory", MB_ICONEXCLAMATION|MB_OK); 415 _getcwd(lpsz, _MAX_PATH); 416 } 417 if((lpsz[0] == '\\') && (lpsz[1] == '\\')) 418 fillUNCRootArray(lpsz); 419 fillListBox(hWnd, lpsz); 420 fillComboBox(hWnd); 421 } 422 423 static void shutDialog(HWND hWnd) 424 { 425 szUNCRoot[0] = '\0'; 426 } 427 428 static void onCommand(HWND hWnd, int id, HWND hWndCtl, UINT codeNotify) 429 { 430 char szCurDir[_MAX_PATH]; 431 switch(id) 432 { 433 case ID_LIST_DIR: 434 if(codeNotify == LBN_DBLCLK) 435 { 436 int index = ListBox_GetCurSel(hWndCtl); 437 DWORD dwItemData = ListBox_GetItemData(hWndCtl, index); 438 439 if(HIWORD(dwItemData) == ID_ICON_OPENSELECT) 440 { 441 shutDialog(hWnd); 442 char szString[_MAX_PATH]; 443 Edit_GetText(GetDlgItem(hWndDirPicker, ID_EDIT_DIR), szString, sizeof(szString)); 444 lstrcpy(lpszStringToReturn, szString); 445 EndDialog(hWnd, IDOK); 446 break; 447 } 448 449 ListBox_GetText(hWndCtl, index, szCurDir); 450 451 char szDir[_MAX_DIR]; 452 LPSTR lpsz; 453 if((HIWORD(dwItemData) == ID_ICON_FOLDEROPEN) && (index != 0)) 454 { 455 GetWindowText(hWndCtl, szDir, sizeof(szDir)); 456 lpsz=_fstrstr(szDir, szCurDir); 457 *(lpsz + lstrlen(szCurDir)) = '\0'; 458 lstrcpy(szCurDir, szDir); 459 } 460 if (_chdir(szCurDir) == 0) 461 { 462 _getcwd(szCurDir, _MAX_PATH); 463 fillListBox(hWndDirPicker, szCurDir); 464 } 465 } 466 break; 467 case ID_COMBO_DIR: 468 if(codeNotify == CBN_SELCHANGE) 469 { 470 char szDrive[80]; 471 int index = ComboBox_GetCurSel(hWndCtl); 472 if(index == CB_ERR) 473 break; 474 ComboBox_GetLBText(hWndCtl, index, szDrive); 475 476 int iCurDrive = _getdrive(); 477 Retry: 478 HCURSOR hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT)); 479 SetCapture(hWndDirPicker); 480 if((0 == _chdrive((int)(szDrive[0] - 'a' + 1))) && (NULL != _getcwd(szCurDir, _MAX_PATH))) 481 { 482 fillListBox(hWndDirPicker, szCurDir); 483 ListBox_SetTopIndex(GetDlgItem(hWndDirPicker, ID_LIST_DIR), 0); 484 SetCursor(hCursorOld); 485 ReleaseCapture(); 486 break; 487 } 488 SetCursor(hCursorOld); 489 ReleaseCapture(); 490 491 char szText[80]; 492 sprintf(szText, "Cannot read drive %c:", szDrive[0]); 493 if(IDRETRY == MessageBox(hWndDirPicker, szText, "Choose Directory", MB_ICONEXCLAMATION|MB_RETRYCANCEL)) 494 goto Retry; 495 496 //Changing drives failed so restore drive and selection 497 _chdrive(iCurDrive); 498 499 sprintf(szDrive, "%c:", (char)(iCurDrive + 'a' - 1)); 500 index = ComboBox_SelectString(hWndCtl, -1, szDrive); 501 } 502 break; 503 case IDOK: 504 shutDialog(hWnd); 505 char szString[_MAX_PATH]; 506 Edit_GetText(GetDlgItem(hWndDirPicker, ID_EDIT_DIR), szString, sizeof(szString)); 507 lstrcpy(lpszStringToReturn, szString); 508 EndDialog(hWnd, IDOK); 509 break; 510 case IDCANCEL: 511 shutDialog(hWnd); 512 lpszStringToReturn[0] = '\0'; 513 EndDialog(hWnd, IDCANCEL); 514 break; 515 default: 516 break; 517 } 518 } 519 520 static BOOL CALLBACK DirPickDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 521 { 522 switch(msg) { 523 case WM_INITDIALOG: 524 onInitDialog(hWnd, (LPSTR)lParam); 525 break; 526 case WM_COMMAND: 527 HANDLE_WM_COMMAND(hWnd, wParam, lParam, onCommand); 528 break; 529 case WM_MEASUREITEM: 530 { 531 static int cyItem = -1; //Height of a listbox item 532 LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT)lParam; 533 if(cyItem == -1) 534 { 535 HFONT hFont = (HFONT)SendMessage(hWnd, WM_GETFONT, 0, 0L); 536 if(hFont == NULL) 537 hFont = GetStockFont(SYSTEM_FONT); 538 HDC hDC = GetDC(hWnd); 539 HFONT hFontOld = SelectFont(hDC, hFont); 540 TEXTMETRIC tm; 541 GetTextMetrics(hDC, &tm); 542 cyItem = max(ITEM_BITMAPHEIGHT, tm.tmHeight); 543 SelectFont(hDC, hFontOld); 544 ReleaseDC(hWnd, hDC); 545 } 546 547 lpmis->itemHeight = cyItem; 548 } 549 break; 550 case WM_DRAWITEM: 551 onDrawItem((LPDRAWITEMSTRUCT)lParam, ((UINT)wParam == ID_COMBO_DIR)); 552 return TRUE; // to prevent default action in listbox (drawing focus) 553 default: 554 return FALSE; 555 } 556 return TRUE; 557 } 558 559 /* 560 * DriveType 561 * 562 * Purpose: 563 * Augments the Windows API GetDriveType with a call to the CD-ROM 564 * extensions to determine if a drive is a floppy, hard disk, CD-ROM, 565 * RAM-drive, or networked drive. 566 * 567 * Parameters: 568 * iDrive UINT containing the zero-based drive index 569 * 570 * Return Value: 571 * UINT One of the following values describing the drive: 572 * DRIVE_FLOPPY, DRIVE_HARD, DRIVE_CDROM, DRIVE_RAMDISK, 573 * DRIVE_NETWORK. 574 * 575 * Copyright (c)1992 Kraig Brockschmidt, All Right Reserved 576 * Compuserve: 70750,2344 577 * Internet : kraigb (at) microsoft.com 578 * 579 */ 580 UINT DriveType(UINT iDrive) 581 { 582 //Validate possible drive indices 583 if((0 > iDrive) || (25 < iDrive)) 584 return (UINT)-1; 585 586 static char path[] = "d:\\"; 587 path[0] = 'a' + iDrive; 588 int iType = GetDriveType(path); 589 590 /* 591 * Under Windows NT, GetDriveType returns complete information 592 * not provided under Windows 3.x which we now get through other 593 * means. 594 */ 595 596 return iType; 597 } 598 599 BOOL PickupDirectory(HWND hWndOwner, LPSTR lpszString) 600 { 601 if(hWndOwner == NULL) 602 hWndOwner = GetDesktopWindow(); 603 int ret = DialogBoxParam(hInst, MAKEINTRESOURCE(ID_DIALOG_CHOOSEDIR), hWndOwner, DirPickDlgProc, (LPARAM)lpszString); 604 return (ret == IDOK); 605 } 606