1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS system libraries
4  * PURPOSE:         Vista functions
5  * PROGRAMMER:      Thomas Weidenmueller <w3seek@reactos.com>
6  */
7 
8 /* INCLUDES *******************************************************************/
9 
10 #include <k32_vista.h>
11 
12 #if _WIN32_WINNT != _WIN32_WINNT_VISTA
13 #error "This file must be compiled with _WIN32_WINNT == _WIN32_WINNT_VISTA"
14 #endif
15 
16 // This is defined only in ntifs.h
17 #define REPARSE_DATA_BUFFER_HEADER_SIZE   FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer)
18 
19 #define NDEBUG
20 #include <debug.h>
21 
22 /* PUBLIC FUNCTIONS ***********************************************************/
23 
24 /*
25  * @implemented
26  */
27 BOOL
28 WINAPI
QueryFullProcessImageNameW(HANDLE hProcess,DWORD dwFlags,LPWSTR lpExeName,PDWORD pdwSize)29 QueryFullProcessImageNameW(HANDLE hProcess,
30                            DWORD dwFlags,
31                            LPWSTR lpExeName,
32                            PDWORD pdwSize)
33 {
34     BYTE Buffer[sizeof(UNICODE_STRING) + MAX_PATH * sizeof(WCHAR)];
35     UNICODE_STRING *DynamicBuffer = NULL;
36     UNICODE_STRING *Result = NULL;
37     NTSTATUS Status;
38     DWORD Needed;
39 
40     Status = NtQueryInformationProcess(hProcess,
41                                        ProcessImageFileName,
42                                        Buffer,
43                                        sizeof(Buffer) - sizeof(WCHAR),
44                                        &Needed);
45     if (Status == STATUS_INFO_LENGTH_MISMATCH)
46     {
47         DynamicBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Needed + sizeof(WCHAR));
48         if (!DynamicBuffer)
49         {
50             BaseSetLastNTError(STATUS_NO_MEMORY);
51             return FALSE;
52         }
53 
54         Status = NtQueryInformationProcess(hProcess,
55                                            ProcessImageFileName,
56                                            (LPBYTE)DynamicBuffer,
57                                            Needed,
58                                            &Needed);
59         Result = DynamicBuffer;
60     }
61     else Result = (PUNICODE_STRING)Buffer;
62 
63     if (!NT_SUCCESS(Status)) goto Cleanup;
64 
65     if (Result->Length / sizeof(WCHAR) + 1 > *pdwSize)
66     {
67         Status = STATUS_BUFFER_TOO_SMALL;
68         goto Cleanup;
69     }
70 
71     *pdwSize = Result->Length / sizeof(WCHAR);
72     memcpy(lpExeName, Result->Buffer, Result->Length);
73     lpExeName[*pdwSize] = 0;
74 
75 Cleanup:
76     RtlFreeHeap(RtlGetProcessHeap(), 0, DynamicBuffer);
77 
78     if (!NT_SUCCESS(Status))
79     {
80         BaseSetLastNTError(Status);
81     }
82 
83     return !Status;
84 }
85 
86 
87 /*
88  * @implemented
89  */
90 BOOL
91 WINAPI
QueryFullProcessImageNameA(HANDLE hProcess,DWORD dwFlags,LPSTR lpExeName,PDWORD pdwSize)92 QueryFullProcessImageNameA(HANDLE hProcess,
93                            DWORD dwFlags,
94                            LPSTR lpExeName,
95                            PDWORD pdwSize)
96 {
97     DWORD pdwSizeW = *pdwSize;
98     BOOL Result;
99     LPWSTR lpExeNameW;
100 
101     lpExeNameW = RtlAllocateHeap(RtlGetProcessHeap(),
102                                  HEAP_ZERO_MEMORY,
103                                  *pdwSize * sizeof(WCHAR));
104     if (!lpExeNameW)
105     {
106         BaseSetLastNTError(STATUS_NO_MEMORY);
107         return FALSE;
108     }
109 
110     Result = QueryFullProcessImageNameW(hProcess, dwFlags, lpExeNameW, &pdwSizeW);
111 
112     if (Result)
113         Result = (0 != WideCharToMultiByte(CP_ACP, 0,
114                                            lpExeNameW,
115                                            -1,
116                                            lpExeName,
117                                            *pdwSize,
118                                            NULL, NULL));
119 
120     if (Result)
121         *pdwSize = strlen(lpExeName);
122 
123     RtlFreeHeap(RtlGetProcessHeap(), 0, lpExeNameW);
124     return Result;
125 }
126 
127 
128 /*
129  * @unimplemented
130  */
131 HRESULT
132 WINAPI
GetApplicationRecoveryCallback(IN HANDLE hProcess,OUT APPLICATION_RECOVERY_CALLBACK * pRecoveryCallback,OUT PVOID * ppvParameter,PDWORD dwPingInterval,PDWORD dwFlags)133 GetApplicationRecoveryCallback(IN HANDLE hProcess,
134                                OUT APPLICATION_RECOVERY_CALLBACK* pRecoveryCallback,
135                                OUT PVOID* ppvParameter,
136                                PDWORD dwPingInterval,
137                                PDWORD dwFlags)
138 {
139     UNIMPLEMENTED;
140     return E_FAIL;
141 }
142 
143 
144 /*
145  * @unimplemented
146  */
147 HRESULT
148 WINAPI
GetApplicationRestart(IN HANDLE hProcess,OUT PWSTR pwzCommandline OPTIONAL,IN OUT PDWORD pcchSize,OUT PDWORD pdwFlags OPTIONAL)149 GetApplicationRestart(IN HANDLE hProcess,
150                       OUT PWSTR pwzCommandline  OPTIONAL,
151                       IN OUT PDWORD pcchSize,
152                       OUT PDWORD pdwFlags  OPTIONAL)
153 {
154     UNIMPLEMENTED;
155     return E_FAIL;
156 }
157 
158 
159 /*
160  * @unimplemented
161  */
162 VOID
163 WINAPI
ApplicationRecoveryFinished(IN BOOL bSuccess)164 ApplicationRecoveryFinished(IN BOOL bSuccess)
165 {
166     UNIMPLEMENTED;
167 }
168 
169 
170 /*
171  * @unimplemented
172  */
173 HRESULT
174 WINAPI
ApplicationRecoveryInProgress(OUT PBOOL pbCancelled)175 ApplicationRecoveryInProgress(OUT PBOOL pbCancelled)
176 {
177     UNIMPLEMENTED;
178     return E_FAIL;
179 }
180 
181 
182 /*
183  * @unimplemented
184  */
185 HRESULT
186 WINAPI
RegisterApplicationRecoveryCallback(IN APPLICATION_RECOVERY_CALLBACK pRecoveryCallback,IN PVOID pvParameter OPTIONAL,DWORD dwPingInterval,DWORD dwFlags)187 RegisterApplicationRecoveryCallback(IN APPLICATION_RECOVERY_CALLBACK pRecoveryCallback,
188                                     IN PVOID pvParameter  OPTIONAL,
189                                     DWORD dwPingInterval,
190                                     DWORD dwFlags)
191 {
192     UNIMPLEMENTED;
193     return E_FAIL;
194 }
195 
196 
197 /*
198  * @unimplemented
199  */
200 HRESULT
201 WINAPI
RegisterApplicationRestart(IN PCWSTR pwzCommandline OPTIONAL,IN DWORD dwFlags)202 RegisterApplicationRestart(IN PCWSTR pwzCommandline  OPTIONAL,
203                            IN DWORD dwFlags)
204 {
205     UNIMPLEMENTED;
206     return E_FAIL;
207 }
208 
209 
210 /*
211  * @implemented
212  */
213 BOOLEAN
214 WINAPI
CreateSymbolicLinkW(IN LPCWSTR lpSymlinkFileName,IN LPCWSTR lpTargetFileName,IN DWORD dwFlags)215 CreateSymbolicLinkW(IN LPCWSTR lpSymlinkFileName,
216                     IN LPCWSTR lpTargetFileName,
217                     IN DWORD dwFlags)
218 {
219     IO_STATUS_BLOCK IoStatusBlock;
220     OBJECT_ATTRIBUTES ObjectAttributes;
221     HANDLE hSymlink = NULL;
222     UNICODE_STRING SymlinkFileName = { 0, 0, NULL };
223     UNICODE_STRING TargetFileName = { 0, 0, NULL };
224     BOOLEAN bAllocatedTarget = FALSE, bRelativePath = FALSE;
225     LPWSTR lpTargetFullFileName = NULL;
226     SIZE_T cbPrintName;
227     SIZE_T cbReparseData;
228     PREPARSE_DATA_BUFFER pReparseData = NULL;
229     PBYTE pBufTail;
230     NTSTATUS Status;
231     ULONG dwCreateOptions;
232     DWORD dwErr;
233 
234     if(!lpSymlinkFileName || !lpTargetFileName || (dwFlags | SYMBOLIC_LINK_FLAG_DIRECTORY) != SYMBOLIC_LINK_FLAG_DIRECTORY)
235     {
236         SetLastError(ERROR_INVALID_PARAMETER);
237         return FALSE;
238     }
239 
240     if(dwFlags & SYMBOLIC_LINK_FLAG_DIRECTORY)
241         dwCreateOptions = FILE_DIRECTORY_FILE;
242     else
243         dwCreateOptions = FILE_NON_DIRECTORY_FILE;
244 
245     switch(RtlDetermineDosPathNameType_U(lpTargetFileName))
246     {
247     case RtlPathTypeUnknown:
248     case RtlPathTypeRooted:
249     case RtlPathTypeRelative:
250         bRelativePath = TRUE;
251         RtlInitUnicodeString(&TargetFileName, lpTargetFileName);
252         break;
253 
254     case RtlPathTypeDriveRelative:
255         {
256             LPWSTR FilePart;
257             SIZE_T cchTargetFullFileName;
258 
259             cchTargetFullFileName = GetFullPathNameW(lpTargetFileName, 0, NULL, &FilePart);
260 
261             if(cchTargetFullFileName == 0)
262             {
263                 dwErr = GetLastError();
264                 goto Cleanup;
265             }
266 
267             lpTargetFullFileName = RtlAllocateHeap(RtlGetProcessHeap(), 0, cchTargetFullFileName * sizeof(WCHAR));
268 
269             if(lpTargetFullFileName == NULL)
270             {
271                 dwErr = ERROR_NOT_ENOUGH_MEMORY;
272                 goto Cleanup;
273             }
274 
275             if(GetFullPathNameW(lpTargetFileName, cchTargetFullFileName, lpTargetFullFileName, &FilePart) == 0)
276             {
277                 dwErr = GetLastError();
278                 goto Cleanup;
279             }
280         }
281 
282         lpTargetFileName = lpTargetFullFileName;
283 
284         // fallthrough
285 
286     case RtlPathTypeUncAbsolute:
287     case RtlPathTypeDriveAbsolute:
288     case RtlPathTypeLocalDevice:
289     case RtlPathTypeRootLocalDevice:
290     default:
291         if(!RtlDosPathNameToNtPathName_U(lpTargetFileName, &TargetFileName, NULL, NULL))
292         {
293             bAllocatedTarget = TRUE;
294             dwErr = ERROR_INVALID_PARAMETER;
295             goto Cleanup;
296         }
297     }
298 
299     cbPrintName = wcslen(lpTargetFileName) * sizeof(WCHAR);
300     cbReparseData = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + TargetFileName.Length + cbPrintName;
301     pReparseData = RtlAllocateHeap(RtlGetProcessHeap(), 0, cbReparseData);
302 
303     if(pReparseData == NULL)
304     {
305         dwErr = ERROR_NOT_ENOUGH_MEMORY;
306         goto Cleanup;
307     }
308 
309     pBufTail = (PBYTE)(pReparseData->SymbolicLinkReparseBuffer.PathBuffer);
310 
311     pReparseData->ReparseTag = (ULONG)IO_REPARSE_TAG_SYMLINK;
312     pReparseData->ReparseDataLength = (USHORT)cbReparseData - REPARSE_DATA_BUFFER_HEADER_SIZE;
313     pReparseData->Reserved = 0;
314 
315     pReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0;
316     pReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength = TargetFileName.Length;
317     pBufTail += pReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset;
318     RtlCopyMemory(pBufTail, TargetFileName.Buffer, TargetFileName.Length);
319 
320     pReparseData->SymbolicLinkReparseBuffer.PrintNameOffset = pReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength;
321     pReparseData->SymbolicLinkReparseBuffer.PrintNameLength = (USHORT)cbPrintName;
322     pBufTail += pReparseData->SymbolicLinkReparseBuffer.PrintNameOffset;
323     RtlCopyMemory(pBufTail, lpTargetFileName, cbPrintName);
324 
325     pReparseData->SymbolicLinkReparseBuffer.Flags = 0;
326 
327     if(bRelativePath)
328         pReparseData->SymbolicLinkReparseBuffer.Flags |= 1; // TODO! give this lone flag a name
329 
330     if(!RtlDosPathNameToNtPathName_U(lpSymlinkFileName, &SymlinkFileName, NULL, NULL))
331     {
332         dwErr = ERROR_PATH_NOT_FOUND;
333         goto Cleanup;
334     }
335 
336     InitializeObjectAttributes(&ObjectAttributes, &SymlinkFileName, OBJ_CASE_INSENSITIVE, NULL, NULL);
337 
338     Status = NtCreateFile
339     (
340         &hSymlink,
341         FILE_WRITE_ATTRIBUTES | DELETE | SYNCHRONIZE,
342         &ObjectAttributes,
343         &IoStatusBlock,
344         NULL,
345         FILE_ATTRIBUTE_NORMAL,
346         0,
347         FILE_CREATE,
348         FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT | dwCreateOptions,
349         NULL,
350         0
351     );
352 
353     if(!NT_SUCCESS(Status))
354     {
355         dwErr = RtlNtStatusToDosError(Status);
356         goto Cleanup;
357     }
358 
359     Status = NtFsControlFile
360     (
361         hSymlink,
362         NULL,
363         NULL,
364         NULL,
365         &IoStatusBlock,
366         FSCTL_SET_REPARSE_POINT,
367         pReparseData,
368         cbReparseData,
369         NULL,
370         0
371     );
372 
373     if(!NT_SUCCESS(Status))
374     {
375         FILE_DISPOSITION_INFORMATION DispInfo;
376         DispInfo.DeleteFile = TRUE;
377         NtSetInformationFile(hSymlink, &IoStatusBlock, &DispInfo, sizeof(DispInfo), FileDispositionInformation);
378 
379         dwErr = RtlNtStatusToDosError(Status);
380         goto Cleanup;
381     }
382 
383     dwErr = NO_ERROR;
384 
385 Cleanup:
386     if(hSymlink)
387         NtClose(hSymlink);
388 
389     RtlFreeUnicodeString(&SymlinkFileName);
390     if (bAllocatedTarget)
391     {
392         RtlFreeHeap(RtlGetProcessHeap(),
393                     0,
394                     TargetFileName.Buffer);
395     }
396 
397     if(lpTargetFullFileName)
398         RtlFreeHeap(RtlGetProcessHeap(), 0, lpTargetFullFileName);
399 
400     if(pReparseData)
401         RtlFreeHeap(RtlGetProcessHeap(), 0, pReparseData);
402 
403     if(dwErr)
404     {
405         SetLastError(dwErr);
406         return FALSE;
407     }
408 
409     return TRUE;
410 }
411 
412 
413 /*
414  * @implemented
415  */
416 BOOLEAN
417 NTAPI
CreateSymbolicLinkA(IN LPCSTR lpSymlinkFileName,IN LPCSTR lpTargetFileName,IN DWORD dwFlags)418 CreateSymbolicLinkA(IN LPCSTR lpSymlinkFileName,
419                     IN LPCSTR lpTargetFileName,
420                     IN DWORD dwFlags)
421 {
422     PWCHAR SymlinkW, TargetW;
423     BOOLEAN Ret;
424 
425     if(!lpSymlinkFileName || !lpTargetFileName)
426     {
427         SetLastError(ERROR_INVALID_PARAMETER);
428         return FALSE;
429     }
430 
431     if (!(SymlinkW = FilenameA2W(lpSymlinkFileName, FALSE)))
432         return FALSE;
433 
434     if (!(TargetW = FilenameA2W(lpTargetFileName, TRUE)))
435         return FALSE;
436 
437     Ret = CreateSymbolicLinkW(SymlinkW,
438                               TargetW,
439                               dwFlags);
440 
441     RtlFreeHeap(RtlGetProcessHeap(), 0, SymlinkW);
442     RtlFreeHeap(RtlGetProcessHeap(), 0, TargetW);
443 
444     return Ret;
445 }
446 
447 
448 /*
449  * @unimplemented
450  */
451 DWORD
452 WINAPI
GetFinalPathNameByHandleW(IN HANDLE hFile,OUT LPWSTR lpszFilePath,IN DWORD cchFilePath,IN DWORD dwFlags)453 GetFinalPathNameByHandleW(IN HANDLE hFile,
454                           OUT LPWSTR lpszFilePath,
455                           IN DWORD cchFilePath,
456                           IN DWORD dwFlags)
457 {
458     if (dwFlags & ~(VOLUME_NAME_DOS | VOLUME_NAME_GUID | VOLUME_NAME_NT |
459                     VOLUME_NAME_NONE | FILE_NAME_NORMALIZED | FILE_NAME_OPENED))
460     {
461         SetLastError(ERROR_INVALID_PARAMETER);
462         return 0;
463     }
464 
465     UNIMPLEMENTED;
466     return 0;
467 }
468 
469 
470 /*
471  * @implemented
472  */
473 DWORD
474 WINAPI
GetFinalPathNameByHandleA(IN HANDLE hFile,OUT LPSTR lpszFilePath,IN DWORD cchFilePath,IN DWORD dwFlags)475 GetFinalPathNameByHandleA(IN HANDLE hFile,
476                           OUT LPSTR lpszFilePath,
477                           IN DWORD cchFilePath,
478                           IN DWORD dwFlags)
479 {
480     WCHAR FilePathW[MAX_PATH];
481     UNICODE_STRING FilePathU;
482     DWORD PrevLastError;
483     DWORD Ret = 0;
484 
485     if (cchFilePath != 0 &&
486         cchFilePath > sizeof(FilePathW) / sizeof(FilePathW[0]))
487     {
488         FilePathU.Length = 0;
489         FilePathU.MaximumLength = (USHORT)cchFilePath * sizeof(WCHAR);
490         FilePathU.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
491                                            0,
492                                            FilePathU.MaximumLength);
493         if (FilePathU.Buffer == NULL)
494         {
495             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
496             return 0;
497         }
498     }
499     else
500     {
501         FilePathU.Length = 0;
502         FilePathU.MaximumLength = sizeof(FilePathW);
503         FilePathU.Buffer = FilePathW;
504     }
505 
506     /* save the last error code */
507     PrevLastError = GetLastError();
508     SetLastError(ERROR_SUCCESS);
509 
510     /* call the unicode version that does all the work */
511     Ret = GetFinalPathNameByHandleW(hFile,
512                                     FilePathU.Buffer,
513                                     cchFilePath,
514                                     dwFlags);
515 
516     if (GetLastError() == ERROR_SUCCESS)
517     {
518         /* no error, restore the last error code and convert the string */
519         SetLastError(PrevLastError);
520 
521         Ret = FilenameU2A_FitOrFail(lpszFilePath,
522                                     cchFilePath,
523                                     &FilePathU);
524     }
525 
526     /* free allocated memory if necessary */
527     if (FilePathU.Buffer != FilePathW)
528     {
529         RtlFreeHeap(RtlGetProcessHeap(),
530                     0,
531                     FilePathU.Buffer);
532     }
533 
534     return Ret;
535 }
536 
537 
538 /*
539  * @unimplemented
540  */
541 BOOL
542 WINAPI
SetFileBandwidthReservation(IN HANDLE hFile,IN DWORD nPeriodMilliseconds,IN DWORD nBytesPerPeriod,IN BOOL bDiscardable,OUT LPDWORD lpTransferSize,OUT LPDWORD lpNumOutstandingRequests)543 SetFileBandwidthReservation(IN HANDLE hFile,
544                             IN DWORD nPeriodMilliseconds,
545                             IN DWORD nBytesPerPeriod,
546                             IN BOOL bDiscardable,
547                             OUT LPDWORD lpTransferSize,
548                             OUT LPDWORD lpNumOutstandingRequests)
549 {
550     UNIMPLEMENTED;
551     return FALSE;
552 }
553 
554 
555 /*
556  * @unimplemented
557  */
558 BOOL
559 WINAPI
GetFileBandwidthReservation(IN HANDLE hFile,OUT LPDWORD lpPeriodMilliseconds,OUT LPDWORD lpBytesPerPeriod,OUT LPBOOL pDiscardable,OUT LPDWORD lpTransferSize,OUT LPDWORD lpNumOutstandingRequests)560 GetFileBandwidthReservation(IN HANDLE hFile,
561                             OUT LPDWORD lpPeriodMilliseconds,
562                             OUT LPDWORD lpBytesPerPeriod,
563                             OUT LPBOOL pDiscardable,
564                             OUT LPDWORD lpTransferSize,
565                             OUT LPDWORD lpNumOutstandingRequests)
566 {
567     UNIMPLEMENTED;
568     return FALSE;
569 }
570 
571 
572 /*
573  * @unimplemented
574  */
575 HANDLE
576 WINAPI
OpenFileById(IN HANDLE hFile,IN LPFILE_ID_DESCRIPTOR lpFileID,IN DWORD dwDesiredAccess,IN DWORD dwShareMode,IN LPSECURITY_ATTRIBUTES lpSecurityAttributes OPTIONAL,IN DWORD dwFlags)577 OpenFileById(IN HANDLE hFile,
578              IN LPFILE_ID_DESCRIPTOR lpFileID,
579              IN DWORD dwDesiredAccess,
580              IN DWORD dwShareMode,
581              IN LPSECURITY_ATTRIBUTES lpSecurityAttributes  OPTIONAL,
582              IN DWORD dwFlags)
583 {
584     UNIMPLEMENTED;
585     return INVALID_HANDLE_VALUE;
586 }
587 
588 
589 
590 /*
591   Vista+ MUI support functions
592 
593   References:
594    Evolution of MUI Support across Windows Versions: http://msdn.microsoft.com/en-US/library/ee264317.aspx
595    Comparing Windows XP Professional Multilingual Options: http://technet.microsoft.com/en-us/library/bb457045.aspx
596 
597   More info:
598    http://msdn.microsoft.com/en-us/goglobal/bb978454.aspx
599    http://msdn.microsoft.com/en-us/library/dd319074.aspx
600 */
601 
602 /* FUNCTIONS *****************************************************************/
603 
604 BOOL
605 WINAPI
GetFileMUIInfo(DWORD dwFlags,PCWSTR pcwszFilePath,PFILEMUIINFO pFileMUIInfo,DWORD * pcbFileMUIInfo)606 GetFileMUIInfo(
607     DWORD dwFlags,
608     PCWSTR pcwszFilePath,
609     PFILEMUIINFO pFileMUIInfo,
610     DWORD *pcbFileMUIInfo)
611 {
612     DPRINT1("%x %p %p %p\n", dwFlags, pcwszFilePath, pFileMUIInfo, pcbFileMUIInfo);
613     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
614     return FALSE;
615 }
616 
617 /*
618  * @unimplemented
619  */
620 BOOL
621 WINAPI
GetFileMUIPath(DWORD dwFlags,PCWSTR pcwszFilePath,PWSTR pwszLanguage,PULONG pcchLanguage,PWSTR pwszFileMUIPath,PULONG pcchFileMUIPath,PULONGLONG pululEnumerator)622 GetFileMUIPath(
623     DWORD dwFlags,
624     PCWSTR pcwszFilePath,
625     PWSTR pwszLanguage,
626     PULONG pcchLanguage,
627     PWSTR pwszFileMUIPath,
628     PULONG pcchFileMUIPath,
629     PULONGLONG pululEnumerator)
630 {
631     DPRINT1("%x %p %p %p %p %p\n", dwFlags, pcwszFilePath, pwszLanguage, pwszFileMUIPath, pcchFileMUIPath, pululEnumerator);
632     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
633     return FALSE;
634 }
635 
636 /*
637  * @unimplemented
638  */
639 #if 0 // This is Windows 7+
640 BOOL
641 WINAPI
642 GetProcessPreferredUILanguages(
643     DWORD dwFlags,
644     PULONG pulNumLanguages,
645     PZZWSTR pwszLanguagesBuffer,
646     PULONG pcchLanguagesBuffer)
647 {
648     DPRINT1("%x %p %p %p\n", dwFlags, pulNumLanguages, pwszLanguagesBuffer, pcchLanguagesBuffer);
649     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
650     return FALSE;
651 }
652 #endif
653 
654 /*
655 * @unimplemented
656 */
657 BOOL
658 WINAPI
GetSystemPreferredUILanguages(DWORD dwFlags,PULONG pulNumLanguages,PZZWSTR pwszLanguagesBuffer,PULONG pcchLanguagesBuffer)659 GetSystemPreferredUILanguages(
660     DWORD dwFlags,
661     PULONG pulNumLanguages,
662     PZZWSTR pwszLanguagesBuffer,
663     PULONG pcchLanguagesBuffer)
664 {
665     DPRINT1("%x %p %p %p\n", dwFlags, pulNumLanguages, pwszLanguagesBuffer, pcchLanguagesBuffer);
666     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
667     return FALSE;
668 }
669 
670 /*
671  * @unimplemented
672  */
673 BOOL
674 WINAPI
GetThreadPreferredUILanguages(DWORD dwFlags,PULONG pulNumLanguages,PZZWSTR pwszLanguagesBuffer,PULONG pcchLanguagesBuffer)675 GetThreadPreferredUILanguages(
676     DWORD dwFlags,
677     PULONG pulNumLanguages,
678     PZZWSTR pwszLanguagesBuffer,
679     PULONG pcchLanguagesBuffer)
680 {
681     DPRINT1("%x %p %p %p\n", dwFlags, pulNumLanguages, pwszLanguagesBuffer, pcchLanguagesBuffer);
682     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
683     return FALSE;
684 }
685 
686 /*
687  * @unimplemented
688  */
689 LANGID
690 WINAPI
GetThreadUILanguage(VOID)691 GetThreadUILanguage(VOID)
692 {
693     UNIMPLEMENTED;
694     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
695     return 0;
696 }
697 
698 /*
699  * @unimplemented
700  */
701 BOOL
702 WINAPI
GetUILanguageInfo(DWORD dwFlags,PCZZWSTR pwmszLanguage,PZZWSTR pwszFallbackLanguages,PDWORD pcchFallbackLanguages,PDWORD pdwAttributes)703 GetUILanguageInfo(
704     DWORD dwFlags,
705     PCZZWSTR pwmszLanguage,
706     PZZWSTR pwszFallbackLanguages,
707     PDWORD pcchFallbackLanguages,
708     PDWORD pdwAttributes)
709 {
710     DPRINT1("%x %p %p %p %p\n", dwFlags, pwmszLanguage, pwszFallbackLanguages, pcchFallbackLanguages, pdwAttributes);
711     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
712     return FALSE;
713 }
714 
715 
716 /*
717  * @unimplemented
718  */
719 BOOL
720 WINAPI
GetUserPreferredUILanguages(DWORD dwFlags,PULONG pulNumLanguages,PZZWSTR pwszLanguagesBuffer,PULONG pcchLanguagesBuffer)721 GetUserPreferredUILanguages(
722     DWORD dwFlags,
723     PULONG pulNumLanguages,
724     PZZWSTR pwszLanguagesBuffer,
725     PULONG pcchLanguagesBuffer)
726 {
727     DPRINT1("%x %p %p %p\n", dwFlags, pulNumLanguages, pwszLanguagesBuffer, pcchLanguagesBuffer);
728     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
729     return FALSE;
730 }
731 
732 /*
733  * @unimplemented
734  */
735 #if 0 // Tis is Windows 7+
736 BOOL
737 WINAPI
738 SetProcessPreferredUILanguages(
739     DWORD dwFlags,
740     PCZZWSTR pwszLanguagesBuffer,
741     PULONG pulNumLanguages)
742 {
743     DPRINT1("%x %p %p\n", dwFlags, pwszLanguagesBuffer, pulNumLanguages);
744     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
745     return FALSE;
746 }
747 #endif
748 
749 /*
750  * @unimplemented
751  */
752 BOOL
753 WINAPI
SetThreadPreferredUILanguages(DWORD dwFlags,PCZZWSTR pwszLanguagesBuffer,PULONG pulNumLanguages)754 SetThreadPreferredUILanguages(
755     DWORD dwFlags,
756     PCZZWSTR pwszLanguagesBuffer,
757     PULONG pulNumLanguages
758     )
759 {
760     DPRINT1("%x %p %p\n", dwFlags, pwszLanguagesBuffer, pulNumLanguages);
761     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
762     return FALSE;
763 }
764 
765