1 /* 2 * ReactOS kernel 3 * Copyright (C) 2004 ReactOS Team 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 */ 19 /* 20 * COPYRIGHT: See COPYING in the top level directory 21 * PROJECT: ReactOS system libraries 22 * FILE: dll/win32/userenv/environment.c 23 * PURPOSE: User environment functions 24 * PROGRAMMER: Eric Kohl 25 */ 26 27 #include "precomp.h" 28 29 #define NDEBUG 30 #include <debug.h> 31 32 static 33 BOOL 34 SetUserEnvironmentVariable(PWSTR* Environment, 35 LPWSTR lpName, 36 LPWSTR lpValue, 37 BOOL bExpand) 38 { 39 NTSTATUS Status; 40 UNICODE_STRING Name; 41 UNICODE_STRING SrcValue, DstValue; 42 ULONG Length; 43 PVOID Buffer = NULL; 44 WCHAR ShortName[MAX_PATH]; 45 46 if (bExpand) 47 { 48 RtlInitUnicodeString(&SrcValue, lpValue); 49 50 Length = 2 * MAX_PATH * sizeof(WCHAR); 51 52 DstValue.Length = 0; 53 DstValue.MaximumLength = Length; 54 DstValue.Buffer = Buffer = LocalAlloc(LPTR, Length); 55 if (DstValue.Buffer == NULL) 56 { 57 DPRINT1("LocalAlloc() failed\n"); 58 return FALSE; 59 } 60 61 Status = RtlExpandEnvironmentStrings_U(*Environment, 62 &SrcValue, 63 &DstValue, 64 &Length); 65 if (!NT_SUCCESS(Status)) 66 { 67 DPRINT1("RtlExpandEnvironmentStrings_U() failed (Status %lx)\n", Status); 68 DPRINT1("Length %lu\n", Length); 69 70 if (Buffer) 71 LocalFree(Buffer); 72 73 return FALSE; 74 } 75 } 76 else 77 { 78 RtlInitUnicodeString(&DstValue, lpValue); 79 } 80 81 if (!_wcsicmp(lpName, L"TEMP") || !_wcsicmp(lpName, L"TMP")) 82 { 83 if (GetShortPathNameW(DstValue.Buffer, ShortName, ARRAYSIZE(ShortName))) 84 { 85 RtlInitUnicodeString(&DstValue, ShortName); 86 } 87 else 88 { 89 DPRINT("GetShortPathNameW() failed for %S (Error %lu)\n", DstValue.Buffer, GetLastError()); 90 } 91 92 DPRINT("Buffer: %S\n", ShortName); 93 } 94 95 RtlInitUnicodeString(&Name, lpName); 96 97 DPRINT("Value: %wZ\n", &DstValue); 98 99 Status = RtlSetEnvironmentVariable(Environment, 100 &Name, 101 &DstValue); 102 103 if (Buffer) 104 LocalFree(Buffer); 105 106 if (!NT_SUCCESS(Status)) 107 { 108 DPRINT1("RtlSetEnvironmentVariable() failed (Status %lx)\n", Status); 109 return FALSE; 110 } 111 112 return TRUE; 113 } 114 115 116 static 117 BOOL 118 AppendUserEnvironmentVariable(PWSTR* Environment, 119 LPWSTR lpName, 120 LPWSTR lpValue) 121 { 122 NTSTATUS Status; 123 UNICODE_STRING Name, Value; 124 125 RtlInitUnicodeString(&Name, lpName); 126 127 Value.Length = 0; 128 Value.MaximumLength = 1024 * sizeof(WCHAR); 129 Value.Buffer = LocalAlloc(LPTR, Value.MaximumLength); 130 if (Value.Buffer == NULL) 131 return FALSE; 132 133 Value.Buffer[0] = UNICODE_NULL; 134 135 Status = RtlQueryEnvironmentVariable_U(*Environment, 136 &Name, 137 &Value); 138 if (NT_SUCCESS(Status)) 139 RtlAppendUnicodeToString(&Value, L";"); 140 141 RtlAppendUnicodeToString(&Value, lpValue); 142 143 Status = RtlSetEnvironmentVariable(Environment, 144 &Name, 145 &Value); 146 LocalFree(Value.Buffer); 147 if (!NT_SUCCESS(Status)) 148 { 149 DPRINT1("RtlSetEnvironmentVariable() failed (Status %lx)\n", Status); 150 return FALSE; 151 } 152 153 return TRUE; 154 } 155 156 157 static 158 HKEY 159 GetCurrentUserKey(HANDLE hToken) 160 { 161 LONG Error; 162 UNICODE_STRING SidString; 163 HKEY hKey; 164 165 if (!GetUserSidStringFromToken(hToken, &SidString)) 166 { 167 DPRINT1("GetUserSidFromToken() failed\n"); 168 return NULL; 169 } 170 171 Error = RegOpenKeyExW(HKEY_USERS, 172 SidString.Buffer, 173 0, 174 MAXIMUM_ALLOWED, 175 &hKey); 176 if (Error != ERROR_SUCCESS) 177 { 178 DPRINT1("RegOpenKeyExW() failed (Error %ld)\n", Error); 179 RtlFreeUnicodeString(&SidString); 180 SetLastError((DWORD)Error); 181 return NULL; 182 } 183 184 RtlFreeUnicodeString(&SidString); 185 186 return hKey; 187 } 188 189 190 static 191 BOOL 192 GetUserAndDomainName(IN HANDLE hToken, 193 OUT LPWSTR *UserName, 194 OUT LPWSTR *DomainName) 195 { 196 BOOL bRet = TRUE; 197 PSID Sid = NULL; 198 LPWSTR lpUserName = NULL; 199 LPWSTR lpDomainName = NULL; 200 DWORD cbUserName = 0; 201 DWORD cbDomainName = 0; 202 SID_NAME_USE SidNameUse; 203 204 Sid = GetUserSid(hToken); 205 if (Sid == NULL) 206 { 207 DPRINT1("GetUserSid() failed\n"); 208 return FALSE; 209 } 210 211 if (!LookupAccountSidW(NULL, 212 Sid, 213 NULL, 214 &cbUserName, 215 NULL, 216 &cbDomainName, 217 &SidNameUse)) 218 { 219 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) 220 { 221 bRet = FALSE; 222 goto done; 223 } 224 } 225 226 lpUserName = LocalAlloc(LPTR, cbUserName * sizeof(WCHAR)); 227 if (lpUserName == NULL) 228 { 229 bRet = FALSE; 230 goto done; 231 } 232 233 lpDomainName = LocalAlloc(LPTR, cbDomainName * sizeof(WCHAR)); 234 if (lpDomainName == NULL) 235 { 236 bRet = FALSE; 237 goto done; 238 } 239 240 if (!LookupAccountSidW(NULL, 241 Sid, 242 lpUserName, 243 &cbUserName, 244 lpDomainName, 245 &cbDomainName, 246 &SidNameUse)) 247 { 248 bRet = FALSE; 249 goto done; 250 } 251 252 *UserName = lpUserName; 253 *DomainName = lpDomainName; 254 255 done: 256 if (bRet == FALSE) 257 { 258 if (lpUserName != NULL) 259 LocalFree(lpUserName); 260 261 if (lpDomainName != NULL) 262 LocalFree(lpDomainName); 263 } 264 265 LocalFree(Sid); 266 267 return bRet; 268 } 269 270 271 static 272 BOOL 273 SetUserEnvironment(PWSTR* Environment, 274 HKEY hKey, 275 LPWSTR lpSubKeyName) 276 { 277 LONG Error; 278 HKEY hEnvKey; 279 DWORD dwValues; 280 DWORD dwMaxValueNameLength; 281 DWORD dwMaxValueDataLength; 282 DWORD dwValueNameLength; 283 DWORD dwValueDataLength; 284 DWORD dwType; 285 DWORD i; 286 LPWSTR lpValueName; 287 LPWSTR lpValueData; 288 289 Error = RegOpenKeyExW(hKey, 290 lpSubKeyName, 291 0, 292 KEY_QUERY_VALUE, 293 &hEnvKey); 294 if (Error != ERROR_SUCCESS) 295 { 296 DPRINT1("RegOpenKeyExW() failed (Error %ld)\n", Error); 297 SetLastError((DWORD)Error); 298 return FALSE; 299 } 300 301 Error = RegQueryInfoKey(hEnvKey, 302 NULL, 303 NULL, 304 NULL, 305 NULL, 306 NULL, 307 NULL, 308 &dwValues, 309 &dwMaxValueNameLength, 310 &dwMaxValueDataLength, 311 NULL, 312 NULL); 313 if (Error != ERROR_SUCCESS) 314 { 315 DPRINT1("RegQueryInforKey() failed (Error %ld)\n", Error); 316 RegCloseKey(hEnvKey); 317 SetLastError((DWORD)Error); 318 return FALSE; 319 } 320 321 if (dwValues == 0) 322 { 323 RegCloseKey(hEnvKey); 324 return TRUE; 325 } 326 327 /* Allocate buffers */ 328 dwMaxValueNameLength++; 329 lpValueName = LocalAlloc(LPTR, dwMaxValueNameLength * sizeof(WCHAR)); 330 if (lpValueName == NULL) 331 { 332 RegCloseKey(hEnvKey); 333 return FALSE; 334 } 335 336 lpValueData = LocalAlloc(LPTR, dwMaxValueDataLength); 337 if (lpValueData == NULL) 338 { 339 LocalFree(lpValueName); 340 RegCloseKey(hEnvKey); 341 return FALSE; 342 } 343 344 /* Enumerate values */ 345 for (i = 0; i < dwValues; i++) 346 { 347 dwValueNameLength = dwMaxValueNameLength; 348 dwValueDataLength = dwMaxValueDataLength; 349 350 Error = RegEnumValueW(hEnvKey, 351 i, 352 lpValueName, 353 &dwValueNameLength, 354 NULL, 355 &dwType, 356 (LPBYTE)lpValueData, 357 &dwValueDataLength); 358 if (Error == ERROR_SUCCESS) 359 { 360 if (!_wcsicmp(lpValueName, L"PATH")) 361 { 362 /* Append 'Path' environment variable */ 363 AppendUserEnvironmentVariable(Environment, 364 lpValueName, 365 lpValueData); 366 } 367 else 368 { 369 /* Set environment variable */ 370 SetUserEnvironmentVariable(Environment, 371 lpValueName, 372 lpValueData, 373 (dwType == REG_EXPAND_SZ)); 374 } 375 } 376 else 377 { 378 LocalFree(lpValueData); 379 LocalFree(lpValueName); 380 RegCloseKey(hEnvKey); 381 382 return FALSE; 383 } 384 } 385 386 LocalFree(lpValueData); 387 LocalFree(lpValueName); 388 RegCloseKey(hEnvKey); 389 390 return TRUE; 391 } 392 393 394 static 395 BOOL 396 SetSystemEnvironment(PWSTR* Environment) 397 { 398 LONG Error; 399 HKEY hEnvKey; 400 DWORD dwValues; 401 DWORD dwMaxValueNameLength; 402 DWORD dwMaxValueDataLength; 403 DWORD dwValueNameLength; 404 DWORD dwValueDataLength; 405 DWORD dwType; 406 DWORD i; 407 LPWSTR lpValueName; 408 LPWSTR lpValueData; 409 410 Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 411 L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", 412 0, 413 KEY_QUERY_VALUE, 414 &hEnvKey); 415 if (Error != ERROR_SUCCESS) 416 { 417 DPRINT1("RegOpenKeyExW() failed (Error %ld)\n", Error); 418 return FALSE; 419 } 420 421 Error = RegQueryInfoKey(hEnvKey, 422 NULL, 423 NULL, 424 NULL, 425 NULL, 426 NULL, 427 NULL, 428 &dwValues, 429 &dwMaxValueNameLength, 430 &dwMaxValueDataLength, 431 NULL, 432 NULL); 433 if (Error != ERROR_SUCCESS) 434 { 435 DPRINT1("RegQueryInforKey() failed (Error %ld)\n", Error); 436 RegCloseKey(hEnvKey); 437 return FALSE; 438 } 439 440 if (dwValues == 0) 441 { 442 RegCloseKey(hEnvKey); 443 return TRUE; 444 } 445 446 /* Allocate buffers */ 447 dwMaxValueNameLength++; 448 lpValueName = LocalAlloc(LPTR, dwMaxValueNameLength * sizeof(WCHAR)); 449 if (lpValueName == NULL) 450 { 451 RegCloseKey(hEnvKey); 452 return FALSE; 453 } 454 455 lpValueData = LocalAlloc(LPTR, dwMaxValueDataLength); 456 if (lpValueData == NULL) 457 { 458 LocalFree(lpValueName); 459 RegCloseKey(hEnvKey); 460 return FALSE; 461 } 462 463 /* Enumerate values */ 464 for (i = 0; i < dwValues; i++) 465 { 466 dwValueNameLength = dwMaxValueNameLength; 467 dwValueDataLength = dwMaxValueDataLength; 468 469 Error = RegEnumValueW(hEnvKey, 470 i, 471 lpValueName, 472 &dwValueNameLength, 473 NULL, 474 &dwType, 475 (LPBYTE)lpValueData, 476 &dwValueDataLength); 477 if (Error == ERROR_SUCCESS) 478 { 479 /* Set environment variable */ 480 SetUserEnvironmentVariable(Environment, 481 lpValueName, 482 lpValueData, 483 (dwType == REG_EXPAND_SZ)); 484 } 485 else 486 { 487 LocalFree(lpValueData); 488 LocalFree(lpValueName); 489 RegCloseKey(hEnvKey); 490 491 return FALSE; 492 } 493 } 494 495 LocalFree(lpValueData); 496 LocalFree(lpValueName); 497 RegCloseKey(hEnvKey); 498 499 return TRUE; 500 } 501 502 503 BOOL 504 WINAPI 505 CreateEnvironmentBlock(OUT LPVOID *lpEnvironment, 506 IN HANDLE hToken, 507 IN BOOL bInherit) 508 { 509 NTSTATUS Status; 510 LONG lError; 511 PWSTR* Environment = (PWSTR*)lpEnvironment; 512 DWORD Length; 513 DWORD dwType; 514 HKEY hKey; 515 HKEY hKeyUser; 516 LPWSTR lpUserName = NULL; 517 LPWSTR lpDomainName = NULL; 518 WCHAR Buffer[MAX_PATH]; 519 WCHAR szValue[1024]; 520 521 DPRINT("CreateEnvironmentBlock() called\n"); 522 523 if (lpEnvironment == NULL) 524 { 525 SetLastError(ERROR_INVALID_PARAMETER); 526 return FALSE; 527 } 528 529 Status = RtlCreateEnvironment((BOOLEAN)bInherit, Environment); 530 if (!NT_SUCCESS(Status)) 531 { 532 DPRINT1("RtlCreateEnvironment() failed (Status %lx)\n", Status); 533 SetLastError(RtlNtStatusToDosError(Status)); 534 return FALSE; 535 } 536 537 /* Set 'SystemRoot' variable */ 538 Length = ARRAYSIZE(Buffer); 539 if (GetEnvironmentVariableW(L"SystemRoot", Buffer, Length)) 540 { 541 SetUserEnvironmentVariable(Environment, 542 L"SystemRoot", 543 Buffer, 544 FALSE); 545 } 546 547 /* Set 'SystemDrive' variable */ 548 if (GetEnvironmentVariableW(L"SystemDrive", Buffer, Length)) 549 { 550 SetUserEnvironmentVariable(Environment, 551 L"SystemDrive", 552 Buffer, 553 FALSE); 554 } 555 556 /* Set variables from Session Manager */ 557 if (!SetSystemEnvironment(Environment)) 558 { 559 RtlDestroyEnvironment(*Environment); 560 return FALSE; 561 } 562 563 /* Set 'COMPUTERNAME' variable */ 564 Length = ARRAYSIZE(Buffer); 565 if (GetComputerNameW(Buffer, &Length)) 566 { 567 SetUserEnvironmentVariable(Environment, 568 L"COMPUTERNAME", 569 Buffer, 570 FALSE); 571 } 572 573 /* Set 'ALLUSERSPROFILE' variable */ 574 Length = ARRAYSIZE(Buffer); 575 if (GetAllUsersProfileDirectoryW(Buffer, &Length)) 576 { 577 SetUserEnvironmentVariable(Environment, 578 L"ALLUSERSPROFILE", 579 Buffer, 580 FALSE); 581 } 582 583 /* Set 'USERPROFILE' variable to the default users profile */ 584 Length = ARRAYSIZE(Buffer); 585 if (GetDefaultUserProfileDirectoryW(Buffer, &Length)) 586 { 587 SetUserEnvironmentVariable(Environment, 588 L"USERPROFILE", 589 Buffer, 590 TRUE); 591 } 592 593 lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 594 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion", 595 0, 596 KEY_READ, 597 &hKey); 598 if (lError == ERROR_SUCCESS) 599 { 600 Length = sizeof(szValue); 601 lError = RegQueryValueExW(hKey, 602 L"ProgramFilesDir", 603 NULL, 604 &dwType, 605 (LPBYTE)szValue, 606 &Length); 607 if (lError == ERROR_SUCCESS) 608 { 609 SetUserEnvironmentVariable(Environment, 610 L"ProgramFiles", 611 szValue, 612 FALSE); 613 } 614 615 Length = sizeof(szValue); 616 lError = RegQueryValueExW(hKey, 617 L"CommonFilesDir", 618 NULL, 619 &dwType, 620 (LPBYTE)szValue, 621 &Length); 622 if (lError == ERROR_SUCCESS) 623 { 624 SetUserEnvironmentVariable(Environment, 625 L"CommonProgramFiles", 626 szValue, 627 FALSE); 628 } 629 630 RegCloseKey(hKey); 631 } 632 633 /* 634 * If no user token is specified, the system environment variables are set 635 * and we stop here, otherwise continue setting the user-specific variables. 636 */ 637 if (hToken == NULL) 638 return TRUE; 639 640 hKeyUser = GetCurrentUserKey(hToken); 641 if (hKeyUser == NULL) 642 { 643 DPRINT1("GetCurrentUserKey() failed\n"); 644 RtlDestroyEnvironment(*Environment); 645 return FALSE; 646 } 647 648 /* Set 'USERPROFILE' variable */ 649 Length = ARRAYSIZE(Buffer); 650 if (GetUserProfileDirectoryW(hToken, Buffer, &Length)) 651 { 652 DWORD MinLen = 2; 653 654 SetUserEnvironmentVariable(Environment, 655 L"USERPROFILE", 656 Buffer, 657 FALSE); 658 659 // FIXME: Strangely enough the following two environment variables 660 // are not set by userenv.dll in Windows... See r68284 / CORE-9875 661 // FIXME2: This is done by msgina.dll !! 662 663 /* At least <drive letter>:<path> */ 664 if (Length > MinLen) 665 { 666 /* Set 'HOMEDRIVE' variable */ 667 StringCchCopyNW(szValue, ARRAYSIZE(Buffer), Buffer, MinLen); 668 SetUserEnvironmentVariable(Environment, 669 L"HOMEDRIVE", 670 szValue, 671 FALSE); 672 673 /* Set 'HOMEPATH' variable */ 674 StringCchCopyNW(szValue, ARRAYSIZE(Buffer), Buffer + MinLen, Length - MinLen); 675 SetUserEnvironmentVariable(Environment, 676 L"HOMEPATH", 677 szValue, 678 FALSE); 679 } 680 } 681 else 682 { 683 DPRINT1("GetUserProfileDirectoryW failed with error %lu\n", GetLastError()); 684 } 685 686 if (GetUserAndDomainName(hToken, 687 &lpUserName, 688 &lpDomainName)) 689 { 690 /* Set 'USERNAME' variable */ 691 SetUserEnvironmentVariable(Environment, 692 L"USERNAME", 693 lpUserName, 694 FALSE); 695 696 /* Set 'USERDOMAIN' variable */ 697 SetUserEnvironmentVariable(Environment, 698 L"USERDOMAIN", 699 lpDomainName, 700 FALSE); 701 702 if (lpUserName != NULL) 703 LocalFree(lpUserName); 704 705 if (lpDomainName != NULL) 706 LocalFree(lpDomainName); 707 } 708 709 /* Set user environment variables */ 710 SetUserEnvironment(Environment, 711 hKeyUser, 712 L"Environment"); 713 714 /* Set user volatile environment variables */ 715 SetUserEnvironment(Environment, 716 hKeyUser, 717 L"Volatile Environment"); 718 719 RegCloseKey(hKeyUser); 720 721 return TRUE; 722 } 723 724 725 BOOL 726 WINAPI 727 DestroyEnvironmentBlock(IN LPVOID lpEnvironment) 728 { 729 DPRINT("DestroyEnvironmentBlock() called\n"); 730 731 if (lpEnvironment == NULL) 732 { 733 SetLastError(ERROR_INVALID_PARAMETER); 734 return FALSE; 735 } 736 737 RtlDestroyEnvironment(lpEnvironment); 738 739 return TRUE; 740 } 741 742 743 BOOL 744 WINAPI 745 ExpandEnvironmentStringsForUserW(IN HANDLE hToken, 746 IN LPCWSTR lpSrc, 747 OUT LPWSTR lpDest, 748 IN DWORD dwSize) 749 { 750 BOOL Ret = FALSE; 751 PVOID lpEnvironment; 752 753 if (lpSrc == NULL || lpDest == NULL || dwSize == 0) 754 { 755 SetLastError(ERROR_INVALID_PARAMETER); 756 return FALSE; 757 } 758 759 if (CreateEnvironmentBlock(&lpEnvironment, 760 hToken, 761 FALSE)) 762 { 763 UNICODE_STRING SrcU, DestU; 764 NTSTATUS Status; 765 766 /* Initialize the strings */ 767 RtlInitUnicodeString(&SrcU, lpSrc); 768 DestU.Length = 0; 769 DestU.MaximumLength = dwSize * sizeof(WCHAR); 770 DestU.Buffer = lpDest; 771 772 /* Expand the strings */ 773 Status = RtlExpandEnvironmentStrings_U((PWSTR)lpEnvironment, 774 &SrcU, 775 &DestU, 776 NULL); 777 778 DestroyEnvironmentBlock(lpEnvironment); 779 780 if (NT_SUCCESS(Status)) 781 { 782 Ret = TRUE; 783 } 784 else 785 { 786 SetLastError(RtlNtStatusToDosError(Status)); 787 } 788 } 789 790 return Ret; 791 } 792 793 794 BOOL 795 WINAPI 796 ExpandEnvironmentStringsForUserA(IN HANDLE hToken, 797 IN LPCSTR lpSrc, 798 OUT LPSTR lpDest, 799 IN DWORD dwSize) 800 { 801 BOOL Ret = FALSE; 802 DWORD dwSrcLen; 803 LPWSTR lpSrcW = NULL, lpDestW = NULL; 804 805 if (lpSrc == NULL || lpDest == NULL || dwSize == 0) 806 { 807 SetLastError(ERROR_INVALID_PARAMETER); 808 return FALSE; 809 } 810 811 dwSrcLen = strlen(lpSrc); 812 lpSrcW = (LPWSTR)GlobalAlloc(GMEM_FIXED, 813 (dwSrcLen + 1) * sizeof(WCHAR)); 814 if (lpSrcW == NULL || 815 MultiByteToWideChar(CP_ACP, 816 0, 817 lpSrc, 818 -1, 819 lpSrcW, 820 dwSrcLen + 1) == 0) 821 { 822 goto Cleanup; 823 } 824 825 lpDestW = (LPWSTR)GlobalAlloc(GMEM_FIXED, 826 dwSize * sizeof(WCHAR)); 827 if (lpDestW == NULL) 828 goto Cleanup; 829 830 Ret = ExpandEnvironmentStringsForUserW(hToken, 831 lpSrcW, 832 lpDestW, 833 dwSize); 834 if (Ret) 835 { 836 if (WideCharToMultiByte(CP_ACP, 837 0, 838 lpDestW, 839 -1, 840 lpDest, 841 dwSize, 842 NULL, 843 NULL) == 0) 844 { 845 Ret = FALSE; 846 } 847 } 848 849 Cleanup: 850 if (lpSrcW != NULL) 851 GlobalFree((HGLOBAL)lpSrcW); 852 853 if (lpDestW != NULL) 854 GlobalFree((HGLOBAL)lpDestW); 855 856 return Ret; 857 } 858 859 /* EOF */ 860