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
32 #include "wine/unicode.h"
33 #include "wine/debug.h"
34 #include "advpack_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(advpack);
38 typedef HRESULT (WINAPI *DLLREGISTER) (void);
40 #define MAX_FIELD_LENGTH 512
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
52 /* parses the destination directory parameters from pszSection
53 * the parameters are of the form: root,key,value,unknown,fallback
54 * we first read the reg value root\\key\\value and if that fails,
55 * use fallback as the destination directory
57 static void get_dest_dir(HINF hInf, PCWSTR pszSection, PWSTR pszBuffer, DWORD dwSize)
60 WCHAR key[MAX_PATH], value[MAX_PATH];
61 WCHAR prefix[PREFIX_LEN];
65 static const WCHAR hklm[] = {'H','K','L','M',0};
66 static const WCHAR hkcu[] = {'H','K','C','U',0};
68 /* load the destination parameters */
69 SetupFindFirstLineW(hInf, pszSection, NULL, &context);
70 SetupGetStringFieldW(&context, 1, prefix, PREFIX_LEN, &size);
71 SetupGetStringFieldW(&context, 2, key, MAX_PATH, &size);
72 SetupGetStringFieldW(&context, 3, value, MAX_PATH, &size);
74 if (!lstrcmpW(prefix, hklm))
75 root = HKEY_LOCAL_MACHINE;
76 else if (!lstrcmpW(prefix, hkcu))
77 root = HKEY_CURRENT_USER;
81 size = dwSize * sizeof(WCHAR);
83 /* fallback to the default destination dir if reg fails */
84 if (RegOpenKeyW(root, key, &subkey) ||
85 RegQueryValueExW(subkey, value, NULL, NULL, (LPBYTE)pszBuffer, &size))
87 SetupGetStringFieldW(&context, 5, pszBuffer, dwSize, NULL);
93 /* loads the LDIDs specified in the install section of an INF */
94 void set_ldids(HINF hInf, LPCWSTR pszInstallSection, LPCWSTR pszWorkingDir)
96 WCHAR field[MAX_FIELD_LENGTH];
97 WCHAR line[MAX_FIELD_LENGTH];
103 static const WCHAR source_dir[] = {'S','o','u','r','c','e','D','i','r',0};
105 static const WCHAR custDestW[] = {
106 'C','u','s','t','o','m','D','e','s','t','i','n','a','t','i','o','n',0
109 if (!SetupGetLineTextW(NULL, hInf, pszInstallSection, custDestW,
110 field, MAX_FIELD_LENGTH, &size))
113 if (!SetupFindFirstLineW(hInf, field, NULL, &context))
118 LPWSTR value, ptr, key, key_copy = NULL;
120 SetupGetLineTextW(&context, NULL, NULL, NULL,
121 line, MAX_FIELD_LENGTH, &size);
123 /* SetupGetLineTextW returns the value if there is only one key, but
124 * returns the whole line if there is more than one key
126 if (!(value = strchrW(line, '=')))
128 SetupGetStringFieldW(&context, 0, NULL, 0, &size);
129 key = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
131 SetupGetStringFieldW(&context, 0, key, size, &size);
140 /* remove leading whitespace from the value */
141 while (*value == ' ')
144 /* FIXME: need to check the query option */
145 ptr = strchrW(value, ',');
149 /* set dest to pszWorkingDir if key is SourceDir */
150 if (pszWorkingDir && !lstrcmpiW(value, source_dir))
151 lstrcpynW(dest, pszWorkingDir, MAX_PATH);
153 get_dest_dir(hInf, value, dest, MAX_PATH);
155 /* set all ldids to dest */
156 while ((ptr = get_parameter(&key, ',')))
159 SetupSetDirectoryIdW(hInf, ldid, dest);
161 HeapFree(GetProcessHeap(), 0, key_copy);
162 } while (SetupFindNextLine(&context, &context));
165 /***********************************************************************
166 * CloseINFEngine (ADVPACK.@)
168 * Closes a handle to an INF file opened with OpenINFEngine.
171 * hInf [I] Handle to the INF file to close.
177 HRESULT WINAPI CloseINFEngine(HINF hInf)
179 TRACE("(%p)\n", hInf);
184 SetupCloseInfFile(hInf);
188 /***********************************************************************
189 * DllMain (ADVPACK.@)
191 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
193 TRACE("(%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
195 if (fdwReason == DLL_PROCESS_ATTACH)
196 DisableThreadLibraryCalls(hinstDLL);
201 /***********************************************************************
202 * IsNTAdmin (ADVPACK.@)
204 * Checks if the user has admin privileges.
207 * reserved [I] Reserved. Must be 0.
208 * pReserved [I] Reserved. Must be NULL.
211 * TRUE if user has admin rights, FALSE otherwise.
213 BOOL WINAPI IsNTAdmin(DWORD reserved, LPDWORD pReserved)
215 SID_IDENTIFIER_AUTHORITY SidAuthority = {SECURITY_NT_AUTHORITY};
216 PTOKEN_GROUPS pTokenGroups;
217 BOOL bSidFound = FALSE;
222 TRACE("(%d, %p)\n", reserved, pReserved);
224 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
227 if (!GetTokenInformation(hToken, TokenGroups, NULL, 0, &dwSize))
229 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
236 pTokenGroups = HeapAlloc(GetProcessHeap(), 0, dwSize);
243 if (!GetTokenInformation(hToken, TokenGroups, pTokenGroups, dwSize, &dwSize))
245 HeapFree(GetProcessHeap(), 0, pTokenGroups);
252 if (!AllocateAndInitializeSid(&SidAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
253 DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pSid))
255 HeapFree(GetProcessHeap(), 0, pTokenGroups);
259 for (i = 0; i < pTokenGroups->GroupCount; i++)
261 if (EqualSid(pSid, pTokenGroups->Groups[i].Sid))
268 HeapFree(GetProcessHeap(), 0, pTokenGroups);
274 /***********************************************************************
275 * NeedRebootInit (ADVPACK.@)
277 * Sets up conditions for reboot checking.
280 * Value required by NeedReboot.
282 DWORD WINAPI NeedRebootInit(VOID)
284 FIXME("(VOID): stub\n");
288 /***********************************************************************
289 * NeedReboot (ADVPACK.@)
291 * Determines whether a reboot is required.
294 * dwRebootCheck [I] Value from NeedRebootInit.
297 * TRUE if a reboot is needed, FALSE otherwise.
302 BOOL WINAPI NeedReboot(DWORD dwRebootCheck)
304 FIXME("(%d): stub\n", dwRebootCheck);
308 /***********************************************************************
309 * OpenINFEngineA (ADVPACK.@)
311 * See OpenINFEngineW.
313 HRESULT WINAPI OpenINFEngineA(LPCSTR pszInfFilename, LPCSTR pszInstallSection,
314 DWORD dwFlags, HINF *phInf, PVOID pvReserved)
316 UNICODE_STRING filenameW, installW;
319 TRACE("(%s, %s, %d, %p, %p)\n", debugstr_a(pszInfFilename),
320 debugstr_a(pszInstallSection), dwFlags, phInf, pvReserved);
322 if (!pszInfFilename || !phInf)
325 RtlCreateUnicodeStringFromAsciiz(&filenameW, pszInfFilename);
326 RtlCreateUnicodeStringFromAsciiz(&installW, pszInstallSection);
328 res = OpenINFEngineW(filenameW.Buffer, installW.Buffer,
329 dwFlags, phInf, pvReserved);
331 RtlFreeUnicodeString(&filenameW);
332 RtlFreeUnicodeString(&installW);
337 /***********************************************************************
338 * OpenINFEngineW (ADVPACK.@)
340 * Opens and returns a handle to an INF file to be used by
341 * TranslateInfStringEx to continuously translate the INF file.
344 * pszInfFilename [I] Filename of the INF to open.
345 * pszInstallSection [I] Name of the Install section in the INF.
346 * dwFlags [I] See advpub.h.
347 * phInf [O] Handle to the loaded INF file.
348 * pvReserved [I] Reserved. Must be NULL.
354 HRESULT WINAPI OpenINFEngineW(LPCWSTR pszInfFilename, LPCWSTR pszInstallSection,
355 DWORD dwFlags, HINF *phInf, PVOID pvReserved)
357 TRACE("(%s, %s, %d, %p, %p)\n", debugstr_w(pszInfFilename),
358 debugstr_w(pszInstallSection), dwFlags, phInf, pvReserved);
360 if (!pszInfFilename || !phInf)
363 *phInf = SetupOpenInfFileW(pszInfFilename, NULL, INF_STYLE_WIN4, NULL);
364 if (*phInf == INVALID_HANDLE_VALUE)
365 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
367 set_ldids(*phInf, pszInstallSection, NULL);
372 /***********************************************************************
373 * RebootCheckOnInstallA (ADVPACK.@)
375 * See RebootCheckOnInstallW.
377 HRESULT WINAPI RebootCheckOnInstallA(HWND hWnd, LPCSTR pszINF,
378 LPCSTR pszSec, DWORD dwReserved)
380 UNICODE_STRING infW, secW;
383 TRACE("(%p, %s, %s, %d)\n", hWnd, debugstr_a(pszINF),
384 debugstr_a(pszSec), dwReserved);
386 if (!pszINF || !pszSec)
389 RtlCreateUnicodeStringFromAsciiz(&infW, pszINF);
390 RtlCreateUnicodeStringFromAsciiz(&secW, pszSec);
392 res = RebootCheckOnInstallW(hWnd, infW.Buffer, secW.Buffer, dwReserved);
394 RtlFreeUnicodeString(&infW);
395 RtlFreeUnicodeString(&secW);
400 /***********************************************************************
401 * RebootCheckOnInstallW (ADVPACK.@)
403 * Checks if a reboot is required for an installed INF section.
406 * hWnd [I] Handle to the window used for messages.
407 * pszINF [I] Filename of the INF file.
408 * pszSec [I] INF section to check.
409 * dwReserved [I] Reserved. Must be 0.
412 * Success: S_OK - Reboot is needed if the INF section is installed.
413 * S_FALSE - Reboot is not needed.
414 * Failure: HRESULT of GetLastError().
417 * if pszSec is NULL, RebootCheckOnInstall checks the DefaultInstall
418 * or DefaultInstall.NT section.
423 HRESULT WINAPI RebootCheckOnInstallW(HWND hWnd, LPCWSTR pszINF,
424 LPCWSTR pszSec, DWORD dwReserved)
426 FIXME("(%p, %s, %s, %d): stub\n", hWnd, debugstr_w(pszINF),
427 debugstr_w(pszSec), dwReserved);
432 /* registers the OCX if do_reg is TRUE, unregisters it otherwise */
433 HRESULT do_ocx_reg(HMODULE hocx, BOOL do_reg)
435 DLLREGISTER reg_func;
438 reg_func = (DLLREGISTER)GetProcAddress(hocx, "DllRegisterServer");
440 reg_func = (DLLREGISTER)GetProcAddress(hocx, "DllUnregisterServer");
449 /***********************************************************************
450 * RegisterOCX (ADVPACK.@)
455 * hWnd [I] Handle to the window used for the display.
456 * hInst [I] Instance of the process.
457 * cmdline [I] Contains parameters in the order OCX,flags,param.
458 * show [I] How the window should be shown.
465 * OCX - Filename of the OCX to register.
466 * flags - Controls the operation of RegisterOCX.
467 * 'I' Call DllRegisterServer and DllInstall.
468 * 'N' Only call DllInstall.
469 * param - Command line passed to DllInstall.
471 HRESULT WINAPI RegisterOCX(HWND hWnd, HINSTANCE hInst, LPCSTR cmdline, INT show)
473 LPWSTR ocx_filename, str_flags, param;
474 LPWSTR cmdline_copy, cmdline_ptr;
475 UNICODE_STRING cmdlineW;
480 TRACE("(%s)\n", debugstr_a(cmdline));
482 RtlCreateUnicodeStringFromAsciiz(&cmdlineW, cmdline);
484 size = (lstrlenW(cmdlineW.Buffer) + 1) * sizeof(WCHAR);
485 cmdline_copy = HeapAlloc(GetProcessHeap(), 0, size);
486 cmdline_ptr = cmdline_copy;
487 lstrcpyW(cmdline_copy, cmdlineW.Buffer);
489 ocx_filename = get_parameter(&cmdline_ptr, ',');
490 if (!ocx_filename || !*ocx_filename)
493 str_flags = get_parameter(&cmdline_ptr, ',');
494 param = get_parameter(&cmdline_ptr, ',');
496 hm = LoadLibraryExW(ocx_filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
500 hr = do_ocx_reg(hm, TRUE);
504 HeapFree(GetProcessHeap(), 0, cmdline_copy);
505 RtlFreeUnicodeString(&cmdlineW);
510 /***********************************************************************
511 * SetPerUserSecValuesA (ADVPACK.@)
513 * See SetPerUserSecValuesW.
515 HRESULT WINAPI SetPerUserSecValuesA(PERUSERSECTIONA* pPerUser)
517 PERUSERSECTIONW perUserW;
519 TRACE("(%p)\n", pPerUser);
524 MultiByteToWideChar(CP_ACP, 0, pPerUser->szGUID, -1, perUserW.szGUID,
525 sizeof(perUserW.szGUID) / sizeof(WCHAR));
526 MultiByteToWideChar(CP_ACP, 0, pPerUser->szDispName, -1, perUserW.szDispName,
527 sizeof(perUserW.szDispName) / sizeof(WCHAR));
528 MultiByteToWideChar(CP_ACP, 0, pPerUser->szLocale, -1, perUserW.szLocale,
529 sizeof(perUserW.szLocale) / sizeof(WCHAR));
530 MultiByteToWideChar(CP_ACP, 0, pPerUser->szStub, -1, perUserW.szStub,
531 sizeof(perUserW.szStub) / sizeof(WCHAR));
532 MultiByteToWideChar(CP_ACP, 0, pPerUser->szVersion, -1, perUserW.szVersion,
533 sizeof(perUserW.szVersion) / sizeof(WCHAR));
534 MultiByteToWideChar(CP_ACP, 0, pPerUser->szCompID, -1, perUserW.szCompID,
535 sizeof(perUserW.szCompID) / sizeof(WCHAR));
536 perUserW.dwIsInstalled = pPerUser->dwIsInstalled;
537 perUserW.bRollback = pPerUser->bRollback;
539 return SetPerUserSecValuesW(&perUserW);
542 /***********************************************************************
543 * SetPerUserSecValuesW (ADVPACK.@)
545 * Prepares the per-user stub values under IsInstalled\{GUID} that
546 * control the per-user installation.
549 * pPerUser [I] Per-user stub values.
555 HRESULT WINAPI SetPerUserSecValuesW(PERUSERSECTIONW* pPerUser)
559 static const WCHAR stub_path[] = {'S','t','u','b','P','a','t','h',0};
560 static const WCHAR version[] = {'V','e','r','s','i','o','n',0};
561 static const WCHAR locale[] = {'L','o','c','a','l','e',0};
562 static const WCHAR compid[] = {'C','o','m','p','o','n','e','n','t','I','D',0};
563 static const WCHAR isinstalled[] = {'I','s','I','n','s','t','a','l','l','e','d',0};
565 TRACE("(%p)\n", pPerUser);
567 if (!pPerUser || !*pPerUser->szGUID)
570 if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, setup_key, 0, NULL, 0, KEY_WRITE,
576 if (RegCreateKeyExW(setup, pPerUser->szGUID, 0, NULL, 0, KEY_ALL_ACCESS,
583 if (*pPerUser->szStub)
585 RegSetValueExW(guid, stub_path, 0, REG_SZ, (LPBYTE)pPerUser->szStub,
586 (lstrlenW(pPerUser->szStub) + 1) * sizeof(WCHAR));
589 if (*pPerUser->szVersion)
591 RegSetValueExW(guid, version, 0, REG_SZ, (LPBYTE)pPerUser->szVersion,
592 (lstrlenW(pPerUser->szVersion) + 1) * sizeof(WCHAR));
595 if (*pPerUser->szLocale)
597 RegSetValueExW(guid, locale, 0, REG_SZ, (LPBYTE)pPerUser->szLocale,
598 (lstrlenW(pPerUser->szLocale) + 1) * sizeof(WCHAR));
601 if (*pPerUser->szCompID)
603 RegSetValueExW(guid, compid, 0, REG_SZ, (LPBYTE)pPerUser->szCompID,
604 (lstrlenW(pPerUser->szCompID) + 1) * sizeof(WCHAR));
607 if (*pPerUser->szDispName)
609 RegSetValueExW(guid, NULL, 0, REG_SZ, (LPBYTE)pPerUser->szDispName,
610 (lstrlenW(pPerUser->szDispName) + 1) * sizeof(WCHAR));
613 RegSetValueExW(guid, isinstalled, 0, REG_DWORD,
614 (LPBYTE)&pPerUser->dwIsInstalled, sizeof(DWORD));
622 /***********************************************************************
623 * TranslateInfStringA (ADVPACK.@)
625 * See TranslateInfStringW.
627 HRESULT WINAPI TranslateInfStringA(LPCSTR pszInfFilename, LPCSTR pszInstallSection,
628 LPCSTR pszTranslateSection, LPCSTR pszTranslateKey, LPSTR pszBuffer,
629 DWORD dwBufferSize, PDWORD pdwRequiredSize, PVOID pvReserved)
631 UNICODE_STRING filenameW, installW;
632 UNICODE_STRING translateW, keyW;
637 TRACE("(%s, %s, %s, %s, %p, %d, %p, %p)\n",
638 debugstr_a(pszInfFilename), debugstr_a(pszInstallSection),
639 debugstr_a(pszTranslateSection), debugstr_a(pszTranslateKey),
640 pszBuffer, dwBufferSize,pdwRequiredSize, pvReserved);
642 if (!pszInfFilename || !pszTranslateSection ||
643 !pszTranslateKey || !pdwRequiredSize)
646 RtlCreateUnicodeStringFromAsciiz(&filenameW, pszInfFilename);
647 RtlCreateUnicodeStringFromAsciiz(&installW, pszInstallSection);
648 RtlCreateUnicodeStringFromAsciiz(&translateW, pszTranslateSection);
649 RtlCreateUnicodeStringFromAsciiz(&keyW, pszTranslateKey);
651 res = TranslateInfStringW(filenameW.Buffer, installW.Buffer,
652 translateW.Buffer, keyW.Buffer, NULL,
653 dwBufferSize, &len, NULL);
657 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
659 res = TranslateInfStringW(filenameW.Buffer, installW.Buffer,
660 translateW.Buffer, keyW.Buffer, bufferW,
664 *pdwRequiredSize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1,
665 NULL, 0, NULL, NULL);
667 if (dwBufferSize >= *pdwRequiredSize)
669 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, pszBuffer,
670 dwBufferSize, NULL, NULL);
673 res = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
676 HeapFree(GetProcessHeap(), 0, bufferW);
679 RtlFreeUnicodeString(&filenameW);
680 RtlFreeUnicodeString(&installW);
681 RtlFreeUnicodeString(&translateW);
682 RtlFreeUnicodeString(&keyW);
687 /***********************************************************************
688 * TranslateInfStringW (ADVPACK.@)
690 * Translates the value of a specified key in an inf file into the
691 * current locale by expanding string macros.
694 * pszInfFilename [I] Filename of the inf file.
695 * pszInstallSection [I]
696 * pszTranslateSection [I] Inf section where the key exists.
697 * pszTranslateKey [I] Key to translate.
698 * pszBuffer [O] Contains the translated string on exit.
699 * dwBufferSize [I] Size on input of pszBuffer.
700 * pdwRequiredSize [O] Length of the translated key.
701 * pvReserved [I] Reserved, must be NULL.
705 * Failure: An hresult error code.
707 HRESULT WINAPI TranslateInfStringW(LPCWSTR pszInfFilename, LPCWSTR pszInstallSection,
708 LPCWSTR pszTranslateSection, LPCWSTR pszTranslateKey, LPWSTR pszBuffer,
709 DWORD dwBufferSize, PDWORD pdwRequiredSize, PVOID pvReserved)
714 TRACE("(%s, %s, %s, %s, %p, %d, %p, %p)\n",
715 debugstr_w(pszInfFilename), debugstr_w(pszInstallSection),
716 debugstr_w(pszTranslateSection), debugstr_w(pszTranslateKey),
717 pszBuffer, dwBufferSize,pdwRequiredSize, pvReserved);
719 if (!pszInfFilename || !pszTranslateSection ||
720 !pszTranslateKey || !pdwRequiredSize)
723 hInf = SetupOpenInfFileW(pszInfFilename, NULL, INF_STYLE_WIN4, NULL);
724 if (hInf == INVALID_HANDLE_VALUE)
725 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
727 set_ldids(hInf, pszInstallSection, NULL);
729 if (!SetupGetLineTextW(NULL, hInf, pszTranslateSection, pszTranslateKey,
730 pszBuffer, dwBufferSize, pdwRequiredSize))
732 if (dwBufferSize < *pdwRequiredSize)
733 hret = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
735 hret = SPAPI_E_LINE_NOT_FOUND;
738 SetupCloseInfFile(hInf);
742 /***********************************************************************
743 * TranslateInfStringExA (ADVPACK.@)
745 * See TranslateInfStringExW.
747 HRESULT WINAPI TranslateInfStringExA(HINF hInf, LPCSTR pszInfFilename,
748 LPCSTR pszTranslateSection, LPCSTR pszTranslateKey,
749 LPSTR pszBuffer, DWORD dwBufferSize,
750 PDWORD pdwRequiredSize, PVOID pvReserved)
752 UNICODE_STRING filenameW, sectionW, keyW;
757 TRACE("(%p, %s, %s, %s, %s, %d, %p, %p)\n", hInf, debugstr_a(pszInfFilename),
758 debugstr_a(pszTranslateSection), debugstr_a(pszTranslateKey),
759 debugstr_a(pszBuffer), dwBufferSize, pdwRequiredSize, pvReserved);
761 if (!pszInfFilename || !pszTranslateSection ||
762 !pszTranslateKey || !pdwRequiredSize)
765 RtlCreateUnicodeStringFromAsciiz(&filenameW, pszInfFilename);
766 RtlCreateUnicodeStringFromAsciiz(§ionW, pszTranslateSection);
767 RtlCreateUnicodeStringFromAsciiz(&keyW, pszTranslateKey);
769 res = TranslateInfStringExW(hInf, filenameW.Buffer, sectionW.Buffer,
770 keyW.Buffer, NULL, 0, &len, NULL);
774 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
776 res = TranslateInfStringExW(hInf, filenameW.Buffer, sectionW.Buffer,
777 keyW.Buffer, bufferW, len, &len, NULL);
781 *pdwRequiredSize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1,
782 NULL, 0, NULL, NULL);
784 if (dwBufferSize >= *pdwRequiredSize)
786 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, pszBuffer,
787 dwBufferSize, NULL, NULL);
790 res = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
793 HeapFree(GetProcessHeap(), 0, bufferW);
796 RtlFreeUnicodeString(&filenameW);
797 RtlFreeUnicodeString(§ionW);
798 RtlFreeUnicodeString(&keyW);
803 /***********************************************************************
804 * TranslateInfStringExW (ADVPACK.@)
806 * Using a handle to an INF file opened with OpenINFEngine, translates
807 * the value of a specified key in an inf file into the current locale
808 * by expanding string macros.
811 * hInf [I] Handle to the INF file.
812 * pszInfFilename [I] Filename of the INF file.
813 * pszTranslateSection [I] Inf section where the key exists.
814 * pszTranslateKey [I] Key to translate.
815 * pszBuffer [O] Contains the translated string on exit.
816 * dwBufferSize [I] Size on input of pszBuffer.
817 * pdwRequiredSize [O] Length of the translated key.
818 * pvReserved [I] Reserved. Must be NULL.
825 * To use TranslateInfStringEx to translate an INF file continuously,
826 * open the INF file with OpenINFEngine, call TranslateInfStringEx as
827 * many times as needed, then release the handle with CloseINFEngine.
828 * When translating more than one keys, this method is more efficient
829 * than calling TranslateInfString, because the INF file is only
832 HRESULT WINAPI TranslateInfStringExW(HINF hInf, LPCWSTR pszInfFilename,
833 LPCWSTR pszTranslateSection, LPCWSTR pszTranslateKey,
834 LPWSTR pszBuffer, DWORD dwBufferSize,
835 PDWORD pdwRequiredSize, PVOID pvReserved)
837 TRACE("(%p, %s, %s, %s, %s, %d, %p, %p)\n", hInf, debugstr_w(pszInfFilename),
838 debugstr_w(pszTranslateSection), debugstr_w(pszTranslateKey),
839 debugstr_w(pszBuffer), dwBufferSize, pdwRequiredSize, pvReserved);
841 if (!hInf || !pszInfFilename || !pszTranslateSection || !pszTranslateKey)
844 if (!SetupGetLineTextW(NULL, hInf, pszTranslateSection, pszTranslateKey,
845 pszBuffer, dwBufferSize, pdwRequiredSize))
847 if (dwBufferSize < *pdwRequiredSize)
848 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
850 return SPAPI_E_LINE_NOT_FOUND;
856 /***********************************************************************
857 * UserInstStubWrapperA (ADVPACK.@)
859 * See UserInstStubWrapperW.
861 HRESULT WINAPI UserInstStubWrapperA(HWND hWnd, HINSTANCE hInstance,
862 LPSTR pszParms, INT nShow)
864 UNICODE_STRING parmsW;
867 TRACE("(%p, %p, %s, %i)\n", hWnd, hInstance, debugstr_a(pszParms), nShow);
872 RtlCreateUnicodeStringFromAsciiz(&parmsW, pszParms);
874 res = UserInstStubWrapperW(hWnd, hInstance, parmsW.Buffer, nShow);
876 RtlFreeUnicodeString(&parmsW);
881 /***********************************************************************
882 * UserInstStubWrapperW (ADVPACK.@)
884 * Launches the user stub wrapper specified by the RealStubPath
885 * registry value under Installed Components\szParms.
888 * hWnd [I] Handle to the window used for the display.
889 * hInstance [I] Instance of the process.
890 * szParms [I] The GUID of the installation.
891 * show [I] How the window should be shown.
898 * If the type of the StubRealPath value is REG_EXPAND_SZ, then
899 * we should call ExpandEnvironmentStrings on the value and
902 HRESULT WINAPI UserInstStubWrapperW(HWND hWnd, HINSTANCE hInstance,
903 LPWSTR pszParms, INT nShow)
906 WCHAR stub[MAX_PATH];
907 DWORD size = MAX_PATH;
911 static const WCHAR real_stub_path[] = {
912 'R','e','a','l','S','t','u','b','P','a','t','h',0
915 TRACE("(%p, %p, %s, %i)\n", hWnd, hInstance, debugstr_w(pszParms), nShow);
917 if (!pszParms || !*pszParms)
920 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, setup_key, 0, KEY_READ, &setup))
925 if (RegOpenKeyExW(setup, pszParms, 0, KEY_READ, &guid))
931 res = RegQueryValueExW(guid, real_stub_path, NULL, NULL, (LPBYTE)stub, &size);
935 /* launch the user stub wrapper */
936 hr = launch_exe(stub, NULL, NULL);
945 /***********************************************************************
946 * UserUnInstStubWrapperA (ADVPACK.@)
948 * See UserUnInstStubWrapperW.
950 HRESULT WINAPI UserUnInstStubWrapperA(HWND hWnd, HINSTANCE hInstance,
951 LPSTR pszParms, INT nShow)
953 UNICODE_STRING parmsW;
956 TRACE("(%p, %p, %s, %i)\n", hWnd, hInstance, debugstr_a(pszParms), nShow);
961 RtlCreateUnicodeStringFromAsciiz(&parmsW, pszParms);
963 res = UserUnInstStubWrapperW(hWnd, hInstance, parmsW.Buffer, nShow);
965 RtlFreeUnicodeString(&parmsW);
970 /***********************************************************************
971 * UserUnInstStubWrapperW (ADVPACK.@)
973 HRESULT WINAPI UserUnInstStubWrapperW(HWND hWnd, HINSTANCE hInstance,
974 LPWSTR pszParms, INT nShow)
976 FIXME("(%p, %p, %s, %i): stub\n", hWnd, hInstance, debugstr_w(pszParms), nShow);