ReactOS  0.4.12-dev-36-g472787f
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  {
50  BaseSearchPathInvalid
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  SIZE_T 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;
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  (ULONG)(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  (ULONG)(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;
1306  SIZE_T LengthNeeded, FilePartSize;
1307  NTSTATUS Status;
1308  DWORD Result = 0;
1309 
1310  /* Default flags for RtlDosSearchPath_Ustr */
1311  Flags = 6;
1312 
1313  /* Clear file part in case we fail */
1314  if (lpFilePart) *lpFilePart = NULL;
1315 
1316  /* Initialize path buffer for free later */
1317  PathString.Buffer = NULL;
1318 
1319  /* Convert filename to a unicode string and eliminate trailing spaces */
1320  RtlInitUnicodeString(&FileNameString, lpFileName);
1321  while ((FileNameString.Length >= sizeof(WCHAR)) &&
1322  (FileNameString.Buffer[(FileNameString.Length / sizeof(WCHAR)) - 1] == L' '))
1323  {
1324  FileNameString.Length -= sizeof(WCHAR);
1325  }
1326 
1327  /* Was it all just spaces? */
1328  if (!FileNameString.Length)
1329  {
1330  /* Fail out */
1332  goto Quickie;
1333  }
1334 
1335  /* Convert extension to a unicode string */
1336  RtlInitUnicodeString(&ExtensionString, lpExtension);
1337 
1338  /* Check if the user sent a path */
1339  if (lpPath)
1340  {
1341  /* Convert it to a unicode string too */
1342  Status = RtlInitUnicodeStringEx(&PathString, lpPath);
1343  if (NT_ERROR(Status))
1344  {
1345  /* Fail if it was too long */
1346  BaseSetLastNTError(Status);
1347  goto Quickie;
1348  }
1349  }
1350  else
1351  {
1352  /* A path wasn't sent, so compute it ourselves */
1353  PathString.Buffer = BaseComputeProcessSearchPath();
1354  if (!PathString.Buffer)
1355  {
1356  /* Fail if we couldn't compute it */
1358  goto Quickie;
1359  }
1360 
1361  /* See how big the computed path is */
1362  LengthNeeded = lstrlenW(PathString.Buffer);
1363  if (LengthNeeded > UNICODE_STRING_MAX_CHARS)
1364  {
1365  /* Fail if it's too long */
1367  goto Quickie;
1368  }
1369 
1370  /* Set the path size now that we have it */
1371  PathString.MaximumLength = PathString.Length = (USHORT)LengthNeeded * sizeof(WCHAR);
1372 
1373  /* Request SxS isolation from RtlDosSearchPath_Ustr */
1374  Flags |= 1;
1375  }
1376 
1377  /* Create the string that describes the output buffer from the caller */
1378  CallerBuffer.Length = 0;
1379  CallerBuffer.Buffer = lpBuffer;
1380 
1381  /* How much space does the caller have? */
1382  if (nBufferLength <= UNICODE_STRING_MAX_CHARS)
1383  {
1384  /* Add it into the string */
1385  CallerBuffer.MaximumLength = (USHORT)nBufferLength * sizeof(WCHAR);
1386  }
1387  else
1388  {
1389  /* Caller wants too much, limit it to the maximum length of a string */
1390  CallerBuffer.MaximumLength = UNICODE_STRING_MAX_BYTES;
1391  }
1392 
1393  /* Call Rtl to do the work */
1394  Status = RtlDosSearchPath_Ustr(Flags,
1395  &PathString,
1396  &FileNameString,
1397  &ExtensionString,
1398  &CallerBuffer,
1399  NULL,
1400  NULL,
1401  &FilePartSize,
1402  &LengthNeeded);
1403  if (NT_ERROR(Status))
1404  {
1405  /* Check for unusual status codes */
1406  if ((Status != STATUS_NO_SUCH_FILE) && (Status != STATUS_BUFFER_TOO_SMALL))
1407  {
1408  /* Print them out since maybe an app needs fixing */
1409  DbgPrint("%s on file %wZ failed; NTSTATUS = %08lx\n",
1410  __FUNCTION__,
1411  &FileNameString,
1412  Status);
1413  DbgPrint(" Path = %wZ\n", &PathString);
1414  }
1415 
1416  /* Check if the failure was due to a small buffer */
1417  if (Status == STATUS_BUFFER_TOO_SMALL)
1418  {
1419  /* Check if the length was actually too big for Rtl to work with */
1420  Result = LengthNeeded / sizeof(WCHAR);
1421  if (Result > 0xFFFFFFFF) BaseSetLastNTError(STATUS_NAME_TOO_LONG);
1422  }
1423  else
1424  {
1425  /* Some other error, set the error code */
1426  BaseSetLastNTError(Status);
1427  }
1428  }
1429  else
1430  {
1431  /* It worked! Write the file part now */
1432  if (lpFilePart) *lpFilePart = &lpBuffer[FilePartSize];
1433 
1434  /* Convert the final result length */
1435  Result = CallerBuffer.Length / sizeof(WCHAR);
1436  }
1437 
1438 Quickie:
1439  /* Check if there was a dynamic path string to free */
1440  if ((PathString.Buffer != lpPath) && (PathString.Buffer))
1441  {
1442  /* And free it */
1443  RtlFreeHeap(RtlGetProcessHeap(), 0, PathString.Buffer);
1444  }
1445 
1446  /* Return the final result length */
1447  return Result;
1448 }
1449 
1450 /*
1451  * @implemented
1452  */
1453 DWORD
1454 WINAPI
1456  OUT LPWSTR lpszLongPath,
1457  IN DWORD cchBuffer)
1458 {
1459  PWCHAR Path, Original, First, Last, Buffer, Src, Dst;
1461  WCHAR LastChar;
1462  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;
1838  WCHAR LastChar;
1839  HANDLE FindHandle;
1840  ULONG ErrorMode;
1841  BOOLEAN Found = FALSE;
1842  WIN32_FIND_DATAW FindFileData;
1843 
1844  /* Initialize so Quickie knows there's nothing to do */
1845  Buffer = Original = NULL;
1846  ReturnLength = 0;
1847 
1848  /* First check if the input path was obviously NULL */
1849  if (!lpszLongPath)
1850  {
1851  /* Fail the request */
1853  return 0;
1854  }
1855 
1856  /* We will be touching removed, removable drives -- don't warn the user */
1858 
1859  /* Do a simple check to see if the path exists */
1860  if (GetFileAttributesW(lpszLongPath) == INVALID_FILE_ATTRIBUTES)
1861  {
1862  /* Windows checks for an application compatibility flag to allow this */
1863  if (!(NtCurrentPeb()) || !(NtCurrentPeb()->AppCompatFlags.LowPart & GetShortPathNameNT4))
1864  {
1865  /* It doesn't, so fail */
1866  ReturnLength = 0;
1867  goto Quickie;
1868  }
1869  }
1870 
1871  /* Now get a pointer to the actual path, skipping indicators */
1872  Path = SkipPathTypeIndicator_U((LPWSTR)lpszLongPath);
1873 
1874  /* Is there any path or filename in there? */
1875  if (!(Path) ||
1876  (*Path == UNICODE_NULL) ||
1877  !(FindLFNorSFN_U(Path, &First, &Last, TRUE)))
1878  {
1879  /* There isn't, so the long path is simply the short path */
1880  ReturnLength = wcslen(lpszLongPath);
1881 
1882  /* Is there space for it? */
1883  if ((cchBuffer > ReturnLength) && (lpszShortPath))
1884  {
1885  /* Make sure the pointers aren't already the same */
1886  if (lpszLongPath != lpszShortPath)
1887  {
1888  /* They're not -- copy the short path into the long path */
1889  RtlMoveMemory(lpszShortPath,
1890  lpszLongPath,
1891  ReturnLength * sizeof(WCHAR) + sizeof(UNICODE_NULL));
1892  }
1893  }
1894  else
1895  {
1896  /* Otherwise, let caller know we need a bigger buffer, include NULL */
1897  ReturnLength++;
1898  }
1899  goto Quickie;
1900  }
1901 
1902  /* We are still in the game -- compute the current size */
1903  Length = wcslen(lpszLongPath) + sizeof(ANSI_NULL);
1904  Original = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR));
1905  if (!Original) goto ErrorQuickie;
1906 
1907  /* Make a copy of it */
1908  wcsncpy(Original, lpszLongPath, Length);
1909 
1910  /* Compute the new first and last markers */
1911  First = &Original[First - lpszLongPath];
1912  Last = &Original[Last - lpszLongPath];
1913 
1914  /* Set the current destination pointer for a copy */
1915  Dst = lpszShortPath;
1916 
1917  /*
1918  * Windows allows the paths to overlap -- we have to be careful with this and
1919  * see if it's same to do so, and if not, allocate our own internal buffer
1920  * that we'll return at the end.
1921  *
1922  * This is also why we use RtlMoveMemory everywhere. Don't use RtlCopyMemory!
1923  */
1924  if ((cchBuffer) && (lpszShortPath) &&
1925  (((lpszShortPath >= lpszLongPath) && (lpszShortPath < &lpszLongPath[Length])) ||
1926  ((lpszShortPath < lpszLongPath) && (&lpszShortPath[cchBuffer] >= lpszLongPath))))
1927  {
1928  Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, cchBuffer * sizeof(WCHAR));
1929  if (!Buffer) goto ErrorQuickie;
1930 
1931  /* New destination */
1932  Dst = Buffer;
1933  }
1934 
1935  /* Prepare for the loop */
1936  Src = Original;
1937  ReturnLength = 0;
1938  while (TRUE)
1939  {
1940  /* Current delta in the loop */
1941  Length = First - Src;
1942 
1943  /* Update the return length by it */
1944  ReturnLength += Length;
1945 
1946  /* Is there a delta? If so, is there space and buffer for it? */
1947  if ((Length) && (cchBuffer > ReturnLength) && (lpszShortPath))
1948  {
1949  RtlMoveMemory(Dst, Src, Length * sizeof(WCHAR));
1950  Dst += Length;
1951  }
1952 
1953  /* "Terminate" this portion of the path's substring so we can do a find */
1954  LastChar = *Last;
1955  *Last = UNICODE_NULL;
1956  FindHandle = FindFirstFileW(Original, &FindFileData);
1957  *Last = LastChar;
1958 
1959  /* This portion wasn't found, so fail */
1960  if (FindHandle == INVALID_HANDLE_VALUE)
1961  {
1962  ReturnLength = 0;
1963  break;
1964  }
1965 
1966  /* Close the find handle */
1967  FindClose(FindHandle);
1968 
1969  /* Now check the length of the short name */
1970  Length = wcslen(FindFileData.cAlternateFileName);
1971  if (Length)
1972  {
1973  /* This is our new first marker */
1974  First = FindFileData.cAlternateFileName;
1975  }
1976  else
1977  {
1978  /* Otherwise, the name is the delta between our current markers */
1979  Length = Last - First;
1980  }
1981 
1982  /* Update the return length with the short name length, if any */
1983  ReturnLength += Length;
1984 
1985  /* Once again check for appropriate space and buffer */
1986  if ((cchBuffer > ReturnLength) && (lpszShortPath))
1987  {
1988  /* And do the copy if there is */
1989  RtlMoveMemory(Dst, First, Length * sizeof(WCHAR));
1990  Dst += Length;
1991  }
1992 
1993  /* Now update the source pointer */
1994  Src = Last;
1995  if (*Src == UNICODE_NULL) break;
1996 
1997  /* Are there more names in there? */
1998  Found = FindLFNorSFN_U(Src, &First, &Last, TRUE);
1999  if (!Found) break;
2000  }
2001 
2002  /* The loop is done, is there anything left? */
2003  if (ReturnLength)
2004  {
2005  /* Get the length of the straggling path */
2006  Length = wcslen(Src);
2007  ReturnLength += Length;
2008 
2009  /* Once again check for appropriate space and buffer */
2010  if ((cchBuffer > ReturnLength) && (lpszShortPath))
2011  {
2012  /* And do the copy if there is -- accounting for NULL here */
2013  RtlMoveMemory(Dst, Src, Length * sizeof(WCHAR) + sizeof(UNICODE_NULL));
2014 
2015  /* What about our buffer? */
2016  if (Buffer)
2017  {
2018  /* Copy it into the caller's long path */
2019  RtlMoveMemory(lpszShortPath,
2020  Buffer,
2021  ReturnLength * sizeof(WCHAR) + sizeof(UNICODE_NULL));
2022  }
2023  }
2024  else
2025  {
2026  /* Buffer is too small, let the caller know, making space for NULL */
2027  ReturnLength++;
2028  }
2029  }
2030 
2031  /* We're all done */
2032  goto Quickie;
2033 
2034 ErrorQuickie:
2035  /* This is the goto for memory failures */
2037 
2038 Quickie:
2039  /* General function end: free memory, restore error mode, return length */
2040  if (Original) RtlFreeHeap(RtlGetProcessHeap(), 0, Original);
2041  if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
2042  SetErrorMode(ErrorMode);
2043  return ReturnLength;
2044 }
2045 
2046 /*
2047  * @implemented
2048  *
2049  * NOTE: Windows returns a dos/short (8.3) path
2050  */
2051 DWORD
2052 WINAPI
2054  OUT LPSTR lpBuffer)
2055 {
2056  WCHAR BufferW[MAX_PATH];
2057  DWORD ret;
2058 
2059  ret = GetTempPathW(MAX_PATH, BufferW);
2060 
2061  if (!ret) return 0;
2062 
2063  if (ret > MAX_PATH)
2064  {
2066  return 0;
2067  }
2068 
2069  return FilenameW2A_FitOrFail(lpBuffer, nBufferLength, BufferW, ret+1);
2070 }
2071 
2072 /*
2073  * @implemented
2074  *
2075  * ripped from wine
2076  */
2077 DWORD
2078 WINAPI
2080  OUT LPWSTR path)
2081 {
2082  static const WCHAR tmp[] = { 'T', 'M', 'P', 0 };
2083  static const WCHAR temp[] = { 'T', 'E', 'M', 'P', 0 };
2084  static const WCHAR userprofile[] = { 'U','S','E','R','P','R','O','F','I','L','E',0 };
2085  WCHAR tmp_path[MAX_PATH];
2086  WCHAR full_tmp_path[MAX_PATH];
2087  UINT ret;
2088 
2089  DPRINT("%u,%p\n", count, path);
2090 
2091  if (!(ret = GetEnvironmentVariableW( tmp, tmp_path, MAX_PATH )) &&
2092  !(ret = GetEnvironmentVariableW( temp, tmp_path, MAX_PATH )) &&
2093  !(ret = GetEnvironmentVariableW( userprofile, tmp_path, MAX_PATH )) &&
2094  !(ret = GetWindowsDirectoryW( tmp_path, MAX_PATH )))
2095  {
2096  return 0;
2097  }
2098 
2099  if (ret > MAX_PATH)
2100  {
2102  return 0;
2103  }
2104 
2105  ret = GetFullPathNameW(tmp_path, MAX_PATH, full_tmp_path, NULL);
2106  if (!ret) return 0;
2107 
2108  if (ret > MAX_PATH - 2)
2109  {
2111  return 0;
2112  }
2113 
2114  if (full_tmp_path[ret-1] != '\\')
2115  {
2116  full_tmp_path[ret++] = '\\';
2117  full_tmp_path[ret] = '\0';
2118  }
2119 
2120  ret++; /* add space for terminating 0 */
2121 
2122  if (count >= ret)
2123  {
2124  lstrcpynW(path, full_tmp_path, count);
2125  /* the remaining buffer must be zeroed up to 32766 bytes in XP or 32767
2126  * bytes after it, we will assume the > XP behavior for now */
2127  memset(path + ret, 0, (min(count, 32767) - ret) * sizeof(WCHAR));
2128  ret--; /* return length without 0 */
2129  }
2130  else if (count)
2131  {
2132  /* the buffer must be cleared if contents will not fit */
2133  memset(path, 0, count * sizeof(WCHAR));
2134  }
2135 
2136  DPRINT("GetTempPathW returning %u, %S\n", ret, path);
2137  return ret;
2138 }
2139 
2140 /*
2141  * @implemented
2142  */
2143 DWORD
2144 WINAPI
2146  OUT LPSTR lpBuffer)
2147 {
2149  NTSTATUS Status;
2151  ULONG MaxLength;
2152 
2153  StaticString = &NtCurrentTeb()->StaticUnicodeString;
2154 
2155  MaxLength = nBufferLength;
2156  if (nBufferLength >= UNICODE_STRING_MAX_BYTES)
2157  {
2158  MaxLength = UNICODE_STRING_MAX_BYTES - 1;
2159  }
2160 
2161  StaticString->Length = (USHORT)RtlGetCurrentDirectory_U(StaticString->MaximumLength,
2162  StaticString->Buffer);
2163  Status = RtlUnicodeToMultiByteSize(&nBufferLength,
2164  StaticString->Buffer,
2165  StaticString->Length);
2166  if (!NT_SUCCESS(Status))
2167  {
2168  BaseSetLastNTError(Status);
2169  return 0;
2170  }
2171 
2172  if (MaxLength <= nBufferLength)
2173  {
2174  return nBufferLength + 1;
2175  }
2176 
2177  AnsiString.Buffer = lpBuffer;
2178  AnsiString.MaximumLength = (USHORT)MaxLength;
2179  Status = BasepUnicodeStringTo8BitString(&AnsiString, StaticString, FALSE);
2180  if (!NT_SUCCESS(Status))
2181  {
2182  BaseSetLastNTError(Status);
2183  return 0;
2184  }
2185 
2186  return AnsiString.Length;
2187 }
2188 
2189 /*
2190  * @implemented
2191  */
2192 DWORD
2193 WINAPI
2196 {
2197  return RtlGetCurrentDirectory_U(nBufferLength * sizeof(WCHAR), lpBuffer) / sizeof(WCHAR);
2198 }
2199 
2200 /*
2201  * @implemented
2202  */
2203 BOOL
2204 WINAPI
2206 {
2208  NTSTATUS Status;
2209 
2210  if (!lpPathName)
2211  {
2213  return FALSE;
2214  }
2215 
2216  DirName = Basep8BitStringToStaticUnicodeString(lpPathName);
2217  if (!DirName) return FALSE;
2218 
2219  if (CheckForSameCurdir(DirName)) return TRUE;
2220 
2221  Status = RtlSetCurrentDirectory_U(DirName);
2222  if (NT_SUCCESS(Status)) return TRUE;
2223 
2224  if ((*DirName->Buffer != L'"') || (DirName->Length <= 2))
2225  {
2226  BaseSetLastNTError(Status);
2227  return 0;
2228  }
2229 
2230  DirName = Basep8BitStringToStaticUnicodeString(lpPathName + 1);
2231  if (!DirName) return FALSE;
2232 
2233  Status = RtlSetCurrentDirectory_U(DirName);
2234  if (!NT_SUCCESS(Status))
2235  {
2236  BaseSetLastNTError(Status);
2237  return FALSE;
2238  }
2239 
2240  return TRUE;
2241 }
2242 
2243 /*
2244  * @implemented
2245  */
2246 BOOL
2247 WINAPI
2249 {
2250  NTSTATUS Status;
2252 
2253  if (!lpPathName)
2254  {
2256  return FALSE;
2257  }
2258 
2259  Status = RtlInitUnicodeStringEx(&UnicodeString, lpPathName);
2260  if (NT_SUCCESS(Status))
2261  {
2262  if (!CheckForSameCurdir(&UnicodeString))
2263  {
2264  Status = RtlSetCurrentDirectory_U(&UnicodeString);
2265  }
2266  }
2267 
2268  if (!NT_SUCCESS(Status))
2269  {
2270  BaseSetLastNTError(Status);
2271  return FALSE;
2272  }
2273 
2274  return TRUE;
2275 }
2276 
2277 /*
2278  * @implemented
2279  */
2280 UINT
2281 WINAPI
2283  IN UINT uSize)
2284 {
2286  NTSTATUS Status;
2287  ULONG AnsiLength;
2288 
2289  /* Get the correct size of the Unicode Base directory */
2290  Status = RtlUnicodeToMultiByteSize(&AnsiLength,
2291  BaseWindowsSystemDirectory.Buffer,
2292  BaseWindowsSystemDirectory.MaximumLength);
2293  if (!NT_SUCCESS(Status)) return 0;
2294 
2295  if (uSize < AnsiLength) return AnsiLength;
2296 
2297  RtlInitEmptyAnsiString(&AnsiString, lpBuffer, uSize);
2298 
2299  Status = BasepUnicodeStringTo8BitString(&AnsiString,
2300  &BaseWindowsSystemDirectory,
2301  FALSE);
2302  if (!NT_SUCCESS(Status)) return 0;
2303 
2304  return AnsiString.Length;
2305 }
2306 
2307 /*
2308  * @implemented
2309  */
2310 UINT
2311 WINAPI
2313  IN UINT uSize)
2314 {
2316 
2317  ReturnLength = BaseWindowsSystemDirectory.MaximumLength;
2318  if ((uSize * sizeof(WCHAR)) >= ReturnLength)
2319  {
2320  RtlCopyMemory(lpBuffer,
2321  BaseWindowsSystemDirectory.Buffer,
2322  BaseWindowsSystemDirectory.Length);
2323  lpBuffer[BaseWindowsSystemDirectory.Length / sizeof(WCHAR)] = ANSI_NULL;
2324 
2325  ReturnLength = BaseWindowsSystemDirectory.Length;
2326  }
2327 
2328  return ReturnLength / sizeof(WCHAR);
2329 }
2330 
2331 /*
2332  * @implemented
2333  */
2334 UINT
2335 WINAPI
2337  IN UINT uSize)
2338 {
2339  /* Is this a TS installation? */
2340  if (gpTermsrvGetWindowsDirectoryA) UNIMPLEMENTED;
2341 
2342  /* Otherwise, call the System API */
2343  return GetSystemWindowsDirectoryA(lpBuffer, uSize);
2344 }
2345 
2346 /*
2347  * @implemented
2348  */
2349 UINT
2350 WINAPI
2352  IN UINT uSize)
2353 {
2354  /* Is this a TS installation? */
2355  if (gpTermsrvGetWindowsDirectoryW) UNIMPLEMENTED;
2356 
2357  /* Otherwise, call the System API */
2358  return GetSystemWindowsDirectoryW(lpBuffer, uSize);
2359 }
2360 
2361 /*
2362  * @implemented
2363  */
2364 UINT
2365 WINAPI
2367  IN UINT uSize)
2368 {
2370  NTSTATUS Status;
2371  ULONG AnsiLength;
2372 
2373  /* Get the correct size of the Unicode Base directory */
2374  Status = RtlUnicodeToMultiByteSize(&AnsiLength,
2375  BaseWindowsDirectory.Buffer,
2376  BaseWindowsDirectory.MaximumLength);
2377  if (!NT_SUCCESS(Status)) return 0;
2378 
2379  if (uSize < AnsiLength) return AnsiLength;
2380 
2381  RtlInitEmptyAnsiString(&AnsiString, lpBuffer, uSize);
2382 
2383  Status = BasepUnicodeStringTo8BitString(&AnsiString,
2384  &BaseWindowsDirectory,
2385  FALSE);
2386  if (!NT_SUCCESS(Status)) return 0;
2387 
2388  return AnsiString.Length;
2389 }
2390 
2391 /*
2392  * @implemented
2393  */
2394 UINT
2395 WINAPI
2397  IN UINT uSize)
2398 {
2400 
2401  ReturnLength = BaseWindowsDirectory.MaximumLength;
2402  if ((uSize * sizeof(WCHAR)) >= ReturnLength)
2403  {
2404  RtlCopyMemory(lpBuffer,
2405  BaseWindowsDirectory.Buffer,
2406  BaseWindowsDirectory.Length);
2407  lpBuffer[BaseWindowsDirectory.Length / sizeof(WCHAR)] = ANSI_NULL;
2408 
2409  ReturnLength = BaseWindowsDirectory.Length;
2410  }
2411 
2412  return ReturnLength / sizeof(WCHAR);
2413 }
2414 
2415 /*
2416  * @unimplemented
2417  */
2418 UINT
2419 WINAPI
2421  IN UINT uSize)
2422 {
2423 #ifdef _WIN64
2424  UNIMPLEMENTED;
2425  return 0;
2426 #else
2428  return 0;
2429 #endif
2430 }
2431 
2432 /*
2433  * @unimplemented
2434  */
2435 UINT
2436 WINAPI
2438  IN UINT uSize)
2439 {
2440 #ifdef _WIN64
2441  UNIMPLEMENTED;
2442  return 0;
2443 #else
2445  return 0;
2446 #endif
2447 }
2448 
2449 /* EOF */
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:753
_Must_inspect_result_ _Out_ PNDIS_STATUS _In_ NDIS_HANDLE _In_ ULONG _Out_ PNDIS_STRING KeyName
Definition: ndis.h:4693
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:2396
_In_ LPCSTR _In_opt_ LPCSTR _In_ DWORD _Out_opt_ LPSTR * lpFilePart
Definition: winbase.h:3015
#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:2366
#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:4693
#define DbgPrint
Definition: loader.c:25
USHORT MaximumLength
Definition: env_spec_w32.h:370
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)
GLuint GLuint GLsizei count
Definition: gl.h:1545
char CHAR
Definition: xmlstorage.h:175
NTSYSAPI NTSTATUS NTAPI RtlUnicodeToMultiByteSize(PULONG MbSize, PCWCH UnicodeString, ULONG UnicodeSize)
LONG NTSTATUS
Definition: precomp.h:26
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:603
IN PDCB IN POEM_STRING IN PUNICODE_STRING UnicodeName
Definition: fatprocs.h:1294
static CHAR AppName[MAX_PATH]
Definition: dem.c:252
UINT WINAPI GetSystemDirectoryA(OUT LPSTR lpBuffer, IN UINT uSize)
Definition: path.c:2282
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
uint16_t * PWCHAR
Definition: typedefs.h:54
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 ret
Definition: path.c:47
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define lstrcpynW
Definition: compat.h:397
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:52
UINT WINAPI GetWindowsDirectoryW(OUT LPWSTR lpBuffer, IN UINT uSize)
Definition: path.c:2351
LPWSTR WINAPI BaseComputeProcessSearchPath(VOID)
Definition: path.c:395
DWORD WINAPI GetLongPathNameA(IN LPCSTR lpszShortPath, OUT LPSTR lpszLongPath, IN DWORD cchBuffer)
Definition: path.c:1670
DWORD WINAPI GetFullPathNameA(IN LPCSTR lpFileName, IN DWORD nBufferLength, OUT LPSTR lpBuffer, OUT LPSTR *lpFilePart)
Definition: path.c:992
WCHAR First[]
Definition: FormatMessage.c:11
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:2079
#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
#define OBJ_NAME_PATH_SEPARATOR
Definition: arcname_tests.c:25
DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName)
Definition: fileinfo.c:802
PWCHAR WINAPI SkipPathTypeIndicator_U(IN LPWSTR Path)
Definition: path.c:739
static DWORD cchBuffer
Definition: fusion.c:83
static TAGREF LPCWSTR LPDWORD LPVOID lpBuffer
Definition: db.cpp:163
unsigned char BOOLEAN
NTSYSAPI NTSTATUS NTAPI RtlQueryEnvironmentVariable_U(_In_opt_ PWSTR Environment, _In_ PCUNICODE_STRING Name, _Out_ PUNICODE_STRING Value)
smooth NULL
Definition: ftsmooth.c:416
_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
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:2437
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
return Found
Definition: dirsup.c:1270
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:3011
#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:227
USHORT MaximumLength
Definition: env_spec_w32.h:377
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:1455
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
unsigned int UINT
Definition: ndis.h:50
DWORD IllegalMask[4]
Definition: path.c:28
NTSYSAPI VOID NTAPI RtlFreeAnsiString(PANSI_STRING AnsiString)
CHAR AnsiBuffer[1024]
Definition: debug.c:15
unsigned long DWORD
Definition: ntddk_ex.h:95
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)
#define SetLastError(x)
Definition: compat.h:409
#define NT_ERROR(Status)
Definition: umtypes.h:106
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
#define INVALID_FILE_ATTRIBUTES
Definition: vfdcmd.c:23
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3393
#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
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
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
static const WCHAR L[]
Definition: oid.c:1087
UINT WINAPI GetSystemWow64DirectoryW(OUT LPWSTR lpBuffer, IN UINT uSize)
Definition: path.c:2420
BOOL WINAPI SetCurrentDirectoryA(IN LPCSTR lpPathName)
Definition: path.c:2205
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:1120
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:3011
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
ULONG_PTR SIZE_T
Definition: typedefs.h:78
#define RTL_CONSTANT_OBJECT_ATTRIBUTES(n, a)
PRTL_UNICODE_STRING_BUFFER Path
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:2053
#define NtCurrentPeb()
Definition: FLS.c:19
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
#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:2248
DWORD WINAPI GetCurrentDirectoryA(IN DWORD nBufferLength, OUT LPSTR lpBuffer)
Definition: path.c:2145
#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:325
UINT WINAPI GetWindowsDirectoryA(OUT LPSTR lpBuffer, IN UINT uSize)
Definition: path.c:2336
UNICODE_STRING FullDllName
Definition: btrfs_drv.h:1768
UINT WINAPI GetSystemDirectoryW(OUT LPWSTR lpBuffer, IN UINT uSize)
Definition: path.c:2312
unsigned int * PULONG
Definition: retypes.h:1
#define min(a, b)
Definition: monoChain.cc:55
NTSYSAPI NTSTATUS WINAPI RtlInitUnicodeStringEx(PUNICODE_STRING, PCWSTR)
#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:2194
NTSYSAPI NTSTATUS NTAPI NtOpenKey(OUT PHANDLE KeyHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes)
Definition: ntapi.c:336
#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
_In_ PFCB _In_ PCD_NAME DirName
Definition: cdprocs.h:741
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
WCHAR * LPWSTR
Definition: xmlstorage.h:184
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
return STATUS_SUCCESS
Definition: btrfs.c:2710
#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
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)
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:3011
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
HANDLE WINAPI FindFirstFileW(IN LPCWSTR lpFileName, OUT LPWIN32_FIND_DATAW lpFindFileData)
Definition: find.c:320
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:502
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68