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