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