4 * Copyright 2004 Huw D M Davies
5 * Copyright 2005 Sami Aario
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.
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.
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
33 #include "wine/unicode.h"
34 #include "wine/debug.h"
35 #include "advpack_private.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(advpack);
39 typedef HRESULT (WINAPI *DLLREGISTER) (void);
41 #define MAX_FIELD_LENGTH 512
44 /* registry path of the Installed Components key for per-user stubs */
45 static const WCHAR setup_key[] = {
46 'S','O','F','T','W','A','R','E','\\',
47 'M','i','c','r','o','s','o','f','t','\\',
48 'A','c','t','i','v','e',' ','S','e','t','u','p','\\',
49 'I','n','s','t','a','l','l','e','d',' ',
50 'C','o','m','p','o','n','e','n','t','s',0
53 /* parses the destination directory parameters from pszSection
54 * the parameters are of the form: root,key,value,unknown,fallback
55 * we first read the reg value root\\key\\value and if that fails,
56 * use fallback as the destination directory
58 static void get_dest_dir(HINF hInf, PCWSTR pszSection, PWSTR pszBuffer, DWORD dwSize)
61 WCHAR key[MAX_PATH], value[MAX_PATH];
62 WCHAR prefix[PREFIX_LEN];
66 static const WCHAR hklm[] = {'H','K','L','M',0};
67 static const WCHAR hkcu[] = {'H','K','C','U',0};
69 /* load the destination parameters */
70 SetupFindFirstLineW(hInf, pszSection, NULL, &context);
71 SetupGetStringFieldW(&context, 1, prefix, PREFIX_LEN, &size);
72 SetupGetStringFieldW(&context, 2, key, MAX_PATH, &size);
73 SetupGetStringFieldW(&context, 3, value, MAX_PATH, &size);
75 if (!lstrcmpW(prefix, hklm))
76 root = HKEY_LOCAL_MACHINE;
77 else if (!lstrcmpW(prefix, hkcu))
78 root = HKEY_CURRENT_USER;
82 size = dwSize * sizeof(WCHAR);
84 /* fallback to the default destination dir if reg fails */
85 if (RegOpenKeyW(root, key, &subkey) ||
86 RegQueryValueExW(subkey, value, NULL, NULL, (LPBYTE)pszBuffer, &size))
88 SetupGetStringFieldW(&context, 5, pszBuffer, dwSize, NULL);
94 /* loads the LDIDs specified in the install section of an INF */
95 void set_ldids(HINF hInf, LPCWSTR pszInstallSection, LPCWSTR pszWorkingDir)
97 WCHAR field[MAX_FIELD_LENGTH];
98 WCHAR line[MAX_FIELD_LENGTH];
104 static const WCHAR source_dir[] = {'S','o','u','r','c','e','D','i','r',0};
106 static const WCHAR custDestW[] = {
107 'C','u','s','t','o','m','D','e','s','t','i','n','a','t','i','o','n',0
110 if (!SetupGetLineTextW(NULL, hInf, pszInstallSection, custDestW,
111 field, MAX_FIELD_LENGTH, &size))
114 if (!SetupFindFirstLineW(hInf, field, NULL, &context))
119 LPWSTR value, ptr, key, key_copy = NULL;
121 SetupGetLineTextW(&context, NULL, NULL, NULL,
122 line, MAX_FIELD_LENGTH, &size);
124 /* SetupGetLineTextW returns the value if there is only one key, but
125 * returns the whole line if there is more than one key
127 if (!(value = strchrW(line, '=')))
129 SetupGetStringFieldW(&context, 0, NULL, 0, &size);
130 key = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
132 SetupGetStringFieldW(&context, 0, key, size, &size);
141 /* remove leading whitespace from the value */
142 while (*value == ' ')
145 /* FIXME: need to check the query option */
146 ptr = strchrW(value, ',');
150 /* set dest to pszWorkingDir if key is SourceDir */
151 if (pszWorkingDir && !lstrcmpiW(value, source_dir))
152 lstrcpynW(dest, pszWorkingDir, MAX_PATH);
154 get_dest_dir(hInf, value, dest, MAX_PATH);
156 /* set all ldids to dest */
157 while ((ptr = get_parameter(&key, ',')))
160 SetupSetDirectoryIdW(hInf, ldid, dest);
162 HeapFree(GetProcessHeap(), 0, key_copy);
163 } while (SetupFindNextLine(&context, &context));
166 /***********************************************************************
167 * CloseINFEngine (ADVPACK.@)
169 * Closes a handle to an INF file opened with OpenINFEngine.
172 * hInf [I] Handle to the INF file to close.
178 HRESULT WINAPI CloseINFEngine(HINF hInf)
180 TRACE("(%p)\n", hInf);
185 SetupCloseInfFile(hInf);
189 /***********************************************************************
190 * DllMain (ADVPACK.@)
192 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
194 TRACE("(%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
196 if (fdwReason == DLL_PROCESS_ATTACH)
197 DisableThreadLibraryCalls(hinstDLL);
202 /***********************************************************************
203 * IsNTAdmin (ADVPACK.@)
205 * Checks if the user has admin privileges.
208 * reserved [I] Reserved. Must be 0.
209 * pReserved [I] Reserved. Must be NULL.
212 * TRUE if user has admin rights, FALSE otherwise.
214 BOOL WINAPI IsNTAdmin(DWORD reserved, LPDWORD pReserved)
216 SID_IDENTIFIER_AUTHORITY SidAuthority = {SECURITY_NT_AUTHORITY};
217 PTOKEN_GROUPS pTokenGroups;
218 BOOL bSidFound = FALSE;
223 TRACE("(%d, %p)\n", reserved, pReserved);
225 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
228 if (!GetTokenInformation(hToken, TokenGroups, NULL, 0, &dwSize))
230 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
237 pTokenGroups = HeapAlloc(GetProcessHeap(), 0, dwSize);
244 if (!GetTokenInformation(hToken, TokenGroups, pTokenGroups, dwSize, &dwSize))
246 HeapFree(GetProcessHeap(), 0, pTokenGroups);
253 if (!AllocateAndInitializeSid(&SidAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
254 DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pSid))
256 HeapFree(GetProcessHeap(), 0, pTokenGroups);
260 for (i = 0; i < pTokenGroups->GroupCount; i++)
262 if (EqualSid(pSid, pTokenGroups->Groups[i].Sid))
269 HeapFree(GetProcessHeap(), 0, pTokenGroups);
275 /***********************************************************************
276 * NeedRebootInit (ADVPACK.@)
278 * Sets up conditions for reboot checking.
281 * Value required by NeedReboot.
283 DWORD WINAPI NeedRebootInit(VOID)
285 FIXME("(VOID): stub\n");
289 /***********************************************************************
290 * NeedReboot (ADVPACK.@)
292 * Determines whether a reboot is required.
295 * dwRebootCheck [I] Value from NeedRebootInit.
298 * TRUE if a reboot is needed, FALSE otherwise.
303 BOOL WINAPI NeedReboot(DWORD dwRebootCheck)
305 FIXME("(%d): stub\n", dwRebootCheck);
309 /***********************************************************************
310 * OpenINFEngineA (ADVPACK.@)
312 * See OpenINFEngineW.
314 HRESULT WINAPI OpenINFEngineA(LPCSTR pszInfFilename, LPCSTR pszInstallSection,
315 DWORD dwFlags, HINF *phInf, PVOID pvReserved)
317 UNICODE_STRING filenameW, installW;
320 TRACE("(%s, %s, %d, %p, %p)\n", debugstr_a(pszInfFilename),
321 debugstr_a(pszInstallSection), dwFlags, phInf, pvReserved);
323 if (!pszInfFilename || !phInf)
326 RtlCreateUnicodeStringFromAsciiz(&filenameW, pszInfFilename);
327 RtlCreateUnicodeStringFromAsciiz(&installW, pszInstallSection);
329 res = OpenINFEngineW(filenameW.Buffer, installW.Buffer,
330 dwFlags, phInf, pvReserved);
332 RtlFreeUnicodeString(&filenameW);
333 RtlFreeUnicodeString(&installW);
338 /***********************************************************************
339 * OpenINFEngineW (ADVPACK.@)
341 * Opens and returns a handle to an INF file to be used by
342 * TranslateInfStringEx to continuously translate the INF file.
345 * pszInfFilename [I] Filename of the INF to open.
346 * pszInstallSection [I] Name of the Install section in the INF.
347 * dwFlags [I] See advpub.h.
348 * phInf [O] Handle to the loaded INF file.
349 * pvReserved [I] Reserved. Must be NULL.
355 HRESULT WINAPI OpenINFEngineW(LPCWSTR pszInfFilename, LPCWSTR pszInstallSection,
356 DWORD dwFlags, HINF *phInf, PVOID pvReserved)
358 TRACE("(%s, %s, %d, %p, %p)\n", debugstr_w(pszInfFilename),
359 debugstr_w(pszInstallSection), dwFlags, phInf, pvReserved);
361 if (!pszInfFilename || !phInf)
364 *phInf = SetupOpenInfFileW(pszInfFilename, NULL, INF_STYLE_WIN4, NULL);
365 if (*phInf == INVALID_HANDLE_VALUE)
366 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
368 set_ldids(*phInf, pszInstallSection, NULL);
373 /***********************************************************************
374 * RebootCheckOnInstallA (ADVPACK.@)
376 * See RebootCheckOnInstallW.
378 HRESULT WINAPI RebootCheckOnInstallA(HWND hWnd, LPCSTR pszINF,
379 LPCSTR pszSec, DWORD dwReserved)
381 UNICODE_STRING infW, secW;
384 TRACE("(%p, %s, %s, %d)\n", hWnd, debugstr_a(pszINF),
385 debugstr_a(pszSec), dwReserved);
387 if (!pszINF || !pszSec)
390 RtlCreateUnicodeStringFromAsciiz(&infW, pszINF);
391 RtlCreateUnicodeStringFromAsciiz(&secW, pszSec);
393 res = RebootCheckOnInstallW(hWnd, infW.Buffer, secW.Buffer, dwReserved);
395 RtlFreeUnicodeString(&infW);
396 RtlFreeUnicodeString(&secW);
401 /***********************************************************************
402 * RebootCheckOnInstallW (ADVPACK.@)
404 * Checks if a reboot is required for an installed INF section.
407 * hWnd [I] Handle to the window used for messages.
408 * pszINF [I] Filename of the INF file.
409 * pszSec [I] INF section to check.
410 * dwReserved [I] Reserved. Must be 0.
413 * Success: S_OK - Reboot is needed if the INF section is installed.
414 * S_FALSE - Reboot is not needed.
415 * Failure: HRESULT of GetLastError().
418 * if pszSec is NULL, RebootCheckOnInstall checks the DefaultInstall
419 * or DefaultInstall.NT section.
424 HRESULT WINAPI RebootCheckOnInstallW(HWND hWnd, LPCWSTR pszINF,
425 LPCWSTR pszSec, DWORD dwReserved)
427 FIXME("(%p, %s, %s, %d): stub\n", hWnd, debugstr_w(pszINF),
428 debugstr_w(pszSec), dwReserved);
433 /* registers the OCX if do_reg is TRUE, unregisters it otherwise */
434 HRESULT do_ocx_reg(HMODULE hocx, BOOL do_reg)
436 DLLREGISTER reg_func;
439 reg_func = (DLLREGISTER)GetProcAddress(hocx, "DllRegisterServer");
441 reg_func = (DLLREGISTER)GetProcAddress(hocx, "DllUnregisterServer");
450 /***********************************************************************
451 * RegisterOCX (ADVPACK.@)
456 * hWnd [I] Handle to the window used for the display.
457 * hInst [I] Instance of the process.
458 * cmdline [I] Contains parameters in the order OCX,flags,param.
459 * show [I] How the window should be shown.
466 * OCX - Filename of the OCX to register.
467 * flags - Controls the operation of RegisterOCX.
468 * 'I' Call DllRegisterServer and DllInstall.
469 * 'N' Only call DllInstall.
470 * param - Command line passed to DllInstall.
472 HRESULT WINAPI RegisterOCX(HWND hWnd, HINSTANCE hInst, LPCSTR cmdline, INT show)
474 LPWSTR ocx_filename, str_flags, param;
475 LPWSTR cmdline_copy, cmdline_ptr;
476 UNICODE_STRING cmdlineW;
481 TRACE("(%s)\n", debugstr_a(cmdline));
483 RtlCreateUnicodeStringFromAsciiz(&cmdlineW, cmdline);
485 size = (lstrlenW(cmdlineW.Buffer) + 1) * sizeof(WCHAR);
486 cmdline_copy = HeapAlloc(GetProcessHeap(), 0, size);
487 cmdline_ptr = cmdline_copy;
488 lstrcpyW(cmdline_copy, cmdlineW.Buffer);
490 ocx_filename = get_parameter(&cmdline_ptr, ',');
491 if (!ocx_filename || !*ocx_filename)
494 str_flags = get_parameter(&cmdline_ptr, ',');
495 param = get_parameter(&cmdline_ptr, ',');
497 hm = LoadLibraryExW(ocx_filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
501 hr = do_ocx_reg(hm, TRUE);
505 HeapFree(GetProcessHeap(), 0, cmdline_copy);
506 RtlFreeUnicodeString(&cmdlineW);
511 /***********************************************************************
512 * SetPerUserSecValuesA (ADVPACK.@)
514 * See SetPerUserSecValuesW.
516 HRESULT WINAPI SetPerUserSecValuesA(PERUSERSECTIONA* pPerUser)
518 PERUSERSECTIONW perUserW;
520 TRACE("(%p)\n", pPerUser);
525 MultiByteToWideChar(CP_ACP, 0, pPerUser->szGUID, -1, perUserW.szGUID,
526 sizeof(perUserW.szGUID) / sizeof(WCHAR));
527 MultiByteToWideChar(CP_ACP, 0, pPerUser->szDispName, -1, perUserW.szDispName,
528 sizeof(perUserW.szDispName) / sizeof(WCHAR));
529 MultiByteToWideChar(CP_ACP, 0, pPerUser->szLocale, -1, perUserW.szLocale,
530 sizeof(perUserW.szLocale) / sizeof(WCHAR));
531 MultiByteToWideChar(CP_ACP, 0, pPerUser->szStub, -1, perUserW.szStub,
532 sizeof(perUserW.szStub) / sizeof(WCHAR));
533 MultiByteToWideChar(CP_ACP, 0, pPerUser->szVersion, -1, perUserW.szVersion,
534 sizeof(perUserW.szVersion) / sizeof(WCHAR));
535 MultiByteToWideChar(CP_ACP, 0, pPerUser->szCompID, -1, perUserW.szCompID,
536 sizeof(perUserW.szCompID) / sizeof(WCHAR));
537 perUserW.dwIsInstalled = pPerUser->dwIsInstalled;
538 perUserW.bRollback = pPerUser->bRollback;
540 return SetPerUserSecValuesW(&perUserW);
543 /***********************************************************************
544 * SetPerUserSecValuesW (ADVPACK.@)
546 * Prepares the per-user stub values under IsInstalled\{GUID} that
547 * control the per-user installation.
550 * pPerUser [I] Per-user stub values.
556 HRESULT WINAPI SetPerUserSecValuesW(PERUSERSECTIONW* pPerUser)
560 static const WCHAR stub_path[] = {'S','t','u','b','P','a','t','h',0};
561 static const WCHAR version[] = {'V','e','r','s','i','o','n',0};
562 static const WCHAR locale[] = {'L','o','c','a','l','e',0};
563 static const WCHAR compid[] = {'C','o','m','p','o','n','e','n','t','I','D',0};
564 static const WCHAR isinstalled[] = {'I','s','I','n','s','t','a','l','l','e','d',0};
566 TRACE("(%p)\n", pPerUser);
568 if (!pPerUser || !*pPerUser->szGUID)
571 if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, setup_key, 0, NULL, 0, KEY_WRITE,
577 if (RegCreateKeyExW(setup, pPerUser->szGUID, 0, NULL, 0, KEY_ALL_ACCESS,
584 if (*pPerUser->szStub)
586 RegSetValueExW(guid, stub_path, 0, REG_SZ, (LPBYTE)pPerUser->szStub,
587 (lstrlenW(pPerUser->szStub) + 1) * sizeof(WCHAR));
590 if (*pPerUser->szVersion)
592 RegSetValueExW(guid, version, 0, REG_SZ, (LPBYTE)pPerUser->szVersion,
593 (lstrlenW(pPerUser->szVersion) + 1) * sizeof(WCHAR));
596 if (*pPerUser->szLocale)
598 RegSetValueExW(guid, locale, 0, REG_SZ, (LPBYTE)pPerUser->szLocale,
599 (lstrlenW(pPerUser->szLocale) + 1) * sizeof(WCHAR));
602 if (*pPerUser->szCompID)
604 RegSetValueExW(guid, compid, 0, REG_SZ, (LPBYTE)pPerUser->szCompID,
605 (lstrlenW(pPerUser->szCompID) + 1) * sizeof(WCHAR));
608 if (*pPerUser->szDispName)
610 RegSetValueExW(guid, NULL, 0, REG_SZ, (LPBYTE)pPerUser->szDispName,
611 (lstrlenW(pPerUser->szDispName) + 1) * sizeof(WCHAR));
614 RegSetValueExW(guid, isinstalled, 0, REG_DWORD,
615 (LPBYTE)&pPerUser->dwIsInstalled, sizeof(DWORD));
623 /***********************************************************************
624 * TranslateInfStringA (ADVPACK.@)
626 * See TranslateInfStringW.
628 HRESULT WINAPI TranslateInfStringA(LPCSTR pszInfFilename, LPCSTR pszInstallSection,
629 LPCSTR pszTranslateSection, LPCSTR pszTranslateKey, LPSTR pszBuffer,
630 DWORD dwBufferSize, PDWORD pdwRequiredSize, PVOID pvReserved)
632 UNICODE_STRING filenameW, installW;
633 UNICODE_STRING translateW, keyW;
638 TRACE("(%s, %s, %s, %s, %p, %d, %p, %p)\n",
639 debugstr_a(pszInfFilename), debugstr_a(pszInstallSection),
640 debugstr_a(pszTranslateSection), debugstr_a(pszTranslateKey),
641 pszBuffer, dwBufferSize,pdwRequiredSize, pvReserved);
643 if (!pszInfFilename || !pszTranslateSection ||
644 !pszTranslateKey || !pdwRequiredSize)
647 RtlCreateUnicodeStringFromAsciiz(&filenameW, pszInfFilename);
648 RtlCreateUnicodeStringFromAsciiz(&installW, pszInstallSection);
649 RtlCreateUnicodeStringFromAsciiz(&translateW, pszTranslateSection);
650 RtlCreateUnicodeStringFromAsciiz(&keyW, pszTranslateKey);
652 res = TranslateInfStringW(filenameW.Buffer, installW.Buffer,
653 translateW.Buffer, keyW.Buffer, NULL,
654 dwBufferSize, &len, NULL);
658 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
660 res = TranslateInfStringW(filenameW.Buffer, installW.Buffer,
661 translateW.Buffer, keyW.Buffer, bufferW,
665 *pdwRequiredSize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1,
666 NULL, 0, NULL, NULL);
668 if (dwBufferSize >= *pdwRequiredSize)
670 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, pszBuffer,
671 dwBufferSize, NULL, NULL);
674 res = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
677 HeapFree(GetProcessHeap(), 0, bufferW);
680 RtlFreeUnicodeString(&filenameW);
681 RtlFreeUnicodeString(&installW);
682 RtlFreeUnicodeString(&translateW);
683 RtlFreeUnicodeString(&keyW);
688 /***********************************************************************
689 * TranslateInfStringW (ADVPACK.@)
691 * Translates the value of a specified key in an inf file into the
692 * current locale by expanding string macros.
695 * pszInfFilename [I] Filename of the inf file.
696 * pszInstallSection [I]
697 * pszTranslateSection [I] Inf section where the key exists.
698 * pszTranslateKey [I] Key to translate.
699 * pszBuffer [O] Contains the translated string on exit.
700 * dwBufferSize [I] Size on input of pszBuffer.
701 * pdwRequiredSize [O] Length of the translated key.
702 * pvReserved [I] Reserved, must be NULL.
706 * Failure: An hresult error code.
708 HRESULT WINAPI TranslateInfStringW(LPCWSTR pszInfFilename, LPCWSTR pszInstallSection,
709 LPCWSTR pszTranslateSection, LPCWSTR pszTranslateKey, LPWSTR pszBuffer,
710 DWORD dwBufferSize, PDWORD pdwRequiredSize, PVOID pvReserved)
715 TRACE("(%s, %s, %s, %s, %p, %d, %p, %p)\n",
716 debugstr_w(pszInfFilename), debugstr_w(pszInstallSection),
717 debugstr_w(pszTranslateSection), debugstr_w(pszTranslateKey),
718 pszBuffer, dwBufferSize,pdwRequiredSize, pvReserved);
720 if (!pszInfFilename || !pszTranslateSection ||
721 !pszTranslateKey || !pdwRequiredSize)
724 hInf = SetupOpenInfFileW(pszInfFilename, NULL, INF_STYLE_WIN4, NULL);
725 if (hInf == INVALID_HANDLE_VALUE)
726 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
728 set_ldids(hInf, pszInstallSection, NULL);
730 if (!SetupGetLineTextW(NULL, hInf, pszTranslateSection, pszTranslateKey,
731 pszBuffer, dwBufferSize, pdwRequiredSize))
733 if (dwBufferSize < *pdwRequiredSize)
734 hret = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
736 hret = SPAPI_E_LINE_NOT_FOUND;
739 SetupCloseInfFile(hInf);
743 /***********************************************************************
744 * TranslateInfStringExA (ADVPACK.@)
746 * See TranslateInfStringExW.
748 HRESULT WINAPI TranslateInfStringExA(HINF hInf, LPCSTR pszInfFilename,
749 LPCSTR pszTranslateSection, LPCSTR pszTranslateKey,
750 LPSTR pszBuffer, DWORD dwBufferSize,
751 PDWORD pdwRequiredSize, PVOID pvReserved)
753 UNICODE_STRING filenameW, sectionW, keyW;
758 TRACE("(%p, %s, %s, %s, %s, %d, %p, %p)\n", hInf, debugstr_a(pszInfFilename),
759 debugstr_a(pszTranslateSection), debugstr_a(pszTranslateKey),
760 debugstr_a(pszBuffer), dwBufferSize, pdwRequiredSize, pvReserved);
762 if (!pszInfFilename || !pszTranslateSection ||
763 !pszTranslateKey || !pdwRequiredSize)
766 RtlCreateUnicodeStringFromAsciiz(&filenameW, pszInfFilename);
767 RtlCreateUnicodeStringFromAsciiz(§ionW, pszTranslateSection);
768 RtlCreateUnicodeStringFromAsciiz(&keyW, pszTranslateKey);
770 res = TranslateInfStringExW(hInf, filenameW.Buffer, sectionW.Buffer,
771 keyW.Buffer, NULL, 0, &len, NULL);
775 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
777 res = TranslateInfStringExW(hInf, filenameW.Buffer, sectionW.Buffer,
778 keyW.Buffer, bufferW, len, &len, NULL);
782 *pdwRequiredSize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1,
783 NULL, 0, NULL, NULL);
785 if (dwBufferSize >= *pdwRequiredSize)
787 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, pszBuffer,
788 dwBufferSize, NULL, NULL);
791 res = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
794 HeapFree(GetProcessHeap(), 0, bufferW);
797 RtlFreeUnicodeString(&filenameW);
798 RtlFreeUnicodeString(§ionW);
799 RtlFreeUnicodeString(&keyW);
804 /***********************************************************************
805 * TranslateInfStringExW (ADVPACK.@)
807 * Using a handle to an INF file opened with OpenINFEngine, translates
808 * the value of a specified key in an inf file into the current locale
809 * by expanding string macros.
812 * hInf [I] Handle to the INF file.
813 * pszInfFilename [I] Filename of the INF file.
814 * pszTranslateSection [I] Inf section where the key exists.
815 * pszTranslateKey [I] Key to translate.
816 * pszBuffer [O] Contains the translated string on exit.
817 * dwBufferSize [I] Size on input of pszBuffer.
818 * pdwRequiredSize [O] Length of the translated key.
819 * pvReserved [I] Reserved. Must be NULL.
826 * To use TranslateInfStringEx to translate an INF file continuously,
827 * open the INF file with OpenINFEngine, call TranslateInfStringEx as
828 * many times as needed, then release the handle with CloseINFEngine.
829 * When translating more than one keys, this method is more efficient
830 * than calling TranslateInfString, because the INF file is only
833 HRESULT WINAPI TranslateInfStringExW(HINF hInf, LPCWSTR pszInfFilename,
834 LPCWSTR pszTranslateSection, LPCWSTR pszTranslateKey,
835 LPWSTR pszBuffer, DWORD dwBufferSize,
836 PDWORD pdwRequiredSize, PVOID pvReserved)
838 TRACE("(%p, %s, %s, %s, %s, %d, %p, %p)\n", hInf, debugstr_w(pszInfFilename),
839 debugstr_w(pszTranslateSection), debugstr_w(pszTranslateKey),
840 debugstr_w(pszBuffer), dwBufferSize, pdwRequiredSize, pvReserved);
842 if (!hInf || !pszInfFilename || !pszTranslateSection || !pszTranslateKey)
845 if (!SetupGetLineTextW(NULL, hInf, pszTranslateSection, pszTranslateKey,
846 pszBuffer, dwBufferSize, pdwRequiredSize))
848 if (dwBufferSize < *pdwRequiredSize)
849 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
851 return SPAPI_E_LINE_NOT_FOUND;
857 /***********************************************************************
858 * UserInstStubWrapperA (ADVPACK.@)
860 * See UserInstStubWrapperW.
862 HRESULT WINAPI UserInstStubWrapperA(HWND hWnd, HINSTANCE hInstance,
863 LPSTR pszParms, INT nShow)
865 UNICODE_STRING parmsW;
868 TRACE("(%p, %p, %s, %i)\n", hWnd, hInstance, debugstr_a(pszParms), nShow);
873 RtlCreateUnicodeStringFromAsciiz(&parmsW, pszParms);
875 res = UserInstStubWrapperW(hWnd, hInstance, parmsW.Buffer, nShow);
877 RtlFreeUnicodeString(&parmsW);
882 /***********************************************************************
883 * UserInstStubWrapperW (ADVPACK.@)
885 * Launches the user stub wrapper specified by the RealStubPath
886 * registry value under Installed Components\szParms.
889 * hWnd [I] Handle to the window used for the display.
890 * hInstance [I] Instance of the process.
891 * szParms [I] The GUID of the installation.
892 * show [I] How the window should be shown.
899 * If the type of the StubRealPath value is REG_EXPAND_SZ, then
900 * we should call ExpandEnvironmentStrings on the value and
903 HRESULT WINAPI UserInstStubWrapperW(HWND hWnd, HINSTANCE hInstance,
904 LPWSTR pszParms, INT nShow)
907 WCHAR stub[MAX_PATH];
908 DWORD size = MAX_PATH;
912 static const WCHAR real_stub_path[] = {
913 'R','e','a','l','S','t','u','b','P','a','t','h',0
916 TRACE("(%p, %p, %s, %i)\n", hWnd, hInstance, debugstr_w(pszParms), nShow);
918 if (!pszParms || !*pszParms)
921 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, setup_key, 0, KEY_READ, &setup))
926 if (RegOpenKeyExW(setup, pszParms, 0, KEY_READ, &guid))
932 res = RegQueryValueExW(guid, real_stub_path, NULL, NULL, (LPBYTE)stub, &size);
936 /* launch the user stub wrapper */
937 hr = launch_exe(stub, NULL, NULL);
946 /***********************************************************************
947 * UserUnInstStubWrapperA (ADVPACK.@)
949 * See UserUnInstStubWrapperW.
951 HRESULT WINAPI UserUnInstStubWrapperA(HWND hWnd, HINSTANCE hInstance,
952 LPSTR pszParms, INT nShow)
954 UNICODE_STRING parmsW;
957 TRACE("(%p, %p, %s, %i)\n", hWnd, hInstance, debugstr_a(pszParms), nShow);
962 RtlCreateUnicodeStringFromAsciiz(&parmsW, pszParms);
964 res = UserUnInstStubWrapperW(hWnd, hInstance, parmsW.Buffer, nShow);
966 RtlFreeUnicodeString(&parmsW);
971 /***********************************************************************
972 * UserUnInstStubWrapperW (ADVPACK.@)
974 HRESULT WINAPI UserUnInstStubWrapperW(HWND hWnd, HINSTANCE hInstance,
975 LPWSTR pszParms, INT nShow)
977 FIXME("(%p, %p, %s, %i): stub\n", hWnd, hInstance, debugstr_w(pszParms), nShow);