msi: Change an ERR to a WARN.
[wine.git] / dlls / advpack / advpack.c
blob446e8da3b5615136c26f6e0bf006435d0d12c311
1 /*
2 * Advpack main
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
22 #include <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winuser.h"
27 #include "winreg.h"
28 #include "winver.h"
29 #include "winternl.h"
30 #include "winnls.h"
31 #include "setupapi.h"
32 #include "advpub.h"
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
42 #define PREFIX_LEN 5
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)
60 INFCONTEXT context;
61 WCHAR key[MAX_PATH], value[MAX_PATH];
62 WCHAR prefix[PREFIX_LEN];
63 HKEY root, subkey;
64 DWORD size;
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;
79 else
80 root = NULL;
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);
91 RegCloseKey(subkey);
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];
99 WCHAR dest[MAX_PATH];
100 INFCONTEXT context;
101 DWORD size;
102 int ldid;
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))
112 return;
114 if (!SetupFindFirstLineW(hInf, field, NULL, &context))
115 return;
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));
131 key_copy = key;
132 SetupGetStringFieldW(&context, 0, key, size, &size);
133 value = line;
135 else
137 key = line;
138 *(value++) = '\0';
141 /* remove leading whitespace from the value */
142 while (*value == ' ')
143 value++;
145 /* FIXME: need to check the query option */
146 ptr = strchrW(value, ',');
147 if (ptr)
148 *ptr = '\0';
150 /* set dest to pszWorkingDir if key is SourceDir */
151 if (pszWorkingDir && !lstrcmpiW(value, source_dir))
152 lstrcpynW(dest, pszWorkingDir, MAX_PATH);
153 else
154 get_dest_dir(hInf, value, dest, MAX_PATH);
156 /* set all ldids to dest */
157 while ((ptr = get_parameter(&key, ',')))
159 ldid = atolW(ptr);
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.
171 * PARAMS
172 * hInf [I] Handle to the INF file to close.
174 * RETURNS
175 * Success: S_OK.
176 * Failure: E_FAIL.
178 HRESULT WINAPI CloseINFEngine(HINF hInf)
180 TRACE("(%p)\n", hInf);
182 if (!hInf)
183 return E_INVALIDARG;
185 SetupCloseInfFile(hInf);
186 return S_OK;
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);
199 return TRUE;
202 /***********************************************************************
203 * IsNTAdmin (ADVPACK.@)
205 * Checks if the user has admin privileges.
207 * PARAMS
208 * reserved [I] Reserved. Must be 0.
209 * pReserved [I] Reserved. Must be NULL.
211 * RETURNS
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;
219 DWORD dwSize, i;
220 HANDLE hToken;
221 PSID pSid;
223 TRACE("(%ld, %p)\n", reserved, pReserved);
225 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
226 return FALSE;
228 if (!GetTokenInformation(hToken, TokenGroups, NULL, 0, &dwSize))
230 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
232 CloseHandle(hToken);
233 return FALSE;
237 pTokenGroups = HeapAlloc(GetProcessHeap(), 0, dwSize);
238 if (!pTokenGroups)
240 CloseHandle(hToken);
241 return FALSE;
244 if (!GetTokenInformation(hToken, TokenGroups, pTokenGroups, dwSize, &dwSize))
246 HeapFree(GetProcessHeap(), 0, pTokenGroups);
247 CloseHandle(hToken);
248 return FALSE;
251 CloseHandle(hToken);
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);
257 return FALSE;
260 for (i = 0; i < pTokenGroups->GroupCount; i++)
262 if (EqualSid(pSid, pTokenGroups->Groups[i].Sid))
264 bSidFound = TRUE;
265 break;
269 HeapFree(GetProcessHeap(), 0, pTokenGroups);
270 FreeSid(pSid);
272 return bSidFound;
275 /***********************************************************************
276 * NeedRebootInit (ADVPACK.@)
278 * Sets up conditions for reboot checking.
280 * RETURNS
281 * Value required by NeedReboot.
283 DWORD WINAPI NeedRebootInit(VOID)
285 FIXME("(VOID): stub\n");
286 return 0;
289 /***********************************************************************
290 * NeedReboot (ADVPACK.@)
292 * Determines whether a reboot is required.
294 * PARAMS
295 * dwRebootCheck [I] Value from NeedRebootInit.
297 * RETURNS
298 * TRUE if a reboot is needed, FALSE otherwise.
300 * BUGS
301 * Unimplemented.
303 BOOL WINAPI NeedReboot(DWORD dwRebootCheck)
305 FIXME("(%ld): stub\n", dwRebootCheck);
306 return FALSE;
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;
318 HRESULT res;
320 TRACE("(%s, %s, %ld, %p, %p)\n", debugstr_a(pszInfFilename),
321 debugstr_a(pszInstallSection), dwFlags, phInf, pvReserved);
323 if (!pszInfFilename || !phInf)
324 return E_INVALIDARG;
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);
335 return res;
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.
344 * PARAMS
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.
351 * RETURNS
352 * Success: S_OK.
353 * Failure: E_FAIL.
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)
362 return E_INVALIDARG;
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);
370 return S_OK;
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;
382 HRESULT res;
384 TRACE("(%p, %s, %s, %ld)\n", hWnd, debugstr_a(pszINF),
385 debugstr_a(pszSec), dwReserved);
387 if (!pszINF || !pszSec)
388 return E_INVALIDARG;
390 RtlCreateUnicodeStringFromAsciiz(&infW, pszINF);
391 RtlCreateUnicodeStringFromAsciiz(&secW, pszSec);
393 res = RebootCheckOnInstallW(hWnd, infW.Buffer, secW.Buffer, dwReserved);
395 RtlFreeUnicodeString(&infW);
396 RtlFreeUnicodeString(&secW);
398 return res;
401 /***********************************************************************
402 * RebootCheckOnInstallW (ADVPACK.@)
404 * Checks if a reboot is required for an installed INF section.
406 * PARAMS
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.
412 * RETURNS
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().
417 * NOTES
418 * if pszSec is NULL, RebootCheckOnInstall checks the DefaultInstall
419 * or DefaultInstall.NT section.
421 * BUGS
422 * Unimplemented.
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);
430 return E_FAIL;
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;
438 if (do_reg)
439 reg_func = (DLLREGISTER)GetProcAddress(hocx, "DllRegisterServer");
440 else
441 reg_func = (DLLREGISTER)GetProcAddress(hocx, "DllUnregisterServer");
443 if (!reg_func)
444 return E_FAIL;
446 reg_func();
447 return S_OK;
450 /***********************************************************************
451 * RegisterOCX (ADVPACK.@)
453 * Registers an OCX.
455 * PARAMS
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.
461 * RETURNS
462 * Success: S_OK.
463 * Failure: E_FAIL.
465 * NOTES
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;
477 HRESULT hr = E_FAIL;
478 HMODULE hm = NULL;
479 DWORD size;
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)
492 goto done;
494 str_flags = get_parameter(&cmdline_ptr, ',');
495 param = get_parameter(&cmdline_ptr, ',');
497 hm = LoadLibraryExW(ocx_filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
498 if (!hm)
499 goto done;
501 hr = do_ocx_reg(hm, TRUE);
503 done:
504 FreeLibrary(hm);
505 HeapFree(GetProcessHeap(), 0, cmdline_copy);
506 RtlFreeUnicodeString(&cmdlineW);
508 return hr;
511 /***********************************************************************
512 * SetPerUserSecValuesA (ADVPACK.@)
514 * See SetPerUserSecValuesW.
516 HRESULT WINAPI SetPerUserSecValuesA(PERUSERSECTIONA* pPerUser)
518 PERUSERSECTIONW perUserW;
520 TRACE("(%p)\n", pPerUser);
522 if (!pPerUser)
523 return E_INVALIDARG;
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.
549 * PARAMS
550 * pPerUser [I] Per-user stub values.
552 * RETURNS
553 * Success: S_OK.
554 * Failure: E_FAIL.
556 HRESULT WINAPI SetPerUserSecValuesW(PERUSERSECTIONW* pPerUser)
558 HKEY setup, guid;
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)
569 return S_OK;
571 if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, setup_key, 0, NULL, 0, KEY_WRITE,
572 NULL, &setup, NULL))
574 return E_FAIL;
577 if (RegCreateKeyExW(setup, pPerUser->szGUID, 0, NULL, 0, KEY_ALL_ACCESS,
578 NULL, &guid, NULL))
580 RegCloseKey(setup);
581 return E_FAIL;
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));
617 RegCloseKey(guid);
618 RegCloseKey(setup);
620 return S_OK;
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;
634 LPWSTR bufferW;
635 HRESULT res;
636 DWORD len = 0;
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)
645 return E_INVALIDARG;
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);
656 if (res == S_OK)
658 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
660 res = TranslateInfStringW(filenameW.Buffer, installW.Buffer,
661 translateW.Buffer, keyW.Buffer, bufferW,
662 len, &len, NULL);
663 if (res == S_OK)
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);
673 else
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);
685 return res;
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.
694 * PARAMS
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.
704 * RETURNS
705 * Success: S_OK.
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)
712 HINF hInf;
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)
721 return E_INVALIDARG;
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);
739 return S_OK;
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;
753 LPWSTR bufferW;
754 HRESULT res;
755 DWORD len = 0;
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)
763 return E_INVALIDARG;
765 RtlCreateUnicodeStringFromAsciiz(&filenameW, pszInfFilename);
766 RtlCreateUnicodeStringFromAsciiz(&sectionW, pszTranslateSection);
767 RtlCreateUnicodeStringFromAsciiz(&keyW, pszTranslateKey);
769 res = TranslateInfStringExW(hInf, filenameW.Buffer, sectionW.Buffer,
770 keyW.Buffer, NULL, 0, &len, NULL);
772 if (res == S_OK)
774 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
776 res = TranslateInfStringExW(hInf, filenameW.Buffer, sectionW.Buffer,
777 keyW.Buffer, bufferW, len, &len, NULL);
779 if (res == S_OK)
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);
789 else
790 res = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
793 HeapFree(GetProcessHeap(), 0, bufferW);
796 RtlFreeUnicodeString(&filenameW);
797 RtlFreeUnicodeString(&sectionW);
798 RtlFreeUnicodeString(&keyW);
800 return res;
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.
810 * PARAMS
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.
820 * RETURNS
821 * Success: S_OK.
822 * Failure: E_FAIL.
824 * NOTES
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
830 * opened once.
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)
842 return E_INVALIDARG;
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;
853 return S_OK;
856 /***********************************************************************
857 * UserInstStubWrapperA (ADVPACK.@)
859 * See UserInstStubWrapperW.
861 HRESULT WINAPI UserInstStubWrapperA(HWND hWnd, HINSTANCE hInstance,
862 LPSTR pszParms, INT nShow)
864 UNICODE_STRING parmsW;
865 HRESULT res;
867 TRACE("(%p, %p, %s, %i)\n", hWnd, hInstance, debugstr_a(pszParms), nShow);
869 if (!pszParms)
870 return E_INVALIDARG;
872 RtlCreateUnicodeStringFromAsciiz(&parmsW, pszParms);
874 res = UserInstStubWrapperW(hWnd, hInstance, parmsW.Buffer, nShow);
876 RtlFreeUnicodeString(&parmsW);
878 return res;
881 /***********************************************************************
882 * UserInstStubWrapperW (ADVPACK.@)
884 * Launches the user stub wrapper specified by the RealStubPath
885 * registry value under Installed Components\szParms.
887 * PARAMS
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.
893 * RETURNS
894 * Success: S_OK.
895 * Failure: E_FAIL.
897 * TODO
898 * If the type of the StubRealPath value is REG_EXPAND_SZ, then
899 * we should call ExpandEnvironmentStrings on the value and
900 * launch the result.
902 HRESULT WINAPI UserInstStubWrapperW(HWND hWnd, HINSTANCE hInstance,
903 LPWSTR pszParms, INT nShow)
905 HKEY setup, guid;
906 WCHAR stub[MAX_PATH];
907 DWORD size = MAX_PATH;
908 HRESULT hr = S_OK;
909 BOOL res;
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)
918 return E_INVALIDARG;
920 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, setup_key, 0, KEY_READ, &setup))
922 return E_FAIL;
925 if (RegOpenKeyExW(setup, pszParms, 0, KEY_READ, &guid))
927 RegCloseKey(setup);
928 return E_FAIL;
931 res = RegQueryValueExW(guid, real_stub_path, NULL, NULL, (LPBYTE)stub, &size);
932 if (res || !*stub)
933 goto done;
935 /* launch the user stub wrapper */
936 hr = launch_exe(stub, NULL, NULL);
938 done:
939 RegCloseKey(setup);
940 RegCloseKey(guid);
942 return hr;
945 /***********************************************************************
946 * UserUnInstStubWrapperA (ADVPACK.@)
948 * See UserUnInstStubWrapperW.
950 HRESULT WINAPI UserUnInstStubWrapperA(HWND hWnd, HINSTANCE hInstance,
951 LPSTR pszParms, INT nShow)
953 UNICODE_STRING parmsW;
954 HRESULT res;
956 TRACE("(%p, %p, %s, %i)\n", hWnd, hInstance, debugstr_a(pszParms), nShow);
958 if (!pszParms)
959 return E_INVALIDARG;
961 RtlCreateUnicodeStringFromAsciiz(&parmsW, pszParms);
963 res = UserUnInstStubWrapperW(hWnd, hInstance, parmsW.Buffer, nShow);
965 RtlFreeUnicodeString(&parmsW);
967 return res;
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);
978 return E_FAIL;