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