1 /* vdir.h 2 * 3 * (c) 1999 Microsoft Corporation. All rights reserved. 4 * Portions (c) 1999 ActiveState Tool Corp, http://www.ActiveState.com/ 5 * 6 * You may distribute under the terms of either the GNU General Public 7 * License or the Artistic License, as specified in the README file. 8 */ 9 10 #ifndef ___VDir_H___ 11 #define ___VDir_H___ 12 13 /* 14 * Allow one slot for each possible drive letter 15 * and one additional slot for a UNC name 16 */ 17 const int driveCount = ('Z'-'A')+1+1; 18 19 class VDir 20 { 21 public: 22 VDir(int bManageDir = 1); 23 ~VDir() {}; 24 25 void Init(VDir* pDir, VMem *pMem); 26 void SetDefaultA(char const *pDefault); 27 void SetDefaultW(WCHAR const *pDefault); 28 char* MapPathA(const char *pInName); 29 WCHAR* MapPathW(const WCHAR *pInName); 30 int SetCurrentDirectoryA(char *lpBuffer); 31 int SetCurrentDirectoryW(WCHAR *lpBuffer); 32 inline int GetDefault(void) { return nDefault; }; 33 34 inline char* GetCurrentDirectoryA(int dwBufSize, char *lpBuffer) 35 { 36 char* ptr = dirTableA[nDefault]; 37 while (--dwBufSize) 38 { 39 if ((*lpBuffer++ = *ptr++) == '\0') 40 break; 41 } 42 *lpBuffer = '\0'; 43 return /* unused */ NULL; 44 }; 45 inline WCHAR* GetCurrentDirectoryW(int dwBufSize, WCHAR *lpBuffer) 46 { 47 WCHAR* ptr = dirTableW[nDefault]; 48 while (--dwBufSize) 49 { 50 if ((*lpBuffer++ = *ptr++) == '\0') 51 break; 52 } 53 *lpBuffer = '\0'; 54 return /* unused */ NULL; 55 }; 56 57 DWORD CalculateEnvironmentSpace(void); 58 LPSTR BuildEnvironmentSpace(LPSTR lpStr); 59 60 protected: 61 int SetDirA(char const *pPath, int index); 62 int SetDirW(WCHAR const *pPath, int index); 63 void FromEnvA(char *pEnv, int index); 64 void FromEnvW(WCHAR *pEnv, int index); 65 66 inline const char *GetDefaultDirA(void) 67 { 68 return dirTableA[nDefault]; 69 }; 70 inline void SetDefaultDirA(char const *pPath, int index) 71 { 72 SetDirA(pPath, index); 73 nDefault = index; 74 }; 75 inline const WCHAR *GetDefaultDirW(void) 76 { 77 return dirTableW[nDefault]; 78 }; 79 inline void SetDefaultDirW(WCHAR const *pPath, int index) 80 { 81 SetDirW(pPath, index); 82 nDefault = index; 83 }; 84 inline const char *GetDirA(int index) 85 { 86 char *ptr = dirTableA[index]; 87 if (!ptr) { 88 /* simulate the existance of this drive */ 89 ptr = szLocalBufferA; 90 ptr[0] = 'A' + index; 91 ptr[1] = ':'; 92 ptr[2] = '\\'; 93 ptr[3] = 0; 94 } 95 return ptr; 96 }; 97 inline const WCHAR *GetDirW(int index) 98 { 99 WCHAR *ptr = dirTableW[index]; 100 if (!ptr) { 101 /* simulate the existance of this drive */ 102 ptr = szLocalBufferW; 103 ptr[0] = 'A' + index; 104 ptr[1] = ':'; 105 ptr[2] = '\\'; 106 ptr[3] = 0; 107 } 108 return ptr; 109 }; 110 111 inline int DriveIndex(char chr) 112 { 113 if (chr == '\\' || chr == '/') 114 return ('Z'-'A')+1; 115 return (chr | 0x20)-'a'; 116 }; 117 118 VMem *pMem; 119 int nDefault, bManageDirectory; 120 char *dirTableA[driveCount]; 121 char szLocalBufferA[MAX_PATH+1]; 122 WCHAR *dirTableW[driveCount]; 123 WCHAR szLocalBufferW[MAX_PATH+1]; 124 }; 125 126 127 VDir::VDir(int bManageDir /* = 1 */) 128 { 129 nDefault = 0; 130 bManageDirectory = bManageDir; 131 memset(dirTableA, 0, sizeof(dirTableA)); 132 memset(dirTableW, 0, sizeof(dirTableW)); 133 } 134 135 void VDir::Init(VDir* pDir, VMem *p) 136 { 137 int index; 138 139 pMem = p; 140 if (pDir) { 141 for (index = 0; index < driveCount; ++index) { 142 SetDirW(pDir->GetDirW(index), index); 143 } 144 nDefault = pDir->GetDefault(); 145 } 146 else { 147 int bSave = bManageDirectory; 148 DWORD driveBits = GetLogicalDrives(); 149 150 bManageDirectory = 0; 151 WCHAR szBuffer[MAX_PATH*driveCount]; 152 if (GetLogicalDriveStringsW(sizeof(szBuffer), szBuffer)) { 153 WCHAR* pEnv = GetEnvironmentStringsW(); 154 WCHAR* ptr = szBuffer; 155 for (index = 0; index < driveCount; ++index) { 156 if (driveBits & (1<<index)) { 157 ptr += SetDirW(ptr, index) + 1; 158 FromEnvW(pEnv, index); 159 } 160 } 161 FreeEnvironmentStringsW(pEnv); 162 } 163 SetDefaultW(L"."); 164 bManageDirectory = bSave; 165 } 166 } 167 168 int VDir::SetDirA(char const *pPath, int index) 169 { 170 char chr, *ptr; 171 int length = 0; 172 WCHAR wBuffer[MAX_PATH+1]; 173 if (index < driveCount && pPath != NULL) { 174 length = strlen(pPath); 175 pMem->Free(dirTableA[index]); 176 ptr = dirTableA[index] = (char*)pMem->Malloc(length+2); 177 if (ptr != NULL) { 178 strcpy(ptr, pPath); 179 ptr += length-1; 180 chr = *ptr++; 181 if (chr != '\\' && chr != '/') { 182 *ptr++ = '\\'; 183 *ptr = '\0'; 184 } 185 MultiByteToWideChar(CP_ACP, 0, dirTableA[index], -1, 186 wBuffer, (sizeof(wBuffer)/sizeof(WCHAR))); 187 length = wcslen(wBuffer); 188 pMem->Free(dirTableW[index]); 189 dirTableW[index] = (WCHAR*)pMem->Malloc((length+1)*2); 190 if (dirTableW[index] != NULL) { 191 wcscpy(dirTableW[index], wBuffer); 192 } 193 } 194 } 195 196 if(bManageDirectory) 197 ::SetCurrentDirectoryA(pPath); 198 199 return length; 200 } 201 202 void VDir::FromEnvA(char *pEnv, int index) 203 { /* gets the directory for index from the environment variable. */ 204 while (*pEnv != '\0') { 205 if ((pEnv[0] == '=') && (DriveIndex(pEnv[1]) == index)) { 206 SetDirA(&pEnv[4], index); 207 break; 208 } 209 else 210 pEnv += strlen(pEnv)+1; 211 } 212 } 213 214 void VDir::FromEnvW(WCHAR *pEnv, int index) 215 { /* gets the directory for index from the environment variable. */ 216 while (*pEnv != '\0') { 217 if ((pEnv[0] == '=') && (DriveIndex((char)pEnv[1]) == index)) { 218 SetDirW(&pEnv[4], index); 219 break; 220 } 221 else 222 pEnv += wcslen(pEnv)+1; 223 } 224 } 225 226 void VDir::SetDefaultA(char const *pDefault) 227 { 228 char szBuffer[MAX_PATH+1]; 229 char *pPtr; 230 231 if (GetFullPathNameA(pDefault, sizeof(szBuffer), szBuffer, &pPtr)) { 232 if (*pDefault != '.' && pPtr != NULL) 233 *pPtr = '\0'; 234 235 SetDefaultDirA(szBuffer, DriveIndex(szBuffer[0])); 236 } 237 } 238 239 int VDir::SetDirW(WCHAR const *pPath, int index) 240 { 241 WCHAR chr, *ptr; 242 int length = 0; 243 if (index < driveCount && pPath != NULL) { 244 length = wcslen(pPath); 245 pMem->Free(dirTableW[index]); 246 ptr = dirTableW[index] = (WCHAR*)pMem->Malloc((length+2)*2); 247 if (ptr != NULL) { 248 char *ansi; 249 wcscpy(ptr, pPath); 250 ptr += length-1; 251 chr = *ptr++; 252 if (chr != '\\' && chr != '/') { 253 *ptr++ = '\\'; 254 *ptr = '\0'; 255 } 256 ansi = win32_ansipath(dirTableW[index]); 257 length = strlen(ansi); 258 pMem->Free(dirTableA[index]); 259 dirTableA[index] = (char*)pMem->Malloc(length+1); 260 if (dirTableA[index] != NULL) { 261 strcpy(dirTableA[index], ansi); 262 } 263 win32_free(ansi); 264 } 265 } 266 267 if(bManageDirectory) 268 ::SetCurrentDirectoryW(pPath); 269 270 return length; 271 } 272 273 void VDir::SetDefaultW(WCHAR const *pDefault) 274 { 275 WCHAR szBuffer[MAX_PATH+1]; 276 WCHAR *pPtr; 277 278 if (GetFullPathNameW(pDefault, (sizeof(szBuffer)/sizeof(WCHAR)), szBuffer, &pPtr)) { 279 if (*pDefault != '.' && pPtr != NULL) 280 *pPtr = '\0'; 281 282 SetDefaultDirW(szBuffer, DriveIndex((char)szBuffer[0])); 283 } 284 } 285 286 inline BOOL IsPathSep(char ch) 287 { 288 return (ch == '\\' || ch == '/'); 289 } 290 291 inline void DoGetFullPathNameA(char* lpBuffer, DWORD dwSize, char* Dest) 292 { 293 char *pPtr; 294 295 /* 296 * On WinNT GetFullPathName does not fail, (or at least always 297 * succeeds when the drive is valid) WinNT does set *Dest to NULL 298 * On Win98 GetFullPathName will set last error if it fails, but 299 * does not touch *Dest 300 */ 301 *Dest = '\0'; 302 GetFullPathNameA(lpBuffer, dwSize, Dest, &pPtr); 303 } 304 305 inline bool IsSpecialFileName(const char* pName) 306 { 307 /* specical file names are devices that the system can open 308 * these include AUX, CON, NUL, PRN, COMx, LPTx, CLOCK$, CONIN$, CONOUT$ 309 * (x is a single digit, and names are case-insensitive) 310 */ 311 char ch = (pName[0] & ~0x20); 312 switch (ch) 313 { 314 case 'A': /* AUX */ 315 if (((pName[1] & ~0x20) == 'U') 316 && ((pName[2] & ~0x20) == 'X') 317 && !pName[3]) 318 return true; 319 break; 320 case 'C': /* CLOCK$, COMx, CON, CONIN$ CONOUT$ */ 321 ch = (pName[1] & ~0x20); 322 switch (ch) 323 { 324 case 'L': /* CLOCK$ */ 325 if (((pName[2] & ~0x20) == 'O') 326 && ((pName[3] & ~0x20) == 'C') 327 && ((pName[4] & ~0x20) == 'K') 328 && (pName[5] == '$') 329 && !pName[6]) 330 return true; 331 break; 332 case 'O': /* COMx, CON, CONIN$ CONOUT$ */ 333 if ((pName[2] & ~0x20) == 'M') { 334 if ((pName[3] >= '1') && (pName[3] <= '9') 335 && !pName[4]) 336 return true; 337 } 338 else if ((pName[2] & ~0x20) == 'N') { 339 if (!pName[3]) 340 return true; 341 else if ((pName[3] & ~0x20) == 'I') { 342 if (((pName[4] & ~0x20) == 'N') 343 && (pName[5] == '$') 344 && !pName[6]) 345 return true; 346 } 347 else if ((pName[3] & ~0x20) == 'O') { 348 if (((pName[4] & ~0x20) == 'U') 349 && ((pName[5] & ~0x20) == 'T') 350 && (pName[6] == '$') 351 && !pName[7]) 352 return true; 353 } 354 } 355 break; 356 } 357 break; 358 case 'L': /* LPTx */ 359 if (((pName[1] & ~0x20) == 'U') 360 && ((pName[2] & ~0x20) == 'X') 361 && (pName[3] >= '1') && (pName[3] <= '9') 362 && !pName[4]) 363 return true; 364 break; 365 case 'N': /* NUL */ 366 if (((pName[1] & ~0x20) == 'U') 367 && ((pName[2] & ~0x20) == 'L') 368 && !pName[3]) 369 return true; 370 break; 371 case 'P': /* PRN */ 372 if (((pName[1] & ~0x20) == 'R') 373 && ((pName[2] & ~0x20) == 'N') 374 && !pName[3]) 375 return true; 376 break; 377 } 378 return false; 379 } 380 381 char *VDir::MapPathA(const char *pInName) 382 { /* 383 * possiblities -- relative path or absolute path with or without drive letter 384 * OR UNC name 385 */ 386 char szBuffer[(MAX_PATH+1)*2]; 387 char szlBuf[MAX_PATH+1]; 388 int length = strlen(pInName); 389 390 if (!length) 391 return (char*)pInName; 392 393 if (length > MAX_PATH) { 394 strncpy(szlBuf, pInName, MAX_PATH); 395 if (IsPathSep(pInName[0]) && !IsPathSep(pInName[1])) { 396 /* absolute path - reduce length by 2 for drive specifier */ 397 szlBuf[MAX_PATH-2] = '\0'; 398 } 399 else 400 szlBuf[MAX_PATH] = '\0'; 401 pInName = szlBuf; 402 } 403 /* strlen(pInName) is now <= MAX_PATH */ 404 405 if (pInName[1] == ':') { 406 /* has drive letter */ 407 if (IsPathSep(pInName[2])) { 408 /* absolute with drive letter */ 409 DoGetFullPathNameA((char*)pInName, sizeof(szLocalBufferA), szLocalBufferA); 410 } 411 else { 412 /* relative path with drive letter */ 413 strcpy(szBuffer, GetDirA(DriveIndex(*pInName))); 414 strcat(szBuffer, &pInName[2]); 415 if(strlen(szBuffer) > MAX_PATH) 416 szBuffer[MAX_PATH] = '\0'; 417 418 DoGetFullPathNameA(szBuffer, sizeof(szLocalBufferA), szLocalBufferA); 419 } 420 } 421 else { 422 /* no drive letter */ 423 if (IsPathSep(pInName[1]) && IsPathSep(pInName[0])) { 424 /* UNC name */ 425 DoGetFullPathNameA((char*)pInName, sizeof(szLocalBufferA), szLocalBufferA); 426 } 427 else { 428 strcpy(szBuffer, GetDefaultDirA()); 429 if (IsPathSep(pInName[0])) { 430 /* absolute path */ 431 strcpy(&szBuffer[2], pInName); 432 DoGetFullPathNameA(szBuffer, sizeof(szLocalBufferA), szLocalBufferA); 433 } 434 else { 435 /* relative path */ 436 if (IsSpecialFileName(pInName)) { 437 return (char*)pInName; 438 } 439 else { 440 strcat(szBuffer, pInName); 441 if (strlen(szBuffer) > MAX_PATH) 442 szBuffer[MAX_PATH] = '\0'; 443 444 DoGetFullPathNameA(szBuffer, sizeof(szLocalBufferA), szLocalBufferA); 445 } 446 } 447 } 448 } 449 450 return szLocalBufferA; 451 } 452 453 int VDir::SetCurrentDirectoryA(char *lpBuffer) 454 { 455 char *pPtr; 456 int length, nRet = -1; 457 458 pPtr = MapPathA(lpBuffer); 459 length = strlen(pPtr); 460 if(length > 3 && IsPathSep(pPtr[length-1])) { 461 /* don't remove the trailing slash from 'x:\' */ 462 pPtr[length-1] = '\0'; 463 } 464 465 DWORD r = GetFileAttributesA(pPtr); 466 if ((r != 0xffffffff) && (r & FILE_ATTRIBUTE_DIRECTORY)) 467 { 468 char szBuffer[(MAX_PATH+1)*2]; 469 DoGetFullPathNameA(pPtr, sizeof(szBuffer), szBuffer); 470 SetDefaultDirA(szBuffer, DriveIndex(szBuffer[0])); 471 nRet = 0; 472 } 473 474 return nRet; 475 } 476 477 DWORD VDir::CalculateEnvironmentSpace(void) 478 { /* the current directory environment strings are stored as '=D:=d:\path' */ 479 int index; 480 DWORD dwSize = 0; 481 for (index = 0; index < driveCount; ++index) { 482 if (dirTableA[index] != NULL) { 483 dwSize += strlen(dirTableA[index]) + 5; /* add 1 for trailing NULL and 4 for '=D:=' */ 484 } 485 } 486 return dwSize; 487 } 488 489 LPSTR VDir::BuildEnvironmentSpace(LPSTR lpStr) 490 { /* store the current directory environment strings as '=D:=d:\path' */ 491 int index, length; 492 LPSTR lpDirStr; 493 for (index = 0; index < driveCount; ++index) { 494 lpDirStr = dirTableA[index]; 495 if (lpDirStr != NULL) { 496 lpStr[0] = '='; 497 lpStr[1] = lpDirStr[0]; 498 lpStr[2] = '\0'; 499 CharUpper(&lpStr[1]); 500 lpStr[2] = ':'; 501 lpStr[3] = '='; 502 strcpy(&lpStr[4], lpDirStr); 503 length = strlen(lpDirStr); 504 lpStr += length + 5; /* add 1 for trailing NULL and 4 for '=D:=' */ 505 if (length > 3 && IsPathSep(lpStr[-2])) { 506 lpStr[-2] = '\0'; /* remove the trailing path separator */ 507 --lpStr; 508 } 509 } 510 } 511 return lpStr; 512 } 513 514 inline BOOL IsPathSep(WCHAR ch) 515 { 516 return (ch == '\\' || ch == '/'); 517 } 518 519 inline void DoGetFullPathNameW(WCHAR* lpBuffer, DWORD dwSize, WCHAR* Dest) 520 { 521 WCHAR *pPtr; 522 523 /* 524 * On WinNT GetFullPathName does not fail, (or at least always 525 * succeeds when the drive is valid) WinNT does set *Dest to NULL 526 * On Win98 GetFullPathName will set last error if it fails, but 527 * does not touch *Dest 528 */ 529 *Dest = '\0'; 530 GetFullPathNameW(lpBuffer, dwSize, Dest, &pPtr); 531 } 532 533 inline bool IsSpecialFileName(const WCHAR* pName) 534 { 535 /* specical file names are devices that the system can open 536 * these include AUX, CON, NUL, PRN, COMx, LPTx, CLOCK$, CONIN$, CONOUT$ 537 * (x is a single digit, and names are case-insensitive) 538 */ 539 WCHAR ch = (pName[0] & ~0x20); 540 switch (ch) 541 { 542 case 'A': /* AUX */ 543 if (((pName[1] & ~0x20) == 'U') 544 && ((pName[2] & ~0x20) == 'X') 545 && !pName[3]) 546 return true; 547 break; 548 case 'C': /* CLOCK$, COMx, CON, CONIN$ CONOUT$ */ 549 ch = (pName[1] & ~0x20); 550 switch (ch) 551 { 552 case 'L': /* CLOCK$ */ 553 if (((pName[2] & ~0x20) == 'O') 554 && ((pName[3] & ~0x20) == 'C') 555 && ((pName[4] & ~0x20) == 'K') 556 && (pName[5] == '$') 557 && !pName[6]) 558 return true; 559 break; 560 case 'O': /* COMx, CON, CONIN$ CONOUT$ */ 561 if ((pName[2] & ~0x20) == 'M') { 562 if ((pName[3] >= '1') && (pName[3] <= '9') 563 && !pName[4]) 564 return true; 565 } 566 else if ((pName[2] & ~0x20) == 'N') { 567 if (!pName[3]) 568 return true; 569 else if ((pName[3] & ~0x20) == 'I') { 570 if (((pName[4] & ~0x20) == 'N') 571 && (pName[5] == '$') 572 && !pName[6]) 573 return true; 574 } 575 else if ((pName[3] & ~0x20) == 'O') { 576 if (((pName[4] & ~0x20) == 'U') 577 && ((pName[5] & ~0x20) == 'T') 578 && (pName[6] == '$') 579 && !pName[7]) 580 return true; 581 } 582 } 583 break; 584 } 585 break; 586 case 'L': /* LPTx */ 587 if (((pName[1] & ~0x20) == 'U') 588 && ((pName[2] & ~0x20) == 'X') 589 && (pName[3] >= '1') && (pName[3] <= '9') 590 && !pName[4]) 591 return true; 592 break; 593 case 'N': /* NUL */ 594 if (((pName[1] & ~0x20) == 'U') 595 && ((pName[2] & ~0x20) == 'L') 596 && !pName[3]) 597 return true; 598 break; 599 case 'P': /* PRN */ 600 if (((pName[1] & ~0x20) == 'R') 601 && ((pName[2] & ~0x20) == 'N') 602 && !pName[3]) 603 return true; 604 break; 605 } 606 return false; 607 } 608 609 WCHAR* VDir::MapPathW(const WCHAR *pInName) 610 { /* 611 * possiblities -- relative path or absolute path with or without drive letter 612 * OR UNC name 613 */ 614 WCHAR szBuffer[(MAX_PATH+1)*2]; 615 WCHAR szlBuf[MAX_PATH+1]; 616 int length = wcslen(pInName); 617 618 if (!length) 619 return (WCHAR*)pInName; 620 621 if (length > MAX_PATH) { 622 wcsncpy(szlBuf, pInName, MAX_PATH); 623 if (IsPathSep(pInName[0]) && !IsPathSep(pInName[1])) { 624 /* absolute path - reduce length by 2 for drive specifier */ 625 szlBuf[MAX_PATH-2] = '\0'; 626 } 627 else 628 szlBuf[MAX_PATH] = '\0'; 629 pInName = szlBuf; 630 } 631 /* strlen(pInName) is now <= MAX_PATH */ 632 633 if (pInName[1] == ':') { 634 /* has drive letter */ 635 if (IsPathSep(pInName[2])) { 636 /* absolute with drive letter */ 637 DoGetFullPathNameW((WCHAR*)pInName, (sizeof(szLocalBufferW)/sizeof(WCHAR)), szLocalBufferW); 638 } 639 else { 640 /* relative path with drive letter */ 641 wcscpy(szBuffer, GetDirW(DriveIndex((char)*pInName))); 642 wcscat(szBuffer, &pInName[2]); 643 if(wcslen(szBuffer) > MAX_PATH) 644 szBuffer[MAX_PATH] = '\0'; 645 646 DoGetFullPathNameW(szBuffer, (sizeof(szLocalBufferW)/sizeof(WCHAR)), szLocalBufferW); 647 } 648 } 649 else { 650 /* no drive letter */ 651 if (IsPathSep(pInName[1]) && IsPathSep(pInName[0])) { 652 /* UNC name */ 653 DoGetFullPathNameW((WCHAR*)pInName, (sizeof(szLocalBufferW)/sizeof(WCHAR)), szLocalBufferW); 654 } 655 else { 656 wcscpy(szBuffer, GetDefaultDirW()); 657 if (IsPathSep(pInName[0])) { 658 /* absolute path */ 659 wcscpy(&szBuffer[2], pInName); 660 DoGetFullPathNameW(szBuffer, (sizeof(szLocalBufferW)/sizeof(WCHAR)), szLocalBufferW); 661 } 662 else { 663 /* relative path */ 664 if (IsSpecialFileName(pInName)) { 665 return (WCHAR*)pInName; 666 } 667 else { 668 wcscat(szBuffer, pInName); 669 if (wcslen(szBuffer) > MAX_PATH) 670 szBuffer[MAX_PATH] = '\0'; 671 672 DoGetFullPathNameW(szBuffer, (sizeof(szLocalBufferW)/sizeof(WCHAR)), szLocalBufferW); 673 } 674 } 675 } 676 } 677 return szLocalBufferW; 678 } 679 680 int VDir::SetCurrentDirectoryW(WCHAR *lpBuffer) 681 { 682 WCHAR *pPtr; 683 int length, nRet = -1; 684 685 pPtr = MapPathW(lpBuffer); 686 length = wcslen(pPtr); 687 if(length > 3 && IsPathSep(pPtr[length-1])) { 688 /* don't remove the trailing slash from 'x:\' */ 689 pPtr[length-1] = '\0'; 690 } 691 692 DWORD r = GetFileAttributesW(pPtr); 693 if ((r != 0xffffffff) && (r & FILE_ATTRIBUTE_DIRECTORY)) 694 { 695 WCHAR wBuffer[(MAX_PATH+1)*2]; 696 DoGetFullPathNameW(pPtr, (sizeof(wBuffer)/sizeof(WCHAR)), wBuffer); 697 SetDefaultDirW(wBuffer, DriveIndex((char)wBuffer[0])); 698 nRet = 0; 699 } 700 701 return nRet; 702 } 703 704 #endif /* ___VDir_H___ */ 705