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