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