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