[CLT2012]
[reactos.git] / dll / win32 / advpack / advpack.c
1 /*
2 * Advpack main
3 *
4 * Copyright 2004 Huw D M Davies
5 * Copyright 2005 Sami Aario
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winuser.h"
27 #include "winreg.h"
28 #include "winternl.h"
29 #include "winnls.h"
30 #include "setupapi.h"
31 #include "advpub.h"
32 #include "wine/unicode.h"
33 #include "wine/debug.h"
34 #include "advpack_private.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(advpack);
37
38 typedef HRESULT (WINAPI *DLLREGISTER) (void);
39
40 #define MAX_FIELD_LENGTH 512
41 #define PREFIX_LEN 5
42
43 /* registry path of the Installed Components key for per-user stubs */
44 static const WCHAR setup_key[] = {
45 'S','O','F','T','W','A','R','E','\\',
46 'M','i','c','r','o','s','o','f','t','\\',
47 'A','c','t','i','v','e',' ','S','e','t','u','p','\\',
48 'I','n','s','t','a','l','l','e','d',' ',
49 'C','o','m','p','o','n','e','n','t','s',0
50 };
51
52 /* Strip single quotes from a token - note size includes NULL */
53 static void strip_quotes(WCHAR *buffer, DWORD *size)
54 {
55 if (buffer[0] == '\'' && (*size > 1) && buffer[*size-2]=='\'')
56 {
57 *size -= 2;
58 buffer[*size] = 0x00;
59 memmove(buffer, buffer + 1, *size * sizeof(WCHAR));
60 }
61 }
62
63 /* parses the destination directory parameters from pszSection
64 * the parameters are of the form: root,key,value,unknown,fallback
65 * we first read the reg value root\\key\\value and if that fails,
66 * use fallback as the destination directory
67 */
68 static void get_dest_dir(HINF hInf, PCWSTR pszSection, PWSTR pszBuffer, DWORD dwSize)
69 {
70 INFCONTEXT context;
71 WCHAR key[MAX_PATH + 2], value[MAX_PATH + 2];
72 WCHAR prefix[PREFIX_LEN + 2];
73 HKEY root, subkey = 0;
74 DWORD size;
75
76 static const WCHAR hklm[] = {'H','K','L','M',0};
77 static const WCHAR hkcu[] = {'H','K','C','U',0};
78
79 /* load the destination parameters */
80 SetupFindFirstLineW(hInf, pszSection, NULL, &context);
81 SetupGetStringFieldW(&context, 1, prefix, PREFIX_LEN + 2, &size);
82 strip_quotes(prefix, &size);
83 SetupGetStringFieldW(&context, 2, key, MAX_PATH + 2, &size);
84 strip_quotes(key, &size);
85 SetupGetStringFieldW(&context, 3, value, MAX_PATH + 2, &size);
86 strip_quotes(value, &size);
87
88 if (!lstrcmpW(prefix, hklm))
89 root = HKEY_LOCAL_MACHINE;
90 else if (!lstrcmpW(prefix, hkcu))
91 root = HKEY_CURRENT_USER;
92 else
93 root = NULL;
94
95 size = dwSize * sizeof(WCHAR);
96
97 /* fallback to the default destination dir if reg fails */
98 if (RegOpenKeyW(root, key, &subkey) ||
99 RegQueryValueExW(subkey, value, NULL, NULL, (LPBYTE)pszBuffer, &size))
100 {
101 SetupGetStringFieldW(&context, 5, pszBuffer, dwSize, &size);
102 strip_quotes(pszBuffer, &size);
103 }
104
105 if (subkey) RegCloseKey(subkey);
106 }
107
108 /* loads the LDIDs specified in the install section of an INF */
109 void set_ldids(HINF hInf, LPCWSTR pszInstallSection, LPCWSTR pszWorkingDir)
110 {
111 WCHAR field[MAX_FIELD_LENGTH];
112 WCHAR line[MAX_FIELD_LENGTH];
113 WCHAR dest[MAX_PATH];
114 INFCONTEXT context;
115 DWORD size;
116 int ldid;
117
118 static const WCHAR source_dir[] = {'S','o','u','r','c','e','D','i','r',0};
119
120 static const WCHAR custDestW[] = {
121 'C','u','s','t','o','m','D','e','s','t','i','n','a','t','i','o','n',0
122 };
123
124 if (!SetupGetLineTextW(NULL, hInf, pszInstallSection, custDestW,
125 field, MAX_FIELD_LENGTH, &size))
126 return;
127
128 if (!SetupFindFirstLineW(hInf, field, NULL, &context))
129 return;
130
131 do
132 {
133 LPWSTR value, ptr, key, key_copy = NULL;
134 DWORD flags = 0;
135
136 SetupGetLineTextW(&context, NULL, NULL, NULL,
137 line, MAX_FIELD_LENGTH, &size);
138
139 /* SetupGetLineTextW returns the value if there is only one key, but
140 * returns the whole line if there is more than one key
141 */
142 if (!(value = strchrW(line, '=')))
143 {
144 SetupGetStringFieldW(&context, 0, NULL, 0, &size);
145 key = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
146 key_copy = key;
147 SetupGetStringFieldW(&context, 0, key, size, &size);
148 value = line;
149 }
150 else
151 {
152 key = line;
153 *(value++) = '\0';
154 }
155
156 /* remove leading whitespace from the value */
157 while (*value == ' ')
158 value++;
159
160 /* Extract the flags */
161 ptr = strchrW(value, ',');
162 if (ptr) {
163 *ptr = '\0';
164 flags = atolW(ptr+1);
165 }
166
167 /* set dest to pszWorkingDir if key is SourceDir */
168 if (pszWorkingDir && !lstrcmpiW(value, source_dir))
169 lstrcpynW(dest, pszWorkingDir, MAX_PATH);
170 else
171 get_dest_dir(hInf, value, dest, MAX_PATH);
172
173 /* If prompting required, provide dialog to request path */
174 if (flags & 0x04)
175 FIXME("Need to support changing paths - default will be used\n");
176
177 /* set all ldids to dest */
178 while ((ptr = get_parameter(&key, ',')))
179 {
180 ldid = atolW(ptr);
181 SetupSetDirectoryIdW(hInf, ldid, dest);
182 }
183 HeapFree(GetProcessHeap(), 0, key_copy);
184 } while (SetupFindNextLine(&context, &context));
185 }
186
187 /***********************************************************************
188 * CloseINFEngine (ADVPACK.@)
189 *
190 * Closes a handle to an INF file opened with OpenINFEngine.
191 *
192 * PARAMS
193 * hInf [I] Handle to the INF file to close.
194 *
195 * RETURNS
196 * Success: S_OK.
197 * Failure: E_FAIL.
198 */
199 HRESULT WINAPI CloseINFEngine(HINF hInf)
200 {
201 TRACE("(%p)\n", hInf);
202
203 if (!hInf)
204 return E_INVALIDARG;
205
206 SetupCloseInfFile(hInf);
207 return S_OK;
208 }
209
210 /***********************************************************************
211 * DllMain (ADVPACK.@)
212 */
213 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
214 {
215 TRACE("(%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
216
217 if (fdwReason == DLL_PROCESS_ATTACH)
218 DisableThreadLibraryCalls(hinstDLL);
219
220 return TRUE;
221 }
222
223 /***********************************************************************
224 * IsNTAdmin (ADVPACK.@)
225 *
226 * Checks if the user has admin privileges.
227 *
228 * PARAMS
229 * reserved [I] Reserved. Must be 0.
230 * pReserved [I] Reserved. Must be NULL.
231 *
232 * RETURNS
233 * TRUE if user has admin rights, FALSE otherwise.
234 */
235 BOOL WINAPI IsNTAdmin(DWORD reserved, LPDWORD pReserved)
236 {
237 SID_IDENTIFIER_AUTHORITY SidAuthority = {SECURITY_NT_AUTHORITY};
238 PTOKEN_GROUPS pTokenGroups;
239 BOOL bSidFound = FALSE;
240 DWORD dwSize, i;
241 HANDLE hToken;
242 PSID pSid;
243
244 TRACE("(%d, %p)\n", reserved, pReserved);
245
246 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
247 return FALSE;
248
249 if (!GetTokenInformation(hToken, TokenGroups, NULL, 0, &dwSize))
250 {
251 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
252 {
253 CloseHandle(hToken);
254 return FALSE;
255 }
256 }
257
258 pTokenGroups = HeapAlloc(GetProcessHeap(), 0, dwSize);
259 if (!pTokenGroups)
260 {
261 CloseHandle(hToken);
262 return FALSE;
263 }
264
265 if (!GetTokenInformation(hToken, TokenGroups, pTokenGroups, dwSize, &dwSize))
266 {
267 HeapFree(GetProcessHeap(), 0, pTokenGroups);
268 CloseHandle(hToken);
269 return FALSE;
270 }
271
272 CloseHandle(hToken);
273
274 if (!AllocateAndInitializeSid(&SidAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
275 DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pSid))
276 {
277 HeapFree(GetProcessHeap(), 0, pTokenGroups);
278 return FALSE;
279 }
280
281 for (i = 0; i < pTokenGroups->GroupCount; i++)
282 {
283 if (EqualSid(pSid, pTokenGroups->Groups[i].Sid))
284 {
285 bSidFound = TRUE;
286 break;
287 }
288 }
289
290 HeapFree(GetProcessHeap(), 0, pTokenGroups);
291 FreeSid(pSid);
292
293 return bSidFound;
294 }
295
296 /***********************************************************************
297 * NeedRebootInit (ADVPACK.@)
298 *
299 * Sets up conditions for reboot checking.
300 *
301 * RETURNS
302 * Value required by NeedReboot.
303 */
304 DWORD WINAPI NeedRebootInit(VOID)
305 {
306 FIXME("(VOID): stub\n");
307 return 0;
308 }
309
310 /***********************************************************************
311 * NeedReboot (ADVPACK.@)
312 *
313 * Determines whether a reboot is required.
314 *
315 * PARAMS
316 * dwRebootCheck [I] Value from NeedRebootInit.
317 *
318 * RETURNS
319 * TRUE if a reboot is needed, FALSE otherwise.
320 *
321 * BUGS
322 * Unimplemented.
323 */
324 BOOL WINAPI NeedReboot(DWORD dwRebootCheck)
325 {
326 FIXME("(%d): stub\n", dwRebootCheck);
327 return FALSE;
328 }
329
330 /***********************************************************************
331 * OpenINFEngineA (ADVPACK.@)
332 *
333 * See OpenINFEngineW.
334 */
335 HRESULT WINAPI OpenINFEngineA(LPCSTR pszInfFilename, LPCSTR pszInstallSection,
336 DWORD dwFlags, HINF *phInf, PVOID pvReserved)
337 {
338 UNICODE_STRING filenameW, installW;
339 HRESULT res;
340
341 TRACE("(%s, %s, %d, %p, %p)\n", debugstr_a(pszInfFilename),
342 debugstr_a(pszInstallSection), dwFlags, phInf, pvReserved);
343
344 if (!pszInfFilename || !phInf)
345 return E_INVALIDARG;
346
347 RtlCreateUnicodeStringFromAsciiz(&filenameW, pszInfFilename);
348 RtlCreateUnicodeStringFromAsciiz(&installW, pszInstallSection);
349
350 res = OpenINFEngineW(filenameW.Buffer, installW.Buffer,
351 dwFlags, phInf, pvReserved);
352
353 RtlFreeUnicodeString(&filenameW);
354 RtlFreeUnicodeString(&installW);
355
356 return res;
357 }
358
359 /***********************************************************************
360 * OpenINFEngineW (ADVPACK.@)
361 *
362 * Opens and returns a handle to an INF file to be used by
363 * TranslateInfStringEx to continuously translate the INF file.
364 *
365 * PARAMS
366 * pszInfFilename [I] Filename of the INF to open.
367 * pszInstallSection [I] Name of the Install section in the INF.
368 * dwFlags [I] See advpub.h.
369 * phInf [O] Handle to the loaded INF file.
370 * pvReserved [I] Reserved. Must be NULL.
371 *
372 * RETURNS
373 * Success: S_OK.
374 * Failure: E_FAIL.
375 */
376 HRESULT WINAPI OpenINFEngineW(LPCWSTR pszInfFilename, LPCWSTR pszInstallSection,
377 DWORD dwFlags, HINF *phInf, PVOID pvReserved)
378 {
379 TRACE("(%s, %s, %d, %p, %p)\n", debugstr_w(pszInfFilename),
380 debugstr_w(pszInstallSection), dwFlags, phInf, pvReserved);
381
382 if (!pszInfFilename || !phInf)
383 return E_INVALIDARG;
384
385 *phInf = SetupOpenInfFileW(pszInfFilename, NULL, INF_STYLE_WIN4, NULL);
386 if (*phInf == INVALID_HANDLE_VALUE)
387 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
388
389 set_ldids(*phInf, pszInstallSection, NULL);
390
391 return S_OK;
392 }
393
394 /***********************************************************************
395 * RebootCheckOnInstallA (ADVPACK.@)
396 *
397 * See RebootCheckOnInstallW.
398 */
399 HRESULT WINAPI RebootCheckOnInstallA(HWND hWnd, LPCSTR pszINF,
400 LPCSTR pszSec, DWORD dwReserved)
401 {
402 UNICODE_STRING infW, secW;
403 HRESULT res;
404
405 TRACE("(%p, %s, %s, %d)\n", hWnd, debugstr_a(pszINF),
406 debugstr_a(pszSec), dwReserved);
407
408 if (!pszINF || !pszSec)
409 return E_INVALIDARG;
410
411 RtlCreateUnicodeStringFromAsciiz(&infW, pszINF);
412 RtlCreateUnicodeStringFromAsciiz(&secW, pszSec);
413
414 res = RebootCheckOnInstallW(hWnd, infW.Buffer, secW.Buffer, dwReserved);
415
416 RtlFreeUnicodeString(&infW);
417 RtlFreeUnicodeString(&secW);
418
419 return res;
420 }
421
422 /***********************************************************************
423 * RebootCheckOnInstallW (ADVPACK.@)
424 *
425 * Checks if a reboot is required for an installed INF section.
426 *
427 * PARAMS
428 * hWnd [I] Handle to the window used for messages.
429 * pszINF [I] Filename of the INF file.
430 * pszSec [I] INF section to check.
431 * dwReserved [I] Reserved. Must be 0.
432 *
433 * RETURNS
434 * Success: S_OK - Reboot is needed if the INF section is installed.
435 * S_FALSE - Reboot is not needed.
436 * Failure: HRESULT of GetLastError().
437 *
438 * NOTES
439 * if pszSec is NULL, RebootCheckOnInstall checks the DefaultInstall
440 * or DefaultInstall.NT section.
441 *
442 * BUGS
443 * Unimplemented.
444 */
445 HRESULT WINAPI RebootCheckOnInstallW(HWND hWnd, LPCWSTR pszINF,
446 LPCWSTR pszSec, DWORD dwReserved)
447 {
448 FIXME("(%p, %s, %s, %d): stub\n", hWnd, debugstr_w(pszINF),
449 debugstr_w(pszSec), dwReserved);
450
451 return E_FAIL;
452 }
453
454 /* registers the OCX if do_reg is TRUE, unregisters it otherwise */
455 HRESULT do_ocx_reg(HMODULE hocx, BOOL do_reg)
456 {
457 DLLREGISTER reg_func;
458
459 if (do_reg)
460 reg_func = (DLLREGISTER)GetProcAddress(hocx, "DllRegisterServer");
461 else
462 reg_func = (DLLREGISTER)GetProcAddress(hocx, "DllUnregisterServer");
463
464 if (!reg_func)
465 return E_FAIL;
466
467 reg_func();
468 return S_OK;
469 }
470
471 /***********************************************************************
472 * RegisterOCX (ADVPACK.@)
473 *
474 * Registers an OCX.
475 *
476 * PARAMS
477 * hWnd [I] Handle to the window used for the display.
478 * hInst [I] Instance of the process.
479 * cmdline [I] Contains parameters in the order OCX,flags,param.
480 * show [I] How the window should be shown.
481 *
482 * RETURNS
483 * Success: S_OK.
484 * Failure: E_FAIL.
485 *
486 * NOTES
487 * OCX - Filename of the OCX to register.
488 * flags - Controls the operation of RegisterOCX.
489 * 'I' Call DllRegisterServer and DllInstall.
490 * 'N' Only call DllInstall.
491 * param - Command line passed to DllInstall.
492 */
493 HRESULT WINAPI RegisterOCX(HWND hWnd, HINSTANCE hInst, LPCSTR cmdline, INT show)
494 {
495 LPWSTR ocx_filename, str_flags, param;
496 LPWSTR cmdline_copy, cmdline_ptr;
497 UNICODE_STRING cmdlineW;
498 HRESULT hr = E_FAIL;
499 HMODULE hm = NULL;
500 DWORD size;
501
502 TRACE("(%s)\n", debugstr_a(cmdline));
503
504 RtlCreateUnicodeStringFromAsciiz(&cmdlineW, cmdline);
505
506 size = (lstrlenW(cmdlineW.Buffer) + 1) * sizeof(WCHAR);
507 cmdline_copy = HeapAlloc(GetProcessHeap(), 0, size);
508 cmdline_ptr = cmdline_copy;
509 lstrcpyW(cmdline_copy, cmdlineW.Buffer);
510
511 ocx_filename = get_parameter(&cmdline_ptr, ',');
512 if (!ocx_filename || !*ocx_filename)
513 goto done;
514
515 str_flags = get_parameter(&cmdline_ptr, ',');
516 param = get_parameter(&cmdline_ptr, ',');
517
518 hm = LoadLibraryExW(ocx_filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
519 if (!hm)
520 goto done;
521
522 hr = do_ocx_reg(hm, TRUE);
523
524 done:
525 FreeLibrary(hm);
526 HeapFree(GetProcessHeap(), 0, cmdline_copy);
527 RtlFreeUnicodeString(&cmdlineW);
528
529 return hr;
530 }
531
532 /***********************************************************************
533 * SetPerUserSecValuesA (ADVPACK.@)
534 *
535 * See SetPerUserSecValuesW.
536 */
537 HRESULT WINAPI SetPerUserSecValuesA(PERUSERSECTIONA* pPerUser)
538 {
539 PERUSERSECTIONW perUserW;
540
541 TRACE("(%p)\n", pPerUser);
542
543 if (!pPerUser)
544 return E_INVALIDARG;
545
546 MultiByteToWideChar(CP_ACP, 0, pPerUser->szGUID, -1, perUserW.szGUID,
547 sizeof(perUserW.szGUID) / sizeof(WCHAR));
548 MultiByteToWideChar(CP_ACP, 0, pPerUser->szDispName, -1, perUserW.szDispName,
549 sizeof(perUserW.szDispName) / sizeof(WCHAR));
550 MultiByteToWideChar(CP_ACP, 0, pPerUser->szLocale, -1, perUserW.szLocale,
551 sizeof(perUserW.szLocale) / sizeof(WCHAR));
552 MultiByteToWideChar(CP_ACP, 0, pPerUser->szStub, -1, perUserW.szStub,
553 sizeof(perUserW.szStub) / sizeof(WCHAR));
554 MultiByteToWideChar(CP_ACP, 0, pPerUser->szVersion, -1, perUserW.szVersion,
555 sizeof(perUserW.szVersion) / sizeof(WCHAR));
556 MultiByteToWideChar(CP_ACP, 0, pPerUser->szCompID, -1, perUserW.szCompID,
557 sizeof(perUserW.szCompID) / sizeof(WCHAR));
558 perUserW.dwIsInstalled = pPerUser->dwIsInstalled;
559 perUserW.bRollback = pPerUser->bRollback;
560
561 return SetPerUserSecValuesW(&perUserW);
562 }
563
564 /***********************************************************************
565 * SetPerUserSecValuesW (ADVPACK.@)
566 *
567 * Prepares the per-user stub values under IsInstalled\{GUID} that
568 * control the per-user installation.
569 *
570 * PARAMS
571 * pPerUser [I] Per-user stub values.
572 *
573 * RETURNS
574 * Success: S_OK.
575 * Failure: E_FAIL.
576 */
577 HRESULT WINAPI SetPerUserSecValuesW(PERUSERSECTIONW* pPerUser)
578 {
579 HKEY setup, guid;
580
581 static const WCHAR stub_path[] = {'S','t','u','b','P','a','t','h',0};
582 static const WCHAR version[] = {'V','e','r','s','i','o','n',0};
583 static const WCHAR locale[] = {'L','o','c','a','l','e',0};
584 static const WCHAR compid[] = {'C','o','m','p','o','n','e','n','t','I','D',0};
585 static const WCHAR isinstalled[] = {'I','s','I','n','s','t','a','l','l','e','d',0};
586
587 TRACE("(%p)\n", pPerUser);
588
589 if (!pPerUser || !*pPerUser->szGUID)
590 return S_OK;
591
592 if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, setup_key, 0, NULL, 0, KEY_WRITE,
593 NULL, &setup, NULL))
594 {
595 return E_FAIL;
596 }
597
598 if (RegCreateKeyExW(setup, pPerUser->szGUID, 0, NULL, 0, KEY_ALL_ACCESS,
599 NULL, &guid, NULL))
600 {
601 RegCloseKey(setup);
602 return E_FAIL;
603 }
604
605 if (*pPerUser->szStub)
606 {
607 RegSetValueExW(guid, stub_path, 0, REG_SZ, (LPBYTE)pPerUser->szStub,
608 (lstrlenW(pPerUser->szStub) + 1) * sizeof(WCHAR));
609 }
610
611 if (*pPerUser->szVersion)
612 {
613 RegSetValueExW(guid, version, 0, REG_SZ, (LPBYTE)pPerUser->szVersion,
614 (lstrlenW(pPerUser->szVersion) + 1) * sizeof(WCHAR));
615 }
616
617 if (*pPerUser->szLocale)
618 {
619 RegSetValueExW(guid, locale, 0, REG_SZ, (LPBYTE)pPerUser->szLocale,
620 (lstrlenW(pPerUser->szLocale) + 1) * sizeof(WCHAR));
621 }
622
623 if (*pPerUser->szCompID)
624 {
625 RegSetValueExW(guid, compid, 0, REG_SZ, (LPBYTE)pPerUser->szCompID,
626 (lstrlenW(pPerUser->szCompID) + 1) * sizeof(WCHAR));
627 }
628
629 if (*pPerUser->szDispName)
630 {
631 RegSetValueExW(guid, NULL, 0, REG_SZ, (LPBYTE)pPerUser->szDispName,
632 (lstrlenW(pPerUser->szDispName) + 1) * sizeof(WCHAR));
633 }
634
635 RegSetValueExW(guid, isinstalled, 0, REG_DWORD,
636 (LPBYTE)&pPerUser->dwIsInstalled, sizeof(DWORD));
637
638 RegCloseKey(guid);
639 RegCloseKey(setup);
640
641 return S_OK;
642 }
643
644 /***********************************************************************
645 * TranslateInfStringA (ADVPACK.@)
646 *
647 * See TranslateInfStringW.
648 */
649 HRESULT WINAPI TranslateInfStringA(LPCSTR pszInfFilename, LPCSTR pszInstallSection,
650 LPCSTR pszTranslateSection, LPCSTR pszTranslateKey, LPSTR pszBuffer,
651 DWORD dwBufferSize, PDWORD pdwRequiredSize, PVOID pvReserved)
652 {
653 UNICODE_STRING filenameW, installW;
654 UNICODE_STRING translateW, keyW;
655 LPWSTR bufferW;
656 HRESULT res;
657 DWORD len = 0;
658
659 TRACE("(%s, %s, %s, %s, %p, %d, %p, %p)\n",
660 debugstr_a(pszInfFilename), debugstr_a(pszInstallSection),
661 debugstr_a(pszTranslateSection), debugstr_a(pszTranslateKey),
662 pszBuffer, dwBufferSize,pdwRequiredSize, pvReserved);
663
664 if (!pszInfFilename || !pszTranslateSection ||
665 !pszTranslateKey || !pdwRequiredSize)
666 return E_INVALIDARG;
667
668 RtlCreateUnicodeStringFromAsciiz(&filenameW, pszInfFilename);
669 RtlCreateUnicodeStringFromAsciiz(&installW, pszInstallSection);
670 RtlCreateUnicodeStringFromAsciiz(&translateW, pszTranslateSection);
671 RtlCreateUnicodeStringFromAsciiz(&keyW, pszTranslateKey);
672
673 res = TranslateInfStringW(filenameW.Buffer, installW.Buffer,
674 translateW.Buffer, keyW.Buffer, NULL,
675 dwBufferSize, &len, NULL);
676
677 if (res == S_OK)
678 {
679 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
680
681 res = TranslateInfStringW(filenameW.Buffer, installW.Buffer,
682 translateW.Buffer, keyW.Buffer, bufferW,
683 len, &len, NULL);
684 if (res == S_OK)
685 {
686 *pdwRequiredSize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1,
687 NULL, 0, NULL, NULL);
688
689 if (dwBufferSize >= *pdwRequiredSize)
690 {
691 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, pszBuffer,
692 dwBufferSize, NULL, NULL);
693 }
694 else
695 res = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
696 }
697
698 HeapFree(GetProcessHeap(), 0, bufferW);
699 }
700
701 RtlFreeUnicodeString(&filenameW);
702 RtlFreeUnicodeString(&installW);
703 RtlFreeUnicodeString(&translateW);
704 RtlFreeUnicodeString(&keyW);
705
706 return res;
707 }
708
709 /***********************************************************************
710 * TranslateInfStringW (ADVPACK.@)
711 *
712 * Translates the value of a specified key in an inf file into the
713 * current locale by expanding string macros.
714 *
715 * PARAMS
716 * pszInfFilename [I] Filename of the inf file.
717 * pszInstallSection [I]
718 * pszTranslateSection [I] Inf section where the key exists.
719 * pszTranslateKey [I] Key to translate.
720 * pszBuffer [O] Contains the translated string on exit.
721 * dwBufferSize [I] Size on input of pszBuffer.
722 * pdwRequiredSize [O] Length of the translated key.
723 * pvReserved [I] Reserved, must be NULL.
724 *
725 * RETURNS
726 * Success: S_OK.
727 * Failure: An hresult error code.
728 */
729 HRESULT WINAPI TranslateInfStringW(LPCWSTR pszInfFilename, LPCWSTR pszInstallSection,
730 LPCWSTR pszTranslateSection, LPCWSTR pszTranslateKey, LPWSTR pszBuffer,
731 DWORD dwBufferSize, PDWORD pdwRequiredSize, PVOID pvReserved)
732 {
733 HINF hInf;
734 HRESULT hret = S_OK;
735
736 TRACE("(%s, %s, %s, %s, %p, %d, %p, %p)\n",
737 debugstr_w(pszInfFilename), debugstr_w(pszInstallSection),
738 debugstr_w(pszTranslateSection), debugstr_w(pszTranslateKey),
739 pszBuffer, dwBufferSize,pdwRequiredSize, pvReserved);
740
741 if (!pszInfFilename || !pszTranslateSection ||
742 !pszTranslateKey || !pdwRequiredSize)
743 return E_INVALIDARG;
744
745 hInf = SetupOpenInfFileW(pszInfFilename, NULL, INF_STYLE_WIN4, NULL);
746 if (hInf == INVALID_HANDLE_VALUE)
747 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
748
749 set_ldids(hInf, pszInstallSection, NULL);
750
751 if (!SetupGetLineTextW(NULL, hInf, pszTranslateSection, pszTranslateKey,
752 pszBuffer, dwBufferSize, pdwRequiredSize))
753 {
754 if (dwBufferSize < *pdwRequiredSize)
755 hret = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
756 else
757 hret = SPAPI_E_LINE_NOT_FOUND;
758 }
759
760 SetupCloseInfFile(hInf);
761 return hret;
762 }
763
764 /***********************************************************************
765 * TranslateInfStringExA (ADVPACK.@)
766 *
767 * See TranslateInfStringExW.
768 */
769 HRESULT WINAPI TranslateInfStringExA(HINF hInf, LPCSTR pszInfFilename,
770 LPCSTR pszTranslateSection, LPCSTR pszTranslateKey,
771 LPSTR pszBuffer, DWORD dwBufferSize,
772 PDWORD pdwRequiredSize, PVOID pvReserved)
773 {
774 UNICODE_STRING filenameW, sectionW, keyW;
775 LPWSTR bufferW;
776 HRESULT res;
777 DWORD len = 0;
778
779 TRACE("(%p, %s, %s, %s, %s, %d, %p, %p)\n", hInf, debugstr_a(pszInfFilename),
780 debugstr_a(pszTranslateSection), debugstr_a(pszTranslateKey),
781 debugstr_a(pszBuffer), dwBufferSize, pdwRequiredSize, pvReserved);
782
783 if (!pszInfFilename || !pszTranslateSection ||
784 !pszTranslateKey || !pdwRequiredSize)
785 return E_INVALIDARG;
786
787 RtlCreateUnicodeStringFromAsciiz(&filenameW, pszInfFilename);
788 RtlCreateUnicodeStringFromAsciiz(&sectionW, pszTranslateSection);
789 RtlCreateUnicodeStringFromAsciiz(&keyW, pszTranslateKey);
790
791 res = TranslateInfStringExW(hInf, filenameW.Buffer, sectionW.Buffer,
792 keyW.Buffer, NULL, 0, &len, NULL);
793
794 if (res == S_OK)
795 {
796 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
797
798 res = TranslateInfStringExW(hInf, filenameW.Buffer, sectionW.Buffer,
799 keyW.Buffer, bufferW, len, &len, NULL);
800
801 if (res == S_OK)
802 {
803 *pdwRequiredSize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1,
804 NULL, 0, NULL, NULL);
805
806 if (dwBufferSize >= *pdwRequiredSize)
807 {
808 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, pszBuffer,
809 dwBufferSize, NULL, NULL);
810 }
811 else
812 res = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
813 }
814
815 HeapFree(GetProcessHeap(), 0, bufferW);
816 }
817
818 RtlFreeUnicodeString(&filenameW);
819 RtlFreeUnicodeString(&sectionW);
820 RtlFreeUnicodeString(&keyW);
821
822 return res;
823 }
824
825 /***********************************************************************
826 * TranslateInfStringExW (ADVPACK.@)
827 *
828 * Using a handle to an INF file opened with OpenINFEngine, translates
829 * the value of a specified key in an inf file into the current locale
830 * by expanding string macros.
831 *
832 * PARAMS
833 * hInf [I] Handle to the INF file.
834 * pszInfFilename [I] Filename of the INF file.
835 * pszTranslateSection [I] Inf section where the key exists.
836 * pszTranslateKey [I] Key to translate.
837 * pszBuffer [O] Contains the translated string on exit.
838 * dwBufferSize [I] Size on input of pszBuffer.
839 * pdwRequiredSize [O] Length of the translated key.
840 * pvReserved [I] Reserved. Must be NULL.
841 *
842 * RETURNS
843 * Success: S_OK.
844 * Failure: E_FAIL.
845 *
846 * NOTES
847 * To use TranslateInfStringEx to translate an INF file continuously,
848 * open the INF file with OpenINFEngine, call TranslateInfStringEx as
849 * many times as needed, then release the handle with CloseINFEngine.
850 * When translating more than one keys, this method is more efficient
851 * than calling TranslateInfString, because the INF file is only
852 * opened once.
853 */
854 HRESULT WINAPI TranslateInfStringExW(HINF hInf, LPCWSTR pszInfFilename,
855 LPCWSTR pszTranslateSection, LPCWSTR pszTranslateKey,
856 LPWSTR pszBuffer, DWORD dwBufferSize,
857 PDWORD pdwRequiredSize, PVOID pvReserved)
858 {
859 TRACE("(%p, %s, %s, %s, %s, %d, %p, %p)\n", hInf, debugstr_w(pszInfFilename),
860 debugstr_w(pszTranslateSection), debugstr_w(pszTranslateKey),
861 debugstr_w(pszBuffer), dwBufferSize, pdwRequiredSize, pvReserved);
862
863 if (!hInf || !pszInfFilename || !pszTranslateSection || !pszTranslateKey)
864 return E_INVALIDARG;
865
866 if (!SetupGetLineTextW(NULL, hInf, pszTranslateSection, pszTranslateKey,
867 pszBuffer, dwBufferSize, pdwRequiredSize))
868 {
869 if (dwBufferSize < *pdwRequiredSize)
870 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
871
872 return SPAPI_E_LINE_NOT_FOUND;
873 }
874
875 return S_OK;
876 }
877
878 /***********************************************************************
879 * UserInstStubWrapperA (ADVPACK.@)
880 *
881 * See UserInstStubWrapperW.
882 */
883 HRESULT WINAPI UserInstStubWrapperA(HWND hWnd, HINSTANCE hInstance,
884 LPSTR pszParms, INT nShow)
885 {
886 UNICODE_STRING parmsW;
887 HRESULT res;
888
889 TRACE("(%p, %p, %s, %i)\n", hWnd, hInstance, debugstr_a(pszParms), nShow);
890
891 if (!pszParms)
892 return E_INVALIDARG;
893
894 RtlCreateUnicodeStringFromAsciiz(&parmsW, pszParms);
895
896 res = UserInstStubWrapperW(hWnd, hInstance, parmsW.Buffer, nShow);
897
898 RtlFreeUnicodeString(&parmsW);
899
900 return res;
901 }
902
903 /***********************************************************************
904 * UserInstStubWrapperW (ADVPACK.@)
905 *
906 * Launches the user stub wrapper specified by the RealStubPath
907 * registry value under Installed Components\szParms.
908 *
909 * PARAMS
910 * hWnd [I] Handle to the window used for the display.
911 * hInstance [I] Instance of the process.
912 * szParms [I] The GUID of the installation.
913 * show [I] How the window should be shown.
914 *
915 * RETURNS
916 * Success: S_OK.
917 * Failure: E_FAIL.
918 *
919 * TODO
920 * If the type of the StubRealPath value is REG_EXPAND_SZ, then
921 * we should call ExpandEnvironmentStrings on the value and
922 * launch the result.
923 */
924 HRESULT WINAPI UserInstStubWrapperW(HWND hWnd, HINSTANCE hInstance,
925 LPWSTR pszParms, INT nShow)
926 {
927 HKEY setup, guid;
928 WCHAR stub[MAX_PATH];
929 DWORD size = MAX_PATH;
930 HRESULT hr = S_OK;
931 BOOL res;
932
933 static const WCHAR real_stub_path[] = {
934 'R','e','a','l','S','t','u','b','P','a','t','h',0
935 };
936
937 TRACE("(%p, %p, %s, %i)\n", hWnd, hInstance, debugstr_w(pszParms), nShow);
938
939 if (!pszParms || !*pszParms)
940 return E_INVALIDARG;
941
942 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, setup_key, 0, KEY_READ, &setup))
943 {
944 return E_FAIL;
945 }
946
947 if (RegOpenKeyExW(setup, pszParms, 0, KEY_READ, &guid))
948 {
949 RegCloseKey(setup);
950 return E_FAIL;
951 }
952
953 res = RegQueryValueExW(guid, real_stub_path, NULL, NULL, (LPBYTE)stub, &size);
954 if (res || !*stub)
955 goto done;
956
957 /* launch the user stub wrapper */
958 hr = launch_exe(stub, NULL, NULL);
959
960 done:
961 RegCloseKey(setup);
962 RegCloseKey(guid);
963
964 return hr;
965 }
966
967 /***********************************************************************
968 * UserUnInstStubWrapperA (ADVPACK.@)
969 *
970 * See UserUnInstStubWrapperW.
971 */
972 HRESULT WINAPI UserUnInstStubWrapperA(HWND hWnd, HINSTANCE hInstance,
973 LPSTR pszParms, INT nShow)
974 {
975 UNICODE_STRING parmsW;
976 HRESULT res;
977
978 TRACE("(%p, %p, %s, %i)\n", hWnd, hInstance, debugstr_a(pszParms), nShow);
979
980 if (!pszParms)
981 return E_INVALIDARG;
982
983 RtlCreateUnicodeStringFromAsciiz(&parmsW, pszParms);
984
985 res = UserUnInstStubWrapperW(hWnd, hInstance, parmsW.Buffer, nShow);
986
987 RtlFreeUnicodeString(&parmsW);
988
989 return res;
990 }
991
992 /***********************************************************************
993 * UserUnInstStubWrapperW (ADVPACK.@)
994 */
995 HRESULT WINAPI UserUnInstStubWrapperW(HWND hWnd, HINSTANCE hInstance,
996 LPWSTR pszParms, INT nShow)
997 {
998 FIXME("(%p, %p, %s, %i): stub\n", hWnd, hInstance, debugstr_w(pszParms), nShow);
999
1000 return E_FAIL;
1001 }