crypt32: Fixed day/month mismatch in time encoding routines.
[wine] / dlls / advpack / install.c
1 /*
2  * Advpack install functions
3  *
4  * Copyright 2006 James Hawkins
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdarg.h>
22 #include <stdlib.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/debug.h"
34 #include "wine/unicode.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(advpack);
37
38 #define SPAPI_ERROR     0xE0000000L
39 #define SPAPI_PREFIX    0x800F0000L
40 #define SPAPI_MASK      0xFFFFL
41 #define HRESULT_FROM_SPAPI(x)   ((x & SPAPI_MASK) | SPAPI_PREFIX)
42
43 #define ADV_HRESULT(x)  ((x & SPAPI_ERROR) ? HRESULT_FROM_SPAPI(x) : HRESULT_FROM_WIN32(x))
44
45 /* sequentially returns pointers to parameters in a parameter list
46  * returns NULL if the parameter is empty, e.g. one,,three  */
47 LPWSTR get_parameter(LPWSTR *params, WCHAR separator)
48 {
49     LPWSTR token = *params;
50
51     if (!*params)
52         return NULL;
53
54     *params = strchrW(*params, separator);
55     if (*params)
56         *(*params)++ = '\0';
57
58     if (!*token)
59         return NULL;
60
61     return token;
62 }
63
64 static BOOL is_full_path(LPWSTR path)
65 {
66     const int MIN_PATH_LEN = 3;
67
68     if (!path || lstrlenW(path) < MIN_PATH_LEN)
69         return FALSE;
70
71     if (path[1] == ':' || (path[0] == '\\' && path[1] == '\\'))
72         return TRUE;
73
74     return FALSE;
75 }
76
77 /* performs a setupapi-level install of the INF file */
78 static HRESULT spapi_install(HINF hinf, LPCWSTR install_sec, LPCWSTR source_path)
79 {
80     BOOL ret;
81     HRESULT res;
82     PVOID context;
83
84     context = SetupInitDefaultQueueCallbackEx(NULL, INVALID_HANDLE_VALUE, 0, 0, NULL);
85     if (!context)
86         return ADV_HRESULT(GetLastError());
87
88     ret = SetupInstallFromInfSectionW(NULL, hinf, install_sec, SPINST_FILES,
89                                       NULL, source_path, SP_COPY_NEWER,
90                                       NULL, context, NULL, NULL);
91     if (!ret)
92     {
93         res = ADV_HRESULT(GetLastError());
94         SetupTermDefaultQueueCallback(context);
95
96         return res;
97     }
98
99     SetupTermDefaultQueueCallback(context);
100
101     ret = SetupInstallFromInfSectionW(NULL, hinf, install_sec,
102                                       SPINST_INIFILES | SPINST_REGISTRY,
103                                       HKEY_LOCAL_MACHINE, NULL, 0,
104                                       NULL, NULL, NULL, NULL);
105     if (!ret)
106         return ADV_HRESULT(GetLastError());
107
108     return S_OK;
109 }
110
111 /* this structure very closely resembles parameters of RunSetupCommand() */
112 typedef struct
113 {
114     HWND hwnd;
115     LPCSTR title;
116     LPCSTR inf_name;
117     LPCSTR dir;
118     LPCSTR section_name;
119 } SETUPCOMMAND_PARAMS;
120
121 /***********************************************************************
122  *      DoInfInstall  (ADVPACK.@)
123  *
124  * Install an INF section.
125  *
126  * PARAMS
127  *  setup [I] Structure containing install information.
128  *
129  * RETURNS
130  *   S_OK                                Everything OK
131  *   HRESULT_FROM_WIN32(GetLastError())  Some other error
132  */
133 HRESULT WINAPI DoInfInstall(const SETUPCOMMAND_PARAMS *setup)
134 {
135     BOOL ret;
136     HINF hinf;
137     void *callback_context;
138
139     TRACE("%p, %s, %s, %s, %s\n", setup->hwnd, debugstr_a(setup->title),
140           debugstr_a(setup->inf_name), debugstr_a(setup->dir),
141           debugstr_a(setup->section_name));
142
143     hinf = SetupOpenInfFileA(setup->inf_name, NULL, INF_STYLE_WIN4, NULL);
144     if (hinf == INVALID_HANDLE_VALUE) return HRESULT_FROM_WIN32(GetLastError());
145
146     callback_context = SetupInitDefaultQueueCallback(setup->hwnd);
147
148     ret = SetupInstallFromInfSectionA(NULL, hinf, setup->section_name, SPINST_ALL,
149                                       NULL, NULL, 0, SetupDefaultQueueCallbackA,
150                                       callback_context, NULL, NULL);
151     SetupTermDefaultQueueCallback(callback_context);
152     SetupCloseInfFile(hinf);
153
154     return ret ? S_OK : HRESULT_FROM_WIN32(GetLastError());
155 }
156
157 /***********************************************************************
158  *             ExecuteCabA    (ADVPACK.@)
159  *
160  * See ExecuteCabW.
161  */
162 HRESULT WINAPI ExecuteCabA(HWND hwnd, CABINFOA* pCab, LPVOID pReserved)
163 {
164     UNICODE_STRING cab, inf, section;
165     CABINFOW cabinfo;
166     HRESULT hr;
167
168     TRACE("(%p, %p, %p)\n", hwnd, pCab, pReserved);
169
170     if (!pCab)
171         return E_INVALIDARG;
172
173     if (pCab->pszCab)
174     {
175         RtlCreateUnicodeStringFromAsciiz(&cab, pCab->pszCab);
176         cabinfo.pszCab = cab.Buffer;
177     }
178     else
179         cabinfo.pszCab = NULL;
180
181     RtlCreateUnicodeStringFromAsciiz(&inf, pCab->pszInf);
182     RtlCreateUnicodeStringFromAsciiz(&section, pCab->pszSection);
183     
184     MultiByteToWideChar(CP_ACP, 0, pCab->szSrcPath, -1, cabinfo.szSrcPath,
185                         sizeof(cabinfo.szSrcPath) / sizeof(WCHAR));
186
187     cabinfo.pszInf = inf.Buffer;
188     cabinfo.pszSection = section.Buffer;
189     cabinfo.dwFlags = pCab->dwFlags;
190
191     hr = ExecuteCabW(hwnd, &cabinfo, pReserved);
192
193     if (pCab->pszCab)
194         RtlFreeUnicodeString(&cab);
195
196     RtlFreeUnicodeString(&inf);
197     RtlFreeUnicodeString(&section);
198
199     return hr;
200 }
201
202 /***********************************************************************
203  *             ExecuteCabW    (ADVPACK.@)
204  * 
205  * Installs the INF file extracted from a specified cabinet file.
206  * 
207  * PARAMS
208  *   hwnd      [I] Handle to the window used for the display.
209  *   pCab      [I] Information about the cabinet file.
210  *   pReserved [I] Reserved.  Must be NULL.
211  * 
212  * RETURNS
213  *   Success: S_OK.
214  *   Failure: E_FAIL.
215  *
216  * BUGS
217  *   Unimplemented
218  */
219 HRESULT WINAPI ExecuteCabW(HWND hwnd, CABINFOW* pCab, LPVOID pReserved)
220 {
221     FIXME("(%p, %p, %p): stub\n", hwnd, pCab, pReserved);
222     return E_FAIL;
223 }
224
225 /***********************************************************************
226  *      LaunchINFSectionA   (ADVPACK.@)
227  *
228  * See LaunchINFSectionW.
229  */
230 INT WINAPI LaunchINFSectionA(HWND hWnd, HINSTANCE hInst, LPSTR cmdline, INT show)
231 {
232     UNICODE_STRING cmd;
233     HRESULT hr;
234
235     TRACE("(%p, %p, %s, %i)\n", hWnd, hInst, debugstr_a(cmdline), show);
236
237     RtlCreateUnicodeStringFromAsciiz(&cmd, cmdline);
238
239     hr = LaunchINFSectionW(hWnd, hInst, cmd.Buffer, show);
240
241     RtlFreeUnicodeString(&cmd);
242
243     return hr;
244 }
245
246 /***********************************************************************
247  *      LaunchINFSectionW   (ADVPACK.@)
248  *
249  * Installs an INF section without BACKUP/ROLLBACK capabilities.
250  *
251  * PARAMS
252  *   hWnd    [I] Handle to parent window, NULL for desktop.
253  *   hInst   [I] Instance of the process.
254  *   cmdline [I] Contains parameters in the order INF,section,flags,reboot.
255  *   show    [I] How the window should be shown.
256  *
257  * RETURNS
258  *  Success: S_OK.
259  *  Failure: S_FALSE
260  *
261  * NOTES
262  *  INF - Filename of the INF to launch.
263  *  section - INF section to install.
264  *  flags - see advpub.h.
265  *  reboot - smart reboot behavior
266  *    'A' Always reboot.
267  *    'I' Reboot if needed (default).
268  *    'N' No reboot.
269  * 
270  * BUGS
271  *  Unimplemented.
272  */
273 INT WINAPI LaunchINFSectionW(HWND hWnd, HINSTANCE hInst, LPWSTR cmdline, INT show)
274 {
275     FIXME("(%p, %p, %s, %i): stub\n", hWnd, hInst, debugstr_w(cmdline), show);
276     return 0;
277 }
278
279 /***********************************************************************
280  *      LaunchINFSectionExA (ADVPACK.@)
281  *
282  * See LaunchINFSectionExW.
283  */
284 HRESULT WINAPI LaunchINFSectionExA(HWND hWnd, HINSTANCE hInst, LPSTR cmdline, INT show)
285 {
286     UNICODE_STRING cmd;
287     HRESULT hr;
288
289     TRACE("(%p, %p, %s, %i): stub\n", hWnd, hInst, debugstr_a(cmdline), show);
290
291     RtlCreateUnicodeStringFromAsciiz(&cmd, cmdline);
292
293     hr = LaunchINFSectionExW(hWnd, hInst, cmd.Buffer, show);
294
295     RtlFreeUnicodeString(&cmd);
296
297     return hr;
298 }
299
300 /***********************************************************************
301  *      LaunchINFSectionExW (ADVPACK.@)
302  *
303  * Installs an INF section with BACKUP/ROLLBACK capabilities.
304  *
305  * PARAMS
306  *   hWnd    [I] Handle to parent window, NULL for desktop.
307  *   hInst   [I] Instance of the process.
308  *   cmdline [I] Contains parameters in the order INF,section,CAB,flags,reboot.
309  *   show    [I] How the window should be shown.
310  *
311  * RETURNS
312  *  Success: S_OK.
313  *  Failure: E_FAIL.
314  *
315  * NOTES
316  *  INF - Filename of the INF to launch.
317  *  section - INF section to install.
318  *  flags - see advpub.h.
319  *  reboot - smart reboot behavior
320  *    'A' Always reboot.
321  *    'I' Reboot if needed (default).
322  *    'N' No reboot.
323  *
324  * BUGS
325  *  Doesn't handle the reboot flag.
326  */
327 HRESULT WINAPI LaunchINFSectionExW(HWND hWnd, HINSTANCE hInst, LPWSTR cmdline, INT show)
328 {
329     LPWSTR cmdline_copy, cmdline_ptr;
330     LPWSTR flags, ptr;
331     CABINFOW cabinfo;
332     HRESULT hr = S_OK;
333
334     TRACE("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_w(cmdline), show);
335
336     if (!cmdline)
337         return E_INVALIDARG;
338
339     cmdline_copy = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(cmdline) + 1) * sizeof(WCHAR));
340     cmdline_ptr = cmdline_copy;
341     lstrcpyW(cmdline_copy, cmdline);
342
343     cabinfo.pszInf = get_parameter(&cmdline_ptr, ',');
344     cabinfo.pszSection = get_parameter(&cmdline_ptr, ',');
345     cabinfo.pszCab = get_parameter(&cmdline_ptr, ',');
346
347     flags = get_parameter(&cmdline_ptr, ',');
348     if (flags)
349         cabinfo.dwFlags = atolW(flags);
350
351     /* get the source path from the cab filename */
352     if (cabinfo.pszCab && *cabinfo.pszCab)
353     {
354         if (!is_full_path(cabinfo.pszCab))
355             goto done;
356
357         lstrcpyW(cabinfo.szSrcPath, cabinfo.pszCab);
358         ptr = strrchrW(cabinfo.szSrcPath, '\\');
359         *(++ptr) = '\0';
360     }
361
362     hr = ExecuteCabW(hWnd, &cabinfo, NULL);
363
364 done:
365     HeapFree(GetProcessHeap(), 0, cmdline_copy);
366
367     return hr;
368 }
369
370 HRESULT launch_exe(LPCWSTR cmd, LPCWSTR dir, HANDLE *phEXE)
371 {
372     STARTUPINFOW si;
373     PROCESS_INFORMATION pi;
374
375     if (phEXE) *phEXE = NULL;
376
377     ZeroMemory(&pi, sizeof(pi));
378     ZeroMemory(&si, sizeof(si));
379     si.cb = sizeof(si);
380
381     if (!CreateProcessW(NULL, (LPWSTR)cmd, NULL, NULL, FALSE,
382                         CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_PROCESS_GROUP,
383                         NULL, dir, &si, &pi))
384     {
385         return HRESULT_FROM_WIN32(GetLastError());
386     }
387
388     CloseHandle(pi.hThread);
389
390     if (phEXE)
391     {
392         *phEXE = pi.hProcess;
393         return S_ASYNCHRONOUS;
394     }
395
396     /* wait for the child process to finish */
397     WaitForSingleObject(pi.hProcess, INFINITE);
398     CloseHandle(pi.hProcess);
399
400     return S_OK;
401 }
402
403 /***********************************************************************
404  *      RunSetupCommandA  (ADVPACK.@)
405  *
406  * See RunSetupCommandW.
407  */
408 HRESULT WINAPI RunSetupCommandA(HWND hWnd, LPCSTR szCmdName,
409                                 LPCSTR szInfSection, LPCSTR szDir,
410                                 LPCSTR lpszTitle, HANDLE *phEXE,
411                                 DWORD dwFlags, LPVOID pvReserved)
412 {
413     UNICODE_STRING cmdname, infsec;
414     UNICODE_STRING dir, title;
415     HRESULT hr;
416
417     TRACE("(%p, %s, %s, %s, %s, %p, %ld, %p)\n",
418           hWnd, debugstr_a(szCmdName), debugstr_a(szInfSection),
419           debugstr_a(szDir), debugstr_a(lpszTitle),
420           phEXE, dwFlags, pvReserved);
421
422     if (!szCmdName || !szDir)
423         return E_INVALIDARG;
424
425     RtlCreateUnicodeStringFromAsciiz(&cmdname, szCmdName);
426     RtlCreateUnicodeStringFromAsciiz(&infsec, szInfSection);
427     RtlCreateUnicodeStringFromAsciiz(&dir, szDir);
428     RtlCreateUnicodeStringFromAsciiz(&title, lpszTitle);
429
430     hr = RunSetupCommandW(hWnd, cmdname.Buffer, infsec.Buffer, dir.Buffer,
431                           title.Buffer, phEXE, dwFlags, pvReserved);
432
433     RtlFreeUnicodeString(&cmdname);
434     RtlFreeUnicodeString(&infsec);
435     RtlFreeUnicodeString(&dir);
436     RtlFreeUnicodeString(&title);
437
438     return hr;
439 }
440
441 /***********************************************************************
442  *      RunSetupCommandW  (ADVPACK.@)
443  *
444  * Executes an install section in an INF file or a program.
445  *
446  * PARAMS
447  *   hWnd          [I] Handle to parent window, NULL for quiet mode
448  *   szCmdName     [I] Inf or EXE filename to execute
449  *   szInfSection  [I] Inf section to install, NULL for DefaultInstall
450  *   szDir         [I] Path to extracted files
451  *   szTitle       [I] Title of all dialogs
452  *   phEXE         [O] Handle of EXE to wait for
453  *   dwFlags       [I] Flags; see include/advpub.h
454  *   pvReserved    [I] Reserved
455  *
456  * RETURNS
457  *   S_OK                                 Everything OK
458  *   S_ASYNCHRONOUS                       OK, required to wait on phEXE
459  *   ERROR_SUCCESS_REBOOT_REQUIRED        Reboot required
460  *   E_INVALIDARG                         Invalid argument given
461  *   HRESULT_FROM_WIN32(ERROR_OLD_WIN_VERSION)
462  *                                        Not supported on this Windows version
463  *   E_UNEXPECTED                         Unexpected error
464  *   HRESULT_FROM_WIN32(GetLastError())   Some other error
465  *
466  * BUGS
467  *   INF install unimplemented.
468  */
469 HRESULT WINAPI RunSetupCommandW(HWND hWnd, LPCWSTR szCmdName,
470                                 LPCWSTR szInfSection, LPCWSTR szDir,
471                                 LPCWSTR lpszTitle, HANDLE *phEXE,
472                                 DWORD dwFlags, LPVOID pvReserved)
473 {
474     HINF hinf;
475     HRESULT hr;
476
477     TRACE("(%p, %s, %s, %s, %s, %p, %ld, %p)\n",
478           hWnd, debugstr_w(szCmdName), debugstr_w(szInfSection),
479           debugstr_w(szDir), debugstr_w(lpszTitle),
480           phEXE, dwFlags, pvReserved);
481
482     if (dwFlags)
483         FIXME("Unhandled flags: 0x%08lx\n", dwFlags);
484
485     if (!szCmdName || !szDir)
486         return E_INVALIDARG;
487
488     if (!(dwFlags & RSC_FLAG_INF))
489         return launch_exe(szCmdName, szDir, phEXE);
490
491     hinf = SetupOpenInfFileW(szCmdName, NULL, INF_STYLE_WIN4, NULL);
492     if (hinf == INVALID_HANDLE_VALUE)
493         return ADV_HRESULT(GetLastError());
494
495     hr = spapi_install(hinf, szInfSection, szDir);
496
497     SetupCloseInfFile(hinf);
498     return hr;
499 }