ReactOS  r76032
path.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Win32 Base API
3  * LICENSE: GPL - See COPYING in the top level directory
4  * FILE: dll/win32/kernel32/client/path.c
5  * PURPOSE: Handles path APIs
6  * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include <k32.h>
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* GLOBALS ********************************************************************/
17 
19 
22 
25 
26 /* This is bitmask for each illegal filename character */
27 /* If someone has time, please feel free to use 0b notation */
29 {
30  0xFFFFFFFF, // None allowed (00 to 1F)
31  0xFC009C05, // 20, 22, 2A, 2B, 2C, 2F, 3A, 3B, 3C, 3D, 3E, 3F not allowed
32  0x38000000, // 5B, 5C, 5D not allowed
33  0x10000000 // 7C not allowed
34 };
35 
37 {
38  {
44  },
45  {
51  }
52 };
53 
55 {
60  BaseSearchPathInvalid
61 };
62 
64 {
70 };
71 
73 {
79 };
80 
82 
84 
85 /* PRIVATE FUNCTIONS **********************************************************/
86 
87 PWCHAR
88 WINAPI
90 {
91  PWCHAR FileNameEnd, FileNameSeparator;
92 
93  /* Find the first slash */
94  FileNameSeparator = wcschr(FileName, OBJ_NAME_PATH_SEPARATOR);
95  if (FileNameSeparator)
96  {
97  /* Find the last one */
98  FileNameEnd = wcsrchr(FileNameSeparator, OBJ_NAME_PATH_SEPARATOR);
99  ASSERT(FileNameEnd);
100 
101  /* Handle the case where they are one and the same */
102  if (FileNameEnd == FileNameSeparator) FileNameEnd++;
103  }
104  else
105  {
106  /* No directory was specified */
107  FileNameEnd = NULL;
108  }
109 
110  /* Return where the directory ends and the filename starts */
111  return FileNameEnd;
112 }
113 
114 LPWSTR
115 WINAPI
117  IN LPWSTR AppName,
119 {
120  PWCHAR PathBuffer, Buffer, AppNameEnd, PathCurrent;
121  ULONG PathLengthInBytes;
123  UNICODE_STRING EnvPath;
125 
126  /* Initialize state */
127  AppNameEnd = Buffer = PathBuffer = NULL;
128  Status = STATUS_SUCCESS;
129  PathLengthInBytes = 0;
130 
131  /* Loop the ordering array */
132  for (Order = PathOrder; *Order != BaseSearchPathInvalid; Order++) {
133  switch (*Order)
134  {
135  /* Compute the size of the DLL path */
136  case BaseSearchPathDll:
137 
138  /* This path only gets called if SetDllDirectory was called */
139  ASSERT(BaseDllDirectory.Buffer != NULL);
140 
141  /* Make sure there's a DLL directory size */
142  if (BaseDllDirectory.Length)
143  {
144  /* Add it, plus the separator */
145  PathLengthInBytes += BaseDllDirectory.Length + sizeof(L';');
146  }
147  break;
148 
149  /* Compute the size of the current path */
151 
152  /* Add ".;" */
153  PathLengthInBytes += (2 * sizeof(WCHAR));
154  break;
155 
156  /* Compute the size of the "PATH" environment variable */
157  case BaseSearchPathEnv:
158 
159  /* Grab PEB lock if one wasn't passed in */
160  if (!Environment) RtlAcquirePebLock();
161 
162  /* Query the size first */
163  EnvPath.MaximumLength = 0;
164  Status = RtlQueryEnvironmentVariable_U(Environment,
165  &BasePathVariableName,
166  &EnvPath);
167  if (Status == STATUS_BUFFER_TOO_SMALL)
168  {
169  /* Compute the size we'll need for the environment */
170  EnvPath.MaximumLength = EnvPath.Length + sizeof(WCHAR);
171  if ((EnvPath.Length + sizeof(WCHAR)) > UNICODE_STRING_MAX_BYTES)
172  {
173  /* Don't let it overflow */
174  EnvPath.MaximumLength = EnvPath.Length;
175  }
176 
177  /* Allocate the environment buffer */
178  Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
179  0,
180  EnvPath.MaximumLength);
181  if (Buffer)
182  {
183  /* Now query the PATH environment variable */
184  EnvPath.Buffer = Buffer;
185  Status = RtlQueryEnvironmentVariable_U(Environment,
186  &BasePathVariableName,
187  &EnvPath);
188  }
189  else
190  {
191  /* Failure case */
192  Status = STATUS_NO_MEMORY;
193  }
194  }
195 
196  /* Release the PEB lock from above */
197  if (!Environment) RtlReleasePebLock();
198 
199  /* There might not be a PATH */
200  if (Status == STATUS_VARIABLE_NOT_FOUND)
201  {
202  /* In this case, skip this PathOrder */
203  EnvPath.Length = EnvPath.MaximumLength = 0;
204  Status = STATUS_SUCCESS;
205  }
206  else if (!NT_SUCCESS(Status))
207  {
208  /* An early failure, go to exit code */
209  goto Quickie;
210  }
211  else
212  {
213  /* Add the length of the PATH variable unless it's empty */
214  ASSERT(!(EnvPath.Length & 1));
215  if (EnvPath.Length)
216  {
217  /* Reserve space for the variable and a semicolon */
218  PathLengthInBytes += (EnvPath.Length + sizeof(L';'));
219  }
220  }
221  break;
222 
223  /* Compute the size of the default search path */
225 
226  /* Just add it... it already has a ';' at the end */
227  ASSERT(!(BaseDefaultPath.Length & 1));
228  PathLengthInBytes += BaseDefaultPath.Length;
229  break;
230 
231  /* Compute the size of the current app directory */
232  case BaseSearchPathApp:
233  /* Find out where the app name ends, to get only the directory */
234  if (AppName) AppNameEnd = BasepEndOfDirName(AppName);
235 
236  /* Check if there was no application name passed in */
237  if (!(AppName) || !(AppNameEnd))
238  {
239  /* Do we have a per-thread CURDIR to use? */
240  if (NtCurrentTeb()->NtTib.SubSystemTib)
241  {
242  /* This means someone added RTL_PERTHREAD_CURDIR */
244  }
245 
246  /* We do not. Do we have the LDR_ENTRY for the executable? */
247  if (!BasepExeLdrEntry)
248  {
249  /* We do not. Grab it */
252  NtCurrentPeb()->ImageBaseAddress);
253  }
254 
255  /* Now do we have it? */
256  if (BasepExeLdrEntry)
257  {
258  /* Yes, so read the name out of it */
260  }
261 
262  /* Find out where the app name ends, to get only the directory */
263  if (AppName) AppNameEnd = BasepEndOfDirName(AppName);
264  }
265 
266  /* So, do we have an application name and its directory? */
267  if ((AppName) && (AppNameEnd))
268  {
269  /* Add the size of the app's directory, plus the separator */
270  PathLengthInBytes += ((AppNameEnd - AppName) * sizeof(WCHAR)) + sizeof(L';');
271  }
272  break;
273 
274  default:
275  break;
276  }
277  }
278 
279  /* Bam, all done, we now have the final path size */
280  ASSERT(PathLengthInBytes > 0);
281  ASSERT(!(PathLengthInBytes & 1));
282 
283  /* Allocate the buffer to hold it */
284  PathBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, PathLengthInBytes);
285  if (!PathBuffer)
286  {
287  /* Failure path */
288  Status = STATUS_NO_MEMORY;
289  goto Quickie;
290  }
291 
292  /* Now we loop again, this time to copy the data */
293  PathCurrent = PathBuffer;
294  for (Order = PathOrder; *Order != BaseSearchPathInvalid; Order++) {
295  switch (*Order)
296  {
297  /* Add the DLL path */
298  case BaseSearchPathDll:
299  if (BaseDllDirectory.Length)
300  {
301  /* Copy it in the buffer, ASSERT there's enough space */
302  ASSERT((((PathCurrent - PathBuffer + 1) * sizeof(WCHAR)) + BaseDllDirectory.Length) <= PathLengthInBytes);
303  RtlCopyMemory(PathCurrent,
304  BaseDllDirectory.Buffer,
305  BaseDllDirectory.Length);
306 
307  /* Update the current pointer, add a separator */
308  PathCurrent += (BaseDllDirectory.Length / sizeof(WCHAR));
309  *PathCurrent++ = ';';
310  }
311  break;
312 
313  /* Add the current application path */
314  case BaseSearchPathApp:
315  if ((AppName) && (AppNameEnd))
316  {
317  /* Copy it in the buffer, ASSERT there's enough space */
318  ASSERT(((PathCurrent - PathBuffer + 1 + (AppNameEnd - AppName)) * sizeof(WCHAR)) <= PathLengthInBytes);
319  RtlCopyMemory(PathCurrent,
320  AppName,
321  (AppNameEnd - AppName) * sizeof(WCHAR));
322 
323  /* Update the current pointer, add a separator */
324  PathCurrent += AppNameEnd - AppName;
325  *PathCurrent++ = ';';
326  }
327  break;
328 
329  /* Add the default search path */
331  /* Copy it in the buffer, ASSERT there's enough space */
332  ASSERT((((PathCurrent - PathBuffer) * sizeof(WCHAR)) + BaseDefaultPath.Length) <= PathLengthInBytes);
333  RtlCopyMemory(PathCurrent, BaseDefaultPath.Buffer, BaseDefaultPath.Length);
334 
335  /* Update the current pointer. The default path already has a ";" */
336  PathCurrent += (BaseDefaultPath.Length / sizeof(WCHAR));
337  break;
338 
339  /* Add the path in the PATH environment variable */
340  case BaseSearchPathEnv:
341  if (EnvPath.Length)
342  {
343  /* Copy it in the buffer, ASSERT there's enough space */
344  ASSERT((((PathCurrent - PathBuffer + 1) * sizeof(WCHAR)) + EnvPath.Length) <= PathLengthInBytes);
345  RtlCopyMemory(PathCurrent, EnvPath.Buffer, EnvPath.Length);
346 
347  /* Update the current pointer, add a separator */
348  PathCurrent += (EnvPath.Length / sizeof(WCHAR));
349  *PathCurrent++ = ';';
350  }
351  break;
352 
353  /* Add the current directory */
355 
356  /* Copy it in the buffer, ASSERT there's enough space */
357  ASSERT(((PathCurrent - PathBuffer + 2) * sizeof(WCHAR)) <= PathLengthInBytes);
358  *PathCurrent++ = '.';
359 
360  /* Add the path separator */
361  *PathCurrent++ = ';';
362  break;
363 
364  default:
365  break;
366  }
367  }
368 
369  /* Everything should've perfectly fit in there */
370  ASSERT((PathCurrent - PathBuffer) * sizeof(WCHAR) == PathLengthInBytes);
371  ASSERT(PathCurrent > PathBuffer);
372 
373  /* Terminate the whole thing */
374  PathCurrent[-1] = UNICODE_NULL;
375 
376 Quickie:
377  /* Exit path: free our buffers */
378  if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
379  if (PathBuffer)
380  {
381  /* This only gets freed in the failure path, since caller wants it */
382  if (!NT_SUCCESS(Status))
383  {
384  RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer);
385  PathBuffer = NULL;
386  }
387  }
388 
389  /* Return the path! */
390  return PathBuffer;
391 }
392 
393 LPWSTR
394 WINAPI
396 {
397  DPRINT("Computing Process Search path\n");
398 
399  /* Compute the path using default process order */
401 }
402 
403 LPWSTR
404 WINAPI
406 {
407  PBASE_SEARCH_PATH_TYPE PathOrder;
408  DPRINT("Computing EXE path: %S\n", FullPath);
409 
410  /* Check if we should use the current directory */
411  PathOrder = NeedCurrentDirectoryForExePathW(FullPath) ?
413 
414  /* And now compute the path */
415  return BasepComputeProcessPath(PathOrder, NULL, NULL);
416 }
417 
418 LPWSTR
419 WINAPI
422 {
423  LPWSTR DllPath = NULL;
424  UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager");
425  UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"SafeDllSearchMode");
427  KEY_VALUE_PARTIAL_INFORMATION PartialInfo;
431  BASE_CURRENT_DIR_PLACEMENT CurrentDirPlacement, OldCurrentDirPlacement;
432 
433  /* Acquire DLL directory lock */
435 
436  /* Check if we have a base dll directory */
437  if (BaseDllDirectory.Buffer)
438  {
439  /* Then compute the process path using DLL order (without curdir) */
440  DllPath = BasepComputeProcessPath(BaseDllOrderNoCurrent, FullPath, Environment);
441 
442  /* Release DLL directory lock */
444 
445  /* Return dll path */
446  return DllPath;
447  }
448 
449  /* Release DLL directory lock */
451 
452  /* Read the current placement */
453  CurrentDirPlacement = BasepDllCurrentDirPlacement;
454  if (CurrentDirPlacement == BaseCurrentDirPlacementInvalid)
455  {
456  /* Open the configuration key */
457  Status = NtOpenKey(&KeyHandle, KEY_QUERY_VALUE, &ObjectAttributes);
458  if (NT_SUCCESS(Status))
459  {
460  /* Query if safe search is enabled */
461  Status = NtQueryValueKey(KeyHandle,
462  &ValueName,
464  &PartialInfo,
465  sizeof(PartialInfo),
466  &ResultLength);
467  if (NT_SUCCESS(Status))
468  {
469  /* Read the value if the size is OK */
470  if (ResultLength == sizeof(PartialInfo))
471  {
472  CurrentDirPlacement = *(PULONG)PartialInfo.Data;
473  }
474  }
475 
476  /* Close the handle */
477  NtClose(KeyHandle);
478 
479  /* Validate the registry value */
480  if ((CurrentDirPlacement <= BaseCurrentDirPlacementInvalid) ||
481  (CurrentDirPlacement >= BaseCurrentDirPlacementMax))
482  {
483  /* Default to safe search */
484  CurrentDirPlacement = BaseCurrentDirPlacementSafe;
485  }
486  }
487 
488  /* Update the placement and read the old one */
490  CurrentDirPlacement,
492  if (OldCurrentDirPlacement != BaseCurrentDirPlacementInvalid)
493  {
494  /* If there already was a placement, use it */
495  CurrentDirPlacement = OldCurrentDirPlacement;
496  }
497  }
498 
499  /* Check if the placement is invalid or not set */
500  if ((CurrentDirPlacement <= BaseCurrentDirPlacementInvalid) ||
501  (CurrentDirPlacement >= BaseCurrentDirPlacementMax))
502  {
503  /* Default to safe search */
504  CurrentDirPlacement = BaseCurrentDirPlacementSafe;
505  }
506 
507  /* Compute the process path using either normal or safe search */
508  DllPath = BasepComputeProcessPath(BaseDllOrderCurrent[CurrentDirPlacement],
509  FullPath,
510  Environment);
511 
512  /* Return dll path */
513  return DllPath;
514 }
515 
516 BOOLEAN
517 WINAPI
519 {
520  PUNICODE_STRING CurDir;
521  USHORT CurLength;
522  BOOLEAN Result;
523  UNICODE_STRING CurDirCopy;
524 
525  CurDir = &NtCurrentPeb()->ProcessParameters->CurrentDirectory.DosPath;
526 
527  CurLength = CurDir->Length;
528  if (CurDir->Length <= 6)
529  {
530  if (CurLength != DirName->Length) return FALSE;
531  }
532  else
533  {
534  if ((CurLength - 2) != DirName->Length) return FALSE;
535  }
536 
538 
539  CurDirCopy = *CurDir;
540  if (CurDirCopy.Length > 6) CurDirCopy.Length -= 2;
541 
542  Result = 0;
543 
544  if (RtlEqualUnicodeString(&CurDirCopy, DirName, TRUE)) Result = TRUE;
545 
547 
548  return Result;
549 }
550 
551 /*
552  * Why not use RtlIsNameLegalDOS8Dot3? In fact the actual algorithm body is
553  * identical (other than the Rtl can optionally check for spaces), however the
554  * Rtl will always convert to OEM, while kernel32 has two possible file modes
555  * (ANSI or OEM). Therefore we must duplicate the algorithm body to get
556  * the correct compatible results
557  */
558 BOOL
559 WINAPI
561  IN ULONG Length)
562 {
563  BOOLEAN HasExtension;
564  UCHAR c;
566  UNICODE_STRING UnicodeName;
567  ANSI_STRING AnsiName;
568  ULONG i, Dots;
570  ASSERT(Name);
571 
572  /* What do you think 8.3 means? */
573  if (Length > 12) return FALSE;
574 
575  /* Sure, any empty name is a short name */
576  if (!Length) return TRUE;
577 
578  /* This could be . or .. or something else */
579  if (*Name == L'.')
580  {
581  /* Which one is it */
582  if ((Length == 1) || ((Length == 2) && *(Name + 1) == L'.'))
583  {
584  /* . or .., this is good */
585  return TRUE;
586  }
587 
588  /* Some other bizare dot-based name, not good */
589  return FALSE;
590  }
591 
592  /* Initialize our two strings */
593  RtlInitEmptyAnsiString(&AnsiName, AnsiBuffer, MAX_PATH);
594  RtlInitEmptyUnicodeString(&UnicodeName, Name, (USHORT)Length * sizeof(WCHAR));
595  UnicodeName.Length = UnicodeName.MaximumLength;
596 
597  /* Now do the conversion */
598  Status = BasepUnicodeStringTo8BitString(&AnsiName, &UnicodeName, FALSE);
599  if (!NT_SUCCESS(Status)) return FALSE;
600 
601  /* Now we loop the name */
602  HasExtension = FALSE;
603  for (i = 0, Dots = Length - 1; i < AnsiName.Length; i++, Dots--)
604  {
605  /* Read the current byte */
606  c = AnsiName.Buffer[i];
607 
608  /* Is it DBCS? */
609  if (IsDBCSLeadByte(c))
610  {
611  /* If we're near the end of the string, we can't allow a DBCS */
612  if ((!(HasExtension) && (i >= 7)) || (i == AnsiName.Length - 1))
613  {
614  return FALSE;
615  }
616 
617  /* Otherwise we skip over it */
618  continue;
619  }
620 
621  /* Check for illegal characters */
622  if ((c > 0x7F) || (IllegalMask[c / 32] & (1 << (c % 32))))
623  {
624  return FALSE;
625  }
626 
627  /* Check if this is perhaps an extension? */
628  if (c == '.')
629  {
630  /* Unless the extension is too large or there's more than one */
631  if ((HasExtension) || (Dots > 3)) return FALSE;
632 
633  /* This looks like an extension */
634  HasExtension = TRUE;
635  }
636 
637  /* 8.3 length was validated, but now we must guard against 9.2 or similar */
638  if ((i >= 8) && !(HasExtension)) return FALSE;
639  }
640 
641  /* You survived the loop, this is a good short name */
642  return TRUE;
643 }
644 
645 BOOL
646 WINAPI
648  IN ULONG Length)
649 {
650  BOOLEAN HasExtension;
651  ULONG i, Dots;
652 
653  /* More than 8.3, any combination of dots, and NULL names are all long */
654  if (!(Length) || (Length > 12) || (*FileName == L'.')) return TRUE;
655 
656  /* Otherwise, initialize our scanning loop */
657  HasExtension = FALSE;
658  for (i = 0, Dots = Length - 1; i < Length; i++, Dots--)
659  {
660  /* Check if this could be an extension */
661  if (FileName[i] == L'.')
662  {
663  /* Unlike the short case, we WANT more than one extension, or a long one */
664  if ((HasExtension) || (Dots > 3))
665  {
666  return TRUE;
667  }
668  HasExtension = TRUE;
669  }
670 
671  /* Check if this would violate the "8" in 8.3, ie. 9.2 */
672  if ((i >= 8) && (!HasExtension)) return TRUE;
673  }
674 
675  /* The name *seems* to conform to 8.3 */
676  return FALSE;
677 }
678 
679 BOOL
680 WINAPI
682  OUT PWCHAR *First,
683  OUT PWCHAR *Last,
684  IN BOOL UseShort)
685 {
686  PWCHAR p;
687  ULONG Length;
688  BOOL Found = 0;
689  ASSERT(Path);
690 
691  /* Loop while there is something in the path */
692  while (TRUE)
693  {
694  /* Loop within the path skipping slashes */
695  while ((*Path == L'\\') || (*Path == L'/')) Path++;
696 
697  /* Make sure there's something after the slashes too! */
698  if (*Path == UNICODE_NULL) break;
699 
700  /* Now skip past the file name until we get to the first slash */
701  p = Path + 1;
702  while ((*p) && ((*p != L'\\') && (*p != L'/'))) p++;
703 
704  /* Whatever is in between those two is now the file name length */
705  Length = p - Path;
706 
707  /*
708  * Check if it is valid
709  * Note that !IsShortName != IsLongName, these two functions simply help
710  * us determine if a conversion is necessary or not.
711  * "Found" really means: "Is a conversion necessary?", hence the "!"
712  */
713  Found = UseShort ? !IsShortName_U(Path, Length) : !IsLongName_U(Path, Length);
714  if (Found)
715  {
716  /* It is! did the caller request to know the markers? */
717  if ((First) && (Last))
718  {
719  /* Return them */
720  *First = Path;
721  *Last = p;
722  }
723  break;
724  }
725 
726  /* Is there anything else following this sub-path/filename? */
727  if (*p == UNICODE_NULL) break;
728 
729  /* Yes, keep going */
730  Path = p + 1;
731  }
732 
733  /* Return if anything was found and valid */
734  return Found;
735 }
736 
737 PWCHAR
738 WINAPI
740 {
741  PWCHAR ReturnPath;
742  ULONG i;
743 
744  /* Check what kind of path this is and how many slashes to skip */
745  switch (RtlDetermineDosPathNameType_U(Path))
746  {
749  {
750  /* Keep going until we bypass the path indicators */
751  for (ReturnPath = Path + 2, i = 2; (i > 0) && (*ReturnPath); ReturnPath++)
752  {
753  /* We look for 2 slashes, so keep at it until we find them */
754  if ((*ReturnPath == L'\\') || (*ReturnPath == L'/')) i--;
755  }
756 
757  return ReturnPath;
758  }
759 
761  return Path + 3;
762 
764  return Path + 2;
765 
766  case RtlPathTypeRooted:
767  return Path + 1;
768 
769  case RtlPathTypeRelative:
770  return Path;
771 
773  default:
774  return NULL;
775  }
776 }
777 
778 BOOL
779 WINAPI
781 {
783  UNICODE_STRING EmptyString;
784 
785  RtlInitEmptyUnicodeString(&EmptyString, NULL, 0);
787  &NoDefaultCurrentDirectoryInExePath,
788  &EmptyString);
789  return !NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL;
790 }
791 
792 /* PUBLIC FUNCTIONS ***********************************************************/
793 
794 /*
795  * @implemented
796  */
797 BOOL
798 WINAPI
800 {
801  UNICODE_STRING OldDirectory, DllDirectory;
802 
803  if (lpPathName)
804  {
805  if (wcschr(lpPathName, L';'))
806  {
808  return FALSE;
809  }
810  if (!RtlCreateUnicodeString(&DllDirectory, lpPathName))
811  {
813  return FALSE;
814  }
815  }
816  else
817  {
818  RtlInitUnicodeString(&DllDirectory, NULL);
819  }
820 
822 
823  OldDirectory = BaseDllDirectory;
824  BaseDllDirectory = DllDirectory;
825 
827 
828  RtlFreeUnicodeString(&OldDirectory);
829  return TRUE;
830 }
831 
832 /*
833  * @implemented
834  */
835 BOOL
836 WINAPI
838 {
839  ANSI_STRING AnsiDllDirectory;
840  UNICODE_STRING OldDirectory, DllDirectory;
842 
843  if (lpPathName)
844  {
845  if (strchr(lpPathName, ';'))
846  {
848  return FALSE;
849  }
850 
851  Status = RtlInitAnsiStringEx(&AnsiDllDirectory, lpPathName);
852  if (NT_SUCCESS(Status))
853  {
854  Status = Basep8BitStringToUnicodeString(&DllDirectory,
855  &AnsiDllDirectory,
856  TRUE);
857  }
858 
859  if (!NT_SUCCESS(Status))
860  {
861  BaseSetLastNTError(Status);
862  return FALSE;
863  }
864  }
865  else
866  {
867  RtlInitUnicodeString(&DllDirectory, NULL);
868  }
869 
871 
872  OldDirectory = BaseDllDirectory;
873  BaseDllDirectory = DllDirectory;
874 
876 
877  RtlFreeUnicodeString(&OldDirectory);
878  return TRUE;
879 }
880 
881 /*
882  * @implemented
883  */
884 DWORD
885 WINAPI
888 {
889  ULONG Length;
890 
892 
893  if ((nBufferLength * sizeof(WCHAR)) > BaseDllDirectory.Length)
894  {
895  RtlCopyMemory(lpBuffer, BaseDllDirectory.Buffer, BaseDllDirectory.Length);
896  Length = BaseDllDirectory.Length / sizeof(WCHAR);
897  lpBuffer[Length] = UNICODE_NULL;
898  }
899  else
900  {
901  Length = (BaseDllDirectory.Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR);
902  if (lpBuffer) *lpBuffer = UNICODE_NULL;
903  }
904 
906  return Length;
907 }
908 
909 /*
910  * @implemented
911  */
912 DWORD
913 WINAPI
916 {
918  ANSI_STRING AnsiDllDirectory;
919  ULONG Length;
920 
921  RtlInitEmptyAnsiString(&AnsiDllDirectory, lpBuffer, (USHORT)nBufferLength);
922 
924 
925  Length = BasepUnicodeStringTo8BitSize(&BaseDllDirectory);
926  if (Length > nBufferLength)
927  {
928  Status = STATUS_SUCCESS;
929  if (lpBuffer) *lpBuffer = ANSI_NULL;
930  }
931  else
932  {
933  --Length;
934  Status = BasepUnicodeStringTo8BitString(&AnsiDllDirectory,
935  &BaseDllDirectory,
936  FALSE);
937  }
938 
940 
941  if (!NT_SUCCESS(Status))
942  {
943  BaseSetLastNTError(Status);
944  Length = 0;
945  if (lpBuffer) *lpBuffer = ANSI_NULL;
946  }
947 
948  return Length;
949 }
950 
951 /*
952  * @implemented
953  */
954 BOOL
955 WINAPI
957 {
958  if (wcschr(ExeName, L'\\')) return TRUE;
959 
961 }
962 
963 /*
964  * @implemented
965  */
966 BOOL
967 WINAPI
969 {
970  if (strchr(ExeName, '\\')) return TRUE;
971 
973 }
974 
975 /*
976  * @implemented
977  *
978  * NOTE: Many of these A functions may seem to do rather complex A<->W mapping
979  * beyond what you would usually expect. There are two main reasons:
980  *
981  * First, these APIs are subject to the ANSI/OEM File API selection status that
982  * the caller has chosen, so we must use the "8BitString" internal Base APIs.
983  *
984  * Secondly, the Wide APIs (coming from the 9x world) are coded to return the
985  * length of the paths in "ANSI" by dividing their internal Wide character count
986  * by two... this is usually correct when dealing with pure-ASCII codepages but
987  * not necessarily when dealing with MBCS pre-Unicode sets, which NT supports
988  * for CJK, for example.
989  */
990 DWORD
991 WINAPI
996 {
998  PWCHAR Buffer = NULL;
999  ULONG PathSize, FilePartSize;
1001  UNICODE_STRING FileNameString, UniString;
1002  PWCHAR LocalFilePart;
1003  PWCHAR* FilePart;
1004 
1005  /* If the caller wants filepart, use a local wide buffer since this is A */
1006  FilePart = lpFilePart != NULL ? &LocalFilePart : NULL;
1007 
1008  /* Initialize for Quickie */
1009  FilePartSize = PathSize = 0;
1010  FileNameString.Buffer = NULL;
1011 
1012  /* First get our string in Unicode */
1013  Status = Basep8BitStringToDynamicUnicodeString(&FileNameString, lpFileName);
1014  if (!NT_SUCCESS(Status)) goto Quickie;
1015 
1016  /* Allocate a buffer to hold teh path name */
1017  Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
1018  0,
1019  MAX_PATH * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1020  if (!Buffer)
1021  {
1023  goto Quickie;
1024  }
1025 
1026  /* Call into RTL to get the full Unicode path name */
1027  PathSize = RtlGetFullPathName_U(FileNameString.Buffer,
1028  MAX_PATH * sizeof(WCHAR),
1029  Buffer,
1030  FilePart);
1031  if (PathSize <= (MAX_PATH * sizeof(WCHAR)))
1032  {
1033  /* The buffer will fit, get the real ANSI string size now */
1034  Status = RtlUnicodeToMultiByteSize(&PathSize, Buffer, PathSize);
1035  if (NT_SUCCESS(Status))
1036  {
1037  /* Now check if the user wanted file part size as well */
1038  if ((PathSize) && (lpFilePart) && (LocalFilePart))
1039  {
1040  /* Yep, so in this case get the length of the file part too */
1041  Status = RtlUnicodeToMultiByteSize(&FilePartSize,
1042  Buffer,
1043  (LocalFilePart - Buffer) *
1044  sizeof(WCHAR));
1045  if (!NT_SUCCESS(Status))
1046  {
1047  /* We failed to do that, so fail the whole call */
1048  BaseSetLastNTError(Status);
1049  PathSize = 0;
1050  }
1051  }
1052  }
1053  }
1054  else
1055  {
1056  /* Reset the path size since the buffer is not large enough */
1057  PathSize = 0;
1058  }
1059 
1060  /* Either no path, or local buffer was too small, enter failure code */
1061  if (!PathSize) goto Quickie;
1062 
1063  /* If the *caller's* buffer was too small, fail, but add in space for NULL */
1064  if (PathSize >= nBufferLength)
1065  {
1066  PathSize++;
1067  goto Quickie;
1068  }
1069 
1070  /* So far so good, initialize a unicode string to convert back to ANSI/OEM */
1071  RtlInitUnicodeString(&UniString, Buffer);
1072  Status = BasepUnicodeStringTo8BitString(&AnsiString, &UniString, TRUE);
1073  if (!NT_SUCCESS(Status))
1074  {
1075  /* Final conversion failed, fail the call */
1076  BaseSetLastNTError(Status);
1077  PathSize = 0;
1078  }
1079  else
1080  {
1081  /* Conversion worked, now copy the ANSI/OEM buffer into the buffer */
1082  RtlCopyMemory(lpBuffer, AnsiString.Buffer, PathSize + 1);
1083  RtlFreeAnsiString(&AnsiString);
1084 
1085  /* And finally, did the caller request file part information? */
1086  if (lpFilePart)
1087  {
1088  /* Use the size we computed earlier and add it to the buffer */
1089  *lpFilePart = LocalFilePart ? &lpBuffer[FilePartSize] : 0;
1090  }
1091  }
1092 
1093 Quickie:
1094  /* Cleanup and return the path size */
1095  if (FileNameString.Buffer) RtlFreeUnicodeString(&FileNameString);
1096  if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
1097  return PathSize;
1098 }
1099 
1100 /*
1101  * @implemented
1102  */
1103 DWORD
1104 WINAPI
1109 {
1110  /* Call Rtl to do the work */
1111  return RtlGetFullPathName_U(lpFileName,
1112  nBufferLength * sizeof(WCHAR),
1113  lpBuffer,
1114  lpFilePart) / sizeof(WCHAR);
1115 }
1116 
1117 /*
1118  * @implemented
1119  */
1120 DWORD
1121 WINAPI
1124  IN LPCSTR lpExtension OPTIONAL,
1126  OUT LPSTR lpBuffer,
1127  OUT LPSTR *lpFilePart OPTIONAL)
1128 {
1129  PUNICODE_STRING FileNameString;
1130  UNICODE_STRING PathString, ExtensionString;
1131  NTSTATUS Status;
1132  ULONG PathSize, FilePartSize, AnsiLength;
1133  PWCHAR LocalFilePart, Buffer;
1134  PWCHAR* FilePart;
1135 
1136  /* If the caller wants filepart, use a local wide buffer since this is A */
1137  FilePart = lpFilePart != NULL ? &LocalFilePart : NULL;
1138 
1139  /* Initialize stuff for Quickie */
1140  PathSize = 0;
1141  Buffer = NULL;
1142  ExtensionString.Buffer = PathString.Buffer = NULL;
1143 
1144  /* Get the UNICODE_STRING file name */
1145  FileNameString = Basep8BitStringToStaticUnicodeString(lpFileName);
1146  if (!FileNameString) return 0;
1147 
1148  /* Did the caller specify an extension */
1149  if (lpExtension)
1150  {
1151  /* Yup, convert it into UNICODE_STRING */
1152  Status = Basep8BitStringToDynamicUnicodeString(&ExtensionString,
1153  lpExtension);
1154  if (!NT_SUCCESS(Status)) goto Quickie;
1155  }
1156 
1157  /* Did the caller specify a path */
1158  if (lpPath)
1159  {
1160  /* Yup, convert it into UNICODE_STRING */
1161  Status = Basep8BitStringToDynamicUnicodeString(&PathString, lpPath);
1162  if (!NT_SUCCESS(Status)) goto Quickie;
1163  }
1164 
1165  /* Allocate our output buffer */
1166  Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, nBufferLength * sizeof(WCHAR));
1167  if (!Buffer)
1168  {
1169  /* It failed, bail out */
1171  goto Quickie;
1172  }
1173 
1174  /* Now run the Wide search with the input buffer lengths */
1175  PathSize = SearchPathW(PathString.Buffer,
1176  FileNameString->Buffer,
1177  ExtensionString.Buffer,
1178  nBufferLength,
1179  Buffer,
1180  FilePart);
1181  if (PathSize <= nBufferLength)
1182  {
1183  /* It fits, but is it empty? If so, bail out */
1184  if (!PathSize) goto Quickie;
1185 
1186  /* The length above is inexact, we need it in ANSI */
1187  Status = RtlUnicodeToMultiByteSize(&AnsiLength, Buffer, PathSize * sizeof(WCHAR));
1188  if (!NT_SUCCESS(Status))
1189  {
1190  /* Conversion failed, fail the call */
1191  PathSize = 0;
1192  BaseSetLastNTError(Status);
1193  goto Quickie;
1194  }
1195 
1196  /* If the correct ANSI size is too big, return required length plus a NULL */
1197  if (AnsiLength >= nBufferLength)
1198  {
1199  PathSize = AnsiLength + 1;
1200  goto Quickie;
1201  }
1202 
1203  /* Now apply the final conversion to ANSI */
1204  Status = RtlUnicodeToMultiByteN(lpBuffer,
1205  nBufferLength - 1,
1206  &AnsiLength,
1207  Buffer,
1208  PathSize * sizeof(WCHAR));
1209  if (!NT_SUCCESS(Status))
1210  {
1211  /* Conversion failed, fail the whole call */
1212  PathSize = 0;
1214  goto Quickie;
1215  }
1216 
1217  /* NULL-terminate and return the real ANSI length */
1218  lpBuffer[AnsiLength] = ANSI_NULL;
1219  PathSize = AnsiLength;
1220 
1221  /* Now check if the user wanted file part size as well */
1222  if (lpFilePart)
1223  {
1224  /* If we didn't get a file part, clear the caller's */
1225  if (!LocalFilePart)
1226  {
1227  *lpFilePart = NULL;
1228  }
1229  else
1230  {
1231  /* Yep, so in this case get the length of the file part too */
1232  Status = RtlUnicodeToMultiByteSize(&FilePartSize,
1233  Buffer,
1234  (LocalFilePart - Buffer) *
1235  sizeof(WCHAR));
1236  if (!NT_SUCCESS(Status))
1237  {
1238  /* We failed to do that, so fail the whole call */
1239  BaseSetLastNTError(Status);
1240  PathSize = 0;
1241  }
1242 
1243  /* Return the file part buffer */
1244  *lpFilePart = lpBuffer + FilePartSize;
1245  }
1246  }
1247  }
1248  else
1249  {
1250  /* Our initial buffer guess was too small, allocate a bigger one */
1251  RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
1252  Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, PathSize * sizeof(WCHAR));
1253  if (!Buffer)
1254  {
1255  /* Out of memory, fail everything */
1257  goto Quickie;
1258  }
1259 
1260  /* Do the search again -- it will fail, we just want the path size */
1261  PathSize = SearchPathW(PathString.Buffer,
1262  FileNameString->Buffer,
1263  ExtensionString.Buffer,
1264  PathSize,
1265  Buffer,
1266  FilePart);
1267  if (!PathSize) goto Quickie;
1268 
1269  /* Convert it to a correct size */
1270  Status = RtlUnicodeToMultiByteSize(&PathSize, Buffer, PathSize * sizeof(WCHAR));
1271  if (NT_SUCCESS(Status))
1272  {
1273  /* Make space for the NULL-char */
1274  PathSize++;
1275  }
1276  else
1277  {
1278  /* Conversion failed for some reason, fail the call */
1279  BaseSetLastNTError(Status);
1280  PathSize = 0;
1281  }
1282  }
1283 
1284 Quickie:
1285  /* Cleanup/complete path */
1286  if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
1287  if (ExtensionString.Buffer) RtlFreeUnicodeString(&ExtensionString);
1288  if (PathString.Buffer) RtlFreeUnicodeString(&PathString);
1289  return PathSize;
1290 }
1291 
1292 /*
1293  * @implemented
1294  */
1295 DWORD
1296 WINAPI
1299  IN LPCWSTR lpExtension OPTIONAL,
1302  OUT LPWSTR *lpFilePart OPTIONAL)
1303 {
1304  UNICODE_STRING FileNameString, ExtensionString, PathString, CallerBuffer;
1305  ULONG Flags, LengthNeeded, FilePartSize;
1306  NTSTATUS Status;
1307  DWORD Result = 0;
1308 
1309  /* Default flags for RtlDosSearchPath_Ustr */
1310  Flags = 6;
1311 
1312  /* Clear file part in case we fail */
1313  if (lpFilePart) *lpFilePart = NULL;
1314 
1315  /* Initialize path buffer for free later */
1316  PathString.Buffer = NULL;
1317 
1318  /* Convert filename to a unicode string and eliminate trailing spaces */
1319  RtlInitUnicodeString(&FileNameString, lpFileName);
1320  while ((FileNameString.Length >= sizeof(WCHAR)) &&
1321  (FileNameString.Buffer[(FileNameString.Length / sizeof(WCHAR)) - 1] == L' '))
1322  {
1323  FileNameString.Length -= sizeof(WCHAR);
1324  }
1325 
1326  /* Was it all just spaces? */
1327  if (!FileNameString.Length)
1328  {
1329  /* Fail out */
1331  goto Quickie;
1332  }
1333 
1334  /* Convert extension to a unicode string */
1335  RtlInitUnicodeString(&ExtensionString, lpExtension);
1336 
1337  /* Check if the user sent a path */
1338  if (lpPath)
1339  {
1340  /* Convert it to a unicode string too */
1341  Status = RtlInitUnicodeStringEx(&PathString, lpPath);
1342  if (NT_ERROR(Status))
1343  {
1344  /* Fail if it was too long */
1345  BaseSetLastNTError(Status);
1346  goto Quickie;
1347  }
1348  }
1349  else
1350  {
1351  /* A path wasn't sent, so compute it ourselves */
1352  PathString.Buffer = BaseComputeProcessSearchPath();
1353  if (!PathString.Buffer)
1354  {
1355  /* Fail if we couldn't compute it */
1357  goto Quickie;
1358  }
1359 
1360  /* See how big the computed path is */
1361  LengthNeeded = lstrlenW(PathString.Buffer);
1362  if (LengthNeeded > UNICODE_STRING_MAX_CHARS)
1363  {
1364  /* Fail if it's too long */
1366  goto Quickie;
1367  }
1368 
1369  /* Set the path size now that we have it */
1370  PathString.MaximumLength = PathString.Length = (USHORT)LengthNeeded * sizeof(WCHAR);
1371 
1372  /* Request SxS isolation from RtlDosSearchPath_Ustr */
1373  Flags |= 1;
1374  }
1375 
1376  /* Create the string that describes the output buffer from the caller */
1377  CallerBuffer.Length = 0;
1378  CallerBuffer.Buffer = lpBuffer;
1379 
1380  /* How much space does the caller have? */
1381  if (nBufferLength <= UNICODE_STRING_MAX_CHARS)
1382  {
1383  /* Add it into the string */
1384  CallerBuffer.MaximumLength = (USHORT)nBufferLength * sizeof(WCHAR);
1385  }
1386  else
1387  {
1388  /* Caller wants too much, limit it to the maximum length of a string */
1389  CallerBuffer.MaximumLength = UNICODE_STRING_MAX_BYTES;
1390  }
1391 
1392  /* Call Rtl to do the work */
1393  Status = RtlDosSearchPath_Ustr(Flags,
1394  &PathString,
1395  &FileNameString,
1396  &ExtensionString,
1397  &CallerBuffer,
1398  NULL,
1399  NULL,
1400  &FilePartSize,
1401  &LengthNeeded);
1402  if (NT_ERROR(Status))
1403  {
1404  /* Check for unusual status codes */
1405  if ((Status != STATUS_NO_SUCH_FILE) && (Status != STATUS_BUFFER_TOO_SMALL))
1406  {
1407  /* Print them out since maybe an app needs fixing */
1408  DbgPrint("%s on file %wZ failed; NTSTATUS = %08lx\n",
1409  __FUNCTION__,
1410  &FileNameString,
1411  Status);
1412  DbgPrint(" Path = %wZ\n", &PathString);
1413  }
1414 
1415  /* Check if the failure was due to a small buffer */
1416  if (Status == STATUS_BUFFER_TOO_SMALL)
1417  {
1418  /* Check if the length was actually too big for Rtl to work with */
1419  Result = LengthNeeded / sizeof(WCHAR);
1420  if (Result > 0xFFFFFFFF) BaseSetLastNTError(STATUS_NAME_TOO_LONG);
1421  }
1422  else
1423  {
1424  /* Some other error, set the error code */
1425  BaseSetLastNTError(Status);
1426  }
1427  }
1428  else
1429  {
1430  /* It worked! Write the file part now */
1431  if (lpFilePart) *lpFilePart = &lpBuffer[FilePartSize];
1432 
1433  /* Convert the final result length */
1434  Result = CallerBuffer.Length / sizeof(WCHAR);
1435  }
1436 
1437 Quickie:
1438  /* Check if there was a dynamic path string to free */
1439  if ((PathString.Buffer != lpPath) && (PathString.Buffer))
1440  {
1441  /* And free it */
1442  RtlFreeHeap(RtlGetProcessHeap(), 0, PathString.Buffer);
1443  }
1444 
1445  /* Return the final result length */
1446  return Result;
1447 }
1448 
1449 /*
1450  * @implemented
1451  */
1452 DWORD
1453 WINAPI
1455  OUT LPWSTR lpszLongPath,
1456  IN DWORD cchBuffer)
1457 {
1458  PWCHAR Path, Original, First, Last, Buffer, Src, Dst;
1459  ULONG Length;
1460  WCHAR LastChar;
1461  HANDLE FindHandle;
1463  ULONG ErrorMode;
1464  BOOLEAN Found = FALSE;
1465  WIN32_FIND_DATAW FindFileData;
1466 
1467  /* Initialize so Quickie knows there's nothing to do */
1468  Buffer = Original = NULL;
1469  ReturnLength = 0;
1470 
1471  /* First check if the input path was obviously NULL */
1472  if (!lpszShortPath)
1473  {
1474  /* Fail the request */
1476  return 0;
1477  }
1478 
1479  /* We will be touching removed, removable drives -- don't warn the user */
1481 
1482  /* Do a simple check to see if the path exists */
1483  if (GetFileAttributesW(lpszShortPath) == INVALID_FILE_ATTRIBUTES)
1484  {
1485  /* It doesn't, so fail */
1486  ReturnLength = 0;
1487  goto Quickie;
1488  }
1489 
1490  /* Now get a pointer to the actual path, skipping indicators */
1491  Path = SkipPathTypeIndicator_U((LPWSTR)lpszShortPath);
1492 
1493  /* Is there any path or filename in there? */
1494  if (!(Path) ||
1495  (*Path == UNICODE_NULL) ||
1496  !(FindLFNorSFN_U(Path, &First, &Last, FALSE)))
1497  {
1498  /* There isn't, so the long path is simply the short path */
1499  ReturnLength = wcslen(lpszShortPath);
1500 
1501  /* Is there space for it? */
1502  if ((cchBuffer > ReturnLength) && (lpszLongPath))
1503  {
1504  /* Make sure the pointers aren't already the same */
1505  if (lpszLongPath != lpszShortPath)
1506  {
1507  /* They're not -- copy the short path into the long path */
1508  RtlMoveMemory(lpszLongPath,
1509  lpszShortPath,
1510  ReturnLength * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1511  }
1512  }
1513  else
1514  {
1515  /* Otherwise, let caller know we need a bigger buffer, include NULL */
1516  ReturnLength++;
1517  }
1518  goto Quickie;
1519  }
1520 
1521  /* We are still in the game -- compute the current size */
1522  Length = wcslen(lpszShortPath) + sizeof(ANSI_NULL);
1523  Original = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR));
1524  if (!Original) goto ErrorQuickie;
1525 
1526  /* Make a copy of it */
1527  RtlMoveMemory(Original, lpszShortPath, Length * sizeof(WCHAR));
1528 
1529  /* Compute the new first and last markers */
1530  First = &Original[First - lpszShortPath];
1531  Last = &Original[Last - lpszShortPath];
1532 
1533  /* Set the current destination pointer for a copy */
1534  Dst = lpszLongPath;
1535 
1536  /*
1537  * Windows allows the paths to overlap -- we have to be careful with this and
1538  * see if it's same to do so, and if not, allocate our own internal buffer
1539  * that we'll return at the end.
1540  *
1541  * This is also why we use RtlMoveMemory everywhere. Don't use RtlCopyMemory!
1542  */
1543  if ((cchBuffer) && (lpszLongPath) &&
1544  (((lpszLongPath >= lpszShortPath) && (lpszLongPath < &lpszShortPath[Length])) ||
1545  ((lpszLongPath < lpszShortPath) && (&lpszLongPath[cchBuffer] >= lpszShortPath))))
1546  {
1547  Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, cchBuffer * sizeof(WCHAR));
1548  if (!Buffer) goto ErrorQuickie;
1549 
1550  /* New destination */
1551  Dst = Buffer;
1552  }
1553 
1554  /* Prepare for the loop */
1555  Src = Original;
1556  ReturnLength = 0;
1557  while (TRUE)
1558  {
1559  /* Current delta in the loop */
1560  Length = First - Src;
1561 
1562  /* Update the return length by it */
1563  ReturnLength += Length;
1564 
1565  /* Is there a delta? If so, is there space and buffer for it? */
1566  if ((Length) && (cchBuffer > ReturnLength) && (lpszLongPath))
1567  {
1568  RtlMoveMemory(Dst, Src, Length * sizeof(WCHAR));
1569  Dst += Length;
1570  }
1571 
1572  /* "Terminate" this portion of the path's substring so we can do a find */
1573  LastChar = *Last;
1574  *Last = UNICODE_NULL;
1575  FindHandle = FindFirstFileW(Original, &FindFileData);
1576  *Last = LastChar;
1577 
1578  /* This portion wasn't found, so fail */
1579  if (FindHandle == INVALID_HANDLE_VALUE)
1580  {
1581  ReturnLength = 0;
1582  break;
1583  }
1584 
1585  /* Close the find handle */
1586  FindClose(FindHandle);
1587 
1588  /* Now check the length of the long name */
1589  Length = wcslen(FindFileData.cFileName);
1590  if (Length)
1591  {
1592  /* This is our new first marker */
1593  First = FindFileData.cFileName;
1594  }
1595  else
1596  {
1597  /* Otherwise, the name is the delta between our current markers */
1598  Length = Last - First;
1599  }
1600 
1601  /* Update the return length with the short name length, if any */
1602  ReturnLength += Length;
1603 
1604  /* Once again check for appropriate space and buffer */
1605  if ((cchBuffer > ReturnLength) && (lpszLongPath))
1606  {
1607  /* And do the copy if there is */
1608  RtlMoveMemory(Dst, First, Length * sizeof(WCHAR));
1609  Dst += Length;
1610  }
1611 
1612  /* Now update the source pointer */
1613  Src = Last;
1614  if (*Src == UNICODE_NULL) break;
1615 
1616  /* Are there more names in there? */
1617  Found = FindLFNorSFN_U(Src, &First, &Last, FALSE);
1618  if (!Found) break;
1619  }
1620 
1621  /* The loop is done, is there anything left? */
1622  if (ReturnLength)
1623  {
1624  /* Get the length of the straggling path */
1625  Length = wcslen(Src);
1626  ReturnLength += Length;
1627 
1628  /* Once again check for appropriate space and buffer */
1629  if ((cchBuffer > ReturnLength) && (lpszLongPath))
1630  {
1631  /* And do the copy if there is -- accounting for NULL here */
1632  RtlMoveMemory(Dst, Src, Length * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1633 
1634  /* What about our buffer? */
1635  if (Buffer)
1636  {
1637  /* Copy it into the caller's long path */
1638  RtlMoveMemory(lpszLongPath,
1639  Buffer,
1640  ReturnLength * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1641  }
1642  }
1643  else
1644  {
1645  /* Buffer is too small, let the caller know, making space for NULL */
1646  ReturnLength++;
1647  }
1648  }
1649 
1650  /* We're all done */
1651  goto Quickie;
1652 
1653 ErrorQuickie:
1654  /* This is the goto for memory failures */
1656 
1657 Quickie:
1658  /* General function end: free memory, restore error mode, return length */
1659  if (Original) RtlFreeHeap(RtlGetProcessHeap(), 0, Original);
1660  if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
1661  SetErrorMode(ErrorMode);
1662  return ReturnLength;
1663 }
1664 
1665 /*
1666  * @implemented
1667  */
1668 DWORD
1669 WINAPI
1671  OUT LPSTR lpszLongPath,
1672  IN DWORD cchBuffer)
1673 {
1675  PWCHAR LongPath;
1676  NTSTATUS Status;
1677  UNICODE_STRING LongPathUni, ShortPathUni;
1678  ANSI_STRING LongPathAnsi;
1679  WCHAR LongPathBuffer[MAX_PATH];
1680 
1681  LongPath = NULL;
1682  LongPathAnsi.Buffer = NULL;
1683  ShortPathUni.Buffer = NULL;
1684  Result = 0;
1685 
1686  if (!lpszShortPath)
1687  {
1689  return 0;
1690  }
1691 
1692  Status = Basep8BitStringToDynamicUnicodeString(&ShortPathUni, lpszShortPath);
1693  if (!NT_SUCCESS(Status)) goto Quickie;
1694 
1695  LongPath = LongPathBuffer;
1696 
1697  PathLength = GetLongPathNameW(ShortPathUni.Buffer, LongPathBuffer, MAX_PATH);
1698  if (PathLength >= MAX_PATH)
1699  {
1700  LongPath = RtlAllocateHeap(RtlGetProcessHeap(), 0, PathLength * sizeof(WCHAR));
1701  if (!LongPath)
1702  {
1703  PathLength = 0;
1705  }
1706  else
1707  {
1708  PathLength = GetLongPathNameW(ShortPathUni.Buffer, LongPath, PathLength);
1709  }
1710  }
1711 
1712  if (!PathLength) goto Quickie;
1713 
1714  ShortPathUni.MaximumLength = (USHORT)PathLength * sizeof(WCHAR) + sizeof(UNICODE_NULL);
1715  LongPathUni.Buffer = LongPath;
1716  LongPathUni.Length = (USHORT)PathLength * sizeof(WCHAR);
1717 
1718  Status = BasepUnicodeStringTo8BitString(&LongPathAnsi, &LongPathUni, TRUE);
1719  if (!NT_SUCCESS(Status))
1720  {
1721  BaseSetLastNTError(Status);
1722  Result = 0;
1723  }
1724 
1725  Result = LongPathAnsi.Length;
1726  if ((lpszLongPath) && (cchBuffer > LongPathAnsi.Length))
1727  {
1728  RtlMoveMemory(lpszLongPath, LongPathAnsi.Buffer, LongPathAnsi.Length);
1729  lpszLongPath[Result] = ANSI_NULL;
1730  }
1731  else
1732  {
1733  Result = LongPathAnsi.Length + sizeof(ANSI_NULL);
1734  }
1735 
1736 Quickie:
1737  if (ShortPathUni.Buffer) RtlFreeUnicodeString(&ShortPathUni);
1738  if (LongPathAnsi.Buffer) RtlFreeAnsiString(&LongPathAnsi);
1739  if ((LongPath) && (LongPath != LongPathBuffer))
1740  {
1741  RtlFreeHeap(RtlGetProcessHeap(), 0, LongPath);
1742  }
1743  return Result;
1744 }
1745 
1746 /*
1747  * @implemented
1748  */
1749 DWORD
1750 WINAPI
1752  OUT LPSTR lpszShortPath,
1753  IN DWORD cchBuffer)
1754 {
1756  PWCHAR ShortPath;
1757  NTSTATUS Status;
1758  UNICODE_STRING LongPathUni, ShortPathUni;
1759  ANSI_STRING ShortPathAnsi;
1760  WCHAR ShortPathBuffer[MAX_PATH];
1761 
1762  ShortPath = NULL;
1763  ShortPathAnsi.Buffer = NULL;
1764  LongPathUni.Buffer = NULL;
1765  Result = 0;
1766 
1767  if (!lpszLongPath)
1768  {
1770  return 0;
1771  }
1772 
1773  Status = Basep8BitStringToDynamicUnicodeString(&LongPathUni, lpszLongPath);
1774  if (!NT_SUCCESS(Status)) goto Quickie;
1775 
1776  ShortPath = ShortPathBuffer;
1777 
1778  PathLength = GetShortPathNameW(LongPathUni.Buffer, ShortPathBuffer, MAX_PATH);
1779  if (PathLength >= MAX_PATH)
1780  {
1781  ShortPath = RtlAllocateHeap(RtlGetProcessHeap(), 0, PathLength * sizeof(WCHAR));
1782  if (!ShortPath)
1783  {
1784  PathLength = 0;
1786  }
1787  else
1788  {
1789  PathLength = GetShortPathNameW(LongPathUni.Buffer, ShortPath, PathLength);
1790  }
1791  }
1792 
1793  if (!PathLength) goto Quickie;
1794 
1795  LongPathUni.MaximumLength = (USHORT)PathLength * sizeof(WCHAR) + sizeof(UNICODE_NULL);
1796  ShortPathUni.Buffer = ShortPath;
1797  ShortPathUni.Length = (USHORT)PathLength * sizeof(WCHAR);
1798 
1799  Status = BasepUnicodeStringTo8BitString(&ShortPathAnsi, &ShortPathUni, TRUE);
1800  if (!NT_SUCCESS(Status))
1801  {
1802  BaseSetLastNTError(Status);
1803  Result = 0;
1804  }
1805 
1806  Result = ShortPathAnsi.Length;
1807  if ((lpszShortPath) && (cchBuffer > ShortPathAnsi.Length))
1808  {
1809  RtlMoveMemory(lpszShortPath, ShortPathAnsi.Buffer, ShortPathAnsi.Length);
1810  lpszShortPath[Result] = ANSI_NULL;
1811  }
1812  else
1813  {
1814  Result = ShortPathAnsi.Length + sizeof(ANSI_NULL);
1815  }
1816 
1817 Quickie:
1818  if (LongPathUni.Buffer) RtlFreeUnicodeString(&LongPathUni);
1819  if (ShortPathAnsi.Buffer) RtlFreeAnsiString(&ShortPathAnsi);
1820  if ((ShortPath) && (ShortPath != ShortPathBuffer))
1821  {
1822  RtlFreeHeap(RtlGetProcessHeap(), 0, ShortPath);
1823  }
1824  return Result;
1825 }
1826 
1827 /*
1828  * @implemented
1829  */
1830 DWORD
1831 WINAPI
1833  OUT LPWSTR lpszShortPath,
1834  IN DWORD cchBuffer)
1835 {
1836  PWCHAR Path, Original, First, Last, Buffer, Src, Dst;
1837  ULONG Length;
1838  WCHAR LastChar;
1839  HANDLE FindHandle;
1841  ULONG ErrorMode;
1842  BOOLEAN Found = FALSE;
1843  WIN32_FIND_DATAW FindFileData;
1844 
1845  /* Initialize so Quickie knows there's nothing to do */
1846  Buffer = Original = NULL;
1847  ReturnLength = 0;
1848 
1849  /* First check if the input path was obviously NULL */
1850  if (!lpszLongPath)
1851  {
1852  /* Fail the request */
1854  return 0;
1855  }
1856 
1857  /* We will be touching removed, removable drives -- don't warn the user */
1859 
1860  /* Do a simple check to see if the path exists */
1861  if (GetFileAttributesW(lpszLongPath) == INVALID_FILE_ATTRIBUTES)
1862  {
1863  /* Windows checks for an application compatibility flag to allow this */
1864  if (!(NtCurrentPeb()) || !(NtCurrentPeb()->AppCompatFlags.LowPart & GetShortPathNameNT4))
1865  {
1866  /* It doesn't, so fail */
1867  ReturnLength = 0;
1868  goto Quickie;
1869  }
1870  }
1871 
1872  /* Now get a pointer to the actual path, skipping indicators */
1873  Path = SkipPathTypeIndicator_U((LPWSTR)lpszLongPath);
1874 
1875  /* Is there any path or filename in there? */
1876  if (!(Path) ||
1877  (*Path == UNICODE_NULL) ||
1878  !(FindLFNorSFN_U(Path, &First, &Last, TRUE)))
1879  {
1880  /* There isn't, so the long path is simply the short path */
1881  ReturnLength = wcslen(lpszLongPath);
1882 
1883  /* Is there space for it? */
1884  if ((cchBuffer > ReturnLength) && (lpszShortPath))
1885  {
1886  /* Make sure the pointers aren't already the same */
1887  if (lpszLongPath != lpszShortPath)
1888  {
1889  /* They're not -- copy the short path into the long path */
1890  RtlMoveMemory(lpszShortPath,
1891  lpszLongPath,
1892  ReturnLength * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1893  }
1894  }
1895  else
1896  {
1897  /* Otherwise, let caller know we need a bigger buffer, include NULL */
1898  ReturnLength++;
1899  }
1900  goto Quickie;
1901  }
1902 
1903  /* We are still in the game -- compute the current size */
1904  Length = wcslen(lpszLongPath) + sizeof(ANSI_NULL);
1905  Original = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR));
1906  if (!Original) goto ErrorQuickie;
1907 
1908  /* Make a copy of it */
1909  wcsncpy(Original, lpszLongPath, Length);
1910 
1911  /* Compute the new first and last markers */
1912  First = &Original[First - lpszLongPath];
1913  Last = &Original[Last - lpszLongPath];
1914 
1915  /* Set the current destination pointer for a copy */
1916  Dst = lpszShortPath;
1917 
1918  /*
1919  * Windows allows the paths to overlap -- we have to be careful with this and
1920  * see if it's same to do so, and if not, allocate our own internal buffer
1921  * that we'll return at the end.
1922  *
1923  * This is also why we use RtlMoveMemory everywhere. Don't use RtlCopyMemory!
1924  */
1925  if ((cchBuffer) && (lpszShortPath) &&
1926  (((lpszShortPath >= lpszLongPath) && (lpszShortPath < &lpszLongPath[Length])) ||
1927  ((lpszShortPath < lpszLongPath) && (&lpszShortPath[cchBuffer] >= lpszLongPath))))
1928  {
1929  Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, cchBuffer * sizeof(WCHAR));
1930  if (!Buffer) goto ErrorQuickie;
1931 
1932  /* New destination */
1933  Dst = Buffer;
1934  }
1935 
1936  /* Prepare for the loop */
1937  Src = Original;
1938  ReturnLength = 0;
1939  while (TRUE)
1940  {
1941  /* Current delta in the loop */
1942  Length = First - Src;
1943 
1944  /* Update the return length by it */
1945  ReturnLength += Length;
1946 
1947  /* Is there a delta? If so, is there space and buffer for it? */
1948  if ((Length) && (cchBuffer > ReturnLength) && (lpszShortPath))
1949  {
1950  RtlMoveMemory(Dst, Src, Length * sizeof(WCHAR));
1951  Dst += Length;
1952  }
1953 
1954  /* "Terminate" this portion of the path's substring so we can do a find */
1955  LastChar = *Last;
1956  *Last = UNICODE_NULL;
1957  FindHandle = FindFirstFileW(Original, &FindFileData);
1958  *Last = LastChar;
1959 
1960  /* This portion wasn't found, so fail */
1961  if (FindHandle == INVALID_HANDLE_VALUE)
1962  {
1963  ReturnLength = 0;
1964  break;
1965  }
1966 
1967  /* Close the find handle */
1968  FindClose(FindHandle);
1969 
1970  /* Now check the length of the short name */
1971  Length = wcslen(FindFileData.cAlternateFileName);
1972  if (Length)
1973  {
1974  /* This is our new first marker */
1975  First = FindFileData.cAlternateFileName;
1976  }
1977  else
1978  {
1979  /* Otherwise, the name is the delta between our current markers */
1980  Length = Last - First;
1981  }
1982 
1983  /* Update the return length with the short name length, if any */
1984  ReturnLength += Length;
1985 
1986  /* Once again check for appropriate space and buffer */
1987  if ((cchBuffer > ReturnLength) && (lpszShortPath))
1988  {
1989  /* And do the copy if there is */
1990  RtlMoveMemory(Dst, First, Length * sizeof(WCHAR));
1991  Dst += Length;
1992  }
1993 
1994  /* Now update the source pointer */
1995  Src = Last;
1996  if (*Src == UNICODE_NULL) break;
1997 
1998  /* Are there more names in there? */
1999  Found = FindLFNorSFN_U(Src, &First, &Last, TRUE);
2000  if (!Found) break;
2001  }
2002 
2003  /* The loop is done, is there anything left? */
2004  if (ReturnLength)
2005  {
2006  /* Get the length of the straggling path */
2007  Length = wcslen(Src);
2008  ReturnLength += Length;
2009 
2010  /* Once again check for appropriate space and buffer */
2011  if ((cchBuffer > ReturnLength) && (lpszShortPath))
2012  {
2013  /* And do the copy if there is -- accounting for NULL here */
2014  RtlMoveMemory(Dst, Src, Length * sizeof(WCHAR) + sizeof(UNICODE_NULL));
2015 
2016  /* What about our buffer? */
2017  if (Buffer)
2018  {
2019  /* Copy it into the caller's long path */
2020  RtlMoveMemory(lpszShortPath,
2021  Buffer,
2022  ReturnLength * sizeof(WCHAR) + sizeof(UNICODE_NULL));
2023  }
2024  }
2025  else
2026  {
2027  /* Buffer is too small, let the caller know, making space for NULL */
2028  ReturnLength++;
2029  }
2030  }
2031 
2032  /* We're all done */
2033  goto Quickie;
2034 
2035 ErrorQuickie:
2036  /* This is the goto for memory failures */
2038 
2039 Quickie:
2040  /* General function end: free memory, restore error mode, return length */
2041  if (Original) RtlFreeHeap(RtlGetProcessHeap(), 0, Original);
2042  if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
2043  SetErrorMode(ErrorMode);
2044  return ReturnLength;
2045 }
2046 
2047 /*
2048  * @implemented
2049  *
2050  * NOTE: Windows returns a dos/short (8.3) path
2051  */
2052 DWORD
2053 WINAPI
2055  OUT LPSTR lpBuffer)
2056 {
2057  WCHAR BufferW[MAX_PATH];
2058  DWORD ret;
2059 
2060  ret = GetTempPathW(MAX_PATH, BufferW);
2061 
2062  if (!ret) return 0;
2063 
2064  if (ret > MAX_PATH)
2065  {
2067  return 0;
2068  }
2069 
2070  return FilenameW2A_FitOrFail(lpBuffer, nBufferLength, BufferW, ret+1);
2071 }
2072 
2073 /*
2074  * @implemented
2075  *
2076  * ripped from wine
2077  */
2078 DWORD
2079 WINAPI
2081  OUT LPWSTR path)
2082 {
2083  static const WCHAR tmp[] = { 'T', 'M', 'P', 0 };
2084  static const WCHAR temp[] = { 'T', 'E', 'M', 'P', 0 };
2085  static const WCHAR userprofile[] = { 'U','S','E','R','P','R','O','F','I','L','E',0 };
2086  WCHAR tmp_path[MAX_PATH];
2087  WCHAR full_tmp_path[MAX_PATH];
2088  UINT ret;
2089 
2090  DPRINT("%u,%p\n", count, path);
2091 
2092  if (!(ret = GetEnvironmentVariableW( tmp, tmp_path, MAX_PATH )) &&
2093  !(ret = GetEnvironmentVariableW( temp, tmp_path, MAX_PATH )) &&
2094  !(ret = GetEnvironmentVariableW( userprofile, tmp_path, MAX_PATH )) &&
2095  !(ret = GetWindowsDirectoryW( tmp_path, MAX_PATH )))
2096  {
2097  return 0;
2098  }
2099 
2100  if (ret > MAX_PATH)
2101  {
2103  return 0;
2104  }
2105 
2106  ret = GetFullPathNameW(tmp_path, MAX_PATH, full_tmp_path, NULL);
2107  if (!ret) return 0;
2108 
2109  if (ret > MAX_PATH - 2)
2110  {
2112  return 0;
2113  }
2114 
2115  if (full_tmp_path[ret-1] != '\\')
2116  {
2117  full_tmp_path[ret++] = '\\';
2118  full_tmp_path[ret] = '\0';
2119  }
2120 
2121  ret++; /* add space for terminating 0 */
2122 
2123  if (count >= ret)
2124  {
2125  lstrcpynW(path, full_tmp_path, count);
2126  /* the remaining buffer must be zeroed up to 32766 bytes in XP or 32767
2127  * bytes after it, we will assume the > XP behavior for now */
2128  memset(path + ret, 0, (min(count, 32767) - ret) * sizeof(WCHAR));
2129  ret--; /* return length without 0 */
2130  }
2131  else if (count)
2132  {
2133  /* the buffer must be cleared if contents will not fit */
2134  memset(path, 0, count * sizeof(WCHAR));
2135  }
2136 
2137  DPRINT("GetTempPathW returning %u, %S\n", ret, path);
2138  return ret;
2139 }
2140 
2141 /*
2142  * @implemented
2143  */
2144 DWORD
2145 WINAPI
2147  OUT LPSTR lpBuffer)
2148 {
2150  NTSTATUS Status;
2152  ULONG MaxLength;
2153 
2154  StaticString = &NtCurrentTeb()->StaticUnicodeString;
2155 
2156  MaxLength = nBufferLength;
2157  if (nBufferLength >= UNICODE_STRING_MAX_BYTES)
2158  {
2159  MaxLength = UNICODE_STRING_MAX_BYTES - 1;
2160  }
2161 
2162  StaticString->Length = (USHORT)RtlGetCurrentDirectory_U(StaticString->MaximumLength,
2163  StaticString->Buffer);
2164  Status = RtlUnicodeToMultiByteSize(&nBufferLength,
2165  StaticString->Buffer,
2166  StaticString->Length);
2167  if (!NT_SUCCESS(Status))
2168  {
2169  BaseSetLastNTError(Status);
2170  return 0;
2171  }
2172 
2173  if (MaxLength <= nBufferLength)
2174  {
2175  return nBufferLength + 1;
2176  }
2177 
2178  AnsiString.Buffer = lpBuffer;
2179  AnsiString.MaximumLength = (USHORT)MaxLength;
2180  Status = BasepUnicodeStringTo8BitString(&AnsiString, StaticString, FALSE);
2181  if (!NT_SUCCESS(Status))
2182  {
2183  BaseSetLastNTError(Status);
2184  return 0;
2185  }
2186 
2187  return AnsiString.Length;
2188 }
2189 
2190 /*
2191  * @implemented
2192  */
2193 DWORD
2194 WINAPI
2197 {
2198  return RtlGetCurrentDirectory_U(nBufferLength * sizeof(WCHAR), lpBuffer) / sizeof(WCHAR);
2199 }
2200 
2201 /*
2202  * @implemented
2203  */
2204 BOOL
2205 WINAPI
2207 {
2208  PUNICODE_STRING DirName;
2209  NTSTATUS Status;
2210 
2211  if (!lpPathName)
2212  {
2214  return FALSE;
2215  }
2216 
2217  DirName = Basep8BitStringToStaticUnicodeString(lpPathName);
2218  if (!DirName) return FALSE;
2219 
2220  if (CheckForSameCurdir(DirName)) return TRUE;
2221 
2222  Status = RtlSetCurrentDirectory_U(DirName);
2223  if (NT_SUCCESS(Status)) return TRUE;
2224 
2225  if ((*DirName->Buffer != L'"') || (DirName->Length <= 2))
2226  {
2227  BaseSetLastNTError(Status);
2228  return 0;
2229  }
2230 
2231  DirName = Basep8BitStringToStaticUnicodeString(lpPathName + 1);
2232  if (!DirName) return FALSE;
2233 
2234  Status = RtlSetCurrentDirectory_U(DirName);
2235  if (!NT_SUCCESS(Status))
2236  {
2237  BaseSetLastNTError(Status);
2238  return FALSE;
2239  }
2240 
2241  return TRUE;
2242 }
2243 
2244 /*
2245  * @implemented
2246  */
2247 BOOL
2248 WINAPI
2250 {
2251  NTSTATUS Status;
2253 
2254  if (!lpPathName)
2255  {
2257  return FALSE;
2258  }
2259 
2260  Status = RtlInitUnicodeStringEx(&UnicodeString, lpPathName);
2261  if (NT_SUCCESS(Status))
2262  {
2263  if (!CheckForSameCurdir(&UnicodeString))
2264  {
2265  Status = RtlSetCurrentDirectory_U(&UnicodeString);
2266  }
2267  }
2268 
2269  if (!NT_SUCCESS(Status))
2270  {
2271  BaseSetLastNTError(Status);
2272  return FALSE;
2273  }
2274 
2275  return TRUE;
2276 }
2277 
2278 /*
2279  * @implemented
2280  */
2281 UINT
2282 WINAPI
2284  IN UINT uSize)
2285 {
2287  NTSTATUS Status;
2288  ULONG AnsiLength;
2289 
2290  /* Get the correct size of the Unicode Base directory */
2291  Status = RtlUnicodeToMultiByteSize(&AnsiLength,
2292  BaseWindowsSystemDirectory.Buffer,
2293  BaseWindowsSystemDirectory.MaximumLength);
2294  if (!NT_SUCCESS(Status)) return 0;
2295 
2296  if (uSize < AnsiLength) return AnsiLength;
2297 
2298  RtlInitEmptyAnsiString(&AnsiString, lpBuffer, uSize);
2299 
2300  Status = BasepUnicodeStringTo8BitString(&AnsiString,
2301  &BaseWindowsSystemDirectory,
2302  FALSE);
2303  if (!NT_SUCCESS(Status)) return 0;
2304 
2305  return AnsiString.Length;
2306 }
2307 
2308 /*
2309  * @implemented
2310  */
2311 UINT
2312 WINAPI
2314  IN UINT uSize)
2315 {
2317 
2318  ReturnLength = BaseWindowsSystemDirectory.MaximumLength;
2319  if ((uSize * sizeof(WCHAR)) >= ReturnLength)
2320  {
2321  RtlCopyMemory(lpBuffer,
2322  BaseWindowsSystemDirectory.Buffer,
2323  BaseWindowsSystemDirectory.Length);
2324  lpBuffer[BaseWindowsSystemDirectory.Length / sizeof(WCHAR)] = ANSI_NULL;
2325 
2326  ReturnLength = BaseWindowsSystemDirectory.Length;
2327  }
2328 
2329  return ReturnLength / sizeof(WCHAR);
2330 }
2331 
2332 /*
2333  * @implemented
2334  */
2335 UINT
2336 WINAPI
2338  IN UINT uSize)
2339 {
2340  /* Is this a TS installation? */
2342 
2343  /* Otherwise, call the System API */
2344  return GetSystemWindowsDirectoryA(lpBuffer, uSize);
2345 }
2346 
2347 /*
2348  * @implemented
2349  */
2350 UINT
2351 WINAPI
2353  IN UINT uSize)
2354 {
2355  /* Is this a TS installation? */
2357 
2358  /* Otherwise, call the System API */
2359  return GetSystemWindowsDirectoryW(lpBuffer, uSize);
2360 }
2361 
2362 /*
2363  * @implemented
2364  */
2365 UINT
2366 WINAPI
2368  IN UINT uSize)
2369 {
2371  NTSTATUS Status;
2372  ULONG AnsiLength;
2373 
2374  /* Get the correct size of the Unicode Base directory */
2375  Status = RtlUnicodeToMultiByteSize(&AnsiLength,
2376  BaseWindowsDirectory.Buffer,
2377  BaseWindowsDirectory.MaximumLength);
2378  if (!NT_SUCCESS(Status)) return 0;
2379 
2380  if (uSize < AnsiLength) return AnsiLength;
2381 
2382  RtlInitEmptyAnsiString(&AnsiString, lpBuffer, uSize);
2383 
2384  Status = BasepUnicodeStringTo8BitString(&AnsiString,
2385  &BaseWindowsDirectory,
2386  FALSE);
2387  if (!NT_SUCCESS(Status)) return 0;
2388 
2389  return AnsiString.Length;
2390 }
2391 
2392 /*
2393  * @implemented
2394  */
2395 UINT
2396 WINAPI
2398  IN UINT uSize)
2399 {
2401 
2402  ReturnLength = BaseWindowsDirectory.MaximumLength;
2403  if ((uSize * sizeof(WCHAR)) >= ReturnLength)
2404  {
2405  RtlCopyMemory(lpBuffer,
2406  BaseWindowsDirectory.Buffer,
2407  BaseWindowsDirectory.Length);
2408  lpBuffer[BaseWindowsDirectory.Length / sizeof(WCHAR)] = ANSI_NULL;
2409 
2410  ReturnLength = BaseWindowsDirectory.Length;
2411  }
2412 
2413  return ReturnLength / sizeof(WCHAR);
2414 }
2415 
2416 /*
2417  * @unimplemented
2418  */
2419 UINT
2420 WINAPI
2422  IN UINT uSize)
2423 {
2424 #ifdef _WIN64
2425  UNIMPLEMENTED;
2426  return 0;
2427 #else
2429  return 0;
2430 #endif
2431 }
2432 
2433 /*
2434  * @unimplemented
2435  */
2436 UINT
2437 WINAPI
2439  IN UINT uSize)
2440 {
2441 #ifdef _WIN64
2442  UNIMPLEMENTED;
2443  return 0;
2444 #else
2446  return 0;
2447 #endif
2448 }
2449 
2450 /* EOF */
DWORD *typedef PVOID
Definition: winlogon.h:52
IN CINT OUT PVOID IN ULONG OUT PULONG ResultLength
Definition: conport.c:47
#define ERROR_INVALID_PARAMETER
Definition: compat.h:91
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:35
UINT WINAPI SetErrorMode(IN UINT uMode)
Definition: except.c:750
_Must_inspect_result_ _Out_ PNDIS_STATUS _In_ NDIS_HANDLE _In_ ULONG _Out_ PNDIS_STRING KeyName
Definition: ndis.h:4692
IN CINT OUT PVOID IN ULONG OUT PULONG ReturnLength
Definition: dumpinfo.c:39
UNICODE_STRING BaseDefaultPath
Definition: path.c:21
PVOID PVOID PWCHAR PVOID Environment
Definition: env.c:45
#define IN
Definition: typedefs.h:38
BOOL WINAPI BasepIsCurDirAllowedForPlainExeNames(VOID)
Definition: path.c:780
PUNICODE_STRING WINAPI Basep8BitStringToStaticUnicodeString(IN LPCSTR String)
Definition: utils.c:188
UINT WINAPI GetSystemWindowsDirectoryW(OUT LPWSTR lpBuffer, IN UINT uSize)
Definition: path.c:2397
_In_ LPCSTR _In_opt_ LPCSTR _In_ DWORD _Out_opt_ LPSTR * lpFilePart
Definition: winbase.h:2963
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
UINT WINAPI GetSystemWindowsDirectoryA(OUT LPSTR lpBuffer, IN UINT uSize)
Definition: path.c:2367
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
*BytesInUnicodeString PWCH UnicodeString
Definition: rtlfuncs.h:1980
BOOL WINAPI IsShortName_U(IN PWCHAR Name, IN ULONG Length)
Definition: path.c:560
#define SEM_FAILCRITICALERRORS
Definition: rtltypes.h:69
_Must_inspect_result_ _Out_ PNDIS_STATUS _In_ NDIS_HANDLE _In_ ULONG _Out_ PNDIS_STRING _Out_ PNDIS_HANDLE KeyHandle
Definition: ndis.h:4692
#define DbgPrint
Definition: loader.c:26
USHORT MaximumLength
Definition: env_spec_w32.h:370
Definition: bidi.c:75
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel)?(CompletionRoutine!=NULL):TRUE)
PRTL_CONVERT_STRINGA BasepUnicodeStringTo8BitString
Definition: utils.c:27
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
__wchar_t WCHAR
Definition: xmlstorage.h:180
NTSYSAPI NTSTATUS WINAPI RtlInitAnsiStringEx(PANSI_STRING, PCSZ)
return STATUS_SUCCESS
Definition: btrfs.c:2664
#define INVALID_FILE_ATTRIBUTES
Definition: test.h:47
char CHAR
Definition: xmlstorage.h:175
NTSYSAPI NTSTATUS NTAPI RtlUnicodeToMultiByteSize(PULONG MbSize, PCWCH UnicodeString, ULONG UnicodeSize)
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:603
static CHAR AppName[MAX_PATH]
Definition: dem.c:252
UINT WINAPI GetSystemDirectoryA(OUT LPSTR lpBuffer, IN UINT uSize)
Definition: path.c:2283
PVOID gpTermsrvGetWindowsDirectoryA
Definition: path.c:23
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
NTSYSAPI NTSTATUS NTAPI RtlEnterCriticalSection(_In_ PRTL_CRITICAL_SECTION CriticalSection)
#define InterlockedCompareExchange
Definition: interlocked.h:104
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define INVALID_HANDLE_VALUE
Definition: compat.h:391
DWORD WINAPI GetFullPathNameW(IN LPCWSTR lpFileName, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart)
Definition: path.c:1105
VOID NTAPI RtlReleasePebLock(VOID)
Definition: libsupp.c:82
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:426
uint16_t * PWCHAR
Definition: typedefs.h:54
*nSize LPSTR lpBuffer
Definition: winbase.h:1973
char * LPSTR
Definition: xmlstorage.h:182
#define WCHAR
Definition: msvc.h:43
static USHORT PathLength
#define UNICODE_STRING_MAX_BYTES
#define lstrlenW
Definition: compat.h:407
BOOL WINAPI NeedCurrentDirectoryForExePathA(IN LPCSTR ExeName)
Definition: path.c:968
UNICODE_STRING BaseDllDirectory
Definition: path.c:21
DWORD DWORD
Definition: winlogon.h:75
DWORD ret
Definition: path.c:52
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define lstrcpynW
Definition: compat.h:397
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:50
UINT WINAPI GetWindowsDirectoryW(OUT LPWSTR lpBuffer, IN UINT uSize)
Definition: path.c:2352
LPWSTR WINAPI BaseComputeProcessSearchPath(VOID)
Definition: path.c:395
DWORD WINAPI GetLongPathNameA(IN LPCSTR lpszShortPath, OUT LPSTR lpszLongPath, IN DWORD cchBuffer)
Definition: path.c:1670
#define OBJ_NAME_PATH_SEPARATOR
Definition: nt_native.h:1240
DWORD WINAPI GetFullPathNameA(IN LPCSTR lpFileName, IN DWORD nBufferLength, OUT LPSTR lpBuffer, OUT LPSTR *lpFilePart)
Definition: path.c:992
ULONG NTAPI RtlGetFullPathName_U(_In_ PCWSTR FileName, _In_ ULONG Size, _Out_z_bytecap_(Size) PWSTR Buffer, _Out_opt_ PWSTR *ShortName)
Definition: path.c:1694
DWORD WINAPI GetDllDirectoryA(IN DWORD nBufferLength, OUT LPSTR lpBuffer)
Definition: path.c:914
_In_ PUNICODE_STRING ValueName
Definition: cmfuncs.h:264
BOOL WINAPI IsLongName_U(IN PWCHAR FileName, IN ULONG Length)
Definition: path.c:647
BOOL WINAPI FindLFNorSFN_U(IN PWCHAR Path, OUT PWCHAR *First, OUT PWCHAR *Last, IN BOOL UseShort)
Definition: path.c:681
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
GLenum GLclampf GLint i
Definition: glfuncs.h:14
BOOLEAN WINAPI Basep8BitStringToDynamicUnicodeString(OUT PUNICODE_STRING UnicodeString, IN LPCSTR String)
Definition: utils.c:225
BASE_SEARCH_PATH_TYPE BaseProcessOrderNoCurrent[BaseSearchPathMax]
Definition: path.c:54
DWORD WINAPI GetTempPathW(IN DWORD count, OUT LPWSTR path)
Definition: path.c:2080
#define FALSE
Definition: types.h:117
#define UNICODE_NULL
#define ANSI_NULL
DWORD WINAPI SearchPathA(IN LPCSTR lpPath OPTIONAL, IN LPCSTR lpFileName, IN LPCSTR lpExtension OPTIONAL, IN DWORD nBufferLength, OUT LPSTR lpBuffer, OUT LPSTR *lpFilePart OPTIONAL)
Definition: path.c:1122
NTSYSAPI NTSTATUS NTAPI RtlLeaveCriticalSection(_In_ PRTL_CRITICAL_SECTION CriticalSection)
PWCHAR WINAPI BasepEndOfDirName(IN PWCHAR FileName)
Definition: path.c:89
DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName)
Definition: fileinfo.c:782
PWCHAR WINAPI SkipPathTypeIndicator_U(IN LPWSTR Path)
Definition: path.c:739
static DWORD cchBuffer
Definition: fusion.c:70
NTSYSAPI NTSTATUS NTAPI RtlQueryEnvironmentVariable_U(_In_opt_ PWSTR Environment, _In_ PCUNICODE_STRING Name, _Out_ PUNICODE_STRING Value)
smooth NULL
Definition: ftsmooth.c:557
BOOL WINAPI IsDBCSLeadByte(BYTE TestByte)
Definition: nls.c:2130
void DPRINT(...)
Definition: polytest.cpp:61
_Check_return_ _CRTIMP _CONST_RETURN wchar_t *__cdecl wcsrchr(_In_z_ const wchar_t *_Str, _In_ wchar_t _Ch)
Definition: bufpool.h:45
UINT WINAPI GetSystemWow64DirectoryA(OUT LPSTR lpBuffer, IN UINT uSize)
Definition: path.c:2438
DWORD BaseSetLastNTError(IN NTSTATUS Status)
Definition: reactos.cpp:166
BOOL WINAPI NeedCurrentDirectoryForExePathW(IN LPCWSTR ExeName)
Definition: path.c:956
BOOL WINAPI SetDllDirectoryA(IN LPCSTR lpPathName)
Definition: path.c:837
const char * LPCSTR
Definition: xmlstorage.h:183
BOOLEAN WINAPI CheckForSameCurdir(IN PUNICODE_STRING DirName)
Definition: path.c:518
PLDR_DATA_TABLE_ENTRY BasepExeLdrEntry
Definition: proc.c:25
_In_ LPCSTR _In_opt_ LPCSTR _In_ DWORD nBufferLength
Definition: winbase.h:2959
#define STATUS_NAME_TOO_LONG
Definition: ntstatus.h:484
PVOID gpTermsrvGetWindowsDirectoryW
Definition: path.c:24
PVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size)
Definition: heap.c:585
#define UNIMPLEMENTED_DBGBREAK(...)
Definition: debug.h:226
USHORT MaximumLength
Definition: env_spec_w32.h:377
unsigned char BOOLEAN
NTSYSAPI NTSTATUS NTAPI NtQueryValueKey(IN HANDLE KeyHandle, IN PUNICODE_STRING ValueName, IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, IN PVOID KeyValueInformation, IN ULONG Length, IN PULONG ResultLength)
DWORD WINAPI GetLongPathNameW(IN LPCWSTR lpszShortPath, OUT LPWSTR lpszLongPath, IN DWORD cchBuffer)
Definition: path.c:1454
unsigned int BOOL
Definition: ntddk_ex.h:94
#define UNICODE_STRING_MAX_CHARS
UNICODE_STRING BaseWindowsDirectory
Definition: path.c:20
_CONST_RETURN wchar_t *__cdecl wcschr(_In_z_ const wchar_t *_Str, wchar_t _Ch)
NTSTATUS NTAPI RtlSetCurrentDirectory_U(IN PUNICODE_STRING Path)
Definition: path.c:1477
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:24
DWORD WINAPI GetShortPathNameW(IN LPCWSTR lpszLongPath, OUT LPWSTR lpszShortPath, IN DWORD cchBuffer)
Definition: path.c:1832
DWORD WINAPI GetShortPathNameA(IN LPCSTR lpszLongPath, OUT LPSTR lpszShortPath, IN DWORD cchBuffer)
Definition: path.c:1751
#define MAX_PATH
Definition: compat.h:26
DWORD IllegalMask[4]
Definition: path.c:28
NTSYSAPI VOID NTAPI RtlFreeAnsiString(PANSI_STRING AnsiString)
CHAR AnsiBuffer[1024]
Definition: debug.c:15
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)
GLuint GLuint GLsizei count
Definition: gl.h:1545
#define SetLastError(x)
Definition: compat.h:409
#define NT_ERROR(Status)
Definition: umtypes.h:94
UINTN VOID * Buffer
Definition: acefiex.h:370
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3392
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
BASE_CURRENT_DIR_PLACEMENT BasepDllCurrentDirPlacement
Definition: path.c:81
ULONG NTAPI RtlGetCurrentDirectory_U(_In_ ULONG MaximumLength, _Out_bytecap_(MaximumLength) PWSTR Buffer)
Definition: path.c:1399
_In_ PUNICODE_STRING Name
Definition: mrx.h:218
unsigned char UCHAR
Definition: xmlstorage.h:181
NTSYSAPI NTSTATUS NTAPI RtlUnicodeToMultiByteN(PCHAR MbString, ULONG MbSize, PULONG ResultSize, PCWCH UnicodeString, ULONG UnicodeSize)
NTSYSAPI BOOLEAN NTAPI RtlCreateUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
DWORD FilenameW2A_FitOrFail(LPSTR DestA, INT destLen, LPCWSTR SourceW, INT sourceLen)
Definition: fileinfo.c:102
#define STATUS_VARIABLE_NOT_FOUND
Definition: ntstatus.h:478
UINT WINAPI GetSystemWow64DirectoryW(OUT LPWSTR lpBuffer, IN UINT uSize)
Definition: path.c:2421
VOID UINTN Length
Definition: acefiex.h:744
BOOL WINAPI SetCurrentDirectoryA(IN LPCSTR lpPathName)
Definition: path.c:2206
RTL_PATH_TYPE NTAPI RtlDetermineDosPathNameType_U(IN PCWSTR Path)
Definition: path.c:1351
NTSTATUS NTAPI LdrEnumerateLoadedModules(IN BOOLEAN ReservedFlag, IN PLDR_ENUM_CALLBACK EnumProc, IN PVOID Context)
Definition: ldrapi.c:1113
static stack_node_t temp
Definition: rpn.c:18
VOID NTAPI BasepLocateExeLdrEntry(IN PLDR_DATA_TABLE_ENTRY Entry, IN PVOID Context, OUT BOOLEAN *StopEnumeration)
Definition: utils.c:156
#define WINAPI
Definition: msvc.h:20
_In_ LPCSTR _In_opt_ LPCSTR lpExtension
Definition: winbase.h:2959
DWORD WINAPI SearchPathW(IN LPCWSTR lpPath OPTIONAL, IN LPCWSTR lpFileName, IN LPCWSTR lpExtension OPTIONAL, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart OPTIONAL)
Definition: path.c:1297
Status
Definition: gdiplustypes.h:24
#define Dst
Definition: mesh.h:153
RTL_CRITICAL_SECTION BaseDllDirectoryLock
Definition: dllmain.c:32
LPWSTR WINAPI BaseComputeProcessDllPath(IN LPWSTR FullPath, IN PVOID Environment)
Definition: path.c:420
enum _BASE_SEARCH_PATH_TYPE * PBASE_SEARCH_PATH_TYPE
#define RTL_CONSTANT_OBJECT_ATTRIBUTES(n, a)
DWORD *typedef HANDLE
Definition: winlogon.h:52
PRTL_UNICODE_STRING_BUFFER Path
LONG NTSTATUS
Definition: DriverTester.h:11
FORCEINLINE struct _TEB * NtCurrentTeb(VOID)
Definition: psfuncs.h:420
_CRTIMP wchar_t *__cdecl wcsncpy(wchar_t *_Dest, const wchar_t *_Source, size_t _Count)
PRTL_COUNT_STRING BasepUnicodeStringTo8BitSize
Definition: utils.c:28
DWORD WINAPI GetTempPathA(IN DWORD nBufferLength, OUT LPSTR lpBuffer)
Definition: path.c:2054
unsigned short USHORT
Definition: pedump.c:61
BASE_SEARCH_PATH_TYPE BaseProcessOrder[BaseSearchPathMax]
Definition: path.c:72
BOOL WINAPI SetDllDirectoryW(IN LPCWSTR lpPathName)
Definition: path.c:799
static BOOLEAN First
Definition: dem.c:250
#define KEY_QUERY_VALUE
Definition: nt_native.h:1016
UNICODE_STRING BaseDefaultPathAppend
Definition: path.c:21
static const char const char * DllPath
Definition: image.c:34
UNICODE_STRING BasePathVariableName
Definition: proc.c:23
BOOL WINAPI SetCurrentDirectoryW(IN LPCWSTR lpPathName)
Definition: path.c:2249
DWORD WINAPI GetCurrentDirectoryA(IN DWORD nBufferLength, OUT LPSTR lpBuffer)
Definition: path.c:2146
#define STATUS_NO_MEMORY
Definition: ntstatus.h:246
#define STATUS_NO_SUCH_FILE
Definition: udferr_usr.h:137
DWORD WINAPI GetDllDirectoryW(IN DWORD nBufferLength, OUT LPWSTR lpBuffer)
Definition: path.c:886
Definition: services.c:311
UINT WINAPI GetWindowsDirectoryA(OUT LPSTR lpBuffer, IN UINT uSize)
Definition: path.c:2337
UNICODE_STRING FullDllName
Definition: btrfs_drv.h:1716
UINT WINAPI GetSystemDirectoryW(OUT LPWSTR lpBuffer, IN UINT uSize)
Definition: path.c:2313
unsigned int * PULONG
Definition: retypes.h:1
#define min(a, b)
Definition: monoChain.cc:55
NTSYSAPI NTSTATUS WINAPI RtlInitUnicodeStringEx(PUNICODE_STRING, PCWSTR)
unsigned int UINT
Definition: ndis.h:50
#define SEM_NOOPENFILEERRORBOX
Definition: rtltypes.h:72
PRTL_CONVERT_STRING Basep8BitStringToUnicodeString
Definition: utils.c:26
VOID NTAPI RtlAcquirePebLock(VOID)
Definition: libsupp.c:72
LPWSTR WINAPI BaseComputeProcessExePath(IN LPWSTR FullPath)
Definition: path.c:405
char * strchr(const char *String, int ch)
Definition: utclib.c:501
DWORD WINAPI GetCurrentDirectoryW(IN DWORD nBufferLength, OUT LPWSTR lpBuffer)
Definition: path.c:2195
NTSYSAPI NTSTATUS NTAPI NtOpenKey(OUT PHANDLE KeyHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes)
Definition: ntapi.c:120
#define OUT
Definition: typedefs.h:39
#define c
Definition: ke_i.h:80
unsigned int ULONG
Definition: retypes.h:1
#define ERROR_CALL_NOT_IMPLEMENTED
Definition: compat.h:92
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define UNIMPLEMENTED
Definition: debug.h:114
enum _BASE_CURRENT_DIR_PLACEMENT BASE_CURRENT_DIR_PLACEMENT
_Must_inspect_result_ _In_ PFILE_OBJECT _In_ SECURITY_INFORMATION _In_ ULONG _Out_opt_ PULONG LengthNeeded
Definition: fltkernel.h:1342
#define __FUNCTION__
Definition: compiler.h:205
UNICODE_STRING NoDefaultCurrentDirectoryInExePath
Definition: path.c:18
GLfloat GLfloat p
Definition: glext.h:8902
#define GetEnvironmentVariableW(x, y, z)
Definition: compat.h:412
#define memset(x, y, z)
Definition: compat.h:39
signed int * PLONG
Definition: retypes.h:5
WCHAR * LPWSTR
Definition: xmlstorage.h:184
BASE_SEARCH_PATH_TYPE BaseDllOrderCurrent[BaseCurrentDirPlacementMax][BaseSearchPathMax]
Definition: path.c:36
NTSYSAPI BOOLEAN NTAPI RtlEqualUnicodeString(PUNICODE_STRING String1, PUNICODE_STRING String2, BOOLEAN CaseInSensitive)
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
IN HDEVINFO IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
Definition: devinst.c:44
enum _BASE_SEARCH_PATH_TYPE BASE_SEARCH_PATH_TYPE
IN PUNICODE_STRING StaticString
LPWSTR WINAPI BasepComputeProcessPath(IN PBASE_SEARCH_PATH_TYPE PathOrder, IN LPWSTR AppName, IN LPVOID Environment)
Definition: path.c:116
_In_ LPCSTR lpFileName
Definition: winbase.h:2959
NTSTATUS NTAPI RtlDosSearchPath_Ustr(IN ULONG Flags, IN PUNICODE_STRING PathString, IN PUNICODE_STRING FileNameString, IN PUNICODE_STRING ExtensionString, IN PUNICODE_STRING CallerBuffer, IN OUT PUNICODE_STRING DynamicString OPTIONAL, OUT PUNICODE_STRING *FullNameOut OPTIONAL, OUT PSIZE_T FilePartSize OPTIONAL, OUT PSIZE_T LengthNeeded OPTIONAL)
Definition: path.c:2273
BASE_SEARCH_PATH_TYPE BaseDllOrderNoCurrent[BaseSearchPathMax]
Definition: path.c:63
#define NtCurrentPeb()
Definition: rtlfuncs.h:1073
HANDLE WINAPI FindFirstFileW(IN LPCWSTR lpFileName, OUT LPWIN32_FIND_DATAW lpFindFileData)
Definition: find.c:318
UNICODE_STRING BaseWindowsSystemDirectory
Definition: path.c:20
#define ERROR_FILENAME_EXCED_RANGE
Definition: winerror.h:263
#define RTL_CONSTANT_STRING(s)
Definition: tunneltest.c:14
BOOL WINAPI FindClose(HANDLE hFindFile)
Definition: find.c:500