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