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 #include <stdlib.h> 24 25 #include "windef.h" 26 #include "winbase.h" 27 #include "winuser.h" 28 #include "winreg.h" 29 #include "winternl.h" 30 #include "winnls.h" 31 #include "setupapi.h" 32 #include "advpub.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 = wcschr(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 = wcschr(value, ','); 162 if (ptr) { 163 *ptr = '\0'; 164 flags = wcstol(ptr+1, NULL, 10); 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 = wcstol(ptr, NULL, 10); 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, ARRAY_SIZE(perUserW.szGUID)); 534 MultiByteToWideChar(CP_ACP, 0, pPerUser->szDispName, -1, perUserW.szDispName, ARRAY_SIZE(perUserW.szDispName)); 535 MultiByteToWideChar(CP_ACP, 0, pPerUser->szLocale, -1, perUserW.szLocale, ARRAY_SIZE(perUserW.szLocale)); 536 MultiByteToWideChar(CP_ACP, 0, pPerUser->szStub, -1, perUserW.szStub, ARRAY_SIZE(perUserW.szStub)); 537 MultiByteToWideChar(CP_ACP, 0, pPerUser->szVersion, -1, perUserW.szVersion, ARRAY_SIZE(perUserW.szVersion)); 538 MultiByteToWideChar(CP_ACP, 0, pPerUser->szCompID, -1, perUserW.szCompID, ARRAY_SIZE(perUserW.szCompID)); 539 perUserW.dwIsInstalled = pPerUser->dwIsInstalled; 540 perUserW.bRollback = pPerUser->bRollback; 541 542 return SetPerUserSecValuesW(&perUserW); 543 } 544 545 /*********************************************************************** 546 * SetPerUserSecValuesW (ADVPACK.@) 547 * 548 * Prepares the per-user stub values under IsInstalled\{GUID} that 549 * control the per-user installation. 550 * 551 * PARAMS 552 * pPerUser [I] Per-user stub values. 553 * 554 * RETURNS 555 * Success: S_OK. 556 * Failure: E_FAIL. 557 */ 558 HRESULT WINAPI SetPerUserSecValuesW(PERUSERSECTIONW* pPerUser) 559 { 560 HKEY setup, guid; 561 562 static const WCHAR stub_path[] = {'S','t','u','b','P','a','t','h',0}; 563 static const WCHAR version[] = {'V','e','r','s','i','o','n',0}; 564 static const WCHAR locale[] = {'L','o','c','a','l','e',0}; 565 static const WCHAR compid[] = {'C','o','m','p','o','n','e','n','t','I','D',0}; 566 static const WCHAR isinstalled[] = {'I','s','I','n','s','t','a','l','l','e','d',0}; 567 568 TRACE("(%p)\n", pPerUser); 569 570 if (!pPerUser || !*pPerUser->szGUID) 571 return S_OK; 572 573 if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, setup_key, 0, NULL, 0, KEY_WRITE, 574 NULL, &setup, NULL)) 575 { 576 return E_FAIL; 577 } 578 579 if (RegCreateKeyExW(setup, pPerUser->szGUID, 0, NULL, 0, KEY_ALL_ACCESS, 580 NULL, &guid, NULL)) 581 { 582 RegCloseKey(setup); 583 return E_FAIL; 584 } 585 586 if (*pPerUser->szStub) 587 { 588 RegSetValueExW(guid, stub_path, 0, REG_SZ, (LPBYTE)pPerUser->szStub, 589 (lstrlenW(pPerUser->szStub) + 1) * sizeof(WCHAR)); 590 } 591 592 if (*pPerUser->szVersion) 593 { 594 RegSetValueExW(guid, version, 0, REG_SZ, (LPBYTE)pPerUser->szVersion, 595 (lstrlenW(pPerUser->szVersion) + 1) * sizeof(WCHAR)); 596 } 597 598 if (*pPerUser->szLocale) 599 { 600 RegSetValueExW(guid, locale, 0, REG_SZ, (LPBYTE)pPerUser->szLocale, 601 (lstrlenW(pPerUser->szLocale) + 1) * sizeof(WCHAR)); 602 } 603 604 if (*pPerUser->szCompID) 605 { 606 RegSetValueExW(guid, compid, 0, REG_SZ, (LPBYTE)pPerUser->szCompID, 607 (lstrlenW(pPerUser->szCompID) + 1) * sizeof(WCHAR)); 608 } 609 610 if (*pPerUser->szDispName) 611 { 612 RegSetValueExW(guid, NULL, 0, REG_SZ, (LPBYTE)pPerUser->szDispName, 613 (lstrlenW(pPerUser->szDispName) + 1) * sizeof(WCHAR)); 614 } 615 616 RegSetValueExW(guid, isinstalled, 0, REG_DWORD, 617 (LPBYTE)&pPerUser->dwIsInstalled, sizeof(DWORD)); 618 619 RegCloseKey(guid); 620 RegCloseKey(setup); 621 622 return S_OK; 623 } 624 625 /*********************************************************************** 626 * TranslateInfStringA (ADVPACK.@) 627 * 628 * See TranslateInfStringW. 629 */ 630 HRESULT WINAPI TranslateInfStringA(LPCSTR pszInfFilename, LPCSTR pszInstallSection, 631 LPCSTR pszTranslateSection, LPCSTR pszTranslateKey, LPSTR pszBuffer, 632 DWORD dwBufferSize, PDWORD pdwRequiredSize, PVOID pvReserved) 633 { 634 UNICODE_STRING filenameW, installW; 635 UNICODE_STRING translateW, keyW; 636 LPWSTR bufferW; 637 HRESULT res; 638 DWORD len = 0; 639 640 TRACE("(%s, %s, %s, %s, %p, %d, %p, %p)\n", 641 debugstr_a(pszInfFilename), debugstr_a(pszInstallSection), 642 debugstr_a(pszTranslateSection), debugstr_a(pszTranslateKey), 643 pszBuffer, dwBufferSize,pdwRequiredSize, pvReserved); 644 645 if (!pszInfFilename || !pszTranslateSection || 646 !pszTranslateKey || !pdwRequiredSize) 647 return E_INVALIDARG; 648 649 RtlCreateUnicodeStringFromAsciiz(&filenameW, pszInfFilename); 650 RtlCreateUnicodeStringFromAsciiz(&installW, pszInstallSection); 651 RtlCreateUnicodeStringFromAsciiz(&translateW, pszTranslateSection); 652 RtlCreateUnicodeStringFromAsciiz(&keyW, pszTranslateKey); 653 654 res = TranslateInfStringW(filenameW.Buffer, installW.Buffer, 655 translateW.Buffer, keyW.Buffer, NULL, 656 dwBufferSize, &len, NULL); 657 658 if (res == S_OK) 659 { 660 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 661 662 res = TranslateInfStringW(filenameW.Buffer, installW.Buffer, 663 translateW.Buffer, keyW.Buffer, bufferW, 664 len, &len, NULL); 665 if (res == S_OK) 666 { 667 *pdwRequiredSize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, 668 NULL, 0, NULL, NULL); 669 670 if (dwBufferSize >= *pdwRequiredSize) 671 { 672 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, pszBuffer, 673 dwBufferSize, NULL, NULL); 674 } 675 else 676 res = E_NOT_SUFFICIENT_BUFFER; 677 } 678 679 HeapFree(GetProcessHeap(), 0, bufferW); 680 } 681 682 RtlFreeUnicodeString(&filenameW); 683 RtlFreeUnicodeString(&installW); 684 RtlFreeUnicodeString(&translateW); 685 RtlFreeUnicodeString(&keyW); 686 687 return res; 688 } 689 690 /*********************************************************************** 691 * TranslateInfStringW (ADVPACK.@) 692 * 693 * Translates the value of a specified key in an inf file into the 694 * current locale by expanding string macros. 695 * 696 * PARAMS 697 * pszInfFilename [I] Filename of the inf file. 698 * pszInstallSection [I] 699 * pszTranslateSection [I] Inf section where the key exists. 700 * pszTranslateKey [I] Key to translate. 701 * pszBuffer [O] Contains the translated string on exit. 702 * dwBufferSize [I] Size on input of pszBuffer. 703 * pdwRequiredSize [O] Length of the translated key. 704 * pvReserved [I] Reserved, must be NULL. 705 * 706 * RETURNS 707 * Success: S_OK. 708 * Failure: An hresult error code. 709 */ 710 HRESULT WINAPI TranslateInfStringW(LPCWSTR pszInfFilename, LPCWSTR pszInstallSection, 711 LPCWSTR pszTranslateSection, LPCWSTR pszTranslateKey, LPWSTR pszBuffer, 712 DWORD dwBufferSize, PDWORD pdwRequiredSize, PVOID pvReserved) 713 { 714 HINF hInf; 715 HRESULT hret = S_OK; 716 717 TRACE("(%s, %s, %s, %s, %p, %d, %p, %p)\n", 718 debugstr_w(pszInfFilename), debugstr_w(pszInstallSection), 719 debugstr_w(pszTranslateSection), debugstr_w(pszTranslateKey), 720 pszBuffer, dwBufferSize,pdwRequiredSize, pvReserved); 721 722 if (!pszInfFilename || !pszTranslateSection || 723 !pszTranslateKey || !pdwRequiredSize) 724 return E_INVALIDARG; 725 726 hInf = SetupOpenInfFileW(pszInfFilename, NULL, INF_STYLE_WIN4, NULL); 727 if (hInf == INVALID_HANDLE_VALUE) 728 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); 729 730 set_ldids(hInf, pszInstallSection, NULL); 731 732 if (!SetupGetLineTextW(NULL, hInf, pszTranslateSection, pszTranslateKey, 733 pszBuffer, dwBufferSize, pdwRequiredSize)) 734 { 735 if (dwBufferSize < *pdwRequiredSize) 736 hret = E_NOT_SUFFICIENT_BUFFER; 737 else 738 hret = SPAPI_E_LINE_NOT_FOUND; 739 } 740 741 SetupCloseInfFile(hInf); 742 return hret; 743 } 744 745 /*********************************************************************** 746 * TranslateInfStringExA (ADVPACK.@) 747 * 748 * See TranslateInfStringExW. 749 */ 750 HRESULT WINAPI TranslateInfStringExA(HINF hInf, LPCSTR pszInfFilename, 751 LPCSTR pszTranslateSection, LPCSTR pszTranslateKey, 752 LPSTR pszBuffer, DWORD dwBufferSize, 753 PDWORD pdwRequiredSize, PVOID pvReserved) 754 { 755 UNICODE_STRING filenameW, sectionW, keyW; 756 LPWSTR bufferW; 757 HRESULT res; 758 DWORD len = 0; 759 760 TRACE("(%p, %s, %s, %s, %p, %d, %p, %p)\n", hInf, debugstr_a(pszInfFilename), 761 debugstr_a(pszTranslateSection), debugstr_a(pszTranslateKey), 762 pszBuffer, dwBufferSize, pdwRequiredSize, pvReserved); 763 764 if (!pszInfFilename || !pszTranslateSection || 765 !pszTranslateKey || !pdwRequiredSize) 766 return E_INVALIDARG; 767 768 RtlCreateUnicodeStringFromAsciiz(&filenameW, pszInfFilename); 769 RtlCreateUnicodeStringFromAsciiz(§ionW, pszTranslateSection); 770 RtlCreateUnicodeStringFromAsciiz(&keyW, pszTranslateKey); 771 772 res = TranslateInfStringExW(hInf, filenameW.Buffer, sectionW.Buffer, 773 keyW.Buffer, NULL, 0, &len, NULL); 774 775 if (res == S_OK) 776 { 777 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 778 779 res = TranslateInfStringExW(hInf, filenameW.Buffer, sectionW.Buffer, 780 keyW.Buffer, bufferW, len, &len, NULL); 781 782 if (res == S_OK) 783 { 784 *pdwRequiredSize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, 785 NULL, 0, NULL, NULL); 786 787 if (dwBufferSize >= *pdwRequiredSize) 788 { 789 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, pszBuffer, 790 dwBufferSize, NULL, NULL); 791 } 792 else 793 res = E_NOT_SUFFICIENT_BUFFER; 794 } 795 796 HeapFree(GetProcessHeap(), 0, bufferW); 797 } 798 799 RtlFreeUnicodeString(&filenameW); 800 RtlFreeUnicodeString(§ionW); 801 RtlFreeUnicodeString(&keyW); 802 803 return res; 804 } 805 806 /*********************************************************************** 807 * TranslateInfStringExW (ADVPACK.@) 808 * 809 * Using a handle to an INF file opened with OpenINFEngine, translates 810 * the value of a specified key in an inf file into the current locale 811 * by expanding string macros. 812 * 813 * PARAMS 814 * hInf [I] Handle to the INF file. 815 * pszInfFilename [I] Filename of the INF file. 816 * pszTranslateSection [I] Inf section where the key exists. 817 * pszTranslateKey [I] Key to translate. 818 * pszBuffer [O] Contains the translated string on exit. 819 * dwBufferSize [I] Size on input of pszBuffer. 820 * pdwRequiredSize [O] Length of the translated key. 821 * pvReserved [I] Reserved. Must be NULL. 822 * 823 * RETURNS 824 * Success: S_OK. 825 * Failure: E_FAIL. 826 * 827 * NOTES 828 * To use TranslateInfStringEx to translate an INF file continuously, 829 * open the INF file with OpenINFEngine, call TranslateInfStringEx as 830 * many times as needed, then release the handle with CloseINFEngine. 831 * When translating more than one keys, this method is more efficient 832 * than calling TranslateInfString, because the INF file is only 833 * opened once. 834 */ 835 HRESULT WINAPI TranslateInfStringExW(HINF hInf, LPCWSTR pszInfFilename, 836 LPCWSTR pszTranslateSection, LPCWSTR pszTranslateKey, 837 LPWSTR pszBuffer, DWORD dwBufferSize, 838 PDWORD pdwRequiredSize, PVOID pvReserved) 839 { 840 TRACE("(%p, %s, %s, %s, %p, %d, %p, %p)\n", hInf, debugstr_w(pszInfFilename), 841 debugstr_w(pszTranslateSection), debugstr_w(pszTranslateKey), 842 pszBuffer, dwBufferSize, pdwRequiredSize, pvReserved); 843 844 if (!hInf || !pszInfFilename || !pszTranslateSection || !pszTranslateKey) 845 return E_INVALIDARG; 846 847 if (!SetupGetLineTextW(NULL, hInf, pszTranslateSection, pszTranslateKey, 848 pszBuffer, dwBufferSize, pdwRequiredSize)) 849 { 850 if (dwBufferSize < *pdwRequiredSize) 851 return E_NOT_SUFFICIENT_BUFFER; 852 853 return SPAPI_E_LINE_NOT_FOUND; 854 } 855 856 return S_OK; 857 } 858 859 /*********************************************************************** 860 * UserInstStubWrapperA (ADVPACK.@) 861 * 862 * See UserInstStubWrapperW. 863 */ 864 HRESULT WINAPI UserInstStubWrapperA(HWND hWnd, HINSTANCE hInstance, 865 LPSTR pszParms, INT nShow) 866 { 867 UNICODE_STRING parmsW; 868 HRESULT res; 869 870 TRACE("(%p, %p, %s, %i)\n", hWnd, hInstance, debugstr_a(pszParms), nShow); 871 872 if (!pszParms) 873 return E_INVALIDARG; 874 875 RtlCreateUnicodeStringFromAsciiz(&parmsW, pszParms); 876 877 res = UserInstStubWrapperW(hWnd, hInstance, parmsW.Buffer, nShow); 878 879 RtlFreeUnicodeString(&parmsW); 880 881 return res; 882 } 883 884 /*********************************************************************** 885 * UserInstStubWrapperW (ADVPACK.@) 886 * 887 * Launches the user stub wrapper specified by the RealStubPath 888 * registry value under Installed Components\szParms. 889 * 890 * PARAMS 891 * hWnd [I] Handle to the window used for the display. 892 * hInstance [I] Instance of the process. 893 * szParms [I] The GUID of the installation. 894 * show [I] How the window should be shown. 895 * 896 * RETURNS 897 * Success: S_OK. 898 * Failure: E_FAIL. 899 * 900 * TODO 901 * If the type of the StubRealPath value is REG_EXPAND_SZ, then 902 * we should call ExpandEnvironmentStrings on the value and 903 * launch the result. 904 */ 905 HRESULT WINAPI UserInstStubWrapperW(HWND hWnd, HINSTANCE hInstance, 906 LPWSTR pszParms, INT nShow) 907 { 908 HKEY setup, guid; 909 WCHAR stub[MAX_PATH]; 910 DWORD size = MAX_PATH; 911 HRESULT hr = S_OK; 912 BOOL res; 913 914 static const WCHAR real_stub_path[] = { 915 'R','e','a','l','S','t','u','b','P','a','t','h',0 916 }; 917 918 TRACE("(%p, %p, %s, %i)\n", hWnd, hInstance, debugstr_w(pszParms), nShow); 919 920 if (!pszParms || !*pszParms) 921 return E_INVALIDARG; 922 923 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, setup_key, 0, KEY_READ, &setup)) 924 { 925 return E_FAIL; 926 } 927 928 if (RegOpenKeyExW(setup, pszParms, 0, KEY_READ, &guid)) 929 { 930 RegCloseKey(setup); 931 return E_FAIL; 932 } 933 934 res = RegQueryValueExW(guid, real_stub_path, NULL, NULL, (LPBYTE)stub, &size); 935 if (res || !*stub) 936 goto done; 937 938 /* launch the user stub wrapper */ 939 hr = launch_exe(stub, NULL, NULL); 940 941 done: 942 RegCloseKey(setup); 943 RegCloseKey(guid); 944 945 return hr; 946 } 947 948 /*********************************************************************** 949 * UserUnInstStubWrapperA (ADVPACK.@) 950 * 951 * See UserUnInstStubWrapperW. 952 */ 953 HRESULT WINAPI UserUnInstStubWrapperA(HWND hWnd, HINSTANCE hInstance, 954 LPSTR pszParms, INT nShow) 955 { 956 UNICODE_STRING parmsW; 957 HRESULT res; 958 959 TRACE("(%p, %p, %s, %i)\n", hWnd, hInstance, debugstr_a(pszParms), nShow); 960 961 if (!pszParms) 962 return E_INVALIDARG; 963 964 RtlCreateUnicodeStringFromAsciiz(&parmsW, pszParms); 965 966 res = UserUnInstStubWrapperW(hWnd, hInstance, parmsW.Buffer, nShow); 967 968 RtlFreeUnicodeString(&parmsW); 969 970 return res; 971 } 972 973 /*********************************************************************** 974 * UserUnInstStubWrapperW (ADVPACK.@) 975 */ 976 HRESULT WINAPI UserUnInstStubWrapperW(HWND hWnd, HINSTANCE hInstance, 977 LPWSTR pszParms, INT nShow) 978 { 979 FIXME("(%p, %p, %s, %i): stub\n", hWnd, hInstance, debugstr_w(pszParms), nShow); 980 981 return E_FAIL; 982 } 983