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 #include <stdlib.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "winreg.h"
29 #include "winternl.h"
30 #include "winnls.h"
31 #include "setupapi.h"
32 #include "advpub.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 */
strip_quotes(WCHAR * buffer,DWORD * size)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 */
get_dest_dir(HINF hInf,PCWSTR pszSection,PWSTR pszBuffer,DWORD dwSize)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 */
set_ldids(HINF hInf,LPCWSTR pszInstallSection,LPCWSTR pszWorkingDir)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 = wcschr(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 = wcschr(value, ',');
162 if (ptr) {
163 *ptr = '\0';
164 flags = wcstol(ptr+1, NULL, 10);
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 = wcstol(ptr, NULL, 10);
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 */
CloseINFEngine(HINF hInf)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 */
IsNTAdmin(DWORD reserved,LPDWORD pReserved)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 */
NeedRebootInit(VOID)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 */
NeedReboot(DWORD dwRebootCheck)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 */
OpenINFEngineA(LPCSTR pszInfFilename,LPCSTR pszInstallSection,DWORD dwFlags,HINF * phInf,PVOID pvReserved)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 */
OpenINFEngineW(LPCWSTR pszInfFilename,LPCWSTR pszInstallSection,DWORD dwFlags,HINF * phInf,PVOID pvReserved)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 */
RebootCheckOnInstallA(HWND hWnd,LPCSTR pszINF,LPCSTR pszSec,DWORD dwReserved)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 */
RebootCheckOnInstallW(HWND hWnd,LPCWSTR pszINF,LPCWSTR pszSec,DWORD dwReserved)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 */
do_ocx_reg(HMODULE hocx,BOOL do_reg,const WCHAR * flags,const WCHAR * param)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 */
RegisterOCX(HWND hWnd,HINSTANCE hInst,LPCSTR cmdline,INT show)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 */
SetPerUserSecValuesA(PERUSERSECTIONA * pPerUser)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, ARRAY_SIZE(perUserW.szGUID));
534 MultiByteToWideChar(CP_ACP, 0, pPerUser->szDispName, -1, perUserW.szDispName, ARRAY_SIZE(perUserW.szDispName));
535 MultiByteToWideChar(CP_ACP, 0, pPerUser->szLocale, -1, perUserW.szLocale, ARRAY_SIZE(perUserW.szLocale));
536 MultiByteToWideChar(CP_ACP, 0, pPerUser->szStub, -1, perUserW.szStub, ARRAY_SIZE(perUserW.szStub));
537 MultiByteToWideChar(CP_ACP, 0, pPerUser->szVersion, -1, perUserW.szVersion, ARRAY_SIZE(perUserW.szVersion));
538 MultiByteToWideChar(CP_ACP, 0, pPerUser->szCompID, -1, perUserW.szCompID, ARRAY_SIZE(perUserW.szCompID));
539 perUserW.dwIsInstalled = pPerUser->dwIsInstalled;
540 perUserW.bRollback = pPerUser->bRollback;
541
542 return SetPerUserSecValuesW(&perUserW);
543 }
544
545 /***********************************************************************
546 * SetPerUserSecValuesW (ADVPACK.@)
547 *
548 * Prepares the per-user stub values under IsInstalled\{GUID} that
549 * control the per-user installation.
550 *
551 * PARAMS
552 * pPerUser [I] Per-user stub values.
553 *
554 * RETURNS
555 * Success: S_OK.
556 * Failure: E_FAIL.
557 */
SetPerUserSecValuesW(PERUSERSECTIONW * pPerUser)558 HRESULT WINAPI SetPerUserSecValuesW(PERUSERSECTIONW* pPerUser)
559 {
560 HKEY setup, guid;
561
562 static const WCHAR stub_path[] = {'S','t','u','b','P','a','t','h',0};
563 static const WCHAR version[] = {'V','e','r','s','i','o','n',0};
564 static const WCHAR locale[] = {'L','o','c','a','l','e',0};
565 static const WCHAR compid[] = {'C','o','m','p','o','n','e','n','t','I','D',0};
566 static const WCHAR isinstalled[] = {'I','s','I','n','s','t','a','l','l','e','d',0};
567
568 TRACE("(%p)\n", pPerUser);
569
570 if (!pPerUser || !*pPerUser->szGUID)
571 return S_OK;
572
573 if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, setup_key, 0, NULL, 0, KEY_WRITE,
574 NULL, &setup, NULL))
575 {
576 return E_FAIL;
577 }
578
579 if (RegCreateKeyExW(setup, pPerUser->szGUID, 0, NULL, 0, KEY_ALL_ACCESS,
580 NULL, &guid, NULL))
581 {
582 RegCloseKey(setup);
583 return E_FAIL;
584 }
585
586 if (*pPerUser->szStub)
587 {
588 RegSetValueExW(guid, stub_path, 0, REG_SZ, (LPBYTE)pPerUser->szStub,
589 (lstrlenW(pPerUser->szStub) + 1) * sizeof(WCHAR));
590 }
591
592 if (*pPerUser->szVersion)
593 {
594 RegSetValueExW(guid, version, 0, REG_SZ, (LPBYTE)pPerUser->szVersion,
595 (lstrlenW(pPerUser->szVersion) + 1) * sizeof(WCHAR));
596 }
597
598 if (*pPerUser->szLocale)
599 {
600 RegSetValueExW(guid, locale, 0, REG_SZ, (LPBYTE)pPerUser->szLocale,
601 (lstrlenW(pPerUser->szLocale) + 1) * sizeof(WCHAR));
602 }
603
604 if (*pPerUser->szCompID)
605 {
606 RegSetValueExW(guid, compid, 0, REG_SZ, (LPBYTE)pPerUser->szCompID,
607 (lstrlenW(pPerUser->szCompID) + 1) * sizeof(WCHAR));
608 }
609
610 if (*pPerUser->szDispName)
611 {
612 RegSetValueExW(guid, NULL, 0, REG_SZ, (LPBYTE)pPerUser->szDispName,
613 (lstrlenW(pPerUser->szDispName) + 1) * sizeof(WCHAR));
614 }
615
616 RegSetValueExW(guid, isinstalled, 0, REG_DWORD,
617 (LPBYTE)&pPerUser->dwIsInstalled, sizeof(DWORD));
618
619 RegCloseKey(guid);
620 RegCloseKey(setup);
621
622 return S_OK;
623 }
624
625 /***********************************************************************
626 * TranslateInfStringA (ADVPACK.@)
627 *
628 * See TranslateInfStringW.
629 */
TranslateInfStringA(LPCSTR pszInfFilename,LPCSTR pszInstallSection,LPCSTR pszTranslateSection,LPCSTR pszTranslateKey,LPSTR pszBuffer,DWORD dwBufferSize,PDWORD pdwRequiredSize,PVOID pvReserved)630 HRESULT WINAPI TranslateInfStringA(LPCSTR pszInfFilename, LPCSTR pszInstallSection,
631 LPCSTR pszTranslateSection, LPCSTR pszTranslateKey, LPSTR pszBuffer,
632 DWORD dwBufferSize, PDWORD pdwRequiredSize, PVOID pvReserved)
633 {
634 UNICODE_STRING filenameW, installW;
635 UNICODE_STRING translateW, keyW;
636 LPWSTR bufferW;
637 HRESULT res;
638 DWORD len = 0;
639
640 TRACE("(%s, %s, %s, %s, %p, %d, %p, %p)\n",
641 debugstr_a(pszInfFilename), debugstr_a(pszInstallSection),
642 debugstr_a(pszTranslateSection), debugstr_a(pszTranslateKey),
643 pszBuffer, dwBufferSize,pdwRequiredSize, pvReserved);
644
645 if (!pszInfFilename || !pszTranslateSection ||
646 !pszTranslateKey || !pdwRequiredSize)
647 return E_INVALIDARG;
648
649 RtlCreateUnicodeStringFromAsciiz(&filenameW, pszInfFilename);
650 RtlCreateUnicodeStringFromAsciiz(&installW, pszInstallSection);
651 RtlCreateUnicodeStringFromAsciiz(&translateW, pszTranslateSection);
652 RtlCreateUnicodeStringFromAsciiz(&keyW, pszTranslateKey);
653
654 res = TranslateInfStringW(filenameW.Buffer, installW.Buffer,
655 translateW.Buffer, keyW.Buffer, NULL,
656 dwBufferSize, &len, NULL);
657
658 if (res == S_OK)
659 {
660 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
661
662 res = TranslateInfStringW(filenameW.Buffer, installW.Buffer,
663 translateW.Buffer, keyW.Buffer, bufferW,
664 len, &len, NULL);
665 if (res == S_OK)
666 {
667 *pdwRequiredSize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1,
668 NULL, 0, NULL, NULL);
669
670 if (dwBufferSize >= *pdwRequiredSize)
671 {
672 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, pszBuffer,
673 dwBufferSize, NULL, NULL);
674 }
675 else
676 res = E_NOT_SUFFICIENT_BUFFER;
677 }
678
679 HeapFree(GetProcessHeap(), 0, bufferW);
680 }
681
682 RtlFreeUnicodeString(&filenameW);
683 RtlFreeUnicodeString(&installW);
684 RtlFreeUnicodeString(&translateW);
685 RtlFreeUnicodeString(&keyW);
686
687 return res;
688 }
689
690 /***********************************************************************
691 * TranslateInfStringW (ADVPACK.@)
692 *
693 * Translates the value of a specified key in an inf file into the
694 * current locale by expanding string macros.
695 *
696 * PARAMS
697 * pszInfFilename [I] Filename of the inf file.
698 * pszInstallSection [I]
699 * pszTranslateSection [I] Inf section where the key exists.
700 * pszTranslateKey [I] Key to translate.
701 * pszBuffer [O] Contains the translated string on exit.
702 * dwBufferSize [I] Size on input of pszBuffer.
703 * pdwRequiredSize [O] Length of the translated key.
704 * pvReserved [I] Reserved, must be NULL.
705 *
706 * RETURNS
707 * Success: S_OK.
708 * Failure: An hresult error code.
709 */
TranslateInfStringW(LPCWSTR pszInfFilename,LPCWSTR pszInstallSection,LPCWSTR pszTranslateSection,LPCWSTR pszTranslateKey,LPWSTR pszBuffer,DWORD dwBufferSize,PDWORD pdwRequiredSize,PVOID pvReserved)710 HRESULT WINAPI TranslateInfStringW(LPCWSTR pszInfFilename, LPCWSTR pszInstallSection,
711 LPCWSTR pszTranslateSection, LPCWSTR pszTranslateKey, LPWSTR pszBuffer,
712 DWORD dwBufferSize, PDWORD pdwRequiredSize, PVOID pvReserved)
713 {
714 HINF hInf;
715 HRESULT hret = S_OK;
716
717 TRACE("(%s, %s, %s, %s, %p, %d, %p, %p)\n",
718 debugstr_w(pszInfFilename), debugstr_w(pszInstallSection),
719 debugstr_w(pszTranslateSection), debugstr_w(pszTranslateKey),
720 pszBuffer, dwBufferSize,pdwRequiredSize, pvReserved);
721
722 if (!pszInfFilename || !pszTranslateSection ||
723 !pszTranslateKey || !pdwRequiredSize)
724 return E_INVALIDARG;
725
726 hInf = SetupOpenInfFileW(pszInfFilename, NULL, INF_STYLE_WIN4, NULL);
727 if (hInf == INVALID_HANDLE_VALUE)
728 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
729
730 set_ldids(hInf, pszInstallSection, NULL);
731
732 if (!SetupGetLineTextW(NULL, hInf, pszTranslateSection, pszTranslateKey,
733 pszBuffer, dwBufferSize, pdwRequiredSize))
734 {
735 if (dwBufferSize < *pdwRequiredSize)
736 hret = E_NOT_SUFFICIENT_BUFFER;
737 else
738 hret = SPAPI_E_LINE_NOT_FOUND;
739 }
740
741 SetupCloseInfFile(hInf);
742 return hret;
743 }
744
745 /***********************************************************************
746 * TranslateInfStringExA (ADVPACK.@)
747 *
748 * See TranslateInfStringExW.
749 */
TranslateInfStringExA(HINF hInf,LPCSTR pszInfFilename,LPCSTR pszTranslateSection,LPCSTR pszTranslateKey,LPSTR pszBuffer,DWORD dwBufferSize,PDWORD pdwRequiredSize,PVOID pvReserved)750 HRESULT WINAPI TranslateInfStringExA(HINF hInf, LPCSTR pszInfFilename,
751 LPCSTR pszTranslateSection, LPCSTR pszTranslateKey,
752 LPSTR pszBuffer, DWORD dwBufferSize,
753 PDWORD pdwRequiredSize, PVOID pvReserved)
754 {
755 UNICODE_STRING filenameW, sectionW, keyW;
756 LPWSTR bufferW;
757 HRESULT res;
758 DWORD len = 0;
759
760 TRACE("(%p, %s, %s, %s, %p, %d, %p, %p)\n", hInf, debugstr_a(pszInfFilename),
761 debugstr_a(pszTranslateSection), debugstr_a(pszTranslateKey),
762 pszBuffer, dwBufferSize, pdwRequiredSize, pvReserved);
763
764 if (!pszInfFilename || !pszTranslateSection ||
765 !pszTranslateKey || !pdwRequiredSize)
766 return E_INVALIDARG;
767
768 RtlCreateUnicodeStringFromAsciiz(&filenameW, pszInfFilename);
769 RtlCreateUnicodeStringFromAsciiz(§ionW, pszTranslateSection);
770 RtlCreateUnicodeStringFromAsciiz(&keyW, pszTranslateKey);
771
772 res = TranslateInfStringExW(hInf, filenameW.Buffer, sectionW.Buffer,
773 keyW.Buffer, NULL, 0, &len, NULL);
774
775 if (res == S_OK)
776 {
777 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
778
779 res = TranslateInfStringExW(hInf, filenameW.Buffer, sectionW.Buffer,
780 keyW.Buffer, bufferW, len, &len, NULL);
781
782 if (res == S_OK)
783 {
784 *pdwRequiredSize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1,
785 NULL, 0, NULL, NULL);
786
787 if (dwBufferSize >= *pdwRequiredSize)
788 {
789 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, pszBuffer,
790 dwBufferSize, NULL, NULL);
791 }
792 else
793 res = E_NOT_SUFFICIENT_BUFFER;
794 }
795
796 HeapFree(GetProcessHeap(), 0, bufferW);
797 }
798
799 RtlFreeUnicodeString(&filenameW);
800 RtlFreeUnicodeString(§ionW);
801 RtlFreeUnicodeString(&keyW);
802
803 return res;
804 }
805
806 /***********************************************************************
807 * TranslateInfStringExW (ADVPACK.@)
808 *
809 * Using a handle to an INF file opened with OpenINFEngine, translates
810 * the value of a specified key in an inf file into the current locale
811 * by expanding string macros.
812 *
813 * PARAMS
814 * hInf [I] Handle to the INF file.
815 * pszInfFilename [I] Filename of the INF file.
816 * pszTranslateSection [I] Inf section where the key exists.
817 * pszTranslateKey [I] Key to translate.
818 * pszBuffer [O] Contains the translated string on exit.
819 * dwBufferSize [I] Size on input of pszBuffer.
820 * pdwRequiredSize [O] Length of the translated key.
821 * pvReserved [I] Reserved. Must be NULL.
822 *
823 * RETURNS
824 * Success: S_OK.
825 * Failure: E_FAIL.
826 *
827 * NOTES
828 * To use TranslateInfStringEx to translate an INF file continuously,
829 * open the INF file with OpenINFEngine, call TranslateInfStringEx as
830 * many times as needed, then release the handle with CloseINFEngine.
831 * When translating more than one keys, this method is more efficient
832 * than calling TranslateInfString, because the INF file is only
833 * opened once.
834 */
TranslateInfStringExW(HINF hInf,LPCWSTR pszInfFilename,LPCWSTR pszTranslateSection,LPCWSTR pszTranslateKey,LPWSTR pszBuffer,DWORD dwBufferSize,PDWORD pdwRequiredSize,PVOID pvReserved)835 HRESULT WINAPI TranslateInfStringExW(HINF hInf, LPCWSTR pszInfFilename,
836 LPCWSTR pszTranslateSection, LPCWSTR pszTranslateKey,
837 LPWSTR pszBuffer, DWORD dwBufferSize,
838 PDWORD pdwRequiredSize, PVOID pvReserved)
839 {
840 TRACE("(%p, %s, %s, %s, %p, %d, %p, %p)\n", hInf, debugstr_w(pszInfFilename),
841 debugstr_w(pszTranslateSection), debugstr_w(pszTranslateKey),
842 pszBuffer, dwBufferSize, pdwRequiredSize, pvReserved);
843
844 if (!hInf || !pszInfFilename || !pszTranslateSection || !pszTranslateKey)
845 return E_INVALIDARG;
846
847 if (!SetupGetLineTextW(NULL, hInf, pszTranslateSection, pszTranslateKey,
848 pszBuffer, dwBufferSize, pdwRequiredSize))
849 {
850 if (dwBufferSize < *pdwRequiredSize)
851 return E_NOT_SUFFICIENT_BUFFER;
852
853 return SPAPI_E_LINE_NOT_FOUND;
854 }
855
856 return S_OK;
857 }
858
859 /***********************************************************************
860 * UserInstStubWrapperA (ADVPACK.@)
861 *
862 * See UserInstStubWrapperW.
863 */
UserInstStubWrapperA(HWND hWnd,HINSTANCE hInstance,LPSTR pszParms,INT nShow)864 HRESULT WINAPI UserInstStubWrapperA(HWND hWnd, HINSTANCE hInstance,
865 LPSTR pszParms, INT nShow)
866 {
867 UNICODE_STRING parmsW;
868 HRESULT res;
869
870 TRACE("(%p, %p, %s, %i)\n", hWnd, hInstance, debugstr_a(pszParms), nShow);
871
872 if (!pszParms)
873 return E_INVALIDARG;
874
875 RtlCreateUnicodeStringFromAsciiz(&parmsW, pszParms);
876
877 res = UserInstStubWrapperW(hWnd, hInstance, parmsW.Buffer, nShow);
878
879 RtlFreeUnicodeString(&parmsW);
880
881 return res;
882 }
883
884 /***********************************************************************
885 * UserInstStubWrapperW (ADVPACK.@)
886 *
887 * Launches the user stub wrapper specified by the RealStubPath
888 * registry value under Installed Components\szParms.
889 *
890 * PARAMS
891 * hWnd [I] Handle to the window used for the display.
892 * hInstance [I] Instance of the process.
893 * szParms [I] The GUID of the installation.
894 * show [I] How the window should be shown.
895 *
896 * RETURNS
897 * Success: S_OK.
898 * Failure: E_FAIL.
899 *
900 * TODO
901 * If the type of the StubRealPath value is REG_EXPAND_SZ, then
902 * we should call ExpandEnvironmentStrings on the value and
903 * launch the result.
904 */
UserInstStubWrapperW(HWND hWnd,HINSTANCE hInstance,LPWSTR pszParms,INT nShow)905 HRESULT WINAPI UserInstStubWrapperW(HWND hWnd, HINSTANCE hInstance,
906 LPWSTR pszParms, INT nShow)
907 {
908 HKEY setup, guid;
909 WCHAR stub[MAX_PATH];
910 DWORD size = sizeof(stub);
911 HRESULT hr = S_OK;
912 BOOL res;
913
914 static const WCHAR real_stub_path[] = {
915 'R','e','a','l','S','t','u','b','P','a','t','h',0
916 };
917
918 TRACE("(%p, %p, %s, %i)\n", hWnd, hInstance, debugstr_w(pszParms), nShow);
919
920 if (!pszParms || !*pszParms)
921 return E_INVALIDARG;
922
923 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, setup_key, 0, KEY_READ, &setup))
924 {
925 return E_FAIL;
926 }
927
928 if (RegOpenKeyExW(setup, pszParms, 0, KEY_READ, &guid))
929 {
930 RegCloseKey(setup);
931 return E_FAIL;
932 }
933
934 res = RegQueryValueExW(guid, real_stub_path, NULL, NULL, (LPBYTE)stub, &size);
935 if (res || !*stub)
936 goto done;
937
938 /* launch the user stub wrapper */
939 hr = launch_exe(stub, NULL, NULL);
940
941 done:
942 RegCloseKey(setup);
943 RegCloseKey(guid);
944
945 return hr;
946 }
947
948 /***********************************************************************
949 * UserUnInstStubWrapperA (ADVPACK.@)
950 *
951 * See UserUnInstStubWrapperW.
952 */
UserUnInstStubWrapperA(HWND hWnd,HINSTANCE hInstance,LPSTR pszParms,INT nShow)953 HRESULT WINAPI UserUnInstStubWrapperA(HWND hWnd, HINSTANCE hInstance,
954 LPSTR pszParms, INT nShow)
955 {
956 UNICODE_STRING parmsW;
957 HRESULT res;
958
959 TRACE("(%p, %p, %s, %i)\n", hWnd, hInstance, debugstr_a(pszParms), nShow);
960
961 if (!pszParms)
962 return E_INVALIDARG;
963
964 RtlCreateUnicodeStringFromAsciiz(&parmsW, pszParms);
965
966 res = UserUnInstStubWrapperW(hWnd, hInstance, parmsW.Buffer, nShow);
967
968 RtlFreeUnicodeString(&parmsW);
969
970 return res;
971 }
972
973 /***********************************************************************
974 * UserUnInstStubWrapperW (ADVPACK.@)
975 */
UserUnInstStubWrapperW(HWND hWnd,HINSTANCE hInstance,LPWSTR pszParms,INT nShow)976 HRESULT WINAPI UserUnInstStubWrapperW(HWND hWnd, HINSTANCE hInstance,
977 LPWSTR pszParms, INT nShow)
978 {
979 FIXME("(%p, %p, %s, %i): stub\n", hWnd, hInstance, debugstr_w(pszParms), nShow);
980
981 return E_FAIL;
982 }
983