1 /* 2 * Advpack main 3 * 4 * Copyright 2004 Huw D M Davies 5 * Copyright 2005 Sami Aario 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 */ 21 22 #include <stdarg.h> 23 24 #include "windef.h" 25 #include "winbase.h" 26 #include "winuser.h" 27 #include "winreg.h" 28 #include "winternl.h" 29 #include "winnls.h" 30 #include "setupapi.h" 31 #include "advpub.h" 32 #include "wine/unicode.h" 33 #include "wine/debug.h" 34 #include "advpack_private.h" 35 36 WINE_DEFAULT_DEBUG_CHANNEL(advpack); 37 38 typedef HRESULT (WINAPI *DLLREGISTER) (void); 39 40 #define MAX_FIELD_LENGTH 512 41 #define PREFIX_LEN 5 42 43 /* registry path of the Installed Components key for per-user stubs */ 44 static const WCHAR setup_key[] = { 45 'S','O','F','T','W','A','R','E','\\', 46 'M','i','c','r','o','s','o','f','t','\\', 47 'A','c','t','i','v','e',' ','S','e','t','u','p','\\', 48 'I','n','s','t','a','l','l','e','d',' ', 49 'C','o','m','p','o','n','e','n','t','s',0 50 }; 51 52 /* Strip single quotes from a token - note size includes NULL */ 53 static void strip_quotes(WCHAR *buffer, DWORD *size) 54 { 55 if (buffer[0] == '\'' && (*size > 1) && buffer[*size-2]=='\'') 56 { 57 *size -= 2; 58 buffer[*size] = 0x00; 59 memmove(buffer, buffer + 1, *size * sizeof(WCHAR)); 60 } 61 } 62 63 /* parses the destination directory parameters from pszSection 64 * the parameters are of the form: root,key,value,unknown,fallback 65 * we first read the reg value root\\key\\value and if that fails, 66 * use fallback as the destination directory 67 */ 68 static void get_dest_dir(HINF hInf, PCWSTR pszSection, PWSTR pszBuffer, DWORD dwSize) 69 { 70 INFCONTEXT context; 71 WCHAR key[MAX_PATH + 2], value[MAX_PATH + 2]; 72 WCHAR prefix[PREFIX_LEN + 2]; 73 HKEY root, subkey = 0; 74 DWORD size; 75 76 static const WCHAR hklm[] = {'H','K','L','M',0}; 77 static const WCHAR hkcu[] = {'H','K','C','U',0}; 78 79 /* load the destination parameters */ 80 SetupFindFirstLineW(hInf, pszSection, NULL, &context); 81 SetupGetStringFieldW(&context, 1, prefix, PREFIX_LEN + 2, &size); 82 strip_quotes(prefix, &size); 83 SetupGetStringFieldW(&context, 2, key, MAX_PATH + 2, &size); 84 strip_quotes(key, &size); 85 SetupGetStringFieldW(&context, 3, value, MAX_PATH + 2, &size); 86 strip_quotes(value, &size); 87 88 if (!lstrcmpW(prefix, hklm)) 89 root = HKEY_LOCAL_MACHINE; 90 else if (!lstrcmpW(prefix, hkcu)) 91 root = HKEY_CURRENT_USER; 92 else 93 root = NULL; 94 95 size = dwSize * sizeof(WCHAR); 96 97 /* fallback to the default destination dir if reg fails */ 98 if (RegOpenKeyW(root, key, &subkey) || 99 RegQueryValueExW(subkey, value, NULL, NULL, (LPBYTE)pszBuffer, &size)) 100 { 101 SetupGetStringFieldW(&context, 5, pszBuffer, dwSize, &size); 102 strip_quotes(pszBuffer, &size); 103 } 104 105 if (subkey) RegCloseKey(subkey); 106 } 107 108 /* loads the LDIDs specified in the install section of an INF */ 109 void set_ldids(HINF hInf, LPCWSTR pszInstallSection, LPCWSTR pszWorkingDir) 110 { 111 WCHAR field[MAX_FIELD_LENGTH]; 112 WCHAR line[MAX_FIELD_LENGTH]; 113 WCHAR dest[MAX_PATH]; 114 INFCONTEXT context; 115 DWORD size; 116 int ldid; 117 118 static const WCHAR source_dir[] = {'S','o','u','r','c','e','D','i','r',0}; 119 120 static const WCHAR custDestW[] = { 121 'C','u','s','t','o','m','D','e','s','t','i','n','a','t','i','o','n',0 122 }; 123 124 if (!SetupGetLineTextW(NULL, hInf, pszInstallSection, custDestW, 125 field, MAX_FIELD_LENGTH, &size)) 126 return; 127 128 if (!SetupFindFirstLineW(hInf, field, NULL, &context)) 129 return; 130 131 do 132 { 133 LPWSTR value, ptr, key, key_copy = NULL; 134 DWORD flags = 0; 135 136 SetupGetLineTextW(&context, NULL, NULL, NULL, 137 line, MAX_FIELD_LENGTH, &size); 138 139 /* SetupGetLineTextW returns the value if there is only one key, but 140 * returns the whole line if there is more than one key 141 */ 142 if (!(value = strchrW(line, '='))) 143 { 144 SetupGetStringFieldW(&context, 0, NULL, 0, &size); 145 key = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)); 146 key_copy = key; 147 SetupGetStringFieldW(&context, 0, key, size, &size); 148 value = line; 149 } 150 else 151 { 152 key = line; 153 *(value++) = '\0'; 154 } 155 156 /* remove leading whitespace from the value */ 157 while (*value == ' ') 158 value++; 159 160 /* Extract the flags */ 161 ptr = strchrW(value, ','); 162 if (ptr) { 163 *ptr = '\0'; 164 flags = atolW(ptr+1); 165 } 166 167 /* set dest to pszWorkingDir if key is SourceDir */ 168 if (pszWorkingDir && !lstrcmpiW(value, source_dir)) 169 lstrcpynW(dest, pszWorkingDir, MAX_PATH); 170 else 171 get_dest_dir(hInf, value, dest, MAX_PATH); 172 173 /* If prompting required, provide dialog to request path */ 174 if (flags & 0x04) 175 FIXME("Need to support changing paths - default will be used\n"); 176 177 /* set all ldids to dest */ 178 while ((ptr = get_parameter(&key, ',', FALSE))) 179 { 180 ldid = atolW(ptr); 181 SetupSetDirectoryIdW(hInf, ldid, dest); 182 } 183 HeapFree(GetProcessHeap(), 0, key_copy); 184 } while (SetupFindNextLine(&context, &context)); 185 } 186 187 /*********************************************************************** 188 * CloseINFEngine (ADVPACK.@) 189 * 190 * Closes a handle to an INF file opened with OpenINFEngine. 191 * 192 * PARAMS 193 * hInf [I] Handle to the INF file to close. 194 * 195 * RETURNS 196 * Success: S_OK. 197 * Failure: E_FAIL. 198 */ 199 HRESULT WINAPI CloseINFEngine(HINF hInf) 200 { 201 TRACE("(%p)\n", hInf); 202 203 if (!hInf) 204 return E_INVALIDARG; 205 206 SetupCloseInfFile(hInf); 207 return S_OK; 208 } 209 210 /*********************************************************************** 211 * IsNTAdmin (ADVPACK.@) 212 * 213 * Checks if the user has admin privileges. 214 * 215 * PARAMS 216 * reserved [I] Reserved. Must be 0. 217 * pReserved [I] Reserved. Must be NULL. 218 * 219 * RETURNS 220 * TRUE if user has admin rights, FALSE otherwise. 221 */ 222 BOOL WINAPI IsNTAdmin(DWORD reserved, LPDWORD pReserved) 223 { 224 SID_IDENTIFIER_AUTHORITY SidAuthority = {SECURITY_NT_AUTHORITY}; 225 PTOKEN_GROUPS pTokenGroups; 226 BOOL bSidFound = FALSE; 227 DWORD dwSize, i; 228 HANDLE hToken; 229 PSID pSid; 230 231 TRACE("(%d, %p)\n", reserved, pReserved); 232 233 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) 234 return FALSE; 235 236 if (!GetTokenInformation(hToken, TokenGroups, NULL, 0, &dwSize)) 237 { 238 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) 239 { 240 CloseHandle(hToken); 241 return FALSE; 242 } 243 } 244 245 pTokenGroups = HeapAlloc(GetProcessHeap(), 0, dwSize); 246 if (!pTokenGroups) 247 { 248 CloseHandle(hToken); 249 return FALSE; 250 } 251 252 if (!GetTokenInformation(hToken, TokenGroups, pTokenGroups, dwSize, &dwSize)) 253 { 254 HeapFree(GetProcessHeap(), 0, pTokenGroups); 255 CloseHandle(hToken); 256 return FALSE; 257 } 258 259 CloseHandle(hToken); 260 261 if (!AllocateAndInitializeSid(&SidAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, 262 DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pSid)) 263 { 264 HeapFree(GetProcessHeap(), 0, pTokenGroups); 265 return FALSE; 266 } 267 268 for (i = 0; i < pTokenGroups->GroupCount; i++) 269 { 270 if (EqualSid(pSid, pTokenGroups->Groups[i].Sid)) 271 { 272 bSidFound = TRUE; 273 break; 274 } 275 } 276 277 HeapFree(GetProcessHeap(), 0, pTokenGroups); 278 FreeSid(pSid); 279 280 return bSidFound; 281 } 282 283 /*********************************************************************** 284 * NeedRebootInit (ADVPACK.@) 285 * 286 * Sets up conditions for reboot checking. 287 * 288 * RETURNS 289 * Value required by NeedReboot. 290 */ 291 DWORD WINAPI NeedRebootInit(VOID) 292 { 293 FIXME("(VOID): stub\n"); 294 return 0; 295 } 296 297 /*********************************************************************** 298 * NeedReboot (ADVPACK.@) 299 * 300 * Determines whether a reboot is required. 301 * 302 * PARAMS 303 * dwRebootCheck [I] Value from NeedRebootInit. 304 * 305 * RETURNS 306 * TRUE if a reboot is needed, FALSE otherwise. 307 * 308 * BUGS 309 * Unimplemented. 310 */ 311 BOOL WINAPI NeedReboot(DWORD dwRebootCheck) 312 { 313 FIXME("(%d): stub\n", dwRebootCheck); 314 return FALSE; 315 } 316 317 /*********************************************************************** 318 * OpenINFEngineA (ADVPACK.@) 319 * 320 * See OpenINFEngineW. 321 */ 322 HRESULT WINAPI OpenINFEngineA(LPCSTR pszInfFilename, LPCSTR pszInstallSection, 323 DWORD dwFlags, HINF *phInf, PVOID pvReserved) 324 { 325 UNICODE_STRING filenameW, installW; 326 HRESULT res; 327 328 TRACE("(%s, %s, %d, %p, %p)\n", debugstr_a(pszInfFilename), 329 debugstr_a(pszInstallSection), dwFlags, phInf, pvReserved); 330 331 if (!pszInfFilename || !phInf) 332 return E_INVALIDARG; 333 334 RtlCreateUnicodeStringFromAsciiz(&filenameW, pszInfFilename); 335 RtlCreateUnicodeStringFromAsciiz(&installW, pszInstallSection); 336 337 res = OpenINFEngineW(filenameW.Buffer, installW.Buffer, 338 dwFlags, phInf, pvReserved); 339 340 RtlFreeUnicodeString(&filenameW); 341 RtlFreeUnicodeString(&installW); 342 343 return res; 344 } 345 346 /*********************************************************************** 347 * OpenINFEngineW (ADVPACK.@) 348 * 349 * Opens and returns a handle to an INF file to be used by 350 * TranslateInfStringEx to continuously translate the INF file. 351 * 352 * PARAMS 353 * pszInfFilename [I] Filename of the INF to open. 354 * pszInstallSection [I] Name of the Install section in the INF. 355 * dwFlags [I] See advpub.h. 356 * phInf [O] Handle to the loaded INF file. 357 * pvReserved [I] Reserved. Must be NULL. 358 * 359 * RETURNS 360 * Success: S_OK. 361 * Failure: E_FAIL. 362 */ 363 HRESULT WINAPI OpenINFEngineW(LPCWSTR pszInfFilename, LPCWSTR pszInstallSection, 364 DWORD dwFlags, HINF *phInf, PVOID pvReserved) 365 { 366 TRACE("(%s, %s, %d, %p, %p)\n", debugstr_w(pszInfFilename), 367 debugstr_w(pszInstallSection), dwFlags, phInf, pvReserved); 368 369 if (!pszInfFilename || !phInf) 370 return E_INVALIDARG; 371 372 *phInf = SetupOpenInfFileW(pszInfFilename, NULL, INF_STYLE_WIN4, NULL); 373 if (*phInf == INVALID_HANDLE_VALUE) 374 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); 375 376 set_ldids(*phInf, pszInstallSection, NULL); 377 378 return S_OK; 379 } 380 381 /*********************************************************************** 382 * RebootCheckOnInstallA (ADVPACK.@) 383 * 384 * See RebootCheckOnInstallW. 385 */ 386 HRESULT WINAPI RebootCheckOnInstallA(HWND hWnd, LPCSTR pszINF, 387 LPCSTR pszSec, DWORD dwReserved) 388 { 389 UNICODE_STRING infW, secW; 390 HRESULT res; 391 392 TRACE("(%p, %s, %s, %d)\n", hWnd, debugstr_a(pszINF), 393 debugstr_a(pszSec), dwReserved); 394 395 if (!pszINF || !pszSec) 396 return E_INVALIDARG; 397 398 RtlCreateUnicodeStringFromAsciiz(&infW, pszINF); 399 RtlCreateUnicodeStringFromAsciiz(&secW, pszSec); 400 401 res = RebootCheckOnInstallW(hWnd, infW.Buffer, secW.Buffer, dwReserved); 402 403 RtlFreeUnicodeString(&infW); 404 RtlFreeUnicodeString(&secW); 405 406 return res; 407 } 408 409 /*********************************************************************** 410 * RebootCheckOnInstallW (ADVPACK.@) 411 * 412 * Checks if a reboot is required for an installed INF section. 413 * 414 * PARAMS 415 * hWnd [I] Handle to the window used for messages. 416 * pszINF [I] Filename of the INF file. 417 * pszSec [I] INF section to check. 418 * dwReserved [I] Reserved. Must be 0. 419 * 420 * RETURNS 421 * Success: S_OK - Reboot is needed if the INF section is installed. 422 * S_FALSE - Reboot is not needed. 423 * Failure: HRESULT of GetLastError(). 424 * 425 * NOTES 426 * if pszSec is NULL, RebootCheckOnInstall checks the DefaultInstall 427 * or DefaultInstall.NT section. 428 * 429 * BUGS 430 * Unimplemented. 431 */ 432 HRESULT WINAPI RebootCheckOnInstallW(HWND hWnd, LPCWSTR pszINF, 433 LPCWSTR pszSec, DWORD dwReserved) 434 { 435 FIXME("(%p, %s, %s, %d): stub\n", hWnd, debugstr_w(pszINF), 436 debugstr_w(pszSec), dwReserved); 437 438 return E_FAIL; 439 } 440 441 /* registers the OCX if do_reg is TRUE, unregisters it otherwise */ 442 HRESULT do_ocx_reg(HMODULE hocx, BOOL do_reg, const WCHAR *flags, const WCHAR *param) 443 { 444 DLLREGISTER reg_func; 445 446 if (do_reg) 447 reg_func = (DLLREGISTER)GetProcAddress(hocx, "DllRegisterServer"); 448 else 449 reg_func = (DLLREGISTER)GetProcAddress(hocx, "DllUnregisterServer"); 450 451 if (!reg_func) 452 return E_FAIL; 453 454 reg_func(); 455 return S_OK; 456 } 457 458 /*********************************************************************** 459 * RegisterOCX (ADVPACK.@) 460 * 461 * Registers an OCX. 462 * 463 * PARAMS 464 * hWnd [I] Handle to the window used for the display. 465 * hInst [I] Instance of the process. 466 * cmdline [I] Contains parameters in the order OCX,flags,param. 467 * show [I] How the window should be shown. 468 * 469 * RETURNS 470 * Success: S_OK. 471 * Failure: E_FAIL. 472 * 473 * NOTES 474 * OCX - Filename of the OCX to register. 475 * flags - Controls the operation of RegisterOCX. 476 * 'I' Call DllRegisterServer and DllInstall. 477 * 'N' Only call DllInstall. 478 * param - Command line passed to DllInstall. 479 */ 480 HRESULT WINAPI RegisterOCX(HWND hWnd, HINSTANCE hInst, LPCSTR cmdline, INT show) 481 { 482 LPWSTR ocx_filename, str_flags, param; 483 LPWSTR cmdline_copy, cmdline_ptr; 484 UNICODE_STRING cmdlineW; 485 HRESULT hr = E_FAIL; 486 HMODULE hm = NULL; 487 DWORD size; 488 489 TRACE("(%s)\n", debugstr_a(cmdline)); 490 491 RtlCreateUnicodeStringFromAsciiz(&cmdlineW, cmdline); 492 493 size = (lstrlenW(cmdlineW.Buffer) + 1) * sizeof(WCHAR); 494 cmdline_copy = HeapAlloc(GetProcessHeap(), 0, size); 495 cmdline_ptr = cmdline_copy; 496 lstrcpyW(cmdline_copy, cmdlineW.Buffer); 497 498 ocx_filename = get_parameter(&cmdline_ptr, ',', TRUE); 499 if (!ocx_filename || !*ocx_filename) 500 goto done; 501 502 str_flags = get_parameter(&cmdline_ptr, ',', TRUE); 503 param = get_parameter(&cmdline_ptr, ',', TRUE); 504 505 hm = LoadLibraryExW(ocx_filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); 506 if (!hm) 507 goto done; 508 509 hr = do_ocx_reg(hm, TRUE, str_flags, param); 510 511 done: 512 FreeLibrary(hm); 513 HeapFree(GetProcessHeap(), 0, cmdline_copy); 514 RtlFreeUnicodeString(&cmdlineW); 515 516 return hr; 517 } 518 519 /*********************************************************************** 520 * SetPerUserSecValuesA (ADVPACK.@) 521 * 522 * See SetPerUserSecValuesW. 523 */ 524 HRESULT WINAPI SetPerUserSecValuesA(PERUSERSECTIONA* pPerUser) 525 { 526 PERUSERSECTIONW perUserW; 527 528 TRACE("(%p)\n", pPerUser); 529 530 if (!pPerUser) 531 return E_INVALIDARG; 532 533 MultiByteToWideChar(CP_ACP, 0, pPerUser->szGUID, -1, perUserW.szGUID, 534 sizeof(perUserW.szGUID) / sizeof(WCHAR)); 535 MultiByteToWideChar(CP_ACP, 0, pPerUser->szDispName, -1, perUserW.szDispName, 536 sizeof(perUserW.szDispName) / sizeof(WCHAR)); 537 MultiByteToWideChar(CP_ACP, 0, pPerUser->szLocale, -1, perUserW.szLocale, 538 sizeof(perUserW.szLocale) / sizeof(WCHAR)); 539 MultiByteToWideChar(CP_ACP, 0, pPerUser->szStub, -1, perUserW.szStub, 540 sizeof(perUserW.szStub) / sizeof(WCHAR)); 541 MultiByteToWideChar(CP_ACP, 0, pPerUser->szVersion, -1, perUserW.szVersion, 542 sizeof(perUserW.szVersion) / sizeof(WCHAR)); 543 MultiByteToWideChar(CP_ACP, 0, pPerUser->szCompID, -1, perUserW.szCompID, 544 sizeof(perUserW.szCompID) / sizeof(WCHAR)); 545 perUserW.dwIsInstalled = pPerUser->dwIsInstalled; 546 perUserW.bRollback = pPerUser->bRollback; 547 548 return SetPerUserSecValuesW(&perUserW); 549 } 550 551 /*********************************************************************** 552 * SetPerUserSecValuesW (ADVPACK.@) 553 * 554 * Prepares the per-user stub values under IsInstalled\{GUID} that 555 * control the per-user installation. 556 * 557 * PARAMS 558 * pPerUser [I] Per-user stub values. 559 * 560 * RETURNS 561 * Success: S_OK. 562 * Failure: E_FAIL. 563 */ 564 HRESULT WINAPI SetPerUserSecValuesW(PERUSERSECTIONW* pPerUser) 565 { 566 HKEY setup, guid; 567 568 static const WCHAR stub_path[] = {'S','t','u','b','P','a','t','h',0}; 569 static const WCHAR version[] = {'V','e','r','s','i','o','n',0}; 570 static const WCHAR locale[] = {'L','o','c','a','l','e',0}; 571 static const WCHAR compid[] = {'C','o','m','p','o','n','e','n','t','I','D',0}; 572 static const WCHAR isinstalled[] = {'I','s','I','n','s','t','a','l','l','e','d',0}; 573 574 TRACE("(%p)\n", pPerUser); 575 576 if (!pPerUser || !*pPerUser->szGUID) 577 return S_OK; 578 579 if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, setup_key, 0, NULL, 0, KEY_WRITE, 580 NULL, &setup, NULL)) 581 { 582 return E_FAIL; 583 } 584 585 if (RegCreateKeyExW(setup, pPerUser->szGUID, 0, NULL, 0, KEY_ALL_ACCESS, 586 NULL, &guid, NULL)) 587 { 588 RegCloseKey(setup); 589 return E_FAIL; 590 } 591 592 if (*pPerUser->szStub) 593 { 594 RegSetValueExW(guid, stub_path, 0, REG_SZ, (LPBYTE)pPerUser->szStub, 595 (lstrlenW(pPerUser->szStub) + 1) * sizeof(WCHAR)); 596 } 597 598 if (*pPerUser->szVersion) 599 { 600 RegSetValueExW(guid, version, 0, REG_SZ, (LPBYTE)pPerUser->szVersion, 601 (lstrlenW(pPerUser->szVersion) + 1) * sizeof(WCHAR)); 602 } 603 604 if (*pPerUser->szLocale) 605 { 606 RegSetValueExW(guid, locale, 0, REG_SZ, (LPBYTE)pPerUser->szLocale, 607 (lstrlenW(pPerUser->szLocale) + 1) * sizeof(WCHAR)); 608 } 609 610 if (*pPerUser->szCompID) 611 { 612 RegSetValueExW(guid, compid, 0, REG_SZ, (LPBYTE)pPerUser->szCompID, 613 (lstrlenW(pPerUser->szCompID) + 1) * sizeof(WCHAR)); 614 } 615 616 if (*pPerUser->szDispName) 617 { 618 RegSetValueExW(guid, NULL, 0, REG_SZ, (LPBYTE)pPerUser->szDispName, 619 (lstrlenW(pPerUser->szDispName) + 1) * sizeof(WCHAR)); 620 } 621 622 RegSetValueExW(guid, isinstalled, 0, REG_DWORD, 623 (LPBYTE)&pPerUser->dwIsInstalled, sizeof(DWORD)); 624 625 RegCloseKey(guid); 626 RegCloseKey(setup); 627 628 return S_OK; 629 } 630 631 /*********************************************************************** 632 * TranslateInfStringA (ADVPACK.@) 633 * 634 * See TranslateInfStringW. 635 */ 636 HRESULT WINAPI TranslateInfStringA(LPCSTR pszInfFilename, LPCSTR pszInstallSection, 637 LPCSTR pszTranslateSection, LPCSTR pszTranslateKey, LPSTR pszBuffer, 638 DWORD dwBufferSize, PDWORD pdwRequiredSize, PVOID pvReserved) 639 { 640 UNICODE_STRING filenameW, installW; 641 UNICODE_STRING translateW, keyW; 642 LPWSTR bufferW; 643 HRESULT res; 644 DWORD len = 0; 645 646 TRACE("(%s, %s, %s, %s, %p, %d, %p, %p)\n", 647 debugstr_a(pszInfFilename), debugstr_a(pszInstallSection), 648 debugstr_a(pszTranslateSection), debugstr_a(pszTranslateKey), 649 pszBuffer, dwBufferSize,pdwRequiredSize, pvReserved); 650 651 if (!pszInfFilename || !pszTranslateSection || 652 !pszTranslateKey || !pdwRequiredSize) 653 return E_INVALIDARG; 654 655 RtlCreateUnicodeStringFromAsciiz(&filenameW, pszInfFilename); 656 RtlCreateUnicodeStringFromAsciiz(&installW, pszInstallSection); 657 RtlCreateUnicodeStringFromAsciiz(&translateW, pszTranslateSection); 658 RtlCreateUnicodeStringFromAsciiz(&keyW, pszTranslateKey); 659 660 res = TranslateInfStringW(filenameW.Buffer, installW.Buffer, 661 translateW.Buffer, keyW.Buffer, NULL, 662 dwBufferSize, &len, NULL); 663 664 if (res == S_OK) 665 { 666 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 667 668 res = TranslateInfStringW(filenameW.Buffer, installW.Buffer, 669 translateW.Buffer, keyW.Buffer, bufferW, 670 len, &len, NULL); 671 if (res == S_OK) 672 { 673 *pdwRequiredSize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, 674 NULL, 0, NULL, NULL); 675 676 if (dwBufferSize >= *pdwRequiredSize) 677 { 678 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, pszBuffer, 679 dwBufferSize, NULL, NULL); 680 } 681 else 682 res = E_NOT_SUFFICIENT_BUFFER; 683 } 684 685 HeapFree(GetProcessHeap(), 0, bufferW); 686 } 687 688 RtlFreeUnicodeString(&filenameW); 689 RtlFreeUnicodeString(&installW); 690 RtlFreeUnicodeString(&translateW); 691 RtlFreeUnicodeString(&keyW); 692 693 return res; 694 } 695 696 /*********************************************************************** 697 * TranslateInfStringW (ADVPACK.@) 698 * 699 * Translates the value of a specified key in an inf file into the 700 * current locale by expanding string macros. 701 * 702 * PARAMS 703 * pszInfFilename [I] Filename of the inf file. 704 * pszInstallSection [I] 705 * pszTranslateSection [I] Inf section where the key exists. 706 * pszTranslateKey [I] Key to translate. 707 * pszBuffer [O] Contains the translated string on exit. 708 * dwBufferSize [I] Size on input of pszBuffer. 709 * pdwRequiredSize [O] Length of the translated key. 710 * pvReserved [I] Reserved, must be NULL. 711 * 712 * RETURNS 713 * Success: S_OK. 714 * Failure: An hresult error code. 715 */ 716 HRESULT WINAPI TranslateInfStringW(LPCWSTR pszInfFilename, LPCWSTR pszInstallSection, 717 LPCWSTR pszTranslateSection, LPCWSTR pszTranslateKey, LPWSTR pszBuffer, 718 DWORD dwBufferSize, PDWORD pdwRequiredSize, PVOID pvReserved) 719 { 720 HINF hInf; 721 HRESULT hret = S_OK; 722 723 TRACE("(%s, %s, %s, %s, %p, %d, %p, %p)\n", 724 debugstr_w(pszInfFilename), debugstr_w(pszInstallSection), 725 debugstr_w(pszTranslateSection), debugstr_w(pszTranslateKey), 726 pszBuffer, dwBufferSize,pdwRequiredSize, pvReserved); 727 728 if (!pszInfFilename || !pszTranslateSection || 729 !pszTranslateKey || !pdwRequiredSize) 730 return E_INVALIDARG; 731 732 hInf = SetupOpenInfFileW(pszInfFilename, NULL, INF_STYLE_WIN4, NULL); 733 if (hInf == INVALID_HANDLE_VALUE) 734 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); 735 736 set_ldids(hInf, pszInstallSection, NULL); 737 738 if (!SetupGetLineTextW(NULL, hInf, pszTranslateSection, pszTranslateKey, 739 pszBuffer, dwBufferSize, pdwRequiredSize)) 740 { 741 if (dwBufferSize < *pdwRequiredSize) 742 hret = E_NOT_SUFFICIENT_BUFFER; 743 else 744 hret = SPAPI_E_LINE_NOT_FOUND; 745 } 746 747 SetupCloseInfFile(hInf); 748 return hret; 749 } 750 751 /*********************************************************************** 752 * TranslateInfStringExA (ADVPACK.@) 753 * 754 * See TranslateInfStringExW. 755 */ 756 HRESULT WINAPI TranslateInfStringExA(HINF hInf, LPCSTR pszInfFilename, 757 LPCSTR pszTranslateSection, LPCSTR pszTranslateKey, 758 LPSTR pszBuffer, DWORD dwBufferSize, 759 PDWORD pdwRequiredSize, PVOID pvReserved) 760 { 761 UNICODE_STRING filenameW, sectionW, keyW; 762 LPWSTR bufferW; 763 HRESULT res; 764 DWORD len = 0; 765 766 TRACE("(%p, %s, %s, %s, %p, %d, %p, %p)\n", hInf, debugstr_a(pszInfFilename), 767 debugstr_a(pszTranslateSection), debugstr_a(pszTranslateKey), 768 pszBuffer, dwBufferSize, pdwRequiredSize, pvReserved); 769 770 if (!pszInfFilename || !pszTranslateSection || 771 !pszTranslateKey || !pdwRequiredSize) 772 return E_INVALIDARG; 773 774 RtlCreateUnicodeStringFromAsciiz(&filenameW, pszInfFilename); 775 RtlCreateUnicodeStringFromAsciiz(§ionW, pszTranslateSection); 776 RtlCreateUnicodeStringFromAsciiz(&keyW, pszTranslateKey); 777 778 res = TranslateInfStringExW(hInf, filenameW.Buffer, sectionW.Buffer, 779 keyW.Buffer, NULL, 0, &len, NULL); 780 781 if (res == S_OK) 782 { 783 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 784 785 res = TranslateInfStringExW(hInf, filenameW.Buffer, sectionW.Buffer, 786 keyW.Buffer, bufferW, len, &len, NULL); 787 788 if (res == S_OK) 789 { 790 *pdwRequiredSize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, 791 NULL, 0, NULL, NULL); 792 793 if (dwBufferSize >= *pdwRequiredSize) 794 { 795 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, pszBuffer, 796 dwBufferSize, NULL, NULL); 797 } 798 else 799 res = E_NOT_SUFFICIENT_BUFFER; 800 } 801 802 HeapFree(GetProcessHeap(), 0, bufferW); 803 } 804 805 RtlFreeUnicodeString(&filenameW); 806 RtlFreeUnicodeString(§ionW); 807 RtlFreeUnicodeString(&keyW); 808 809 return res; 810 } 811 812 /*********************************************************************** 813 * TranslateInfStringExW (ADVPACK.@) 814 * 815 * Using a handle to an INF file opened with OpenINFEngine, translates 816 * the value of a specified key in an inf file into the current locale 817 * by expanding string macros. 818 * 819 * PARAMS 820 * hInf [I] Handle to the INF file. 821 * pszInfFilename [I] Filename of the INF file. 822 * pszTranslateSection [I] Inf section where the key exists. 823 * pszTranslateKey [I] Key to translate. 824 * pszBuffer [O] Contains the translated string on exit. 825 * dwBufferSize [I] Size on input of pszBuffer. 826 * pdwRequiredSize [O] Length of the translated key. 827 * pvReserved [I] Reserved. Must be NULL. 828 * 829 * RETURNS 830 * Success: S_OK. 831 * Failure: E_FAIL. 832 * 833 * NOTES 834 * To use TranslateInfStringEx to translate an INF file continuously, 835 * open the INF file with OpenINFEngine, call TranslateInfStringEx as 836 * many times as needed, then release the handle with CloseINFEngine. 837 * When translating more than one keys, this method is more efficient 838 * than calling TranslateInfString, because the INF file is only 839 * opened once. 840 */ 841 HRESULT WINAPI TranslateInfStringExW(HINF hInf, LPCWSTR pszInfFilename, 842 LPCWSTR pszTranslateSection, LPCWSTR pszTranslateKey, 843 LPWSTR pszBuffer, DWORD dwBufferSize, 844 PDWORD pdwRequiredSize, PVOID pvReserved) 845 { 846 TRACE("(%p, %s, %s, %s, %p, %d, %p, %p)\n", hInf, debugstr_w(pszInfFilename), 847 debugstr_w(pszTranslateSection), debugstr_w(pszTranslateKey), 848 pszBuffer, dwBufferSize, pdwRequiredSize, pvReserved); 849 850 if (!hInf || !pszInfFilename || !pszTranslateSection || !pszTranslateKey) 851 return E_INVALIDARG; 852 853 if (!SetupGetLineTextW(NULL, hInf, pszTranslateSection, pszTranslateKey, 854 pszBuffer, dwBufferSize, pdwRequiredSize)) 855 { 856 if (dwBufferSize < *pdwRequiredSize) 857 return E_NOT_SUFFICIENT_BUFFER; 858 859 return SPAPI_E_LINE_NOT_FOUND; 860 } 861 862 return S_OK; 863 } 864 865 /*********************************************************************** 866 * UserInstStubWrapperA (ADVPACK.@) 867 * 868 * See UserInstStubWrapperW. 869 */ 870 HRESULT WINAPI UserInstStubWrapperA(HWND hWnd, HINSTANCE hInstance, 871 LPSTR pszParms, INT nShow) 872 { 873 UNICODE_STRING parmsW; 874 HRESULT res; 875 876 TRACE("(%p, %p, %s, %i)\n", hWnd, hInstance, debugstr_a(pszParms), nShow); 877 878 if (!pszParms) 879 return E_INVALIDARG; 880 881 RtlCreateUnicodeStringFromAsciiz(&parmsW, pszParms); 882 883 res = UserInstStubWrapperW(hWnd, hInstance, parmsW.Buffer, nShow); 884 885 RtlFreeUnicodeString(&parmsW); 886 887 return res; 888 } 889 890 /*********************************************************************** 891 * UserInstStubWrapperW (ADVPACK.@) 892 * 893 * Launches the user stub wrapper specified by the RealStubPath 894 * registry value under Installed Components\szParms. 895 * 896 * PARAMS 897 * hWnd [I] Handle to the window used for the display. 898 * hInstance [I] Instance of the process. 899 * szParms [I] The GUID of the installation. 900 * show [I] How the window should be shown. 901 * 902 * RETURNS 903 * Success: S_OK. 904 * Failure: E_FAIL. 905 * 906 * TODO 907 * If the type of the StubRealPath value is REG_EXPAND_SZ, then 908 * we should call ExpandEnvironmentStrings on the value and 909 * launch the result. 910 */ 911 HRESULT WINAPI UserInstStubWrapperW(HWND hWnd, HINSTANCE hInstance, 912 LPWSTR pszParms, INT nShow) 913 { 914 HKEY setup, guid; 915 WCHAR stub[MAX_PATH]; 916 DWORD size = MAX_PATH; 917 HRESULT hr = S_OK; 918 BOOL res; 919 920 static const WCHAR real_stub_path[] = { 921 'R','e','a','l','S','t','u','b','P','a','t','h',0 922 }; 923 924 TRACE("(%p, %p, %s, %i)\n", hWnd, hInstance, debugstr_w(pszParms), nShow); 925 926 if (!pszParms || !*pszParms) 927 return E_INVALIDARG; 928 929 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, setup_key, 0, KEY_READ, &setup)) 930 { 931 return E_FAIL; 932 } 933 934 if (RegOpenKeyExW(setup, pszParms, 0, KEY_READ, &guid)) 935 { 936 RegCloseKey(setup); 937 return E_FAIL; 938 } 939 940 res = RegQueryValueExW(guid, real_stub_path, NULL, NULL, (LPBYTE)stub, &size); 941 if (res || !*stub) 942 goto done; 943 944 /* launch the user stub wrapper */ 945 hr = launch_exe(stub, NULL, NULL); 946 947 done: 948 RegCloseKey(setup); 949 RegCloseKey(guid); 950 951 return hr; 952 } 953 954 /*********************************************************************** 955 * UserUnInstStubWrapperA (ADVPACK.@) 956 * 957 * See UserUnInstStubWrapperW. 958 */ 959 HRESULT WINAPI UserUnInstStubWrapperA(HWND hWnd, HINSTANCE hInstance, 960 LPSTR pszParms, INT nShow) 961 { 962 UNICODE_STRING parmsW; 963 HRESULT res; 964 965 TRACE("(%p, %p, %s, %i)\n", hWnd, hInstance, debugstr_a(pszParms), nShow); 966 967 if (!pszParms) 968 return E_INVALIDARG; 969 970 RtlCreateUnicodeStringFromAsciiz(&parmsW, pszParms); 971 972 res = UserUnInstStubWrapperW(hWnd, hInstance, parmsW.Buffer, nShow); 973 974 RtlFreeUnicodeString(&parmsW); 975 976 return res; 977 } 978 979 /*********************************************************************** 980 * UserUnInstStubWrapperW (ADVPACK.@) 981 */ 982 HRESULT WINAPI UserUnInstStubWrapperW(HWND hWnd, HINSTANCE hInstance, 983 LPWSTR pszParms, INT nShow) 984 { 985 FIXME("(%p, %p, %s, %i): stub\n", hWnd, hInstance, debugstr_w(pszParms), nShow); 986 987 return E_FAIL; 988 } 989