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