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, %ld, %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("(%ld, %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("(%ld): 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, %ld, %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, %ld, %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 LPSTR pszSec, DWORD dwReserved)
381 UNICODE_STRING infW, secW;
384 TRACE("(%p, %s, %s, %ld)\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 LPWSTR pszSec, DWORD dwReserved)
427 FIXME("(%p, %s, %s, %ld): 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, %ld, %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)
714 TRACE("(%s, %s, %s, %s, %p, %ld, %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 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
735 return 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, %ld, %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, %ld, %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);