Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpath.c
Go to the documentation of this file.
00001 /* 00002 * Path Functions 00003 * 00004 * Copyright 1999, 2000 Juergen Schmied 00005 * Copyright 2001, 2002 Jon Griffiths 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00020 */ 00021 00022 #include "config.h" 00023 #include "wine/port.h" 00024 00025 #include <stdarg.h> 00026 #include <string.h> 00027 #include <stdlib.h> 00028 00029 #include "wine/unicode.h" 00030 #include "windef.h" 00031 #include "winbase.h" 00032 #include "wingdi.h" 00033 #include "winuser.h" 00034 #include "winreg.h" 00035 #include "winternl.h" 00036 #define NO_SHLWAPI_STREAM 00037 #include "shlwapi.h" 00038 #include "wine/debug.h" 00039 00040 WINE_DEFAULT_DEBUG_CHANNEL(shell); 00041 00042 /* Get a function pointer from a DLL handle */ 00043 #define GET_FUNC(func, module, name, fail) \ 00044 do { \ 00045 if (!func) { \ 00046 if (!SHLWAPI_h##module && !(SHLWAPI_h##module = LoadLibraryA(#module ".dll"))) return fail; \ 00047 func = (fn##func)GetProcAddress(SHLWAPI_h##module, name); \ 00048 if (!func) return fail; \ 00049 } \ 00050 } while (0) 00051 00052 /* DLL handles for late bound calls */ 00053 static HMODULE SHLWAPI_hshell32; 00054 00055 /* Function pointers for GET_FUNC macro; these need to be global because of gcc bug */ 00056 typedef BOOL (WINAPI *fnpIsNetDrive)(int); 00057 static fnpIsNetDrive pIsNetDrive; 00058 00059 HRESULT WINAPI SHGetWebFolderFilePathW(LPCWSTR,LPWSTR,DWORD); 00060 00061 /************************************************************************* 00062 * PathAppendA [SHLWAPI.@] 00063 * 00064 * Append one path to another. 00065 * 00066 * PARAMS 00067 * lpszPath [I/O] Initial part of path, and destination for output 00068 * lpszAppend [I] Path to append 00069 * 00070 * RETURNS 00071 * Success: TRUE. lpszPath contains the newly created path. 00072 * Failure: FALSE, if either path is NULL, or PathCombineA() fails. 00073 * 00074 * NOTES 00075 * lpszAppend must contain at least one backslash ('\') if not NULL. 00076 * Because PathCombineA() is used to join the paths, the resulting 00077 * path is also canonicalized. 00078 */ 00079 BOOL WINAPI PathAppendA (LPSTR lpszPath, LPCSTR lpszAppend) 00080 { 00081 TRACE("(%s,%s)\n",debugstr_a(lpszPath), debugstr_a(lpszAppend)); 00082 00083 if (lpszPath && lpszAppend) 00084 { 00085 if (!PathIsUNCA(lpszAppend)) 00086 while (*lpszAppend == '\\') 00087 lpszAppend++; 00088 if (PathCombineA(lpszPath, lpszPath, lpszAppend)) 00089 return TRUE; 00090 } 00091 return FALSE; 00092 } 00093 00094 /************************************************************************* 00095 * PathAppendW [SHLWAPI.@] 00096 * 00097 * See PathAppendA. 00098 */ 00099 BOOL WINAPI PathAppendW(LPWSTR lpszPath, LPCWSTR lpszAppend) 00100 { 00101 TRACE("(%s,%s)\n",debugstr_w(lpszPath), debugstr_w(lpszAppend)); 00102 00103 if (lpszPath && lpszAppend) 00104 { 00105 if (!PathIsUNCW(lpszAppend)) 00106 while (*lpszAppend == '\\') 00107 lpszAppend++; 00108 if (PathCombineW(lpszPath, lpszPath, lpszAppend)) 00109 return TRUE; 00110 } 00111 return FALSE; 00112 } 00113 00114 /************************************************************************* 00115 * PathCombineA [SHLWAPI.@] 00116 * 00117 * Combine two paths together. 00118 * 00119 * PARAMS 00120 * lpszDest [O] Destination for combined path 00121 * lpszDir [I] Directory path 00122 * lpszFile [I] File path 00123 * 00124 * RETURNS 00125 * Success: The output path 00126 * Failure: NULL, if inputs are invalid. 00127 * 00128 * NOTES 00129 * lpszDest should be at least MAX_PATH in size, and may point to the same 00130 * memory location as lpszDir. The combined path is canonicalised. 00131 */ 00132 LPSTR WINAPI PathCombineA(LPSTR lpszDest, LPCSTR lpszDir, LPCSTR lpszFile) 00133 { 00134 WCHAR szDest[MAX_PATH]; 00135 WCHAR szDir[MAX_PATH]; 00136 WCHAR szFile[MAX_PATH]; 00137 TRACE("(%p,%s,%s)\n", lpszDest, debugstr_a(lpszDir), debugstr_a(lpszFile)); 00138 00139 /* Invalid parameters */ 00140 if (!lpszDest) 00141 return NULL; 00142 if (!lpszDir && !lpszFile) 00143 { 00144 lpszDest[0] = 0; 00145 return NULL; 00146 } 00147 00148 if (lpszDir) 00149 MultiByteToWideChar(CP_ACP,0,lpszDir,-1,szDir,MAX_PATH); 00150 if (lpszFile) 00151 MultiByteToWideChar(CP_ACP,0,lpszFile,-1,szFile,MAX_PATH); 00152 00153 if (PathCombineW(szDest, lpszDir ? szDir : NULL, lpszFile ? szFile : NULL)) 00154 if (WideCharToMultiByte(CP_ACP,0,szDest,-1,lpszDest,MAX_PATH,0,0)) 00155 return lpszDest; 00156 00157 lpszDest[0] = 0; 00158 return NULL; 00159 } 00160 00161 /************************************************************************* 00162 * PathCombineW [SHLWAPI.@] 00163 * 00164 * See PathCombineA. 00165 */ 00166 LPWSTR WINAPI PathCombineW(LPWSTR lpszDest, LPCWSTR lpszDir, LPCWSTR lpszFile) 00167 { 00168 WCHAR szTemp[MAX_PATH]; 00169 BOOL bUseBoth = FALSE, bStrip = FALSE; 00170 00171 TRACE("(%p,%s,%s)\n", lpszDest, debugstr_w(lpszDir), debugstr_w(lpszFile)); 00172 00173 /* Invalid parameters */ 00174 if (!lpszDest) 00175 return NULL; 00176 if (!lpszDir && !lpszFile) 00177 { 00178 lpszDest[0] = 0; 00179 return NULL; 00180 } 00181 00182 if ((!lpszFile || !*lpszFile) && lpszDir) 00183 { 00184 /* Use dir only */ 00185 lstrcpynW(szTemp, lpszDir, MAX_PATH); 00186 } 00187 else if (!lpszDir || !*lpszDir || !PathIsRelativeW(lpszFile)) 00188 { 00189 if (!lpszDir || !*lpszDir || *lpszFile != '\\' || PathIsUNCW(lpszFile)) 00190 { 00191 /* Use file only */ 00192 lstrcpynW(szTemp, lpszFile, MAX_PATH); 00193 } 00194 else 00195 { 00196 bUseBoth = TRUE; 00197 bStrip = TRUE; 00198 } 00199 } 00200 else 00201 bUseBoth = TRUE; 00202 00203 if (bUseBoth) 00204 { 00205 lstrcpynW(szTemp, lpszDir, MAX_PATH); 00206 if (bStrip) 00207 { 00208 PathStripToRootW(szTemp); 00209 lpszFile++; /* Skip '\' */ 00210 } 00211 if (!PathAddBackslashW(szTemp) || strlenW(szTemp) + strlenW(lpszFile) >= MAX_PATH) 00212 { 00213 lpszDest[0] = 0; 00214 return NULL; 00215 } 00216 strcatW(szTemp, lpszFile); 00217 } 00218 00219 PathCanonicalizeW(lpszDest, szTemp); 00220 return lpszDest; 00221 } 00222 00223 /************************************************************************* 00224 * PathAddBackslashA [SHLWAPI.@] 00225 * 00226 * Append a backslash ('\') to a path if one doesn't exist. 00227 * 00228 * PARAMS 00229 * lpszPath [I/O] The path to append a backslash to. 00230 * 00231 * RETURNS 00232 * Success: The position of the last backslash in the path. 00233 * Failure: NULL, if lpszPath is NULL or the path is too large. 00234 */ 00235 LPSTR WINAPI PathAddBackslashA(LPSTR lpszPath) 00236 { 00237 size_t iLen; 00238 LPSTR prev = lpszPath; 00239 00240 TRACE("(%s)\n",debugstr_a(lpszPath)); 00241 00242 if (!lpszPath || (iLen = strlen(lpszPath)) >= MAX_PATH) 00243 return NULL; 00244 00245 if (iLen) 00246 { 00247 do { 00248 lpszPath = CharNextA(prev); 00249 if (*lpszPath) 00250 prev = lpszPath; 00251 } while (*lpszPath); 00252 if (*prev != '\\') 00253 { 00254 *lpszPath++ = '\\'; 00255 *lpszPath = '\0'; 00256 } 00257 } 00258 return lpszPath; 00259 } 00260 00261 /************************************************************************* 00262 * PathAddBackslashW [SHLWAPI.@] 00263 * 00264 * See PathAddBackslashA. 00265 */ 00266 LPWSTR WINAPI PathAddBackslashW( LPWSTR lpszPath ) 00267 { 00268 size_t iLen; 00269 00270 TRACE("(%s)\n",debugstr_w(lpszPath)); 00271 00272 if (!lpszPath || (iLen = strlenW(lpszPath)) >= MAX_PATH) 00273 return NULL; 00274 00275 if (iLen) 00276 { 00277 lpszPath += iLen; 00278 if (lpszPath[-1] != '\\') 00279 { 00280 *lpszPath++ = '\\'; 00281 *lpszPath = '\0'; 00282 } 00283 } 00284 return lpszPath; 00285 } 00286 00287 /************************************************************************* 00288 * PathBuildRootA [SHLWAPI.@] 00289 * 00290 * Create a root drive string (e.g. "A:\") from a drive number. 00291 * 00292 * PARAMS 00293 * lpszPath [O] Destination for the drive string 00294 * 00295 * RETURNS 00296 * lpszPath 00297 * 00298 * NOTES 00299 * If lpszPath is NULL or drive is invalid, nothing is written to lpszPath. 00300 */ 00301 LPSTR WINAPI PathBuildRootA(LPSTR lpszPath, int drive) 00302 { 00303 TRACE("(%p,%d)\n", lpszPath, drive); 00304 00305 if (lpszPath && drive >= 0 && drive < 26) 00306 { 00307 lpszPath[0] = 'A' + drive; 00308 lpszPath[1] = ':'; 00309 lpszPath[2] = '\\'; 00310 lpszPath[3] = '\0'; 00311 } 00312 return lpszPath; 00313 } 00314 00315 /************************************************************************* 00316 * PathBuildRootW [SHLWAPI.@] 00317 * 00318 * See PathBuildRootA. 00319 */ 00320 LPWSTR WINAPI PathBuildRootW(LPWSTR lpszPath, int drive) 00321 { 00322 TRACE("(%p,%d)\n", lpszPath, drive); 00323 00324 if (lpszPath && drive >= 0 && drive < 26) 00325 { 00326 lpszPath[0] = 'A' + drive; 00327 lpszPath[1] = ':'; 00328 lpszPath[2] = '\\'; 00329 lpszPath[3] = '\0'; 00330 } 00331 return lpszPath; 00332 } 00333 00334 /************************************************************************* 00335 * PathFindFileNameA [SHLWAPI.@] 00336 * 00337 * Locate the start of the file name in a path 00338 * 00339 * PARAMS 00340 * lpszPath [I] Path to search 00341 * 00342 * RETURNS 00343 * A pointer to the first character of the file name 00344 */ 00345 LPSTR WINAPI PathFindFileNameA(LPCSTR lpszPath) 00346 { 00347 LPCSTR lastSlash = lpszPath; 00348 00349 TRACE("(%s)\n",debugstr_a(lpszPath)); 00350 00351 while (lpszPath && *lpszPath) 00352 { 00353 if ((*lpszPath == '\\' || *lpszPath == '/' || *lpszPath == ':') && 00354 lpszPath[1] && lpszPath[1] != '\\' && lpszPath[1] != '/') 00355 lastSlash = lpszPath + 1; 00356 lpszPath = CharNextA(lpszPath); 00357 } 00358 return (LPSTR)lastSlash; 00359 } 00360 00361 /************************************************************************* 00362 * PathFindFileNameW [SHLWAPI.@] 00363 * 00364 * See PathFindFileNameA. 00365 */ 00366 LPWSTR WINAPI PathFindFileNameW(LPCWSTR lpszPath) 00367 { 00368 LPCWSTR lastSlash = lpszPath; 00369 00370 TRACE("(%s)\n",debugstr_w(lpszPath)); 00371 00372 while (lpszPath && *lpszPath) 00373 { 00374 if ((*lpszPath == '\\' || *lpszPath == '/' || *lpszPath == ':') && 00375 lpszPath[1] && lpszPath[1] != '\\' && lpszPath[1] != '/') 00376 lastSlash = lpszPath + 1; 00377 lpszPath++; 00378 } 00379 return (LPWSTR)lastSlash; 00380 } 00381 00382 /************************************************************************* 00383 * PathFindExtensionA [SHLWAPI.@] 00384 * 00385 * Locate the start of the file extension in a path 00386 * 00387 * PARAMS 00388 * lpszPath [I] The path to search 00389 * 00390 * RETURNS 00391 * A pointer to the first character of the extension, the end of 00392 * the string if the path has no extension, or NULL If lpszPath is NULL 00393 */ 00394 LPSTR WINAPI PathFindExtensionA( LPCSTR lpszPath ) 00395 { 00396 LPCSTR lastpoint = NULL; 00397 00398 TRACE("(%s)\n", debugstr_a(lpszPath)); 00399 00400 if (lpszPath) 00401 { 00402 while (*lpszPath) 00403 { 00404 if (*lpszPath == '\\' || *lpszPath==' ') 00405 lastpoint = NULL; 00406 else if (*lpszPath == '.') 00407 lastpoint = lpszPath; 00408 lpszPath = CharNextA(lpszPath); 00409 } 00410 } 00411 return (LPSTR)(lastpoint ? lastpoint : lpszPath); 00412 } 00413 00414 /************************************************************************* 00415 * PathFindExtensionW [SHLWAPI.@] 00416 * 00417 * See PathFindExtensionA. 00418 */ 00419 LPWSTR WINAPI PathFindExtensionW( LPCWSTR lpszPath ) 00420 { 00421 LPCWSTR lastpoint = NULL; 00422 00423 TRACE("(%s)\n", debugstr_w(lpszPath)); 00424 00425 if (lpszPath) 00426 { 00427 while (*lpszPath) 00428 { 00429 if (*lpszPath == '\\' || *lpszPath==' ') 00430 lastpoint = NULL; 00431 else if (*lpszPath == '.') 00432 lastpoint = lpszPath; 00433 lpszPath++; 00434 } 00435 } 00436 return (LPWSTR)(lastpoint ? lastpoint : lpszPath); 00437 } 00438 00439 /************************************************************************* 00440 * PathGetArgsA [SHLWAPI.@] 00441 * 00442 * Find the next argument in a string delimited by spaces. 00443 * 00444 * PARAMS 00445 * lpszPath [I] The string to search for arguments in 00446 * 00447 * RETURNS 00448 * The start of the next argument in lpszPath, or NULL if lpszPath is NULL 00449 * 00450 * NOTES 00451 * Spaces in quoted strings are ignored as delimiters. 00452 */ 00453 LPSTR WINAPI PathGetArgsA(LPCSTR lpszPath) 00454 { 00455 BOOL bSeenQuote = FALSE; 00456 00457 TRACE("(%s)\n",debugstr_a(lpszPath)); 00458 00459 if (lpszPath) 00460 { 00461 while (*lpszPath) 00462 { 00463 if ((*lpszPath==' ') && !bSeenQuote) 00464 return (LPSTR)lpszPath + 1; 00465 if (*lpszPath == '"') 00466 bSeenQuote = !bSeenQuote; 00467 lpszPath = CharNextA(lpszPath); 00468 } 00469 } 00470 return (LPSTR)lpszPath; 00471 } 00472 00473 /************************************************************************* 00474 * PathGetArgsW [SHLWAPI.@] 00475 * 00476 * See PathGetArgsA. 00477 */ 00478 LPWSTR WINAPI PathGetArgsW(LPCWSTR lpszPath) 00479 { 00480 BOOL bSeenQuote = FALSE; 00481 00482 TRACE("(%s)\n",debugstr_w(lpszPath)); 00483 00484 if (lpszPath) 00485 { 00486 while (*lpszPath) 00487 { 00488 if ((*lpszPath==' ') && !bSeenQuote) 00489 return (LPWSTR)lpszPath + 1; 00490 if (*lpszPath == '"') 00491 bSeenQuote = !bSeenQuote; 00492 lpszPath++; 00493 } 00494 } 00495 return (LPWSTR)lpszPath; 00496 } 00497 00498 /************************************************************************* 00499 * PathGetDriveNumberA [SHLWAPI.@] 00500 * 00501 * Return the drive number from a path 00502 * 00503 * PARAMS 00504 * lpszPath [I] Path to get the drive number from 00505 * 00506 * RETURNS 00507 * Success: The drive number corresponding to the drive in the path 00508 * Failure: -1, if lpszPath contains no valid drive 00509 */ 00510 int WINAPI PathGetDriveNumberA(LPCSTR lpszPath) 00511 { 00512 TRACE ("(%s)\n",debugstr_a(lpszPath)); 00513 00514 if (lpszPath && !IsDBCSLeadByte(*lpszPath) && lpszPath[1] == ':' && 00515 tolower(*lpszPath) >= 'a' && tolower(*lpszPath) <= 'z') 00516 return tolower(*lpszPath) - 'a'; 00517 return -1; 00518 } 00519 00520 /************************************************************************* 00521 * PathGetDriveNumberW [SHLWAPI.@] 00522 * 00523 * See PathGetDriveNumberA. 00524 */ 00525 int WINAPI PathGetDriveNumberW(LPCWSTR lpszPath) 00526 { 00527 TRACE ("(%s)\n",debugstr_w(lpszPath)); 00528 00529 if (lpszPath) 00530 { 00531 WCHAR tl = tolowerW(lpszPath[0]); 00532 if (tl >= 'a' && tl <= 'z' && lpszPath[1] == ':') 00533 return tl - 'a'; 00534 } 00535 return -1; 00536 } 00537 00538 /************************************************************************* 00539 * PathRemoveFileSpecA [SHLWAPI.@] 00540 * 00541 * Remove the file specification from a path. 00542 * 00543 * PARAMS 00544 * lpszPath [I/O] Path to remove the file spec from 00545 * 00546 * RETURNS 00547 * TRUE If the path was valid and modified 00548 * FALSE Otherwise 00549 */ 00550 BOOL WINAPI PathRemoveFileSpecA(LPSTR lpszPath) 00551 { 00552 LPSTR lpszFileSpec = lpszPath; 00553 BOOL bModified = FALSE; 00554 00555 TRACE("(%s)\n",debugstr_a(lpszPath)); 00556 00557 if(lpszPath) 00558 { 00559 /* Skip directory or UNC path */ 00560 if (*lpszPath == '\\') 00561 lpszFileSpec = ++lpszPath; 00562 if (*lpszPath == '\\') 00563 lpszFileSpec = ++lpszPath; 00564 00565 while (*lpszPath) 00566 { 00567 if(*lpszPath == '\\') 00568 lpszFileSpec = lpszPath; /* Skip dir */ 00569 else if(*lpszPath == ':') 00570 { 00571 lpszFileSpec = ++lpszPath; /* Skip drive */ 00572 if (*lpszPath == '\\') 00573 lpszFileSpec++; 00574 } 00575 if (!(lpszPath = CharNextA(lpszPath))) 00576 break; 00577 } 00578 00579 if (*lpszFileSpec) 00580 { 00581 *lpszFileSpec = '\0'; 00582 bModified = TRUE; 00583 } 00584 } 00585 return bModified; 00586 } 00587 00588 /************************************************************************* 00589 * PathRemoveFileSpecW [SHLWAPI.@] 00590 * 00591 * See PathRemoveFileSpecA. 00592 */ 00593 BOOL WINAPI PathRemoveFileSpecW(LPWSTR lpszPath) 00594 { 00595 LPWSTR lpszFileSpec = lpszPath; 00596 BOOL bModified = FALSE; 00597 00598 TRACE("(%s)\n",debugstr_w(lpszPath)); 00599 00600 if(lpszPath) 00601 { 00602 /* Skip directory or UNC path */ 00603 if (*lpszPath == '\\') 00604 lpszFileSpec = ++lpszPath; 00605 if (*lpszPath == '\\') 00606 lpszFileSpec = ++lpszPath; 00607 00608 while (*lpszPath) 00609 { 00610 if(*lpszPath == '\\') 00611 lpszFileSpec = lpszPath; /* Skip dir */ 00612 else if(*lpszPath == ':') 00613 { 00614 lpszFileSpec = ++lpszPath; /* Skip drive */ 00615 if (*lpszPath == '\\') 00616 lpszFileSpec++; 00617 } 00618 lpszPath++; 00619 } 00620 00621 if (*lpszFileSpec) 00622 { 00623 *lpszFileSpec = '\0'; 00624 bModified = TRUE; 00625 } 00626 } 00627 return bModified; 00628 } 00629 00630 /************************************************************************* 00631 * PathStripPathA [SHLWAPI.@] 00632 * 00633 * Remove the initial path from the beginning of a filename 00634 * 00635 * PARAMS 00636 * lpszPath [I/O] Path to remove the initial path from 00637 * 00638 * RETURNS 00639 * Nothing. 00640 */ 00641 void WINAPI PathStripPathA(LPSTR lpszPath) 00642 { 00643 TRACE("(%s)\n", debugstr_a(lpszPath)); 00644 00645 if (lpszPath) 00646 { 00647 LPSTR lpszFileName = PathFindFileNameA(lpszPath); 00648 if(lpszFileName) 00649 RtlMoveMemory(lpszPath, lpszFileName, strlen(lpszFileName)+1); 00650 } 00651 } 00652 00653 /************************************************************************* 00654 * PathStripPathW [SHLWAPI.@] 00655 * 00656 * See PathStripPathA. 00657 */ 00658 void WINAPI PathStripPathW(LPWSTR lpszPath) 00659 { 00660 LPWSTR lpszFileName; 00661 00662 TRACE("(%s)\n", debugstr_w(lpszPath)); 00663 lpszFileName = PathFindFileNameW(lpszPath); 00664 if(lpszFileName) 00665 RtlMoveMemory(lpszPath, lpszFileName, (strlenW(lpszFileName)+1)*sizeof(WCHAR)); 00666 } 00667 00668 /************************************************************************* 00669 * PathStripToRootA [SHLWAPI.@] 00670 * 00671 * Reduce a path to its root. 00672 * 00673 * PARAMS 00674 * lpszPath [I/O] the path to reduce 00675 * 00676 * RETURNS 00677 * Success: TRUE if the stripped path is a root path 00678 * Failure: FALSE if the path cannot be stripped or is NULL 00679 */ 00680 BOOL WINAPI PathStripToRootA(LPSTR lpszPath) 00681 { 00682 TRACE("(%s)\n", debugstr_a(lpszPath)); 00683 00684 if (!lpszPath) 00685 return FALSE; 00686 while(!PathIsRootA(lpszPath)) 00687 if (!PathRemoveFileSpecA(lpszPath)) 00688 return FALSE; 00689 return TRUE; 00690 } 00691 00692 /************************************************************************* 00693 * PathStripToRootW [SHLWAPI.@] 00694 * 00695 * See PathStripToRootA. 00696 */ 00697 BOOL WINAPI PathStripToRootW(LPWSTR lpszPath) 00698 { 00699 TRACE("(%s)\n", debugstr_w(lpszPath)); 00700 00701 if (!lpszPath) 00702 return FALSE; 00703 while(!PathIsRootW(lpszPath)) 00704 if (!PathRemoveFileSpecW(lpszPath)) 00705 return FALSE; 00706 return TRUE; 00707 } 00708 00709 /************************************************************************* 00710 * PathRemoveArgsA [SHLWAPI.@] 00711 * 00712 * Strip space separated arguments from a path. 00713 * 00714 * PARAMS 00715 * lpszPath [I/O] Path to remove arguments from 00716 * 00717 * RETURNS 00718 * Nothing. 00719 */ 00720 void WINAPI PathRemoveArgsA(LPSTR lpszPath) 00721 { 00722 TRACE("(%s)\n",debugstr_a(lpszPath)); 00723 00724 if(lpszPath) 00725 { 00726 LPSTR lpszArgs = PathGetArgsA(lpszPath); 00727 if (*lpszArgs) 00728 lpszArgs[-1] = '\0'; 00729 else 00730 { 00731 LPSTR lpszLastChar = CharPrevA(lpszPath, lpszArgs); 00732 if(*lpszLastChar == ' ') 00733 *lpszLastChar = '\0'; 00734 } 00735 } 00736 } 00737 00738 /************************************************************************* 00739 * PathRemoveArgsW [SHLWAPI.@] 00740 * 00741 * See PathRemoveArgsA. 00742 */ 00743 void WINAPI PathRemoveArgsW(LPWSTR lpszPath) 00744 { 00745 TRACE("(%s)\n",debugstr_w(lpszPath)); 00746 00747 if(lpszPath) 00748 { 00749 LPWSTR lpszArgs = PathGetArgsW(lpszPath); 00750 if (*lpszArgs || (lpszArgs > lpszPath && lpszArgs[-1] == ' ')) 00751 lpszArgs[-1] = '\0'; 00752 } 00753 } 00754 00755 /************************************************************************* 00756 * PathRemoveExtensionA [SHLWAPI.@] 00757 * 00758 * Remove the file extension from a path 00759 * 00760 * PARAMS 00761 * lpszPath [I/O] Path to remove the extension from 00762 * 00763 * RETURNS 00764 * Nothing. 00765 */ 00766 void WINAPI PathRemoveExtensionA(LPSTR lpszPath) 00767 { 00768 TRACE("(%s)\n", debugstr_a(lpszPath)); 00769 00770 if (lpszPath) 00771 { 00772 lpszPath = PathFindExtensionA(lpszPath); 00773 *lpszPath = '\0'; 00774 } 00775 } 00776 00777 /************************************************************************* 00778 * PathRemoveExtensionW [SHLWAPI.@] 00779 * 00780 * See PathRemoveExtensionA. 00781 */ 00782 void WINAPI PathRemoveExtensionW(LPWSTR lpszPath) 00783 { 00784 TRACE("(%s)\n", debugstr_w(lpszPath)); 00785 00786 if (lpszPath) 00787 { 00788 lpszPath = PathFindExtensionW(lpszPath); 00789 *lpszPath = '\0'; 00790 } 00791 } 00792 00793 /************************************************************************* 00794 * PathRemoveBackslashA [SHLWAPI.@] 00795 * 00796 * Remove a trailing backslash from a path. 00797 * 00798 * PARAMS 00799 * lpszPath [I/O] Path to remove backslash from 00800 * 00801 * RETURNS 00802 * Success: A pointer to the end of the path 00803 * Failure: NULL, if lpszPath is NULL 00804 */ 00805 LPSTR WINAPI PathRemoveBackslashA( LPSTR lpszPath ) 00806 { 00807 LPSTR szTemp = NULL; 00808 00809 TRACE("(%s)\n", debugstr_a(lpszPath)); 00810 00811 if(lpszPath) 00812 { 00813 szTemp = CharPrevA(lpszPath, lpszPath + strlen(lpszPath)); 00814 if (!PathIsRootA(lpszPath) && *szTemp == '\\') 00815 *szTemp = '\0'; 00816 } 00817 return szTemp; 00818 } 00819 00820 /************************************************************************* 00821 * PathRemoveBackslashW [SHLWAPI.@] 00822 * 00823 * See PathRemoveBackslashA. 00824 */ 00825 LPWSTR WINAPI PathRemoveBackslashW( LPWSTR lpszPath ) 00826 { 00827 LPWSTR szTemp = NULL; 00828 00829 TRACE("(%s)\n", debugstr_w(lpszPath)); 00830 00831 if(lpszPath) 00832 { 00833 szTemp = lpszPath + strlenW(lpszPath); 00834 if (szTemp > lpszPath) szTemp--; 00835 if (!PathIsRootW(lpszPath) && *szTemp == '\\') 00836 *szTemp = '\0'; 00837 } 00838 return szTemp; 00839 } 00840 00841 /************************************************************************* 00842 * PathRemoveBlanksA [SHLWAPI.@] 00843 * 00844 * Remove Spaces from the start and end of a path. 00845 * 00846 * PARAMS 00847 * lpszPath [I/O] Path to strip blanks from 00848 * 00849 * RETURNS 00850 * Nothing. 00851 */ 00852 VOID WINAPI PathRemoveBlanksA(LPSTR lpszPath) 00853 { 00854 TRACE("(%s)\n", debugstr_a(lpszPath)); 00855 00856 if(lpszPath && *lpszPath) 00857 { 00858 LPSTR start = lpszPath; 00859 00860 while (*lpszPath == ' ') 00861 lpszPath = CharNextA(lpszPath); 00862 00863 while(*lpszPath) 00864 *start++ = *lpszPath++; 00865 00866 if (start != lpszPath) 00867 while (start[-1] == ' ') 00868 start--; 00869 *start = '\0'; 00870 } 00871 } 00872 00873 /************************************************************************* 00874 * PathRemoveBlanksW [SHLWAPI.@] 00875 * 00876 * See PathRemoveBlanksA. 00877 */ 00878 VOID WINAPI PathRemoveBlanksW(LPWSTR lpszPath) 00879 { 00880 TRACE("(%s)\n", debugstr_w(lpszPath)); 00881 00882 if(lpszPath && *lpszPath) 00883 { 00884 LPWSTR start = lpszPath; 00885 00886 while (*lpszPath == ' ') 00887 lpszPath++; 00888 00889 while(*lpszPath) 00890 *start++ = *lpszPath++; 00891 00892 if (start != lpszPath) 00893 while (start[-1] == ' ') 00894 start--; 00895 *start = '\0'; 00896 } 00897 } 00898 00899 /************************************************************************* 00900 * PathQuoteSpacesA [SHLWAPI.@] 00901 * 00902 * Surround a path containing spaces in quotes. 00903 * 00904 * PARAMS 00905 * lpszPath [I/O] Path to quote 00906 * 00907 * RETURNS 00908 * Nothing. 00909 * 00910 * NOTES 00911 * The path is not changed if it is invalid or has no spaces. 00912 */ 00913 VOID WINAPI PathQuoteSpacesA(LPSTR lpszPath) 00914 { 00915 TRACE("(%s)\n", debugstr_a(lpszPath)); 00916 00917 if(lpszPath && StrChrA(lpszPath,' ')) 00918 { 00919 size_t iLen = strlen(lpszPath) + 1; 00920 00921 if (iLen + 2 < MAX_PATH) 00922 { 00923 memmove(lpszPath + 1, lpszPath, iLen); 00924 lpszPath[0] = '"'; 00925 lpszPath[iLen] = '"'; 00926 lpszPath[iLen + 1] = '\0'; 00927 } 00928 } 00929 } 00930 00931 /************************************************************************* 00932 * PathQuoteSpacesW [SHLWAPI.@] 00933 * 00934 * See PathQuoteSpacesA. 00935 */ 00936 VOID WINAPI PathQuoteSpacesW(LPWSTR lpszPath) 00937 { 00938 TRACE("(%s)\n", debugstr_w(lpszPath)); 00939 00940 if(lpszPath && StrChrW(lpszPath,' ')) 00941 { 00942 int iLen = strlenW(lpszPath) + 1; 00943 00944 if (iLen + 2 < MAX_PATH) 00945 { 00946 memmove(lpszPath + 1, lpszPath, iLen * sizeof(WCHAR)); 00947 lpszPath[0] = '"'; 00948 lpszPath[iLen] = '"'; 00949 lpszPath[iLen + 1] = '\0'; 00950 } 00951 } 00952 } 00953 00954 /************************************************************************* 00955 * PathUnquoteSpacesA [SHLWAPI.@] 00956 * 00957 * Remove quotes ("") from around a path, if present. 00958 * 00959 * PARAMS 00960 * lpszPath [I/O] Path to strip quotes from 00961 * 00962 * RETURNS 00963 * Nothing 00964 * 00965 * NOTES 00966 * If the path contains a single quote only, an empty string will result. 00967 * Otherwise quotes are only removed if they appear at the start and end 00968 * of the path. 00969 */ 00970 VOID WINAPI PathUnquoteSpacesA(LPSTR lpszPath) 00971 { 00972 TRACE("(%s)\n", debugstr_a(lpszPath)); 00973 00974 if (lpszPath && *lpszPath == '"') 00975 { 00976 DWORD dwLen = strlen(lpszPath) - 1; 00977 00978 if (lpszPath[dwLen] == '"') 00979 { 00980 lpszPath[dwLen] = '\0'; 00981 for (; *lpszPath; lpszPath++) 00982 *lpszPath = lpszPath[1]; 00983 } 00984 } 00985 } 00986 00987 /************************************************************************* 00988 * PathUnquoteSpacesW [SHLWAPI.@] 00989 * 00990 * See PathUnquoteSpacesA. 00991 */ 00992 VOID WINAPI PathUnquoteSpacesW(LPWSTR lpszPath) 00993 { 00994 TRACE("(%s)\n", debugstr_w(lpszPath)); 00995 00996 if (lpszPath && *lpszPath == '"') 00997 { 00998 DWORD dwLen = strlenW(lpszPath) - 1; 00999 01000 if (lpszPath[dwLen] == '"') 01001 { 01002 lpszPath[dwLen] = '\0'; 01003 for (; *lpszPath; lpszPath++) 01004 *lpszPath = lpszPath[1]; 01005 } 01006 } 01007 } 01008 01009 /************************************************************************* 01010 * PathParseIconLocationA [SHLWAPI.@] 01011 * 01012 * Parse the location of an icon from a path. 01013 * 01014 * PARAMS 01015 * lpszPath [I/O] The path to parse the icon location from. 01016 * 01017 * RETURNS 01018 * Success: The number of the icon 01019 * Failure: 0 if the path does not contain an icon location or is NULL 01020 * 01021 * NOTES 01022 * The path has surrounding quotes and spaces removed regardless 01023 * of whether the call succeeds or not. 01024 */ 01025 int WINAPI PathParseIconLocationA(LPSTR lpszPath) 01026 { 01027 int iRet = 0; 01028 LPSTR lpszComma; 01029 01030 TRACE("(%s)\n", debugstr_a(lpszPath)); 01031 01032 if (lpszPath) 01033 { 01034 if ((lpszComma = strchr(lpszPath, ','))) 01035 { 01036 *lpszComma++ = '\0'; 01037 iRet = StrToIntA(lpszComma); 01038 } 01039 PathUnquoteSpacesA(lpszPath); 01040 PathRemoveBlanksA(lpszPath); 01041 } 01042 return iRet; 01043 } 01044 01045 /************************************************************************* 01046 * PathParseIconLocationW [SHLWAPI.@] 01047 * 01048 * See PathParseIconLocationA. 01049 */ 01050 int WINAPI PathParseIconLocationW(LPWSTR lpszPath) 01051 { 01052 int iRet = 0; 01053 LPWSTR lpszComma; 01054 01055 TRACE("(%s)\n", debugstr_w(lpszPath)); 01056 01057 if (lpszPath) 01058 { 01059 if ((lpszComma = StrChrW(lpszPath, ','))) 01060 { 01061 *lpszComma++ = '\0'; 01062 iRet = StrToIntW(lpszComma); 01063 } 01064 PathUnquoteSpacesW(lpszPath); 01065 PathRemoveBlanksW(lpszPath); 01066 } 01067 return iRet; 01068 } 01069 01070 /************************************************************************* 01071 * @ [SHLWAPI.4] 01072 * 01073 * Unicode version of PathFileExistsDefExtA. 01074 */ 01075 BOOL WINAPI PathFileExistsDefExtW(LPWSTR lpszPath,DWORD dwWhich) 01076 { 01077 static const WCHAR pszExts[7][5] = { { '.', 'p', 'i', 'f', 0}, 01078 { '.', 'c', 'o', 'm', 0}, 01079 { '.', 'e', 'x', 'e', 0}, 01080 { '.', 'b', 'a', 't', 0}, 01081 { '.', 'l', 'n', 'k', 0}, 01082 { '.', 'c', 'm', 'd', 0}, 01083 { 0, 0, 0, 0, 0} }; 01084 01085 TRACE("(%s,%d)\n", debugstr_w(lpszPath), dwWhich); 01086 01087 if (!lpszPath || PathIsUNCServerW(lpszPath) || PathIsUNCServerShareW(lpszPath)) 01088 return FALSE; 01089 01090 if (dwWhich) 01091 { 01092 LPCWSTR szExt = PathFindExtensionW(lpszPath); 01093 if (!*szExt || dwWhich & 0x40) 01094 { 01095 size_t iChoose = 0; 01096 int iLen = lstrlenW(lpszPath); 01097 if (iLen > (MAX_PATH - 5)) 01098 return FALSE; 01099 while ( (dwWhich & 0x1) && pszExts[iChoose][0] ) 01100 { 01101 lstrcpyW(lpszPath + iLen, pszExts[iChoose]); 01102 if (PathFileExistsW(lpszPath)) 01103 return TRUE; 01104 iChoose++; 01105 dwWhich >>= 1; 01106 } 01107 *(lpszPath + iLen) = (WCHAR)'\0'; 01108 return FALSE; 01109 } 01110 } 01111 return PathFileExistsW(lpszPath); 01112 } 01113 01114 /************************************************************************* 01115 * @ [SHLWAPI.3] 01116 * 01117 * Determine if a file exists locally and is of an executable type. 01118 * 01119 * PARAMS 01120 * lpszPath [I/O] File to search for 01121 * dwWhich [I] Type of executable to search for 01122 * 01123 * RETURNS 01124 * TRUE If the file was found. lpszPath contains the file name. 01125 * FALSE Otherwise. 01126 * 01127 * NOTES 01128 * lpszPath is modified in place and must be at least MAX_PATH in length. 01129 * If the function returns FALSE, the path is modified to its original state. 01130 * If the given path contains an extension or dwWhich is 0, executable 01131 * extensions are not checked. 01132 * 01133 * Ordinals 3-6 are a classic case of MS exposing limited functionality to 01134 * users (here through PathFindOnPathA()) and keeping advanced functionality for 01135 * their own developers exclusive use. Monopoly, anyone? 01136 */ 01137 BOOL WINAPI PathFileExistsDefExtA(LPSTR lpszPath,DWORD dwWhich) 01138 { 01139 BOOL bRet = FALSE; 01140 01141 TRACE("(%s,%d)\n", debugstr_a(lpszPath), dwWhich); 01142 01143 if (lpszPath) 01144 { 01145 WCHAR szPath[MAX_PATH]; 01146 MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH); 01147 bRet = PathFileExistsDefExtW(szPath, dwWhich); 01148 if (bRet) 01149 WideCharToMultiByte(CP_ACP,0,szPath,-1,lpszPath,MAX_PATH,0,0); 01150 } 01151 return bRet; 01152 } 01153 01154 /************************************************************************* 01155 * SHLWAPI_PathFindInOtherDirs 01156 * 01157 * Internal helper for SHLWAPI_PathFindOnPathExA/W. 01158 */ 01159 static BOOL SHLWAPI_PathFindInOtherDirs(LPWSTR lpszFile, DWORD dwWhich) 01160 { 01161 static const WCHAR szSystem[] = { 'S','y','s','t','e','m','\0'}; 01162 static const WCHAR szPath[] = { 'P','A','T','H','\0'}; 01163 DWORD dwLenPATH; 01164 LPCWSTR lpszCurr; 01165 WCHAR *lpszPATH; 01166 WCHAR buff[MAX_PATH]; 01167 01168 TRACE("(%s,%08x)\n", debugstr_w(lpszFile), dwWhich); 01169 01170 /* Try system directories */ 01171 GetSystemDirectoryW(buff, MAX_PATH); 01172 if (!PathAppendW(buff, lpszFile)) 01173 return FALSE; 01174 if (PathFileExistsDefExtW(buff, dwWhich)) 01175 { 01176 strcpyW(lpszFile, buff); 01177 return TRUE; 01178 } 01179 GetWindowsDirectoryW(buff, MAX_PATH); 01180 if (!PathAppendW(buff, szSystem ) || !PathAppendW(buff, lpszFile)) 01181 return FALSE; 01182 if (PathFileExistsDefExtW(buff, dwWhich)) 01183 { 01184 strcpyW(lpszFile, buff); 01185 return TRUE; 01186 } 01187 GetWindowsDirectoryW(buff, MAX_PATH); 01188 if (!PathAppendW(buff, lpszFile)) 01189 return FALSE; 01190 if (PathFileExistsDefExtW(buff, dwWhich)) 01191 { 01192 strcpyW(lpszFile, buff); 01193 return TRUE; 01194 } 01195 /* Try dirs listed in %PATH% */ 01196 dwLenPATH = GetEnvironmentVariableW(szPath, buff, MAX_PATH); 01197 01198 if (!dwLenPATH || !(lpszPATH = HeapAlloc(GetProcessHeap(), 0, (dwLenPATH + 1) * sizeof (WCHAR)))) 01199 return FALSE; 01200 01201 GetEnvironmentVariableW(szPath, lpszPATH, dwLenPATH + 1); 01202 lpszCurr = lpszPATH; 01203 while (lpszCurr) 01204 { 01205 LPCWSTR lpszEnd = lpszCurr; 01206 LPWSTR pBuff = buff; 01207 01208 while (*lpszEnd == ' ') 01209 lpszEnd++; 01210 while (*lpszEnd && *lpszEnd != ';') 01211 *pBuff++ = *lpszEnd++; 01212 *pBuff = '\0'; 01213 01214 if (*lpszEnd) 01215 lpszCurr = lpszEnd + 1; 01216 else 01217 lpszCurr = NULL; /* Last Path, terminate after this */ 01218 01219 if (!PathAppendW(buff, lpszFile)) 01220 { 01221 HeapFree(GetProcessHeap(), 0, lpszPATH); 01222 return FALSE; 01223 } 01224 if (PathFileExistsDefExtW(buff, dwWhich)) 01225 { 01226 strcpyW(lpszFile, buff); 01227 HeapFree(GetProcessHeap(), 0, lpszPATH); 01228 return TRUE; 01229 } 01230 } 01231 HeapFree(GetProcessHeap(), 0, lpszPATH); 01232 return FALSE; 01233 } 01234 01235 /************************************************************************* 01236 * @ [SHLWAPI.5] 01237 * 01238 * Search a range of paths for a specific type of executable. 01239 * 01240 * PARAMS 01241 * lpszFile [I/O] File to search for 01242 * lppszOtherDirs [I] Other directories to look in 01243 * dwWhich [I] Type of executable to search for 01244 * 01245 * RETURNS 01246 * Success: TRUE. The path to the executable is stored in lpszFile. 01247 * Failure: FALSE. The path to the executable is unchanged. 01248 */ 01249 BOOL WINAPI PathFindOnPathExA(LPSTR lpszFile,LPCSTR *lppszOtherDirs,DWORD dwWhich) 01250 { 01251 WCHAR szFile[MAX_PATH]; 01252 WCHAR buff[MAX_PATH]; 01253 01254 TRACE("(%s,%p,%08x)\n", debugstr_a(lpszFile), lppszOtherDirs, dwWhich); 01255 01256 if (!lpszFile || !PathIsFileSpecA(lpszFile)) 01257 return FALSE; 01258 01259 MultiByteToWideChar(CP_ACP,0,lpszFile,-1,szFile,MAX_PATH); 01260 01261 /* Search provided directories first */ 01262 if (lppszOtherDirs && *lppszOtherDirs) 01263 { 01264 WCHAR szOther[MAX_PATH]; 01265 LPCSTR *lpszOtherPath = lppszOtherDirs; 01266 01267 while (lpszOtherPath && *lpszOtherPath && (*lpszOtherPath)[0]) 01268 { 01269 MultiByteToWideChar(CP_ACP,0,*lpszOtherPath,-1,szOther,MAX_PATH); 01270 PathCombineW(buff, szOther, szFile); 01271 if (PathFileExistsDefExtW(buff, dwWhich)) 01272 { 01273 WideCharToMultiByte(CP_ACP,0,buff,-1,lpszFile,MAX_PATH,0,0); 01274 return TRUE; 01275 } 01276 lpszOtherPath++; 01277 } 01278 } 01279 /* Not found, try system and path dirs */ 01280 if (SHLWAPI_PathFindInOtherDirs(szFile, dwWhich)) 01281 { 01282 WideCharToMultiByte(CP_ACP,0,szFile,-1,lpszFile,MAX_PATH,0,0); 01283 return TRUE; 01284 } 01285 return FALSE; 01286 } 01287 01288 /************************************************************************* 01289 * @ [SHLWAPI.6] 01290 * 01291 * Unicode version of PathFindOnPathExA. 01292 */ 01293 BOOL WINAPI PathFindOnPathExW(LPWSTR lpszFile,LPCWSTR *lppszOtherDirs,DWORD dwWhich) 01294 { 01295 WCHAR buff[MAX_PATH]; 01296 01297 TRACE("(%s,%p,%08x)\n", debugstr_w(lpszFile), lppszOtherDirs, dwWhich); 01298 01299 if (!lpszFile || !PathIsFileSpecW(lpszFile)) 01300 return FALSE; 01301 01302 /* Search provided directories first */ 01303 if (lppszOtherDirs && *lppszOtherDirs) 01304 { 01305 LPCWSTR *lpszOtherPath = lppszOtherDirs; 01306 while (lpszOtherPath && *lpszOtherPath && (*lpszOtherPath)[0]) 01307 { 01308 PathCombineW(buff, *lpszOtherPath, lpszFile); 01309 if (PathFileExistsDefExtW(buff, dwWhich)) 01310 { 01311 strcpyW(lpszFile, buff); 01312 return TRUE; 01313 } 01314 lpszOtherPath++; 01315 } 01316 } 01317 /* Not found, try system and path dirs */ 01318 return SHLWAPI_PathFindInOtherDirs(lpszFile, dwWhich); 01319 } 01320 01321 /************************************************************************* 01322 * PathFindOnPathA [SHLWAPI.@] 01323 * 01324 * Search a range of paths for an executable. 01325 * 01326 * PARAMS 01327 * lpszFile [I/O] File to search for 01328 * lppszOtherDirs [I] Other directories to look in 01329 * 01330 * RETURNS 01331 * Success: TRUE. The path to the executable is stored in lpszFile. 01332 * Failure: FALSE. The path to the executable is unchanged. 01333 */ 01334 BOOL WINAPI PathFindOnPathA(LPSTR lpszFile, LPCSTR *lppszOtherDirs) 01335 { 01336 TRACE("(%s,%p)\n", debugstr_a(lpszFile), lppszOtherDirs); 01337 return PathFindOnPathExA(lpszFile, lppszOtherDirs, 0); 01338 } 01339 01340 /************************************************************************* 01341 * PathFindOnPathW [SHLWAPI.@] 01342 * 01343 * See PathFindOnPathA. 01344 */ 01345 BOOL WINAPI PathFindOnPathW(LPWSTR lpszFile, LPCWSTR *lppszOtherDirs) 01346 { 01347 TRACE("(%s,%p)\n", debugstr_w(lpszFile), lppszOtherDirs); 01348 return PathFindOnPathExW(lpszFile,lppszOtherDirs, 0); 01349 } 01350 01351 /************************************************************************* 01352 * PathCompactPathExA [SHLWAPI.@] 01353 * 01354 * Compact a path into a given number of characters. 01355 * 01356 * PARAMS 01357 * lpszDest [O] Destination for compacted path 01358 * lpszPath [I] Source path 01359 * cchMax [I] Maximum size of compacted path 01360 * dwFlags [I] Reserved 01361 * 01362 * RETURNS 01363 * Success: TRUE. The compacted path is written to lpszDest. 01364 * Failure: FALSE. lpszPath is undefined. 01365 * 01366 * NOTES 01367 * If cchMax is given as 0, lpszDest will still be NUL terminated. 01368 * 01369 * The Win32 version of this function contains a bug: When cchMax == 7, 01370 * 8 bytes will be written to lpszDest. This bug is fixed in the Wine 01371 * implementation. 01372 * 01373 * Some relative paths will be different when cchMax == 5 or 6. This occurs 01374 * because Win32 will insert a "\" in lpszDest, even if one is 01375 * not present in the original path. 01376 */ 01377 BOOL WINAPI PathCompactPathExA(LPSTR lpszDest, LPCSTR lpszPath, 01378 UINT cchMax, DWORD dwFlags) 01379 { 01380 BOOL bRet = FALSE; 01381 01382 TRACE("(%p,%s,%d,0x%08x)\n", lpszDest, debugstr_a(lpszPath), cchMax, dwFlags); 01383 01384 if (lpszPath && lpszDest) 01385 { 01386 WCHAR szPath[MAX_PATH]; 01387 WCHAR szDest[MAX_PATH]; 01388 01389 MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH); 01390 szDest[0] = '\0'; 01391 bRet = PathCompactPathExW(szDest, szPath, cchMax, dwFlags); 01392 WideCharToMultiByte(CP_ACP,0,szDest,-1,lpszDest,MAX_PATH,0,0); 01393 } 01394 return bRet; 01395 } 01396 01397 /************************************************************************* 01398 * PathCompactPathExW [SHLWAPI.@] 01399 * 01400 * See PathCompactPathExA. 01401 */ 01402 BOOL WINAPI PathCompactPathExW(LPWSTR lpszDest, LPCWSTR lpszPath, 01403 UINT cchMax, DWORD dwFlags) 01404 { 01405 static const WCHAR szEllipses[] = { '.', '.', '.', '\0' }; 01406 LPCWSTR lpszFile; 01407 DWORD dwLen, dwFileLen = 0; 01408 01409 TRACE("(%p,%s,%d,0x%08x)\n", lpszDest, debugstr_w(lpszPath), cchMax, dwFlags); 01410 01411 if (!lpszPath) 01412 return FALSE; 01413 01414 if (!lpszDest) 01415 { 01416 WARN("Invalid lpszDest would crash under Win32!\n"); 01417 return FALSE; 01418 } 01419 01420 *lpszDest = '\0'; 01421 01422 if (cchMax < 2) 01423 return TRUE; 01424 01425 dwLen = strlenW(lpszPath) + 1; 01426 01427 if (dwLen < cchMax) 01428 { 01429 /* Don't need to compact */ 01430 memcpy(lpszDest, lpszPath, dwLen * sizeof(WCHAR)); 01431 return TRUE; 01432 } 01433 01434 /* Path must be compacted to fit into lpszDest */ 01435 lpszFile = PathFindFileNameW(lpszPath); 01436 dwFileLen = lpszPath + dwLen - lpszFile; 01437 01438 if (dwFileLen == dwLen) 01439 { 01440 /* No root in psth */ 01441 if (cchMax <= 4) 01442 { 01443 while (--cchMax > 0) /* No room left for anything but ellipses */ 01444 *lpszDest++ = '.'; 01445 *lpszDest = '\0'; 01446 return TRUE; 01447 } 01448 /* Compact the file name with ellipses at the end */ 01449 cchMax -= 4; 01450 memcpy(lpszDest, lpszFile, cchMax * sizeof(WCHAR)); 01451 strcpyW(lpszDest + cchMax, szEllipses); 01452 return TRUE; 01453 } 01454 /* We have a root in the path */ 01455 lpszFile--; /* Start compacted filename with the path separator */ 01456 dwFileLen++; 01457 01458 if (dwFileLen + 3 > cchMax) 01459 { 01460 /* Compact the file name */ 01461 if (cchMax <= 4) 01462 { 01463 while (--cchMax > 0) /* No room left for anything but ellipses */ 01464 *lpszDest++ = '.'; 01465 *lpszDest = '\0'; 01466 return TRUE; 01467 } 01468 strcpyW(lpszDest, szEllipses); 01469 lpszDest += 3; 01470 cchMax -= 4; 01471 *lpszDest++ = *lpszFile++; 01472 if (cchMax <= 4) 01473 { 01474 while (--cchMax > 0) /* No room left for anything but ellipses */ 01475 *lpszDest++ = '.'; 01476 *lpszDest = '\0'; 01477 return TRUE; 01478 } 01479 cchMax -= 4; 01480 memcpy(lpszDest, lpszFile, cchMax * sizeof(WCHAR)); 01481 strcpyW(lpszDest + cchMax, szEllipses); 01482 return TRUE; 01483 } 01484 01485 /* Only the root needs to be Compacted */ 01486 dwLen = cchMax - dwFileLen - 3; 01487 memcpy(lpszDest, lpszPath, dwLen * sizeof(WCHAR)); 01488 strcpyW(lpszDest + dwLen, szEllipses); 01489 strcpyW(lpszDest + dwLen + 3, lpszFile); 01490 return TRUE; 01491 } 01492 01493 /************************************************************************* 01494 * PathIsRelativeA [SHLWAPI.@] 01495 * 01496 * Determine if a path is a relative path. 01497 * 01498 * PARAMS 01499 * lpszPath [I] Path to check 01500 * 01501 * RETURNS 01502 * TRUE: The path is relative, or is invalid. 01503 * FALSE: The path is not relative. 01504 */ 01505 BOOL WINAPI PathIsRelativeA (LPCSTR lpszPath) 01506 { 01507 TRACE("(%s)\n",debugstr_a(lpszPath)); 01508 01509 if (!lpszPath || !*lpszPath || IsDBCSLeadByte(*lpszPath)) 01510 return TRUE; 01511 if (*lpszPath == '\\' || (*lpszPath && lpszPath[1] == ':')) 01512 return FALSE; 01513 return TRUE; 01514 } 01515 01516 /************************************************************************* 01517 * PathIsRelativeW [SHLWAPI.@] 01518 * 01519 * See PathIsRelativeA. 01520 */ 01521 BOOL WINAPI PathIsRelativeW (LPCWSTR lpszPath) 01522 { 01523 TRACE("(%s)\n",debugstr_w(lpszPath)); 01524 01525 if (!lpszPath || !*lpszPath) 01526 return TRUE; 01527 if (*lpszPath == '\\' || (*lpszPath && lpszPath[1] == ':')) 01528 return FALSE; 01529 return TRUE; 01530 } 01531 01532 /************************************************************************* 01533 * PathIsRootA [SHLWAPI.@] 01534 * 01535 * Determine if a path is a root path. 01536 * 01537 * PARAMS 01538 * lpszPath [I] Path to check 01539 * 01540 * RETURNS 01541 * TRUE If lpszPath is valid and a root path, 01542 * FALSE Otherwise 01543 */ 01544 BOOL WINAPI PathIsRootA(LPCSTR lpszPath) 01545 { 01546 TRACE("(%s)\n", debugstr_a(lpszPath)); 01547 01548 if (lpszPath && *lpszPath) 01549 { 01550 if (*lpszPath == '\\') 01551 { 01552 if (!lpszPath[1]) 01553 return TRUE; /* \ */ 01554 else if (lpszPath[1]=='\\') 01555 { 01556 BOOL bSeenSlash = FALSE; 01557 lpszPath += 2; 01558 01559 /* Check for UNC root path */ 01560 while (*lpszPath) 01561 { 01562 if (*lpszPath == '\\') 01563 { 01564 if (bSeenSlash) 01565 return FALSE; 01566 bSeenSlash = TRUE; 01567 } 01568 lpszPath = CharNextA(lpszPath); 01569 } 01570 return TRUE; 01571 } 01572 } 01573 else if (lpszPath[1] == ':' && lpszPath[2] == '\\' && lpszPath[3] == '\0') 01574 return TRUE; /* X:\ */ 01575 } 01576 return FALSE; 01577 } 01578 01579 /************************************************************************* 01580 * PathIsRootW [SHLWAPI.@] 01581 * 01582 * See PathIsRootA. 01583 */ 01584 BOOL WINAPI PathIsRootW(LPCWSTR lpszPath) 01585 { 01586 TRACE("(%s)\n", debugstr_w(lpszPath)); 01587 01588 if (lpszPath && *lpszPath) 01589 { 01590 if (*lpszPath == '\\') 01591 { 01592 if (!lpszPath[1]) 01593 return TRUE; /* \ */ 01594 else if (lpszPath[1]=='\\') 01595 { 01596 BOOL bSeenSlash = FALSE; 01597 lpszPath += 2; 01598 01599 /* Check for UNC root path */ 01600 while (*lpszPath) 01601 { 01602 if (*lpszPath == '\\') 01603 { 01604 if (bSeenSlash) 01605 return FALSE; 01606 bSeenSlash = TRUE; 01607 } 01608 lpszPath++; 01609 } 01610 return TRUE; 01611 } 01612 } 01613 else if (lpszPath[1] == ':' && lpszPath[2] == '\\' && lpszPath[3] == '\0') 01614 return TRUE; /* X:\ */ 01615 } 01616 return FALSE; 01617 } 01618 01619 /************************************************************************* 01620 * PathIsDirectoryA [SHLWAPI.@] 01621 * 01622 * Determine if a path is a valid directory 01623 * 01624 * PARAMS 01625 * lpszPath [I] Path to check. 01626 * 01627 * RETURNS 01628 * FILE_ATTRIBUTE_DIRECTORY if lpszPath exists and can be read (See Notes) 01629 * FALSE if lpszPath is invalid or not a directory. 01630 * 01631 * NOTES 01632 * Although this function is prototyped as returning a BOOL, it returns 01633 * FILE_ATTRIBUTE_DIRECTORY for success. This means that code such as: 01634 * 01635 *| if (PathIsDirectoryA("c:\\windows\\") == TRUE) 01636 *| ... 01637 * 01638 * will always fail. 01639 */ 01640 BOOL WINAPI PathIsDirectoryA(LPCSTR lpszPath) 01641 { 01642 DWORD dwAttr; 01643 01644 TRACE("(%s)\n", debugstr_a(lpszPath)); 01645 01646 if (!lpszPath || PathIsUNCServerA(lpszPath)) 01647 return FALSE; 01648 01649 if (PathIsUNCServerShareA(lpszPath)) 01650 { 01651 FIXME("UNC Server Share not yet supported - FAILING\n"); 01652 return FALSE; 01653 } 01654 01655 if ((dwAttr = GetFileAttributesA(lpszPath)) == INVALID_FILE_ATTRIBUTES) 01656 return FALSE; 01657 return dwAttr & FILE_ATTRIBUTE_DIRECTORY; 01658 } 01659 01660 /************************************************************************* 01661 * PathIsDirectoryW [SHLWAPI.@] 01662 * 01663 * See PathIsDirectoryA. 01664 */ 01665 BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath) 01666 { 01667 DWORD dwAttr; 01668 01669 TRACE("(%s)\n", debugstr_w(lpszPath)); 01670 01671 if (!lpszPath || PathIsUNCServerW(lpszPath)) 01672 return FALSE; 01673 01674 if (PathIsUNCServerShareW(lpszPath)) 01675 { 01676 FIXME("UNC Server Share not yet supported - FAILING\n"); 01677 return FALSE; 01678 } 01679 01680 if ((dwAttr = GetFileAttributesW(lpszPath)) == INVALID_FILE_ATTRIBUTES) 01681 return FALSE; 01682 return dwAttr & FILE_ATTRIBUTE_DIRECTORY; 01683 } 01684 01685 /************************************************************************* 01686 * PathFileExistsA [SHLWAPI.@] 01687 * 01688 * Determine if a file exists. 01689 * 01690 * PARAMS 01691 * lpszPath [I] Path to check 01692 * 01693 * RETURNS 01694 * TRUE If the file exists and is readable 01695 * FALSE Otherwise 01696 */ 01697 BOOL WINAPI PathFileExistsA(LPCSTR lpszPath) 01698 { 01699 UINT iPrevErrMode; 01700 DWORD dwAttr; 01701 01702 TRACE("(%s)\n",debugstr_a(lpszPath)); 01703 01704 if (!lpszPath) 01705 return FALSE; 01706 01707 /* Prevent a dialog box if path is on a disk that has been ejected. */ 01708 iPrevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS); 01709 dwAttr = GetFileAttributesA(lpszPath); 01710 SetErrorMode(iPrevErrMode); 01711 return dwAttr == INVALID_FILE_ATTRIBUTES ? FALSE : TRUE; 01712 } 01713 01714 /************************************************************************* 01715 * PathFileExistsW [SHLWAPI.@] 01716 * 01717 * See PathFileExistsA. 01718 */ 01719 BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath) 01720 { 01721 UINT iPrevErrMode; 01722 DWORD dwAttr; 01723 01724 TRACE("(%s)\n",debugstr_w(lpszPath)); 01725 01726 if (!lpszPath) 01727 return FALSE; 01728 01729 iPrevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS); 01730 dwAttr = GetFileAttributesW(lpszPath); 01731 SetErrorMode(iPrevErrMode); 01732 return dwAttr == INVALID_FILE_ATTRIBUTES ? FALSE : TRUE; 01733 } 01734 01735 /************************************************************************* 01736 * PathFileExistsAndAttributesA [SHLWAPI.445] 01737 * 01738 * Determine if a file exists. 01739 * 01740 * PARAMS 01741 * lpszPath [I] Path to check 01742 * dwAttr [O] attributes of file 01743 * 01744 * RETURNS 01745 * TRUE If the file exists and is readable 01746 * FALSE Otherwise 01747 */ 01748 BOOL WINAPI PathFileExistsAndAttributesA(LPCSTR lpszPath, DWORD *dwAttr) 01749 { 01750 UINT iPrevErrMode; 01751 DWORD dwVal = 0; 01752 01753 TRACE("(%s %p)\n", debugstr_a(lpszPath), dwAttr); 01754 01755 if (dwAttr) 01756 *dwAttr = INVALID_FILE_ATTRIBUTES; 01757 01758 if (!lpszPath) 01759 return FALSE; 01760 01761 iPrevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS); 01762 dwVal = GetFileAttributesA(lpszPath); 01763 SetErrorMode(iPrevErrMode); 01764 if (dwAttr) 01765 *dwAttr = dwVal; 01766 return (dwVal != INVALID_FILE_ATTRIBUTES); 01767 } 01768 01769 /************************************************************************* 01770 * PathFileExistsAndAttributesW [SHLWAPI.446] 01771 * 01772 * See PathFileExistsA. 01773 */ 01774 BOOL WINAPI PathFileExistsAndAttributesW(LPCWSTR lpszPath, DWORD *dwAttr) 01775 { 01776 UINT iPrevErrMode; 01777 DWORD dwVal; 01778 01779 TRACE("(%s %p)\n", debugstr_w(lpszPath), dwAttr); 01780 01781 if (!lpszPath) 01782 return FALSE; 01783 01784 iPrevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS); 01785 dwVal = GetFileAttributesW(lpszPath); 01786 SetErrorMode(iPrevErrMode); 01787 if (dwAttr) 01788 *dwAttr = dwVal; 01789 return (dwVal != INVALID_FILE_ATTRIBUTES); 01790 } 01791 01792 /************************************************************************* 01793 * PathMatchSingleMaskA [internal] 01794 */ 01795 static BOOL PathMatchSingleMaskA(LPCSTR name, LPCSTR mask) 01796 { 01797 while (*name && *mask && *mask!=';') 01798 { 01799 if (*mask == '*') 01800 { 01801 do 01802 { 01803 if (PathMatchSingleMaskA(name,mask+1)) 01804 return TRUE; /* try substrings */ 01805 } while (*name++); 01806 return FALSE; 01807 } 01808 01809 if (toupper(*mask) != toupper(*name) && *mask != '?') 01810 return FALSE; 01811 01812 name = CharNextA(name); 01813 mask = CharNextA(mask); 01814 } 01815 01816 if (!*name) 01817 { 01818 while (*mask == '*') 01819 mask++; 01820 if (!*mask || *mask == ';') 01821 return TRUE; 01822 } 01823 return FALSE; 01824 } 01825 01826 /************************************************************************* 01827 * PathMatchSingleMaskW [internal] 01828 */ 01829 static BOOL PathMatchSingleMaskW(LPCWSTR name, LPCWSTR mask) 01830 { 01831 while (*name && *mask && *mask != ';') 01832 { 01833 if (*mask == '*') 01834 { 01835 do 01836 { 01837 if (PathMatchSingleMaskW(name,mask+1)) 01838 return TRUE; /* try substrings */ 01839 } while (*name++); 01840 return FALSE; 01841 } 01842 01843 if (toupperW(*mask) != toupperW(*name) && *mask != '?') 01844 return FALSE; 01845 01846 name++; 01847 mask++; 01848 } 01849 if (!*name) 01850 { 01851 while (*mask == '*') 01852 mask++; 01853 if (!*mask || *mask == ';') 01854 return TRUE; 01855 } 01856 return FALSE; 01857 } 01858 01859 /************************************************************************* 01860 * PathMatchSpecA [SHLWAPI.@] 01861 * 01862 * Determine if a path matches one or more search masks. 01863 * 01864 * PARAMS 01865 * lpszPath [I] Path to check 01866 * lpszMask [I] Search mask(s) 01867 * 01868 * RETURNS 01869 * TRUE If lpszPath is valid and is matched 01870 * FALSE Otherwise 01871 * 01872 * NOTES 01873 * Multiple search masks may be given if they are separated by ";". The 01874 * pattern "*.*" is treated specially in that it matches all paths (for 01875 * backwards compatibility with DOS). 01876 */ 01877 BOOL WINAPI PathMatchSpecA(LPCSTR lpszPath, LPCSTR lpszMask) 01878 { 01879 TRACE("(%s,%s)\n", lpszPath, lpszMask); 01880 01881 if (!lstrcmpA(lpszMask, "*.*")) 01882 return TRUE; /* Matches every path */ 01883 01884 while (*lpszMask) 01885 { 01886 while (*lpszMask == ' ') 01887 lpszMask++; /* Eat leading spaces */ 01888 01889 if (PathMatchSingleMaskA(lpszPath, lpszMask)) 01890 return TRUE; /* Matches the current mask */ 01891 01892 while (*lpszMask && *lpszMask != ';') 01893 lpszMask = CharNextA(lpszMask); /* masks separated by ';' */ 01894 01895 if (*lpszMask == ';') 01896 lpszMask++; 01897 } 01898 return FALSE; 01899 } 01900 01901 /************************************************************************* 01902 * PathMatchSpecW [SHLWAPI.@] 01903 * 01904 * See PathMatchSpecA. 01905 */ 01906 BOOL WINAPI PathMatchSpecW(LPCWSTR lpszPath, LPCWSTR lpszMask) 01907 { 01908 static const WCHAR szStarDotStar[] = { '*', '.', '*', '\0' }; 01909 01910 TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszMask)); 01911 01912 if (!lstrcmpW(lpszMask, szStarDotStar)) 01913 return TRUE; /* Matches every path */ 01914 01915 while (*lpszMask) 01916 { 01917 while (*lpszMask == ' ') 01918 lpszMask++; /* Eat leading spaces */ 01919 01920 if (PathMatchSingleMaskW(lpszPath, lpszMask)) 01921 return TRUE; /* Matches the current path */ 01922 01923 while (*lpszMask && *lpszMask != ';') 01924 lpszMask++; /* masks separated by ';' */ 01925 01926 if (*lpszMask == ';') 01927 lpszMask++; 01928 } 01929 return FALSE; 01930 } 01931 01932 /************************************************************************* 01933 * PathIsSameRootA [SHLWAPI.@] 01934 * 01935 * Determine if two paths share the same root. 01936 * 01937 * PARAMS 01938 * lpszPath1 [I] Source path 01939 * lpszPath2 [I] Path to compare with 01940 * 01941 * RETURNS 01942 * TRUE If both paths are valid and share the same root. 01943 * FALSE If either path is invalid or the paths do not share the same root. 01944 */ 01945 BOOL WINAPI PathIsSameRootA(LPCSTR lpszPath1, LPCSTR lpszPath2) 01946 { 01947 LPCSTR lpszStart; 01948 int dwLen; 01949 01950 TRACE("(%s,%s)\n", debugstr_a(lpszPath1), debugstr_a(lpszPath2)); 01951 01952 if (!lpszPath1 || !lpszPath2 || !(lpszStart = PathSkipRootA(lpszPath1))) 01953 return FALSE; 01954 01955 dwLen = PathCommonPrefixA(lpszPath1, lpszPath2, NULL) + 1; 01956 if (lpszStart - lpszPath1 > dwLen) 01957 return FALSE; /* Paths not common up to length of the root */ 01958 return TRUE; 01959 } 01960 01961 /************************************************************************* 01962 * PathIsSameRootW [SHLWAPI.@] 01963 * 01964 * See PathIsSameRootA. 01965 */ 01966 BOOL WINAPI PathIsSameRootW(LPCWSTR lpszPath1, LPCWSTR lpszPath2) 01967 { 01968 LPCWSTR lpszStart; 01969 int dwLen; 01970 01971 TRACE("(%s,%s)\n", debugstr_w(lpszPath1), debugstr_w(lpszPath2)); 01972 01973 if (!lpszPath1 || !lpszPath2 || !(lpszStart = PathSkipRootW(lpszPath1))) 01974 return FALSE; 01975 01976 dwLen = PathCommonPrefixW(lpszPath1, lpszPath2, NULL) + 1; 01977 if (lpszStart - lpszPath1 > dwLen) 01978 return FALSE; /* Paths not common up to length of the root */ 01979 return TRUE; 01980 } 01981 01982 /************************************************************************* 01983 * PathIsContentTypeA [SHLWAPI.@] 01984 * 01985 * Determine if a file is of a given registered content type. 01986 * 01987 * PARAMS 01988 * lpszPath [I] File to check 01989 * lpszContentType [I] Content type to check for 01990 * 01991 * RETURNS 01992 * TRUE If lpszPath is a given registered content type, 01993 * FALSE Otherwise. 01994 * 01995 * NOTES 01996 * This function looks up the registered content type for lpszPath. If 01997 * a content type is registered, it is compared (case insensitively) to 01998 * lpszContentType. Only if this matches does the function succeed. 01999 */ 02000 BOOL WINAPI PathIsContentTypeA(LPCSTR lpszPath, LPCSTR lpszContentType) 02001 { 02002 LPCSTR szExt; 02003 DWORD dwDummy; 02004 char szBuff[MAX_PATH]; 02005 02006 TRACE("(%s,%s)\n", debugstr_a(lpszPath), debugstr_a(lpszContentType)); 02007 02008 if (lpszPath && (szExt = PathFindExtensionA(lpszPath)) && *szExt && 02009 !SHGetValueA(HKEY_CLASSES_ROOT, szExt, "Content Type", 02010 REG_NONE, szBuff, &dwDummy) && 02011 !strcasecmp(lpszContentType, szBuff)) 02012 { 02013 return TRUE; 02014 } 02015 return FALSE; 02016 } 02017 02018 /************************************************************************* 02019 * PathIsContentTypeW [SHLWAPI.@] 02020 * 02021 * See PathIsContentTypeA. 02022 */ 02023 BOOL WINAPI PathIsContentTypeW(LPCWSTR lpszPath, LPCWSTR lpszContentType) 02024 { 02025 static const WCHAR szContentType[] = { 'C','o','n','t','e','n','t',' ','T','y','p','e','\0' }; 02026 LPCWSTR szExt; 02027 DWORD dwDummy; 02028 WCHAR szBuff[MAX_PATH]; 02029 02030 TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszContentType)); 02031 02032 if (lpszPath && (szExt = PathFindExtensionW(lpszPath)) && *szExt && 02033 !SHGetValueW(HKEY_CLASSES_ROOT, szExt, szContentType, 02034 REG_NONE, szBuff, &dwDummy) && 02035 !strcmpiW(lpszContentType, szBuff)) 02036 { 02037 return TRUE; 02038 } 02039 return FALSE; 02040 } 02041 02042 /************************************************************************* 02043 * PathIsFileSpecA [SHLWAPI.@] 02044 * 02045 * Determine if a path is a file specification. 02046 * 02047 * PARAMS 02048 * lpszPath [I] Path to check 02049 * 02050 * RETURNS 02051 * TRUE If lpszPath is a file specification (i.e. Contains no directories). 02052 * FALSE Otherwise. 02053 */ 02054 BOOL WINAPI PathIsFileSpecA(LPCSTR lpszPath) 02055 { 02056 TRACE("(%s)\n", debugstr_a(lpszPath)); 02057 02058 if (!lpszPath) 02059 return FALSE; 02060 02061 while (*lpszPath) 02062 { 02063 if (*lpszPath == '\\' || *lpszPath == ':') 02064 return FALSE; 02065 lpszPath = CharNextA(lpszPath); 02066 } 02067 return TRUE; 02068 } 02069 02070 /************************************************************************* 02071 * PathIsFileSpecW [SHLWAPI.@] 02072 * 02073 * See PathIsFileSpecA. 02074 */ 02075 BOOL WINAPI PathIsFileSpecW(LPCWSTR lpszPath) 02076 { 02077 TRACE("(%s)\n", debugstr_w(lpszPath)); 02078 02079 if (!lpszPath) 02080 return FALSE; 02081 02082 while (*lpszPath) 02083 { 02084 if (*lpszPath == '\\' || *lpszPath == ':') 02085 return FALSE; 02086 lpszPath++; 02087 } 02088 return TRUE; 02089 } 02090 02091 /************************************************************************* 02092 * PathIsPrefixA [SHLWAPI.@] 02093 * 02094 * Determine if a path is a prefix of another. 02095 * 02096 * PARAMS 02097 * lpszPrefix [I] Prefix 02098 * lpszPath [I] Path to check 02099 * 02100 * RETURNS 02101 * TRUE If lpszPath has lpszPrefix as its prefix, 02102 * FALSE If either path is NULL or lpszPrefix is not a prefix 02103 */ 02104 BOOL WINAPI PathIsPrefixA (LPCSTR lpszPrefix, LPCSTR lpszPath) 02105 { 02106 TRACE("(%s,%s)\n", debugstr_a(lpszPrefix), debugstr_a(lpszPath)); 02107 02108 if (lpszPrefix && lpszPath && 02109 PathCommonPrefixA(lpszPath, lpszPrefix, NULL) == (int)strlen(lpszPrefix)) 02110 return TRUE; 02111 return FALSE; 02112 } 02113 02114 /************************************************************************* 02115 * PathIsPrefixW [SHLWAPI.@] 02116 * 02117 * See PathIsPrefixA. 02118 */ 02119 BOOL WINAPI PathIsPrefixW(LPCWSTR lpszPrefix, LPCWSTR lpszPath) 02120 { 02121 TRACE("(%s,%s)\n", debugstr_w(lpszPrefix), debugstr_w(lpszPath)); 02122 02123 if (lpszPrefix && lpszPath && 02124 PathCommonPrefixW(lpszPath, lpszPrefix, NULL) == (int)strlenW(lpszPrefix)) 02125 return TRUE; 02126 return FALSE; 02127 } 02128 02129 /************************************************************************* 02130 * PathIsSystemFolderA [SHLWAPI.@] 02131 * 02132 * Determine if a path or file attributes are a system folder. 02133 * 02134 * PARAMS 02135 * lpszPath [I] Path to check. 02136 * dwAttrib [I] Attributes to check, if lpszPath is NULL. 02137 * 02138 * RETURNS 02139 * TRUE If lpszPath or dwAttrib are a system folder. 02140 * FALSE If GetFileAttributesA() fails or neither parameter is a system folder. 02141 */ 02142 BOOL WINAPI PathIsSystemFolderA(LPCSTR lpszPath, DWORD dwAttrib) 02143 { 02144 TRACE("(%s,0x%08x)\n", debugstr_a(lpszPath), dwAttrib); 02145 02146 if (lpszPath && *lpszPath) 02147 dwAttrib = GetFileAttributesA(lpszPath); 02148 02149 if (dwAttrib == INVALID_FILE_ATTRIBUTES || !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY) || 02150 !(dwAttrib & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY))) 02151 return FALSE; 02152 return TRUE; 02153 } 02154 02155 /************************************************************************* 02156 * PathIsSystemFolderW [SHLWAPI.@] 02157 * 02158 * See PathIsSystemFolderA. 02159 */ 02160 BOOL WINAPI PathIsSystemFolderW(LPCWSTR lpszPath, DWORD dwAttrib) 02161 { 02162 TRACE("(%s,0x%08x)\n", debugstr_w(lpszPath), dwAttrib); 02163 02164 if (lpszPath && *lpszPath) 02165 dwAttrib = GetFileAttributesW(lpszPath); 02166 02167 if (dwAttrib == INVALID_FILE_ATTRIBUTES || !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY) || 02168 !(dwAttrib & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY))) 02169 return FALSE; 02170 return TRUE; 02171 } 02172 02173 /************************************************************************* 02174 * PathIsUNCA [SHLWAPI.@] 02175 * 02176 * Determine if a path is in UNC format. 02177 * 02178 * PARAMS 02179 * lpszPath [I] Path to check 02180 * 02181 * RETURNS 02182 * TRUE: The path is UNC. 02183 * FALSE: The path is not UNC or is NULL. 02184 */ 02185 BOOL WINAPI PathIsUNCA(LPCSTR lpszPath) 02186 { 02187 TRACE("(%s)\n",debugstr_a(lpszPath)); 02188 02189 if (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\') && (lpszPath[2]!='?')) 02190 return TRUE; 02191 return FALSE; 02192 } 02193 02194 /************************************************************************* 02195 * PathIsUNCW [SHLWAPI.@] 02196 * 02197 * See PathIsUNCA. 02198 */ 02199 BOOL WINAPI PathIsUNCW(LPCWSTR lpszPath) 02200 { 02201 TRACE("(%s)\n",debugstr_w(lpszPath)); 02202 02203 if (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\') && (lpszPath[2]!='?')) 02204 return TRUE; 02205 return FALSE; 02206 } 02207 02208 /************************************************************************* 02209 * PathIsUNCServerA [SHLWAPI.@] 02210 * 02211 * Determine if a path is a UNC server name ("\\SHARENAME"). 02212 * 02213 * PARAMS 02214 * lpszPath [I] Path to check. 02215 * 02216 * RETURNS 02217 * TRUE If lpszPath is a valid UNC server name. 02218 * FALSE Otherwise. 02219 * 02220 * NOTES 02221 * This routine is bug compatible with Win32: Server names with a 02222 * trailing backslash (e.g. "\\FOO\"), return FALSE incorrectly. 02223 * Fixing this bug may break other shlwapi functions! 02224 */ 02225 BOOL WINAPI PathIsUNCServerA(LPCSTR lpszPath) 02226 { 02227 TRACE("(%s)\n", debugstr_a(lpszPath)); 02228 02229 if (lpszPath && *lpszPath++ == '\\' && *lpszPath++ == '\\') 02230 { 02231 while (*lpszPath) 02232 { 02233 if (*lpszPath == '\\') 02234 return FALSE; 02235 lpszPath = CharNextA(lpszPath); 02236 } 02237 return TRUE; 02238 } 02239 return FALSE; 02240 } 02241 02242 /************************************************************************* 02243 * PathIsUNCServerW [SHLWAPI.@] 02244 * 02245 * See PathIsUNCServerA. 02246 */ 02247 BOOL WINAPI PathIsUNCServerW(LPCWSTR lpszPath) 02248 { 02249 TRACE("(%s)\n", debugstr_w(lpszPath)); 02250 02251 if (lpszPath && lpszPath[0] == '\\' && lpszPath[1] == '\\') 02252 { 02253 return !strchrW( lpszPath + 2, '\\' ); 02254 } 02255 return FALSE; 02256 } 02257 02258 /************************************************************************* 02259 * PathIsUNCServerShareA [SHLWAPI.@] 02260 * 02261 * Determine if a path is a UNC server share ("\\SHARENAME\SHARE"). 02262 * 02263 * PARAMS 02264 * lpszPath [I] Path to check. 02265 * 02266 * RETURNS 02267 * TRUE If lpszPath is a valid UNC server share. 02268 * FALSE Otherwise. 02269 * 02270 * NOTES 02271 * This routine is bug compatible with Win32: Server shares with a 02272 * trailing backslash (e.g. "\\FOO\BAR\"), return FALSE incorrectly. 02273 * Fixing this bug may break other shlwapi functions! 02274 */ 02275 BOOL WINAPI PathIsUNCServerShareA(LPCSTR lpszPath) 02276 { 02277 TRACE("(%s)\n", debugstr_a(lpszPath)); 02278 02279 if (lpszPath && *lpszPath++ == '\\' && *lpszPath++ == '\\') 02280 { 02281 BOOL bSeenSlash = FALSE; 02282 while (*lpszPath) 02283 { 02284 if (*lpszPath == '\\') 02285 { 02286 if (bSeenSlash) 02287 return FALSE; 02288 bSeenSlash = TRUE; 02289 } 02290 lpszPath = CharNextA(lpszPath); 02291 } 02292 return bSeenSlash; 02293 } 02294 return FALSE; 02295 } 02296 02297 /************************************************************************* 02298 * PathIsUNCServerShareW [SHLWAPI.@] 02299 * 02300 * See PathIsUNCServerShareA. 02301 */ 02302 BOOL WINAPI PathIsUNCServerShareW(LPCWSTR lpszPath) 02303 { 02304 TRACE("(%s)\n", debugstr_w(lpszPath)); 02305 02306 if (lpszPath && *lpszPath++ == '\\' && *lpszPath++ == '\\') 02307 { 02308 BOOL bSeenSlash = FALSE; 02309 while (*lpszPath) 02310 { 02311 if (*lpszPath == '\\') 02312 { 02313 if (bSeenSlash) 02314 return FALSE; 02315 bSeenSlash = TRUE; 02316 } 02317 lpszPath++; 02318 } 02319 return bSeenSlash; 02320 } 02321 return FALSE; 02322 } 02323 02324 /************************************************************************* 02325 * PathCanonicalizeA [SHLWAPI.@] 02326 * 02327 * Convert a path to its canonical form. 02328 * 02329 * PARAMS 02330 * lpszBuf [O] Output path 02331 * lpszPath [I] Path to canonicalize 02332 * 02333 * RETURNS 02334 * Success: TRUE. lpszBuf contains the output path, 02335 * Failure: FALSE, If input path is invalid. lpszBuf is undefined 02336 */ 02337 BOOL WINAPI PathCanonicalizeA(LPSTR lpszBuf, LPCSTR lpszPath) 02338 { 02339 BOOL bRet = FALSE; 02340 02341 TRACE("(%p,%s)\n", lpszBuf, debugstr_a(lpszPath)); 02342 02343 if (lpszBuf) 02344 *lpszBuf = '\0'; 02345 02346 if (!lpszBuf || !lpszPath) 02347 SetLastError(ERROR_INVALID_PARAMETER); 02348 else 02349 { 02350 WCHAR szPath[MAX_PATH]; 02351 WCHAR szBuff[MAX_PATH]; 02352 int ret = MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH); 02353 02354 if (!ret) { 02355 WARN("Failed to convert string to widechar (too long?), LE %d.\n", GetLastError()); 02356 return FALSE; 02357 } 02358 bRet = PathCanonicalizeW(szBuff, szPath); 02359 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszBuf,MAX_PATH,0,0); 02360 } 02361 return bRet; 02362 } 02363 02364 02365 /************************************************************************* 02366 * PathCanonicalizeW [SHLWAPI.@] 02367 * 02368 * See PathCanonicalizeA. 02369 */ 02370 BOOL WINAPI PathCanonicalizeW(LPWSTR lpszBuf, LPCWSTR lpszPath) 02371 { 02372 LPWSTR lpszDst = lpszBuf; 02373 LPCWSTR lpszSrc = lpszPath; 02374 02375 TRACE("(%p,%s)\n", lpszBuf, debugstr_w(lpszPath)); 02376 02377 if (lpszBuf) 02378 *lpszDst = '\0'; 02379 02380 if (!lpszBuf || !lpszPath) 02381 { 02382 SetLastError(ERROR_INVALID_PARAMETER); 02383 return FALSE; 02384 } 02385 02386 if (!*lpszPath) 02387 { 02388 *lpszBuf++ = '\\'; 02389 *lpszBuf = '\0'; 02390 return TRUE; 02391 } 02392 02393 /* Copy path root */ 02394 if (*lpszSrc == '\\') 02395 { 02396 *lpszDst++ = *lpszSrc++; 02397 } 02398 else if (*lpszSrc && lpszSrc[1] == ':') 02399 { 02400 /* X:\ */ 02401 *lpszDst++ = *lpszSrc++; 02402 *lpszDst++ = *lpszSrc++; 02403 if (*lpszSrc == '\\') 02404 *lpszDst++ = *lpszSrc++; 02405 } 02406 02407 /* Canonicalize the rest of the path */ 02408 while (*lpszSrc) 02409 { 02410 if (*lpszSrc == '.') 02411 { 02412 if (lpszSrc[1] == '\\' && (lpszSrc == lpszPath || lpszSrc[-1] == '\\' || lpszSrc[-1] == ':')) 02413 { 02414 lpszSrc += 2; /* Skip .\ */ 02415 } 02416 else if (lpszSrc[1] == '.' && (lpszDst == lpszBuf || lpszDst[-1] == '\\')) 02417 { 02418 /* \.. backs up a directory, over the root if it has no \ following X:. 02419 * .. is ignored if it would remove a UNC server name or inital \\ 02420 */ 02421 if (lpszDst != lpszBuf) 02422 { 02423 *lpszDst = '\0'; /* Allow PathIsUNCServerShareA test on lpszBuf */ 02424 if (lpszDst > lpszBuf+1 && lpszDst[-1] == '\\' && 02425 (lpszDst[-2] != '\\' || lpszDst > lpszBuf+2)) 02426 { 02427 if (lpszDst[-2] == ':' && (lpszDst > lpszBuf+3 || lpszDst[-3] == ':')) 02428 { 02429 lpszDst -= 2; 02430 while (lpszDst > lpszBuf && *lpszDst != '\\') 02431 lpszDst--; 02432 if (*lpszDst == '\\') 02433 lpszDst++; /* Reset to last '\' */ 02434 else 02435 lpszDst = lpszBuf; /* Start path again from new root */ 02436 } 02437 else if (lpszDst[-2] != ':' && !PathIsUNCServerShareW(lpszBuf)) 02438 lpszDst -= 2; 02439 } 02440 while (lpszDst > lpszBuf && *lpszDst != '\\') 02441 lpszDst--; 02442 if (lpszDst == lpszBuf) 02443 { 02444 *lpszDst++ = '\\'; 02445 lpszSrc++; 02446 } 02447 } 02448 lpszSrc += 2; /* Skip .. in src path */ 02449 } 02450 else 02451 *lpszDst++ = *lpszSrc++; 02452 } 02453 else 02454 *lpszDst++ = *lpszSrc++; 02455 } 02456 /* Append \ to naked drive specs */ 02457 if (lpszDst - lpszBuf == 2 && lpszDst[-1] == ':') 02458 *lpszDst++ = '\\'; 02459 *lpszDst++ = '\0'; 02460 return TRUE; 02461 } 02462 02463 /************************************************************************* 02464 * PathFindNextComponentA [SHLWAPI.@] 02465 * 02466 * Find the next component in a path. 02467 * 02468 * PARAMS 02469 * lpszPath [I] Path to find next component in 02470 * 02471 * RETURNS 02472 * Success: A pointer to the next component, or the end of the string. 02473 * Failure: NULL, If lpszPath is invalid 02474 * 02475 * NOTES 02476 * A 'component' is either a backslash character (\) or UNC marker (\\). 02477 * Because of this, relative paths (e.g "c:foo") are regarded as having 02478 * only one component. 02479 */ 02480 LPSTR WINAPI PathFindNextComponentA(LPCSTR lpszPath) 02481 { 02482 LPSTR lpszSlash; 02483 02484 TRACE("(%s)\n", debugstr_a(lpszPath)); 02485 02486 if(!lpszPath || !*lpszPath) 02487 return NULL; 02488 02489 if ((lpszSlash = StrChrA(lpszPath, '\\'))) 02490 { 02491 if (lpszSlash[1] == '\\') 02492 lpszSlash++; 02493 return lpszSlash + 1; 02494 } 02495 return (LPSTR)lpszPath + strlen(lpszPath); 02496 } 02497 02498 /************************************************************************* 02499 * PathFindNextComponentW [SHLWAPI.@] 02500 * 02501 * See PathFindNextComponentA. 02502 */ 02503 LPWSTR WINAPI PathFindNextComponentW(LPCWSTR lpszPath) 02504 { 02505 LPWSTR lpszSlash; 02506 02507 TRACE("(%s)\n", debugstr_w(lpszPath)); 02508 02509 if(!lpszPath || !*lpszPath) 02510 return NULL; 02511 02512 if ((lpszSlash = StrChrW(lpszPath, '\\'))) 02513 { 02514 if (lpszSlash[1] == '\\') 02515 lpszSlash++; 02516 return lpszSlash + 1; 02517 } 02518 return (LPWSTR)lpszPath + strlenW(lpszPath); 02519 } 02520 02521 /************************************************************************* 02522 * PathAddExtensionA [SHLWAPI.@] 02523 * 02524 * Add a file extension to a path 02525 * 02526 * PARAMS 02527 * lpszPath [I/O] Path to add extension to 02528 * lpszExtension [I] Extension to add to lpszPath 02529 * 02530 * RETURNS 02531 * TRUE If the path was modified, 02532 * FALSE If lpszPath or lpszExtension are invalid, lpszPath has an 02533 * extension already, or the new path length is too big. 02534 * 02535 * FIXME 02536 * What version of shlwapi.dll adds "exe" if lpszExtension is NULL? Win2k 02537 * does not do this, so the behaviour was removed. 02538 */ 02539 BOOL WINAPI PathAddExtensionA(LPSTR lpszPath, LPCSTR lpszExtension) 02540 { 02541 size_t dwLen; 02542 02543 TRACE("(%s,%s)\n", debugstr_a(lpszPath), debugstr_a(lpszExtension)); 02544 02545 if (!lpszPath || !lpszExtension || *(PathFindExtensionA(lpszPath))) 02546 return FALSE; 02547 02548 dwLen = strlen(lpszPath); 02549 02550 if (dwLen + strlen(lpszExtension) >= MAX_PATH) 02551 return FALSE; 02552 02553 strcpy(lpszPath + dwLen, lpszExtension); 02554 return TRUE; 02555 } 02556 02557 /************************************************************************* 02558 * PathAddExtensionW [SHLWAPI.@] 02559 * 02560 * See PathAddExtensionA. 02561 */ 02562 BOOL WINAPI PathAddExtensionW(LPWSTR lpszPath, LPCWSTR lpszExtension) 02563 { 02564 size_t dwLen; 02565 02566 TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszExtension)); 02567 02568 if (!lpszPath || !lpszExtension || *(PathFindExtensionW(lpszPath))) 02569 return FALSE; 02570 02571 dwLen = strlenW(lpszPath); 02572 02573 if (dwLen + strlenW(lpszExtension) >= MAX_PATH) 02574 return FALSE; 02575 02576 strcpyW(lpszPath + dwLen, lpszExtension); 02577 return TRUE; 02578 } 02579 02580 /************************************************************************* 02581 * PathMakePrettyA [SHLWAPI.@] 02582 * 02583 * Convert an uppercase DOS filename into lowercase. 02584 * 02585 * PARAMS 02586 * lpszPath [I/O] Path to convert. 02587 * 02588 * RETURNS 02589 * TRUE If the path was an uppercase DOS path and was converted, 02590 * FALSE Otherwise. 02591 */ 02592 BOOL WINAPI PathMakePrettyA(LPSTR lpszPath) 02593 { 02594 LPSTR pszIter = lpszPath; 02595 02596 TRACE("(%s)\n", debugstr_a(lpszPath)); 02597 02598 if (!pszIter) 02599 return FALSE; 02600 02601 if (*pszIter) 02602 { 02603 do 02604 { 02605 if (islower(*pszIter) || IsDBCSLeadByte(*pszIter)) 02606 return FALSE; /* Not DOS path */ 02607 pszIter++; 02608 } while (*pszIter); 02609 pszIter = lpszPath + 1; 02610 while (*pszIter) 02611 { 02612 *pszIter = tolower(*pszIter); 02613 pszIter++; 02614 } 02615 } 02616 return TRUE; 02617 } 02618 02619 /************************************************************************* 02620 * PathMakePrettyW [SHLWAPI.@] 02621 * 02622 * See PathMakePrettyA. 02623 */ 02624 BOOL WINAPI PathMakePrettyW(LPWSTR lpszPath) 02625 { 02626 LPWSTR pszIter = lpszPath; 02627 02628 TRACE("(%s)\n", debugstr_w(lpszPath)); 02629 02630 if (!pszIter) 02631 return FALSE; 02632 02633 if (*pszIter) 02634 { 02635 do 02636 { 02637 if (islowerW(*pszIter)) 02638 return FALSE; /* Not DOS path */ 02639 pszIter++; 02640 } while (*pszIter); 02641 pszIter = lpszPath + 1; 02642 while (*pszIter) 02643 { 02644 *pszIter = tolowerW(*pszIter); 02645 pszIter++; 02646 } 02647 } 02648 return TRUE; 02649 } 02650 02651 /************************************************************************* 02652 * PathCommonPrefixA [SHLWAPI.@] 02653 * 02654 * Determine the length of the common prefix between two paths. 02655 * 02656 * PARAMS 02657 * lpszFile1 [I] First path for comparison 02658 * lpszFile2 [I] Second path for comparison 02659 * achPath [O] Destination for common prefix string 02660 * 02661 * RETURNS 02662 * The length of the common prefix. This is 0 if there is no common 02663 * prefix between the paths or if any parameters are invalid. If the prefix 02664 * is non-zero and achPath is not NULL, achPath is filled with the common 02665 * part of the prefix and NUL terminated. 02666 * 02667 * NOTES 02668 * A common prefix of 2 is always returned as 3. It is thus possible for 02669 * the length returned to be invalid (i.e. Longer than one or both of the 02670 * strings given as parameters). This Win32 behaviour has been implemented 02671 * here, and cannot be changed (fixed?) without breaking other SHLWAPI calls. 02672 * To work around this when using this function, always check that the byte 02673 * at [common_prefix_len-1] is not a NUL. If it is, deduct 1 from the prefix. 02674 */ 02675 int WINAPI PathCommonPrefixA(LPCSTR lpszFile1, LPCSTR lpszFile2, LPSTR achPath) 02676 { 02677 size_t iLen = 0; 02678 LPCSTR lpszIter1 = lpszFile1; 02679 LPCSTR lpszIter2 = lpszFile2; 02680 02681 TRACE("(%s,%s,%p)\n", debugstr_a(lpszFile1), debugstr_a(lpszFile2), achPath); 02682 02683 if (achPath) 02684 *achPath = '\0'; 02685 02686 if (!lpszFile1 || !lpszFile2) 02687 return 0; 02688 02689 /* Handle roots first */ 02690 if (PathIsUNCA(lpszFile1)) 02691 { 02692 if (!PathIsUNCA(lpszFile2)) 02693 return 0; 02694 lpszIter1 += 2; 02695 lpszIter2 += 2; 02696 } 02697 else if (PathIsUNCA(lpszFile2)) 02698 return 0; /* Know already lpszFile1 is not UNC */ 02699 02700 do 02701 { 02702 /* Update len */ 02703 if ((!*lpszIter1 || *lpszIter1 == '\\') && 02704 (!*lpszIter2 || *lpszIter2 == '\\')) 02705 iLen = lpszIter1 - lpszFile1; /* Common to this point */ 02706 02707 if (!*lpszIter1 || (tolower(*lpszIter1) != tolower(*lpszIter2))) 02708 break; /* Strings differ at this point */ 02709 02710 lpszIter1++; 02711 lpszIter2++; 02712 } while (1); 02713 02714 if (iLen == 2) 02715 iLen++; /* Feature/Bug compatible with Win32 */ 02716 02717 if (iLen && achPath) 02718 { 02719 memcpy(achPath,lpszFile1,iLen); 02720 achPath[iLen] = '\0'; 02721 } 02722 return iLen; 02723 } 02724 02725 /************************************************************************* 02726 * PathCommonPrefixW [SHLWAPI.@] 02727 * 02728 * See PathCommonPrefixA. 02729 */ 02730 int WINAPI PathCommonPrefixW(LPCWSTR lpszFile1, LPCWSTR lpszFile2, LPWSTR achPath) 02731 { 02732 size_t iLen = 0; 02733 LPCWSTR lpszIter1 = lpszFile1; 02734 LPCWSTR lpszIter2 = lpszFile2; 02735 02736 TRACE("(%s,%s,%p)\n", debugstr_w(lpszFile1), debugstr_w(lpszFile2), achPath); 02737 02738 if (achPath) 02739 *achPath = '\0'; 02740 02741 if (!lpszFile1 || !lpszFile2) 02742 return 0; 02743 02744 /* Handle roots first */ 02745 if (PathIsUNCW(lpszFile1)) 02746 { 02747 if (!PathIsUNCW(lpszFile2)) 02748 return 0; 02749 lpszIter1 += 2; 02750 lpszIter2 += 2; 02751 } 02752 else if (PathIsUNCW(lpszFile2)) 02753 return 0; /* Know already lpszFile1 is not UNC */ 02754 02755 do 02756 { 02757 /* Update len */ 02758 if ((!*lpszIter1 || *lpszIter1 == '\\') && 02759 (!*lpszIter2 || *lpszIter2 == '\\')) 02760 iLen = lpszIter1 - lpszFile1; /* Common to this point */ 02761 02762 if (!*lpszIter1 || (tolowerW(*lpszIter1) != tolowerW(*lpszIter2))) 02763 break; /* Strings differ at this point */ 02764 02765 lpszIter1++; 02766 lpszIter2++; 02767 } while (1); 02768 02769 if (iLen == 2) 02770 iLen++; /* Feature/Bug compatible with Win32 */ 02771 02772 if (iLen && achPath) 02773 { 02774 memcpy(achPath,lpszFile1,iLen * sizeof(WCHAR)); 02775 achPath[iLen] = '\0'; 02776 } 02777 return iLen; 02778 } 02779 02780 /************************************************************************* 02781 * PathCompactPathA [SHLWAPI.@] 02782 * 02783 * Make a path fit into a given width when printed to a DC. 02784 * 02785 * PARAMS 02786 * hDc [I] Destination DC 02787 * lpszPath [I/O] Path to be printed to hDc 02788 * dx [I] Desired width 02789 * 02790 * RETURNS 02791 * TRUE If the path was modified/went well. 02792 * FALSE Otherwise. 02793 */ 02794 BOOL WINAPI PathCompactPathA(HDC hDC, LPSTR lpszPath, UINT dx) 02795 { 02796 BOOL bRet = FALSE; 02797 02798 TRACE("(%p,%s,%d)\n", hDC, debugstr_a(lpszPath), dx); 02799 02800 if (lpszPath) 02801 { 02802 WCHAR szPath[MAX_PATH]; 02803 MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH); 02804 bRet = PathCompactPathW(hDC, szPath, dx); 02805 WideCharToMultiByte(CP_ACP,0,szPath,-1,lpszPath,MAX_PATH,0,0); 02806 } 02807 return bRet; 02808 } 02809 02810 /************************************************************************* 02811 * PathCompactPathW [SHLWAPI.@] 02812 * 02813 * See PathCompactPathA. 02814 */ 02815 BOOL WINAPI PathCompactPathW(HDC hDC, LPWSTR lpszPath, UINT dx) 02816 { 02817 static const WCHAR szEllipses[] = { '.', '.', '.', '\0' }; 02818 BOOL bRet = TRUE; 02819 HDC hdc = 0; 02820 WCHAR buff[MAX_PATH]; 02821 SIZE size; 02822 DWORD dwLen; 02823 02824 TRACE("(%p,%s,%d)\n", hDC, debugstr_w(lpszPath), dx); 02825 02826 if (!lpszPath) 02827 return FALSE; 02828 02829 if (!hDC) 02830 hdc = hDC = GetDC(0); 02831 02832 /* Get the length of the whole path */ 02833 dwLen = strlenW(lpszPath); 02834 GetTextExtentPointW(hDC, lpszPath, dwLen, &size); 02835 02836 if ((UINT)size.cx > dx) 02837 { 02838 /* Path too big, must reduce it */ 02839 LPWSTR sFile; 02840 DWORD dwEllipsesLen = 0, dwPathLen = 0; 02841 02842 sFile = PathFindFileNameW(lpszPath); 02843 if (sFile != lpszPath) sFile--; 02844 02845 /* Get the size of ellipses */ 02846 GetTextExtentPointW(hDC, szEllipses, 3, &size); 02847 dwEllipsesLen = size.cx; 02848 /* Get the size of the file name */ 02849 GetTextExtentPointW(hDC, sFile, strlenW(sFile), &size); 02850 dwPathLen = size.cx; 02851 02852 if (sFile != lpszPath) 02853 { 02854 LPWSTR sPath = sFile; 02855 BOOL bEllipses = FALSE; 02856 02857 /* The path includes a file name. Include as much of the path prior to 02858 * the file name as possible, allowing for the ellipses, e.g: 02859 * c:\some very long path\filename ==> c:\some v...\filename 02860 */ 02861 lstrcpynW(buff, sFile, MAX_PATH); 02862 02863 do 02864 { 02865 DWORD dwTotalLen = bEllipses? dwPathLen + dwEllipsesLen : dwPathLen; 02866 02867 GetTextExtentPointW(hDC, lpszPath, sPath - lpszPath, &size); 02868 dwTotalLen += size.cx; 02869 if (dwTotalLen <= dx) 02870 break; 02871 sPath--; 02872 if (!bEllipses) 02873 { 02874 bEllipses = TRUE; 02875 sPath -= 2; 02876 } 02877 } while (sPath > lpszPath); 02878 02879 if (sPath > lpszPath) 02880 { 02881 if (bEllipses) 02882 { 02883 strcpyW(sPath, szEllipses); 02884 strcpyW(sPath+3, buff); 02885 } 02886 bRet = TRUE; 02887 goto end; 02888 } 02889 strcpyW(lpszPath, szEllipses); 02890 strcpyW(lpszPath+3, buff); 02891 bRet = FALSE; 02892 goto end; 02893 } 02894 02895 /* Trim the path by adding ellipses to the end, e.g: 02896 * A very long file name.txt ==> A very... 02897 */ 02898 dwLen = strlenW(lpszPath); 02899 02900 if (dwLen > MAX_PATH - 3) 02901 dwLen = MAX_PATH - 3; 02902 lstrcpynW(buff, sFile, dwLen); 02903 02904 do { 02905 dwLen--; 02906 GetTextExtentPointW(hDC, buff, dwLen, &size); 02907 } while (dwLen && size.cx + dwEllipsesLen > dx); 02908 02909 if (!dwLen) 02910 { 02911 DWORD dwWritten = 0; 02912 02913 dwEllipsesLen /= 3; /* Size of a single '.' */ 02914 02915 /* Write as much of the Ellipses string as possible */ 02916 while (dwWritten + dwEllipsesLen < dx && dwLen < 3) 02917 { 02918 *lpszPath++ = '.'; 02919 dwWritten += dwEllipsesLen; 02920 dwLen++; 02921 } 02922 *lpszPath = '\0'; 02923 bRet = FALSE; 02924 } 02925 else 02926 { 02927 strcpyW(buff + dwLen, szEllipses); 02928 strcpyW(lpszPath, buff); 02929 } 02930 } 02931 02932 end: 02933 if (hdc) 02934 ReleaseDC(0, hdc); 02935 02936 return bRet; 02937 } 02938 02939 /************************************************************************* 02940 * PathGetCharTypeA [SHLWAPI.@] 02941 * 02942 * Categorise a character from a file path. 02943 * 02944 * PARAMS 02945 * ch [I] Character to get the type of 02946 * 02947 * RETURNS 02948 * A set of GCT_ bit flags (from "shlwapi.h") indicating the character type. 02949 */ 02950 UINT WINAPI PathGetCharTypeA(UCHAR ch) 02951 { 02952 return PathGetCharTypeW(ch); 02953 } 02954 02955 /************************************************************************* 02956 * PathGetCharTypeW [SHLWAPI.@] 02957 * 02958 * See PathGetCharTypeA. 02959 */ 02960 UINT WINAPI PathGetCharTypeW(WCHAR ch) 02961 { 02962 UINT flags = 0; 02963 02964 TRACE("(%d)\n", ch); 02965 02966 if (!ch || ch < ' ' || ch == '<' || ch == '>' || 02967 ch == '"' || ch == '|' || ch == '/') 02968 flags = GCT_INVALID; /* Invalid */ 02969 else if (ch == '*' || ch=='?') 02970 flags = GCT_WILD; /* Wildchars */ 02971 else if ((ch == '\\') || (ch == ':')) 02972 return GCT_SEPARATOR; /* Path separators */ 02973 else 02974 { 02975 if (ch < 126) 02976 { 02977 if ((ch & 0x1 && ch != ';') || !ch || isalnum(ch) || ch == '$' || ch == '&' || ch == '(' || 02978 ch == '.' || ch == '@' || ch == '^' || 02979 ch == '\'' || ch == 130 || ch == '`') 02980 flags |= GCT_SHORTCHAR; /* All these are valid for DOS */ 02981 } 02982 else 02983 flags |= GCT_SHORTCHAR; /* Bug compatible with win32 */ 02984 flags |= GCT_LFNCHAR; /* Valid for long file names */ 02985 } 02986 return flags; 02987 } 02988 02989 /************************************************************************* 02990 * SHLWAPI_UseSystemForSystemFolders 02991 * 02992 * Internal helper for PathMakeSystemFolderW. 02993 */ 02994 static BOOL SHLWAPI_UseSystemForSystemFolders(void) 02995 { 02996 static BOOL bCheckedReg = FALSE; 02997 static BOOL bUseSystemForSystemFolders = FALSE; 02998 02999 if (!bCheckedReg) 03000 { 03001 bCheckedReg = TRUE; 03002 03003 /* Key tells Win what file attributes to use on system folders */ 03004 if (SHGetValueA(HKEY_LOCAL_MACHINE, 03005 "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer", 03006 "UseSystemForSystemFolders", 0, 0, 0)) 03007 bUseSystemForSystemFolders = TRUE; 03008 } 03009 return bUseSystemForSystemFolders; 03010 } 03011 03012 /************************************************************************* 03013 * PathMakeSystemFolderA [SHLWAPI.@] 03014 * 03015 * Set system folder attribute for a path. 03016 * 03017 * PARAMS 03018 * lpszPath [I] The path to turn into a system folder 03019 * 03020 * RETURNS 03021 * TRUE If the path was changed to/already was a system folder 03022 * FALSE If the path is invalid or SetFileAttributesA() fails 03023 */ 03024 BOOL WINAPI PathMakeSystemFolderA(LPCSTR lpszPath) 03025 { 03026 BOOL bRet = FALSE; 03027 03028 TRACE("(%s)\n", debugstr_a(lpszPath)); 03029 03030 if (lpszPath && *lpszPath) 03031 { 03032 WCHAR szPath[MAX_PATH]; 03033 MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH); 03034 bRet = PathMakeSystemFolderW(szPath); 03035 } 03036 return bRet; 03037 } 03038 03039 /************************************************************************* 03040 * PathMakeSystemFolderW [SHLWAPI.@] 03041 * 03042 * See PathMakeSystemFolderA. 03043 */ 03044 BOOL WINAPI PathMakeSystemFolderW(LPCWSTR lpszPath) 03045 { 03046 DWORD dwDefaultAttr = FILE_ATTRIBUTE_READONLY, dwAttr; 03047 WCHAR buff[MAX_PATH]; 03048 03049 TRACE("(%s)\n", debugstr_w(lpszPath)); 03050 03051 if (!lpszPath || !*lpszPath) 03052 return FALSE; 03053 03054 /* If the directory is already a system directory, don't do anything */ 03055 GetSystemDirectoryW(buff, MAX_PATH); 03056 if (!strcmpW(buff, lpszPath)) 03057 return TRUE; 03058 03059 GetWindowsDirectoryW(buff, MAX_PATH); 03060 if (!strcmpW(buff, lpszPath)) 03061 return TRUE; 03062 03063 /* "UseSystemForSystemFolders" Tells Win what attributes to use */ 03064 if (SHLWAPI_UseSystemForSystemFolders()) 03065 dwDefaultAttr = FILE_ATTRIBUTE_SYSTEM; 03066 03067 if ((dwAttr = GetFileAttributesW(lpszPath)) == INVALID_FILE_ATTRIBUTES) 03068 return FALSE; 03069 03070 /* Change file attributes to system attributes */ 03071 dwAttr &= ~(FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_READONLY); 03072 return SetFileAttributesW(lpszPath, dwAttr | dwDefaultAttr); 03073 } 03074 03075 /************************************************************************* 03076 * PathRenameExtensionA [SHLWAPI.@] 03077 * 03078 * Swap the file extension in a path with another extension. 03079 * 03080 * PARAMS 03081 * lpszPath [I/O] Path to swap the extension in 03082 * lpszExt [I] The new extension 03083 * 03084 * RETURNS 03085 * TRUE if lpszPath was modified, 03086 * FALSE if lpszPath or lpszExt is NULL, or the new path is too long 03087 */ 03088 BOOL WINAPI PathRenameExtensionA(LPSTR lpszPath, LPCSTR lpszExt) 03089 { 03090 LPSTR lpszExtension; 03091 03092 TRACE("(%s,%s)\n", debugstr_a(lpszPath), debugstr_a(lpszExt)); 03093 03094 lpszExtension = PathFindExtensionA(lpszPath); 03095 03096 if (!lpszExtension || (lpszExtension - lpszPath + strlen(lpszExt) >= MAX_PATH)) 03097 return FALSE; 03098 03099 strcpy(lpszExtension, lpszExt); 03100 return TRUE; 03101 } 03102 03103 /************************************************************************* 03104 * PathRenameExtensionW [SHLWAPI.@] 03105 * 03106 * See PathRenameExtensionA. 03107 */ 03108 BOOL WINAPI PathRenameExtensionW(LPWSTR lpszPath, LPCWSTR lpszExt) 03109 { 03110 LPWSTR lpszExtension; 03111 03112 TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszExt)); 03113 03114 lpszExtension = PathFindExtensionW(lpszPath); 03115 03116 if (!lpszExtension || (lpszExtension - lpszPath + strlenW(lpszExt) >= MAX_PATH)) 03117 return FALSE; 03118 03119 strcpyW(lpszExtension, lpszExt); 03120 return TRUE; 03121 } 03122 03123 /************************************************************************* 03124 * PathSearchAndQualifyA [SHLWAPI.@] 03125 * 03126 * Determine if a given path is correct and fully qualified. 03127 * 03128 * PARAMS 03129 * lpszPath [I] Path to check 03130 * lpszBuf [O] Output for correct path 03131 * cchBuf [I] Size of lpszBuf 03132 * 03133 * RETURNS 03134 * Unknown. 03135 */ 03136 BOOL WINAPI PathSearchAndQualifyA(LPCSTR lpszPath, LPSTR lpszBuf, UINT cchBuf) 03137 { 03138 TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszPath), lpszBuf, cchBuf); 03139 03140 if(SearchPathA(NULL, lpszPath, NULL, cchBuf, lpszBuf, NULL)) 03141 return TRUE; 03142 return !!GetFullPathNameA(lpszPath, cchBuf, lpszBuf, NULL); 03143 } 03144 03145 /************************************************************************* 03146 * PathSearchAndQualifyW [SHLWAPI.@] 03147 * 03148 * See PathSearchAndQualifyA. 03149 */ 03150 BOOL WINAPI PathSearchAndQualifyW(LPCWSTR lpszPath, LPWSTR lpszBuf, UINT cchBuf) 03151 { 03152 TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszPath), lpszBuf, cchBuf); 03153 03154 if(SearchPathW(NULL, lpszPath, NULL, cchBuf, lpszBuf, NULL)) 03155 return TRUE; 03156 return !!GetFullPathNameW(lpszPath, cchBuf, lpszBuf, NULL); 03157 } 03158 03159 /************************************************************************* 03160 * PathSkipRootA [SHLWAPI.@] 03161 * 03162 * Return the portion of a path following the drive letter or mount point. 03163 * 03164 * PARAMS 03165 * lpszPath [I] The path to skip on 03166 * 03167 * RETURNS 03168 * Success: A pointer to the next character after the root. 03169 * Failure: NULL, if lpszPath is invalid, has no root or is a multibyte string. 03170 */ 03171 LPSTR WINAPI PathSkipRootA(LPCSTR lpszPath) 03172 { 03173 TRACE("(%s)\n", debugstr_a(lpszPath)); 03174 03175 if (!lpszPath || !*lpszPath) 03176 return NULL; 03177 03178 if (*lpszPath == '\\' && lpszPath[1] == '\\') 03179 { 03180 /* Network share: skip share server and mount point */ 03181 lpszPath += 2; 03182 if ((lpszPath = StrChrA(lpszPath, '\\')) && 03183 (lpszPath = StrChrA(lpszPath + 1, '\\'))) 03184 lpszPath++; 03185 return (LPSTR)lpszPath; 03186 } 03187 03188 if (IsDBCSLeadByte(*lpszPath)) 03189 return NULL; 03190 03191 /* Check x:\ */ 03192 if (lpszPath[0] && lpszPath[1] == ':' && lpszPath[2] == '\\') 03193 return (LPSTR)lpszPath + 3; 03194 return NULL; 03195 } 03196 03197 /************************************************************************* 03198 * PathSkipRootW [SHLWAPI.@] 03199 * 03200 * See PathSkipRootA. 03201 */ 03202 LPWSTR WINAPI PathSkipRootW(LPCWSTR lpszPath) 03203 { 03204 TRACE("(%s)\n", debugstr_w(lpszPath)); 03205 03206 if (!lpszPath || !*lpszPath) 03207 return NULL; 03208 03209 if (*lpszPath == '\\' && lpszPath[1] == '\\') 03210 { 03211 /* Network share: skip share server and mount point */ 03212 lpszPath += 2; 03213 if ((lpszPath = StrChrW(lpszPath, '\\')) && 03214 (lpszPath = StrChrW(lpszPath + 1, '\\'))) 03215 lpszPath++; 03216 return (LPWSTR)lpszPath; 03217 } 03218 03219 /* Check x:\ */ 03220 if (lpszPath[0] && lpszPath[1] == ':' && lpszPath[2] == '\\') 03221 return (LPWSTR)lpszPath + 3; 03222 return NULL; 03223 } 03224 03225 /************************************************************************* 03226 * PathCreateFromUrlA [SHLWAPI.@] 03227 * 03228 * See PathCreateFromUrlW 03229 */ 03230 HRESULT WINAPI PathCreateFromUrlA(LPCSTR pszUrl, LPSTR pszPath, 03231 LPDWORD pcchPath, DWORD dwReserved) 03232 { 03233 WCHAR bufW[MAX_PATH]; 03234 WCHAR *pathW = bufW; 03235 UNICODE_STRING urlW; 03236 HRESULT ret; 03237 DWORD lenW = sizeof(bufW)/sizeof(WCHAR), lenA; 03238 03239 if(!RtlCreateUnicodeStringFromAsciiz(&urlW, pszUrl)) 03240 return E_INVALIDARG; 03241 if((ret = PathCreateFromUrlW(urlW.Buffer, pathW, &lenW, dwReserved)) == E_POINTER) { 03242 pathW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR)); 03243 ret = PathCreateFromUrlW(urlW.Buffer, pathW, &lenW, dwReserved); 03244 } 03245 if(ret == S_OK) { 03246 RtlUnicodeToMultiByteSize(&lenA, pathW, lenW * sizeof(WCHAR)); 03247 if(*pcchPath > lenA) { 03248 RtlUnicodeToMultiByteN(pszPath, *pcchPath - 1, &lenA, pathW, lenW * sizeof(WCHAR)); 03249 pszPath[lenA] = 0; 03250 *pcchPath = lenA; 03251 } else { 03252 *pcchPath = lenA + 1; 03253 ret = E_POINTER; 03254 } 03255 } 03256 if(pathW != bufW) HeapFree(GetProcessHeap(), 0, pathW); 03257 RtlFreeUnicodeString(&urlW); 03258 return ret; 03259 } 03260 03261 /************************************************************************* 03262 * PathCreateFromUrlW [SHLWAPI.@] 03263 * 03264 * Create a path from a URL 03265 * 03266 * PARAMS 03267 * lpszUrl [I] URL to convert into a path 03268 * lpszPath [O] Output buffer for the resulting Path 03269 * pcchPath [I] Length of lpszPath 03270 * dwFlags [I] Flags controlling the conversion 03271 * 03272 * RETURNS 03273 * Success: S_OK. lpszPath contains the URL in path format, 03274 * Failure: An HRESULT error code such as E_INVALIDARG. 03275 */ 03276 HRESULT WINAPI PathCreateFromUrlW(LPCWSTR pszUrl, LPWSTR pszPath, 03277 LPDWORD pcchPath, DWORD dwReserved) 03278 { 03279 static const WCHAR file_colon[] = { 'f','i','l','e',':',0 }; 03280 HRESULT hr; 03281 DWORD nslashes = 0; 03282 WCHAR *ptr; 03283 03284 TRACE("(%s,%p,%p,0x%08x)\n", debugstr_w(pszUrl), pszPath, pcchPath, dwReserved); 03285 03286 if (!pszUrl || !pszPath || !pcchPath || !*pcchPath) 03287 return E_INVALIDARG; 03288 03289 03290 if (strncmpW(pszUrl, file_colon, 5)) 03291 return E_INVALIDARG; 03292 pszUrl += 5; 03293 03294 while(*pszUrl == '/' || *pszUrl == '\\') { 03295 nslashes++; 03296 pszUrl++; 03297 } 03298 03299 if(isalphaW(*pszUrl) && (pszUrl[1] == ':' || pszUrl[1] == '|') && (pszUrl[2] == '/' || pszUrl[2] == '\\')) 03300 nslashes = 0; 03301 03302 switch(nslashes) { 03303 case 2: 03304 pszUrl -= 2; 03305 break; 03306 case 0: 03307 break; 03308 default: 03309 pszUrl -= 1; 03310 break; 03311 } 03312 03313 hr = UrlUnescapeW((LPWSTR)pszUrl, pszPath, pcchPath, 0); 03314 if(hr != S_OK) return hr; 03315 03316 for(ptr = pszPath; *ptr; ptr++) 03317 if(*ptr == '/') *ptr = '\\'; 03318 03319 while(*pszPath == '\\') 03320 pszPath++; 03321 03322 if(isalphaW(*pszPath) && pszPath[1] == '|' && pszPath[2] == '\\') /* c|\ -> c:\ */ 03323 pszPath[1] = ':'; 03324 03325 if(nslashes == 2 && (ptr = strchrW(pszPath, '\\'))) { /* \\host\c:\ -> \\hostc:\ */ 03326 ptr++; 03327 if(isalphaW(*ptr) && (ptr[1] == ':' || ptr[1] == '|') && ptr[2] == '\\') { 03328 memmove(ptr - 1, ptr, (strlenW(ptr) + 1) * sizeof(WCHAR)); 03329 (*pcchPath)--; 03330 } 03331 } 03332 03333 TRACE("Returning %s\n",debugstr_w(pszPath)); 03334 03335 return hr; 03336 } 03337 03338 /************************************************************************* 03339 * PathRelativePathToA [SHLWAPI.@] 03340 * 03341 * Create a relative path from one path to another. 03342 * 03343 * PARAMS 03344 * lpszPath [O] Destination for relative path 03345 * lpszFrom [I] Source path 03346 * dwAttrFrom [I] File attribute of source path 03347 * lpszTo [I] Destination path 03348 * dwAttrTo [I] File attributes of destination path 03349 * 03350 * RETURNS 03351 * TRUE If a relative path can be formed. lpszPath contains the new path 03352 * FALSE If the paths are not relative or any parameters are invalid 03353 * 03354 * NOTES 03355 * lpszTo should be at least MAX_PATH in length. 03356 * 03357 * Calling this function with relative paths for lpszFrom or lpszTo may 03358 * give erroneous results. 03359 * 03360 * The Win32 version of this function contains a bug where the lpszTo string 03361 * may be referenced 1 byte beyond the end of the string. As a result random 03362 * garbage may be written to the output path, depending on what lies beyond 03363 * the last byte of the string. This bug occurs because of the behaviour of 03364 * PathCommonPrefix() (see notes for that function), and no workaround seems 03365 * possible with Win32. 03366 * 03367 * This bug has been fixed here, so for example the relative path from "\\" 03368 * to "\\" is correctly determined as "." in this implementation. 03369 */ 03370 BOOL WINAPI PathRelativePathToA(LPSTR lpszPath, LPCSTR lpszFrom, DWORD dwAttrFrom, 03371 LPCSTR lpszTo, DWORD dwAttrTo) 03372 { 03373 BOOL bRet = FALSE; 03374 03375 TRACE("(%p,%s,0x%08x,%s,0x%08x)\n", lpszPath, debugstr_a(lpszFrom), 03376 dwAttrFrom, debugstr_a(lpszTo), dwAttrTo); 03377 03378 if(lpszPath && lpszFrom && lpszTo) 03379 { 03380 WCHAR szPath[MAX_PATH]; 03381 WCHAR szFrom[MAX_PATH]; 03382 WCHAR szTo[MAX_PATH]; 03383 MultiByteToWideChar(CP_ACP,0,lpszFrom,-1,szFrom,MAX_PATH); 03384 MultiByteToWideChar(CP_ACP,0,lpszTo,-1,szTo,MAX_PATH); 03385 bRet = PathRelativePathToW(szPath,szFrom,dwAttrFrom,szTo,dwAttrTo); 03386 WideCharToMultiByte(CP_ACP,0,szPath,-1,lpszPath,MAX_PATH,0,0); 03387 } 03388 return bRet; 03389 } 03390 03391 /************************************************************************* 03392 * PathRelativePathToW [SHLWAPI.@] 03393 * 03394 * See PathRelativePathToA. 03395 */ 03396 BOOL WINAPI PathRelativePathToW(LPWSTR lpszPath, LPCWSTR lpszFrom, DWORD dwAttrFrom, 03397 LPCWSTR lpszTo, DWORD dwAttrTo) 03398 { 03399 static const WCHAR szPrevDirSlash[] = { '.', '.', '\\', '\0' }; 03400 static const WCHAR szPrevDir[] = { '.', '.', '\0' }; 03401 WCHAR szFrom[MAX_PATH]; 03402 WCHAR szTo[MAX_PATH]; 03403 DWORD dwLen; 03404 03405 TRACE("(%p,%s,0x%08x,%s,0x%08x)\n", lpszPath, debugstr_w(lpszFrom), 03406 dwAttrFrom, debugstr_w(lpszTo), dwAttrTo); 03407 03408 if(!lpszPath || !lpszFrom || !lpszTo) 03409 return FALSE; 03410 03411 *lpszPath = '\0'; 03412 lstrcpynW(szFrom, lpszFrom, MAX_PATH); 03413 lstrcpynW(szTo, lpszTo, MAX_PATH); 03414 03415 if(!(dwAttrFrom & FILE_ATTRIBUTE_DIRECTORY)) 03416 PathRemoveFileSpecW(szFrom); 03417 if(!(dwAttrFrom & FILE_ATTRIBUTE_DIRECTORY)) 03418 PathRemoveFileSpecW(szTo); 03419 03420 /* Paths can only be relative if they have a common root */ 03421 if(!(dwLen = PathCommonPrefixW(szFrom, szTo, 0))) 03422 return FALSE; 03423 03424 /* Strip off lpszFrom components to the root, by adding "..\" */ 03425 lpszFrom = szFrom + dwLen; 03426 if (!*lpszFrom) 03427 { 03428 lpszPath[0] = '.'; 03429 lpszPath[1] = '\0'; 03430 } 03431 if (*lpszFrom == '\\') 03432 lpszFrom++; 03433 03434 while (*lpszFrom) 03435 { 03436 lpszFrom = PathFindNextComponentW(lpszFrom); 03437 strcatW(lpszPath, *lpszFrom ? szPrevDirSlash : szPrevDir); 03438 } 03439 03440 /* From the root add the components of lpszTo */ 03441 lpszTo += dwLen; 03442 /* We check lpszTo[-1] to avoid skipping end of string. See the notes for 03443 * this function. 03444 */ 03445 if (*lpszTo && lpszTo[-1]) 03446 { 03447 if (*lpszTo != '\\') 03448 lpszTo--; 03449 dwLen = strlenW(lpszPath); 03450 if (dwLen + strlenW(lpszTo) >= MAX_PATH) 03451 { 03452 *lpszPath = '\0'; 03453 return FALSE; 03454 } 03455 strcpyW(lpszPath + dwLen, lpszTo); 03456 } 03457 return TRUE; 03458 } 03459 03460 /************************************************************************* 03461 * PathUnmakeSystemFolderA [SHLWAPI.@] 03462 * 03463 * Remove the system folder attributes from a path. 03464 * 03465 * PARAMS 03466 * lpszPath [I] The path to remove attributes from 03467 * 03468 * RETURNS 03469 * Success: TRUE. 03470 * Failure: FALSE, if lpszPath is NULL, empty, not a directory, or calling 03471 * SetFileAttributesA() fails. 03472 */ 03473 BOOL WINAPI PathUnmakeSystemFolderA(LPCSTR lpszPath) 03474 { 03475 DWORD dwAttr; 03476 03477 TRACE("(%s)\n", debugstr_a(lpszPath)); 03478 03479 if (!lpszPath || !*lpszPath || (dwAttr = GetFileAttributesA(lpszPath)) == INVALID_FILE_ATTRIBUTES || 03480 !(dwAttr & FILE_ATTRIBUTE_DIRECTORY)) 03481 return FALSE; 03482 03483 dwAttr &= ~(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM); 03484 return SetFileAttributesA(lpszPath, dwAttr); 03485 } 03486 03487 /************************************************************************* 03488 * PathUnmakeSystemFolderW [SHLWAPI.@] 03489 * 03490 * See PathUnmakeSystemFolderA. 03491 */ 03492 BOOL WINAPI PathUnmakeSystemFolderW(LPCWSTR lpszPath) 03493 { 03494 DWORD dwAttr; 03495 03496 TRACE("(%s)\n", debugstr_w(lpszPath)); 03497 03498 if (!lpszPath || !*lpszPath || (dwAttr = GetFileAttributesW(lpszPath)) == INVALID_FILE_ATTRIBUTES || 03499 !(dwAttr & FILE_ATTRIBUTE_DIRECTORY)) 03500 return FALSE; 03501 03502 dwAttr &= ~(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM); 03503 return SetFileAttributesW(lpszPath, dwAttr); 03504 } 03505 03506 03507 /************************************************************************* 03508 * PathSetDlgItemPathA [SHLWAPI.@] 03509 * 03510 * Set the text of a dialog item to a path, shrinking the path to fit 03511 * if it is too big for the item. 03512 * 03513 * PARAMS 03514 * hDlg [I] Dialog handle 03515 * id [I] ID of item in the dialog 03516 * lpszPath [I] Path to set as the items text 03517 * 03518 * RETURNS 03519 * Nothing. 03520 * 03521 * NOTES 03522 * If lpszPath is NULL, a blank string ("") is set (i.e. The previous 03523 * window text is erased). 03524 */ 03525 VOID WINAPI PathSetDlgItemPathA(HWND hDlg, int id, LPCSTR lpszPath) 03526 { 03527 WCHAR szPath[MAX_PATH]; 03528 03529 TRACE("(%p,%8x,%s)\n",hDlg, id, debugstr_a(lpszPath)); 03530 03531 if (lpszPath) 03532 MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH); 03533 else 03534 szPath[0] = '\0'; 03535 PathSetDlgItemPathW(hDlg, id, szPath); 03536 } 03537 03538 /************************************************************************* 03539 * PathSetDlgItemPathW [SHLWAPI.@] 03540 * 03541 * See PathSetDlgItemPathA. 03542 */ 03543 VOID WINAPI PathSetDlgItemPathW(HWND hDlg, int id, LPCWSTR lpszPath) 03544 { 03545 WCHAR path[MAX_PATH + 1]; 03546 HWND hwItem; 03547 RECT rect; 03548 HDC hdc; 03549 HGDIOBJ hPrevObj; 03550 03551 TRACE("(%p,%8x,%s)\n",hDlg, id, debugstr_w(lpszPath)); 03552 03553 if (!(hwItem = GetDlgItem(hDlg, id))) 03554 return; 03555 03556 if (lpszPath) 03557 lstrcpynW(path, lpszPath, sizeof(path) / sizeof(WCHAR)); 03558 else 03559 path[0] = '\0'; 03560 03561 GetClientRect(hwItem, &rect); 03562 hdc = GetDC(hDlg); 03563 hPrevObj = SelectObject(hdc, (HGDIOBJ)SendMessageW(hwItem,WM_GETFONT,0,0)); 03564 03565 if (hPrevObj) 03566 { 03567 PathCompactPathW(hdc, path, rect.right); 03568 SelectObject(hdc, hPrevObj); 03569 } 03570 03571 ReleaseDC(hDlg, hdc); 03572 SetWindowTextW(hwItem, path); 03573 } 03574 03575 /************************************************************************* 03576 * PathIsNetworkPathA [SHLWAPI.@] 03577 * 03578 * Determine if the given path is a network path. 03579 * 03580 * PARAMS 03581 * lpszPath [I] Path to check 03582 * 03583 * RETURNS 03584 * TRUE If lpszPath is a UNC share or mapped network drive, or 03585 * FALSE If lpszPath is a local drive or cannot be determined 03586 */ 03587 BOOL WINAPI PathIsNetworkPathA(LPCSTR lpszPath) 03588 { 03589 int dwDriveNum; 03590 03591 TRACE("(%s)\n",debugstr_a(lpszPath)); 03592 03593 if (!lpszPath) 03594 return FALSE; 03595 if (*lpszPath == '\\' && lpszPath[1] == '\\') 03596 return TRUE; 03597 dwDriveNum = PathGetDriveNumberA(lpszPath); 03598 if (dwDriveNum == -1) 03599 return FALSE; 03600 GET_FUNC(pIsNetDrive, shell32, (LPCSTR)66, FALSE); /* ord 66 = shell32.IsNetDrive */ 03601 return pIsNetDrive(dwDriveNum); 03602 } 03603 03604 /************************************************************************* 03605 * PathIsNetworkPathW [SHLWAPI.@] 03606 * 03607 * See PathIsNetworkPathA. 03608 */ 03609 BOOL WINAPI PathIsNetworkPathW(LPCWSTR lpszPath) 03610 { 03611 int dwDriveNum; 03612 03613 TRACE("(%s)\n", debugstr_w(lpszPath)); 03614 03615 if (!lpszPath) 03616 return FALSE; 03617 if (*lpszPath == '\\' && lpszPath[1] == '\\') 03618 return TRUE; 03619 dwDriveNum = PathGetDriveNumberW(lpszPath); 03620 if (dwDriveNum == -1) 03621 return FALSE; 03622 GET_FUNC(pIsNetDrive, shell32, (LPCSTR)66, FALSE); /* ord 66 = shell32.IsNetDrive */ 03623 return pIsNetDrive(dwDriveNum); 03624 } 03625 03626 /************************************************************************* 03627 * PathIsLFNFileSpecA [SHLWAPI.@] 03628 * 03629 * Determine if the given path is a long file name 03630 * 03631 * PARAMS 03632 * lpszPath [I] Path to check 03633 * 03634 * RETURNS 03635 * TRUE If path is a long file name, 03636 * FALSE If path is a valid DOS short file name 03637 */ 03638 BOOL WINAPI PathIsLFNFileSpecA(LPCSTR lpszPath) 03639 { 03640 DWORD dwNameLen = 0, dwExtLen = 0; 03641 03642 TRACE("(%s)\n",debugstr_a(lpszPath)); 03643 03644 if (!lpszPath) 03645 return FALSE; 03646 03647 while (*lpszPath) 03648 { 03649 if (*lpszPath == ' ') 03650 return TRUE; /* DOS names cannot have spaces */ 03651 if (*lpszPath == '.') 03652 { 03653 if (dwExtLen) 03654 return TRUE; /* DOS names have only one dot */ 03655 dwExtLen = 1; 03656 } 03657 else if (dwExtLen) 03658 { 03659 dwExtLen++; 03660 if (dwExtLen > 4) 03661 return TRUE; /* DOS extensions are <= 3 chars*/ 03662 } 03663 else 03664 { 03665 dwNameLen++; 03666 if (dwNameLen > 8) 03667 return TRUE; /* DOS names are <= 8 chars */ 03668 } 03669 lpszPath += IsDBCSLeadByte(*lpszPath) ? 2 : 1; 03670 } 03671 return FALSE; /* Valid DOS path */ 03672 } 03673 03674 /************************************************************************* 03675 * PathIsLFNFileSpecW [SHLWAPI.@] 03676 * 03677 * See PathIsLFNFileSpecA. 03678 */ 03679 BOOL WINAPI PathIsLFNFileSpecW(LPCWSTR lpszPath) 03680 { 03681 DWORD dwNameLen = 0, dwExtLen = 0; 03682 03683 TRACE("(%s)\n",debugstr_w(lpszPath)); 03684 03685 if (!lpszPath) 03686 return FALSE; 03687 03688 while (*lpszPath) 03689 { 03690 if (*lpszPath == ' ') 03691 return TRUE; /* DOS names cannot have spaces */ 03692 if (*lpszPath == '.') 03693 { 03694 if (dwExtLen) 03695 return TRUE; /* DOS names have only one dot */ 03696 dwExtLen = 1; 03697 } 03698 else if (dwExtLen) 03699 { 03700 dwExtLen++; 03701 if (dwExtLen > 4) 03702 return TRUE; /* DOS extensions are <= 3 chars*/ 03703 } 03704 else 03705 { 03706 dwNameLen++; 03707 if (dwNameLen > 8) 03708 return TRUE; /* DOS names are <= 8 chars */ 03709 } 03710 lpszPath++; 03711 } 03712 return FALSE; /* Valid DOS path */ 03713 } 03714 03715 /************************************************************************* 03716 * PathIsDirectoryEmptyA [SHLWAPI.@] 03717 * 03718 * Determine if a given directory is empty. 03719 * 03720 * PARAMS 03721 * lpszPath [I] Directory to check 03722 * 03723 * RETURNS 03724 * TRUE If the directory exists and contains no files, 03725 * FALSE Otherwise 03726 */ 03727 BOOL WINAPI PathIsDirectoryEmptyA(LPCSTR lpszPath) 03728 { 03729 BOOL bRet = FALSE; 03730 03731 TRACE("(%s)\n",debugstr_a(lpszPath)); 03732 03733 if (lpszPath) 03734 { 03735 WCHAR szPath[MAX_PATH]; 03736 MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH); 03737 bRet = PathIsDirectoryEmptyW(szPath); 03738 } 03739 return bRet; 03740 } 03741 03742 /************************************************************************* 03743 * PathIsDirectoryEmptyW [SHLWAPI.@] 03744 * 03745 * See PathIsDirectoryEmptyA. 03746 */ 03747 BOOL WINAPI PathIsDirectoryEmptyW(LPCWSTR lpszPath) 03748 { 03749 static const WCHAR szAllFiles[] = { '*', '.', '*', '\0' }; 03750 WCHAR szSearch[MAX_PATH]; 03751 DWORD dwLen; 03752 HANDLE hfind; 03753 BOOL retVal = FALSE; 03754 WIN32_FIND_DATAW find_data; 03755 03756 TRACE("(%s)\n",debugstr_w(lpszPath)); 03757 03758 if (!lpszPath || !PathIsDirectoryW(lpszPath)) 03759 return FALSE; 03760 03761 lstrcpynW(szSearch, lpszPath, MAX_PATH); 03762 PathAddBackslashW(szSearch); 03763 dwLen = strlenW(szSearch); 03764 if (dwLen > MAX_PATH - 4) 03765 return FALSE; 03766 03767 strcpyW(szSearch + dwLen, szAllFiles); 03768 hfind = FindFirstFileW(szSearch, &find_data); 03769 03770 if (hfind != INVALID_HANDLE_VALUE && 03771 find_data.cFileName[0] == '.' && 03772 find_data.cFileName[1] == '.') 03773 { 03774 /* The only directory entry should be the parent */ 03775 if (!FindNextFileW(hfind, &find_data)) 03776 retVal = TRUE; 03777 FindClose(hfind); 03778 } 03779 return retVal; 03780 } 03781 03782 03783 /************************************************************************* 03784 * PathFindSuffixArrayA [SHLWAPI.@] 03785 * 03786 * Find a suffix string in an array of suffix strings 03787 * 03788 * PARAMS 03789 * lpszSuffix [I] Suffix string to search for 03790 * lppszArray [I] Array of suffix strings to search 03791 * dwCount [I] Number of elements in lppszArray 03792 * 03793 * RETURNS 03794 * Success: The index of the position of lpszSuffix in lppszArray 03795 * Failure: 0, if any parameters are invalid or lpszSuffix is not found 03796 * 03797 * NOTES 03798 * The search is case sensitive. 03799 * The match is made against the end of the suffix string, so for example: 03800 * lpszSuffix="fooBAR" matches "BAR", but lpszSuffix="fooBARfoo" does not. 03801 */ 03802 LPCSTR WINAPI PathFindSuffixArrayA(LPCSTR lpszSuffix, LPCSTR *lppszArray, int dwCount) 03803 { 03804 size_t dwLen; 03805 int dwRet = 0; 03806 03807 TRACE("(%s,%p,%d)\n",debugstr_a(lpszSuffix), lppszArray, dwCount); 03808 03809 if (lpszSuffix && lppszArray && dwCount > 0) 03810 { 03811 dwLen = strlen(lpszSuffix); 03812 03813 while (dwRet < dwCount) 03814 { 03815 size_t dwCompareLen = strlen(*lppszArray); 03816 if (dwCompareLen < dwLen) 03817 { 03818 if (!strcmp(lpszSuffix + dwLen - dwCompareLen, *lppszArray)) 03819 return *lppszArray; /* Found */ 03820 } 03821 dwRet++; 03822 lppszArray++; 03823 } 03824 } 03825 return NULL; 03826 } 03827 03828 /************************************************************************* 03829 * PathFindSuffixArrayW [SHLWAPI.@] 03830 * 03831 * See PathFindSuffixArrayA. 03832 */ 03833 LPCWSTR WINAPI PathFindSuffixArrayW(LPCWSTR lpszSuffix, LPCWSTR *lppszArray, int dwCount) 03834 { 03835 size_t dwLen; 03836 int dwRet = 0; 03837 03838 TRACE("(%s,%p,%d)\n",debugstr_w(lpszSuffix), lppszArray, dwCount); 03839 03840 if (lpszSuffix && lppszArray && dwCount > 0) 03841 { 03842 dwLen = strlenW(lpszSuffix); 03843 03844 while (dwRet < dwCount) 03845 { 03846 size_t dwCompareLen = strlenW(*lppszArray); 03847 if (dwCompareLen < dwLen) 03848 { 03849 if (!strcmpW(lpszSuffix + dwLen - dwCompareLen, *lppszArray)) 03850 return *lppszArray; /* Found */ 03851 } 03852 dwRet++; 03853 lppszArray++; 03854 } 03855 } 03856 return NULL; 03857 } 03858 03859 /************************************************************************* 03860 * PathUndecorateA [SHLWAPI.@] 03861 * 03862 * Undecorate a file path 03863 * 03864 * PARAMS 03865 * lpszPath [I/O] Path to remove any decoration from 03866 * 03867 * RETURNS 03868 * Nothing 03869 * 03870 * NOTES 03871 * A decorations form is "path[n].ext" where "n" is an optional decimal number. 03872 */ 03873 VOID WINAPI PathUndecorateA(LPSTR lpszPath) 03874 { 03875 TRACE("(%s)\n",debugstr_a(lpszPath)); 03876 03877 if (lpszPath) 03878 { 03879 LPSTR lpszExt = PathFindExtensionA(lpszPath); 03880 if (lpszExt > lpszPath && lpszExt[-1] == ']') 03881 { 03882 LPSTR lpszSkip = lpszExt - 2; 03883 if (*lpszSkip == '[') 03884 lpszSkip++; /* [] (no number) */ 03885 else 03886 while (lpszSkip > lpszPath && isdigit(lpszSkip[-1])) 03887 lpszSkip--; 03888 if (lpszSkip > lpszPath && lpszSkip[-1] == '[' && lpszSkip[-2] != '\\') 03889 { 03890 /* remove the [n] */ 03891 lpszSkip--; 03892 while (*lpszExt) 03893 *lpszSkip++ = *lpszExt++; 03894 *lpszSkip = '\0'; 03895 } 03896 } 03897 } 03898 } 03899 03900 /************************************************************************* 03901 * PathUndecorateW [SHLWAPI.@] 03902 * 03903 * See PathUndecorateA. 03904 */ 03905 VOID WINAPI PathUndecorateW(LPWSTR lpszPath) 03906 { 03907 TRACE("(%s)\n",debugstr_w(lpszPath)); 03908 03909 if (lpszPath) 03910 { 03911 LPWSTR lpszExt = PathFindExtensionW(lpszPath); 03912 if (lpszExt > lpszPath && lpszExt[-1] == ']') 03913 { 03914 LPWSTR lpszSkip = lpszExt - 2; 03915 if (*lpszSkip == '[') 03916 lpszSkip++; /* [] (no number) */ 03917 else 03918 while (lpszSkip > lpszPath && isdigitW(lpszSkip[-1])) 03919 lpszSkip--; 03920 if (lpszSkip > lpszPath && lpszSkip[-1] == '[' && lpszSkip[-2] != '\\') 03921 { 03922 /* remove the [n] */ 03923 lpszSkip--; 03924 while (*lpszExt) 03925 *lpszSkip++ = *lpszExt++; 03926 *lpszSkip = '\0'; 03927 } 03928 } 03929 } 03930 } 03931 03932 /************************************************************************* 03933 * PathUnExpandEnvStringsA [SHLWAPI.@] 03934 * 03935 * Substitute folder names in a path with their corresponding environment 03936 * strings. 03937 * 03938 * PARAMS 03939 * pszPath [I] Buffer containing the path to unexpand. 03940 * pszBuf [O] Buffer to receive the unexpanded path. 03941 * cchBuf [I] Size of pszBuf in characters. 03942 * 03943 * RETURNS 03944 * Success: TRUE 03945 * Failure: FALSE 03946 */ 03947 BOOL WINAPI PathUnExpandEnvStringsA(LPCSTR pszPath, LPSTR pszBuf, UINT cchBuf) 03948 { 03949 FIXME("(%s,%s,0x%08x)\n", debugstr_a(pszPath), debugstr_a(pszBuf), cchBuf); 03950 return FALSE; 03951 } 03952 03953 /************************************************************************* 03954 * PathUnExpandEnvStringsW [SHLWAPI.@] 03955 * 03956 * Unicode version of PathUnExpandEnvStringsA. 03957 */ 03958 BOOL WINAPI PathUnExpandEnvStringsW(LPCWSTR pszPath, LPWSTR pszBuf, UINT cchBuf) 03959 { 03960 FIXME("(%s,%s,0x%08x)\n", debugstr_w(pszPath), debugstr_w(pszBuf), cchBuf); 03961 return FALSE; 03962 } 03963 03964 /************************************************************************* 03965 * @ [SHLWAPI.440] 03966 * 03967 * Find localised or default web content in "%WINDOWS%\web\". 03968 * 03969 * PARAMS 03970 * lpszFile [I] File name containing content to look for 03971 * lpszPath [O] Buffer to contain the full path to the file 03972 * dwPathLen [I] Length of lpszPath 03973 * 03974 * RETURNS 03975 * Success: S_OK. lpszPath contains the full path to the content. 03976 * Failure: E_FAIL. The content does not exist or lpszPath is too short. 03977 */ 03978 HRESULT WINAPI SHGetWebFolderFilePathA(LPCSTR lpszFile, LPSTR lpszPath, DWORD dwPathLen) 03979 { 03980 WCHAR szFile[MAX_PATH], szPath[MAX_PATH]; 03981 HRESULT hRet; 03982 03983 TRACE("(%s,%p,%d)\n", lpszFile, lpszPath, dwPathLen); 03984 03985 MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, szFile, MAX_PATH); 03986 szPath[0] = '\0'; 03987 hRet = SHGetWebFolderFilePathW(szFile, szPath, dwPathLen); 03988 WideCharToMultiByte(CP_ACP, 0, szPath, -1, lpszPath, dwPathLen, 0, 0); 03989 return hRet; 03990 } 03991 03992 /************************************************************************* 03993 * @ [SHLWAPI.441] 03994 * 03995 * Unicode version of SHGetWebFolderFilePathA. 03996 */ 03997 HRESULT WINAPI SHGetWebFolderFilePathW(LPCWSTR lpszFile, LPWSTR lpszPath, DWORD dwPathLen) 03998 { 03999 static const WCHAR szWeb[] = {'\\','W','e','b','\\','\0'}; 04000 static const WCHAR szWebMui[] = {'m','u','i','\\','%','0','4','x','\\','\0'}; 04001 #define szWebLen (sizeof(szWeb)/sizeof(WCHAR)) 04002 #define szWebMuiLen ((sizeof(szWebMui)+1)/sizeof(WCHAR)) 04003 DWORD dwLen, dwFileLen; 04004 LANGID lidSystem, lidUser; 04005 04006 TRACE("(%s,%p,%d)\n", debugstr_w(lpszFile), lpszPath, dwPathLen); 04007 04008 /* Get base directory for web content */ 04009 dwLen = GetSystemWindowsDirectoryW(lpszPath, dwPathLen); 04010 if (dwLen > 0 && lpszPath[dwLen-1] == '\\') 04011 dwLen--; 04012 04013 dwFileLen = strlenW(lpszFile); 04014 04015 if (dwLen + dwFileLen + szWebLen >= dwPathLen) 04016 return E_FAIL; /* lpszPath too short */ 04017 04018 strcpyW(lpszPath+dwLen, szWeb); 04019 dwLen += szWebLen; 04020 dwPathLen = dwPathLen - dwLen; /* Remaining space */ 04021 04022 lidSystem = GetSystemDefaultUILanguage(); 04023 lidUser = GetUserDefaultUILanguage(); 04024 04025 if (lidSystem != lidUser) 04026 { 04027 if (dwFileLen + szWebMuiLen < dwPathLen) 04028 { 04029 /* Use localised content in the users UI language if present */ 04030 wsprintfW(lpszPath + dwLen, szWebMui, lidUser); 04031 strcpyW(lpszPath + dwLen + szWebMuiLen, lpszFile); 04032 if (PathFileExistsW(lpszPath)) 04033 return S_OK; 04034 } 04035 } 04036 04037 /* Fall back to OS default installed content */ 04038 strcpyW(lpszPath + dwLen, lpszFile); 04039 if (PathFileExistsW(lpszPath)) 04040 return S_OK; 04041 return E_FAIL; 04042 } 04043 04044 #define PATH_CHAR_CLASS_LETTER 0x00000001 04045 #define PATH_CHAR_CLASS_ASTERIX 0x00000002 04046 #define PATH_CHAR_CLASS_DOT 0x00000004 04047 #define PATH_CHAR_CLASS_BACKSLASH 0x00000008 04048 #define PATH_CHAR_CLASS_COLON 0x00000010 04049 #define PATH_CHAR_CLASS_SEMICOLON 0x00000020 04050 #define PATH_CHAR_CLASS_COMMA 0x00000040 04051 #define PATH_CHAR_CLASS_SPACE 0x00000080 04052 #define PATH_CHAR_CLASS_OTHER_VALID 0x00000100 04053 #define PATH_CHAR_CLASS_DOUBLEQUOTE 0x00000200 04054 04055 #define PATH_CHAR_CLASS_INVALID 0x00000000 04056 #define PATH_CHAR_CLASS_ANY 0xffffffff 04057 04058 static const DWORD SHELL_charclass[] = 04059 { 04060 /* 0x00 */ PATH_CHAR_CLASS_INVALID, /* 0x01 */ PATH_CHAR_CLASS_INVALID, 04061 /* 0x02 */ PATH_CHAR_CLASS_INVALID, /* 0x03 */ PATH_CHAR_CLASS_INVALID, 04062 /* 0x04 */ PATH_CHAR_CLASS_INVALID, /* 0x05 */ PATH_CHAR_CLASS_INVALID, 04063 /* 0x06 */ PATH_CHAR_CLASS_INVALID, /* 0x07 */ PATH_CHAR_CLASS_INVALID, 04064 /* 0x08 */ PATH_CHAR_CLASS_INVALID, /* 0x09 */ PATH_CHAR_CLASS_INVALID, 04065 /* 0x0a */ PATH_CHAR_CLASS_INVALID, /* 0x0b */ PATH_CHAR_CLASS_INVALID, 04066 /* 0x0c */ PATH_CHAR_CLASS_INVALID, /* 0x0d */ PATH_CHAR_CLASS_INVALID, 04067 /* 0x0e */ PATH_CHAR_CLASS_INVALID, /* 0x0f */ PATH_CHAR_CLASS_INVALID, 04068 /* 0x10 */ PATH_CHAR_CLASS_INVALID, /* 0x11 */ PATH_CHAR_CLASS_INVALID, 04069 /* 0x12 */ PATH_CHAR_CLASS_INVALID, /* 0x13 */ PATH_CHAR_CLASS_INVALID, 04070 /* 0x14 */ PATH_CHAR_CLASS_INVALID, /* 0x15 */ PATH_CHAR_CLASS_INVALID, 04071 /* 0x16 */ PATH_CHAR_CLASS_INVALID, /* 0x17 */ PATH_CHAR_CLASS_INVALID, 04072 /* 0x18 */ PATH_CHAR_CLASS_INVALID, /* 0x19 */ PATH_CHAR_CLASS_INVALID, 04073 /* 0x1a */ PATH_CHAR_CLASS_INVALID, /* 0x1b */ PATH_CHAR_CLASS_INVALID, 04074 /* 0x1c */ PATH_CHAR_CLASS_INVALID, /* 0x1d */ PATH_CHAR_CLASS_INVALID, 04075 /* 0x1e */ PATH_CHAR_CLASS_INVALID, /* 0x1f */ PATH_CHAR_CLASS_INVALID, 04076 /* ' ' */ PATH_CHAR_CLASS_SPACE, /* '!' */ PATH_CHAR_CLASS_OTHER_VALID, 04077 /* '"' */ PATH_CHAR_CLASS_DOUBLEQUOTE, /* '#' */ PATH_CHAR_CLASS_OTHER_VALID, 04078 /* '$' */ PATH_CHAR_CLASS_OTHER_VALID, /* '%' */ PATH_CHAR_CLASS_OTHER_VALID, 04079 /* '&' */ PATH_CHAR_CLASS_OTHER_VALID, /* '\'' */ PATH_CHAR_CLASS_OTHER_VALID, 04080 /* '(' */ PATH_CHAR_CLASS_OTHER_VALID, /* ')' */ PATH_CHAR_CLASS_OTHER_VALID, 04081 /* '*' */ PATH_CHAR_CLASS_ASTERIX, /* '+' */ PATH_CHAR_CLASS_OTHER_VALID, 04082 /* ',' */ PATH_CHAR_CLASS_COMMA, /* '-' */ PATH_CHAR_CLASS_OTHER_VALID, 04083 /* '.' */ PATH_CHAR_CLASS_DOT, /* '/' */ PATH_CHAR_CLASS_INVALID, 04084 /* '0' */ PATH_CHAR_CLASS_OTHER_VALID, /* '1' */ PATH_CHAR_CLASS_OTHER_VALID, 04085 /* '2' */ PATH_CHAR_CLASS_OTHER_VALID, /* '3' */ PATH_CHAR_CLASS_OTHER_VALID, 04086 /* '4' */ PATH_CHAR_CLASS_OTHER_VALID, /* '5' */ PATH_CHAR_CLASS_OTHER_VALID, 04087 /* '6' */ PATH_CHAR_CLASS_OTHER_VALID, /* '7' */ PATH_CHAR_CLASS_OTHER_VALID, 04088 /* '8' */ PATH_CHAR_CLASS_OTHER_VALID, /* '9' */ PATH_CHAR_CLASS_OTHER_VALID, 04089 /* ':' */ PATH_CHAR_CLASS_COLON, /* ';' */ PATH_CHAR_CLASS_SEMICOLON, 04090 /* '<' */ PATH_CHAR_CLASS_INVALID, /* '=' */ PATH_CHAR_CLASS_OTHER_VALID, 04091 /* '>' */ PATH_CHAR_CLASS_INVALID, /* '?' */ PATH_CHAR_CLASS_LETTER, 04092 /* '@' */ PATH_CHAR_CLASS_OTHER_VALID, /* 'A' */ PATH_CHAR_CLASS_ANY, 04093 /* 'B' */ PATH_CHAR_CLASS_ANY, /* 'C' */ PATH_CHAR_CLASS_ANY, 04094 /* 'D' */ PATH_CHAR_CLASS_ANY, /* 'E' */ PATH_CHAR_CLASS_ANY, 04095 /* 'F' */ PATH_CHAR_CLASS_ANY, /* 'G' */ PATH_CHAR_CLASS_ANY, 04096 /* 'H' */ PATH_CHAR_CLASS_ANY, /* 'I' */ PATH_CHAR_CLASS_ANY, 04097 /* 'J' */ PATH_CHAR_CLASS_ANY, /* 'K' */ PATH_CHAR_CLASS_ANY, 04098 /* 'L' */ PATH_CHAR_CLASS_ANY, /* 'M' */ PATH_CHAR_CLASS_ANY, 04099 /* 'N' */ PATH_CHAR_CLASS_ANY, /* 'O' */ PATH_CHAR_CLASS_ANY, 04100 /* 'P' */ PATH_CHAR_CLASS_ANY, /* 'Q' */ PATH_CHAR_CLASS_ANY, 04101 /* 'R' */ PATH_CHAR_CLASS_ANY, /* 'S' */ PATH_CHAR_CLASS_ANY, 04102 /* 'T' */ PATH_CHAR_CLASS_ANY, /* 'U' */ PATH_CHAR_CLASS_ANY, 04103 /* 'V' */ PATH_CHAR_CLASS_ANY, /* 'W' */ PATH_CHAR_CLASS_ANY, 04104 /* 'X' */ PATH_CHAR_CLASS_ANY, /* 'Y' */ PATH_CHAR_CLASS_ANY, 04105 /* 'Z' */ PATH_CHAR_CLASS_ANY, /* '[' */ PATH_CHAR_CLASS_OTHER_VALID, 04106 /* '\\' */ PATH_CHAR_CLASS_BACKSLASH, /* ']' */ PATH_CHAR_CLASS_OTHER_VALID, 04107 /* '^' */ PATH_CHAR_CLASS_OTHER_VALID, /* '_' */ PATH_CHAR_CLASS_OTHER_VALID, 04108 /* '`' */ PATH_CHAR_CLASS_OTHER_VALID, /* 'a' */ PATH_CHAR_CLASS_ANY, 04109 /* 'b' */ PATH_CHAR_CLASS_ANY, /* 'c' */ PATH_CHAR_CLASS_ANY, 04110 /* 'd' */ PATH_CHAR_CLASS_ANY, /* 'e' */ PATH_CHAR_CLASS_ANY, 04111 /* 'f' */ PATH_CHAR_CLASS_ANY, /* 'g' */ PATH_CHAR_CLASS_ANY, 04112 /* 'h' */ PATH_CHAR_CLASS_ANY, /* 'i' */ PATH_CHAR_CLASS_ANY, 04113 /* 'j' */ PATH_CHAR_CLASS_ANY, /* 'k' */ PATH_CHAR_CLASS_ANY, 04114 /* 'l' */ PATH_CHAR_CLASS_ANY, /* 'm' */ PATH_CHAR_CLASS_ANY, 04115 /* 'n' */ PATH_CHAR_CLASS_ANY, /* 'o' */ PATH_CHAR_CLASS_ANY, 04116 /* 'p' */ PATH_CHAR_CLASS_ANY, /* 'q' */ PATH_CHAR_CLASS_ANY, 04117 /* 'r' */ PATH_CHAR_CLASS_ANY, /* 's' */ PATH_CHAR_CLASS_ANY, 04118 /* 't' */ PATH_CHAR_CLASS_ANY, /* 'u' */ PATH_CHAR_CLASS_ANY, 04119 /* 'v' */ PATH_CHAR_CLASS_ANY, /* 'w' */ PATH_CHAR_CLASS_ANY, 04120 /* 'x' */ PATH_CHAR_CLASS_ANY, /* 'y' */ PATH_CHAR_CLASS_ANY, 04121 /* 'z' */ PATH_CHAR_CLASS_ANY, /* '{' */ PATH_CHAR_CLASS_OTHER_VALID, 04122 /* '|' */ PATH_CHAR_CLASS_INVALID, /* '}' */ PATH_CHAR_CLASS_OTHER_VALID, 04123 /* '~' */ PATH_CHAR_CLASS_OTHER_VALID 04124 }; 04125 04126 /************************************************************************* 04127 * @ [SHLWAPI.455] 04128 * 04129 * Check if an ASCII char is of a certain class 04130 */ 04131 BOOL WINAPI PathIsValidCharA( char c, DWORD class ) 04132 { 04133 if ((unsigned)c > 0x7e) 04134 return class & PATH_CHAR_CLASS_OTHER_VALID; 04135 04136 return class & SHELL_charclass[(unsigned)c]; 04137 } 04138 04139 /************************************************************************* 04140 * @ [SHLWAPI.456] 04141 * 04142 * Check if a Unicode char is of a certain class 04143 */ 04144 BOOL WINAPI PathIsValidCharW( WCHAR c, DWORD class ) 04145 { 04146 if (c > 0x7e) 04147 return class & PATH_CHAR_CLASS_OTHER_VALID; 04148 04149 return class & SHELL_charclass[c]; 04150 } Generated on Mon May 28 2012 04:18:03 for ReactOS by
1.7.6.1
|