xref: /reactos/dll/win32/advpack/advpack.c (revision 703c56be)
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(&sectionW, 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(&sectionW);
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