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 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 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 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 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 164 ApplicationRecoveryFinished(IN BOOL bSuccess) 165 { 166 UNIMPLEMENTED; 167 } 168 169 170 /* 171 * @unimplemented 172 */ 173 HRESULT 174 WINAPI 175 ApplicationRecoveryInProgress(OUT PBOOL pbCancelled) 176 { 177 UNIMPLEMENTED; 178 return E_FAIL; 179 } 180 181 182 /* 183 * @unimplemented 184 */ 185 HRESULT 186 WINAPI 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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