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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 "winternl.h"
29 #include "winnls.h"
30 #include "setupapi.h"
31 #include "advpub.h"
32 #include "ole2.h"
33 #include "wine/debug.h"
34 #include "advpack_private.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) ((HRESULT)((x & SPAPI_MASK) | SPAPI_PREFIX))
42
43 #define ADV_HRESULT(x) ((x & SPAPI_ERROR) ? HRESULT_FROM_SPAPI(x) : HRESULT_FROM_WIN32(x))
44
45 #define ADV_SUCCESS 0
46 #define ADV_FAILURE 1
47
48 /* contains information about a specific install instance */
49 typedef struct _ADVInfo
50 {
51 HINF hinf;
52 LPWSTR inf_path;
53 LPWSTR inf_filename;
54 LPWSTR install_sec;
55 LPWSTR working_dir;
56 DWORD flags;
57 BOOL need_reboot;
58 } ADVInfo;
59
60 typedef HRESULT (*iterate_fields_func)(HINF hinf, PCWSTR field, const void *arg);
61
62 /* Advanced INF commands */
63 static const WCHAR CheckAdminRights[] = {
64 'C','h','e','c','k','A','d','m','i','n','R','i','g','h','t','s',0
65 };
66 static const WCHAR DelDirs[] = {'D','e','l','D','i','r','s',0};
67 static const WCHAR PerUserInstall[] = {'P','e','r','U','s','e','r','I','n','s','t','a','l','l',0};
68 static const WCHAR RegisterOCXs[] = {'R','e','g','i','s','t','e','r','O','C','X','s',0};
69 static const WCHAR RunPreSetupCommands[] = {
70 'R','u','n','P','r','e','S','e','t','u','p','C','o','m','m','a','n','d','s',0
71 };
72 static const WCHAR RunPostSetupCommands[] = {
73 'R','u','n','P','o','s','t','S','e','t','u','p','C','o','m','m','a','n','d','s',0
74 };
75
76 /* Advanced INF callbacks */
del_dirs_callback(HINF hinf,PCWSTR field,const void * arg)77 static HRESULT del_dirs_callback(HINF hinf, PCWSTR field, const void *arg)
78 {
79 INFCONTEXT context;
80 HRESULT hr = S_OK;
81 DWORD size;
82
83 BOOL ok = SetupFindFirstLineW(hinf, field, NULL, &context);
84
85 for (; ok; ok = SetupFindNextLine(&context, &context))
86 {
87 WCHAR directory[MAX_INF_STRING_LENGTH];
88
89 if (!SetupGetLineTextW(&context, NULL, NULL, NULL, directory,
90 MAX_INF_STRING_LENGTH, &size))
91 continue;
92
93 if (DelNodeW(directory, ADN_DEL_IF_EMPTY) != S_OK)
94 hr = E_FAIL;
95 }
96
97 return hr;
98 }
99
per_user_install_callback(HINF hinf,PCWSTR field,const void * arg)100 static HRESULT per_user_install_callback(HINF hinf, PCWSTR field, const void *arg)
101 {
102 PERUSERSECTIONW per_user;
103 INFCONTEXT context;
104 DWORD size;
105
106 static const WCHAR disp_name[] = {'D','i','s','p','l','a','y','N','a','m','e',0};
107 static const WCHAR version[] = {'V','e','r','s','i','o','n',0};
108 static const WCHAR is_installed[] = {'I','s','I','n','s','t','a','l','l','e','d',0};
109 static const WCHAR comp_id[] = {'C','o','m','p','o','n','e','n','t','I','D',0};
110 static const WCHAR guid[] = {'G','U','I','D',0};
111 static const WCHAR locale[] = {'L','o','c','a','l','e',0};
112 static const WCHAR stub_path[] = {'S','t','u','b','P','a','t','h',0};
113
114 per_user.bRollback = FALSE;
115 per_user.dwIsInstalled = 0;
116
117 SetupGetLineTextW(NULL, hinf, field, disp_name, per_user.szDispName, ARRAY_SIZE(per_user.szDispName), &size);
118
119 SetupGetLineTextW(NULL, hinf, field, version, per_user.szVersion, ARRAY_SIZE(per_user.szVersion), &size);
120
121 if (SetupFindFirstLineW(hinf, field, is_installed, &context))
122 {
123 SetupGetIntField(&context, 1, (PINT)&per_user.dwIsInstalled);
124 }
125
126 SetupGetLineTextW(NULL, hinf, field, comp_id, per_user.szCompID, ARRAY_SIZE(per_user.szCompID), &size);
127
128 SetupGetLineTextW(NULL, hinf, field, guid, per_user.szGUID, ARRAY_SIZE(per_user.szGUID), &size);
129
130 SetupGetLineTextW(NULL, hinf, field, locale, per_user.szLocale, ARRAY_SIZE(per_user.szLocale), &size);
131
132 SetupGetLineTextW(NULL, hinf, field, stub_path, per_user.szStub, ARRAY_SIZE(per_user.szStub), &size);
133
134 return SetPerUserSecValuesW(&per_user);
135 }
136
register_ocxs_callback(HINF hinf,PCWSTR field,const void * arg)137 static HRESULT register_ocxs_callback(HINF hinf, PCWSTR field, const void *arg)
138 {
139 HMODULE hm;
140 INFCONTEXT context;
141 HRESULT hr = S_OK;
142
143 BOOL ok = SetupFindFirstLineW(hinf, field, NULL, &context);
144
145 for (; ok; ok = SetupFindNextLine(&context, &context))
146 {
147 WCHAR buffer[MAX_INF_STRING_LENGTH];
148
149 /* get OCX filename */
150 if (!SetupGetStringFieldW(&context, 1, buffer, ARRAY_SIZE(buffer), NULL))
151 continue;
152
153 hm = LoadLibraryExW(buffer, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
154 if (hm)
155 {
156 if (do_ocx_reg(hm, TRUE, NULL, NULL) != S_OK)
157 hr = E_FAIL;
158
159 FreeLibrary(hm);
160 }
161 else
162 hr = E_FAIL;
163
164 if (FAILED(hr))
165 {
166 /* FIXME: display a message box */
167 break;
168 }
169 }
170
171 return hr;
172 }
173
run_setup_commands_callback(HINF hinf,PCWSTR field,const void * arg)174 static HRESULT run_setup_commands_callback(HINF hinf, PCWSTR field, const void *arg)
175 {
176 const ADVInfo *info = (const ADVInfo *)arg;
177 INFCONTEXT context;
178 HRESULT hr = S_OK;
179 DWORD size;
180
181 BOOL ok = SetupFindFirstLineW(hinf, field, NULL, &context);
182
183 for (; ok; ok = SetupFindNextLine(&context, &context))
184 {
185 WCHAR buffer[MAX_INF_STRING_LENGTH];
186
187 if (!SetupGetLineTextW(&context, NULL, NULL, NULL, buffer,
188 MAX_INF_STRING_LENGTH, &size))
189 continue;
190
191 if (launch_exe(buffer, info->working_dir, NULL) != S_OK)
192 hr = E_FAIL;
193 }
194
195 return hr;
196 }
197
198 /* sequentially returns pointers to parameters in a parameter list
199 * returns NULL if the parameter is empty, e.g. one,,three */
get_parameter(LPWSTR * params,WCHAR separator,BOOL quoted)200 LPWSTR get_parameter(LPWSTR *params, WCHAR separator, BOOL quoted)
201 {
202 LPWSTR token = *params;
203
204 if (!*params)
205 return NULL;
206
207 if (quoted && *token == '"')
208 {
209 WCHAR *end = wcschr(token + 1, '"');
210 if (end)
211 {
212 *end = 0;
213 *params = end + 1;
214 token = token + 1;
215 }
216 }
217
218 *params = wcschr(*params, separator);
219 if (*params)
220 *(*params)++ = '\0';
221
222 if (!*token)
223 return NULL;
224
225 return token;
226 }
227
is_full_path(LPCWSTR path)228 static BOOL is_full_path(LPCWSTR path)
229 {
230 const int MIN_PATH_LEN = 3;
231
232 if (!path || lstrlenW(path) < MIN_PATH_LEN)
233 return FALSE;
234
235 if ((path[1] == ':' && path[2] == '\\') || (path[0] == '\\' && path[1] == '\\'))
236 return TRUE;
237
238 return FALSE;
239 }
240
241 /* retrieves the contents of a field, dynamically growing the buffer if necessary */
get_field_string(INFCONTEXT * context,DWORD index,WCHAR * buffer,const WCHAR * static_buffer,DWORD * size)242 static WCHAR *get_field_string(INFCONTEXT *context, DWORD index, WCHAR *buffer,
243 const WCHAR *static_buffer, DWORD *size)
244 {
245 DWORD required;
246
247 if (SetupGetStringFieldW(context, index, buffer, *size, &required)) return buffer;
248
249 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
250 {
251 /* now grow the buffer */
252 if (buffer != static_buffer) HeapFree(GetProcessHeap(), 0, buffer);
253 if (!(buffer = HeapAlloc(GetProcessHeap(), 0, required*sizeof(WCHAR)))) return NULL;
254 *size = required;
255 if (SetupGetStringFieldW(context, index, buffer, *size, &required)) return buffer;
256 }
257
258 if (buffer != static_buffer) HeapFree(GetProcessHeap(), 0, buffer);
259 return NULL;
260 }
261
262 /* iterates over all fields of a certain key of a certain section */
iterate_section_fields(HINF hinf,PCWSTR section,PCWSTR key,iterate_fields_func callback,void * arg)263 static HRESULT iterate_section_fields(HINF hinf, PCWSTR section, PCWSTR key,
264 iterate_fields_func callback, void *arg)
265 {
266 WCHAR static_buffer[200];
267 WCHAR *buffer = static_buffer;
268 DWORD size = ARRAY_SIZE(static_buffer);
269 INFCONTEXT context;
270 HRESULT hr = E_FAIL;
271
272 BOOL ok = SetupFindFirstLineW(hinf, section, key, &context);
273 while (ok)
274 {
275 UINT i, count = SetupGetFieldCount(&context);
276
277 for (i = 1; i <= count; i++)
278 {
279 if (!(buffer = get_field_string(&context, i, buffer, static_buffer, &size)))
280 goto done;
281
282 if ((hr = callback(hinf, buffer, arg)) != S_OK)
283 goto done;
284 }
285
286 ok = SetupFindNextMatchLineW(&context, key, &context);
287 }
288
289 hr = S_OK;
290
291 done:
292 if (buffer != static_buffer) HeapFree(GetProcessHeap(), 0, buffer);
293 return hr;
294 }
295
check_admin_rights(const ADVInfo * info)296 static HRESULT check_admin_rights(const ADVInfo *info)
297 {
298 INT check;
299 INFCONTEXT context;
300 HRESULT hr = S_OK;
301
302 if (!SetupFindFirstLineW(info->hinf, info->install_sec,
303 CheckAdminRights, &context))
304 return S_OK;
305
306 if (!SetupGetIntField(&context, 1, &check))
307 return S_OK;
308
309 if (check == 1)
310 hr = IsNTAdmin(0, NULL) ? S_OK : E_FAIL;
311
312 return hr;
313 }
314
315 /* performs a setupapi-level install of the INF file */
spapi_install(const ADVInfo * info)316 static HRESULT spapi_install(const ADVInfo *info)
317 {
318 BOOL ret;
319 HRESULT res;
320 PVOID context;
321
322 context = SetupInitDefaultQueueCallbackEx(NULL, INVALID_HANDLE_VALUE, 0, 0, NULL);
323 if (!context)
324 return ADV_HRESULT(GetLastError());
325
326 ret = SetupInstallFromInfSectionW(NULL, info->hinf, info->install_sec,
327 SPINST_FILES, NULL, info->working_dir,
328 SP_COPY_NEWER, SetupDefaultQueueCallbackW,
329 context, NULL, NULL);
330 if (!ret)
331 {
332 res = ADV_HRESULT(GetLastError());
333 SetupTermDefaultQueueCallback(context);
334
335 return res;
336 }
337
338 SetupTermDefaultQueueCallback(context);
339
340 ret = SetupInstallFromInfSectionW(NULL, info->hinf, info->install_sec,
341 SPINST_INIFILES | SPINST_REGISTRY | SPINST_REGSVR,
342 HKEY_LOCAL_MACHINE, NULL, 0,
343 NULL, NULL, NULL, NULL);
344 if (!ret)
345 return ADV_HRESULT(GetLastError());
346
347 return S_OK;
348 }
349
350 /* processes the Advanced INF commands */
adv_install(ADVInfo * info)351 static HRESULT adv_install(ADVInfo *info)
352 {
353 HRESULT hr;
354
355 hr = check_admin_rights(info);
356 if (hr != S_OK)
357 return hr;
358
359 hr = iterate_section_fields(info->hinf, info->install_sec, RunPreSetupCommands,
360 run_setup_commands_callback, info);
361 if (hr != S_OK)
362 return hr;
363
364 OleInitialize(NULL);
365 hr = iterate_section_fields(info->hinf, info->install_sec,
366 RegisterOCXs, register_ocxs_callback, NULL);
367 OleUninitialize();
368 if (hr != S_OK)
369 return hr;
370
371 hr = iterate_section_fields(info->hinf, info->install_sec,
372 PerUserInstall, per_user_install_callback, info);
373 if (hr != S_OK)
374 return hr;
375
376 hr = iterate_section_fields(info->hinf, info->install_sec, RunPostSetupCommands,
377 run_setup_commands_callback, info);
378 if (hr != S_OK)
379 return hr;
380
381 hr = iterate_section_fields(info->hinf, info->install_sec,
382 DelDirs, del_dirs_callback, info);
383 if (hr != S_OK)
384 return hr;
385
386 return hr;
387 }
388
389 /* determines the proper working directory for the INF file */
get_working_dir(ADVInfo * info,LPCWSTR inf_filename,LPCWSTR working_dir)390 static HRESULT get_working_dir(ADVInfo *info, LPCWSTR inf_filename, LPCWSTR working_dir)
391 {
392 WCHAR path[MAX_PATH];
393 LPCWSTR ptr;
394 DWORD len;
395
396 static const WCHAR backslash[] = {'\\',0};
397 static const WCHAR inf_dir[] = {'\\','I','N','F',0};
398
399 if ((ptr = wcsrchr(inf_filename, '\\')))
400 {
401 len = ptr - inf_filename + 1;
402 ptr = inf_filename;
403 }
404 else if (working_dir && *working_dir)
405 {
406 len = lstrlenW(working_dir) + 1;
407 ptr = working_dir;
408 }
409 else
410 {
411 GetCurrentDirectoryW(MAX_PATH, path);
412 lstrcatW(path, backslash);
413 lstrcatW(path, inf_filename);
414
415 /* check if the INF file is in the current directory */
416 if (GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
417 {
418 GetCurrentDirectoryW(MAX_PATH, path);
419 }
420 else
421 {
422 /* default to the windows\inf directory if all else fails */
423 GetWindowsDirectoryW(path, MAX_PATH);
424 lstrcatW(path, inf_dir);
425 }
426
427 len = lstrlenW(path) + 1;
428 ptr = path;
429 }
430
431 info->working_dir = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
432 if (!info->working_dir)
433 return E_OUTOFMEMORY;
434
435 lstrcpynW(info->working_dir, ptr, len);
436
437 return S_OK;
438 }
439
440 /* loads the INF file and performs checks on it */
install_init(LPCWSTR inf_filename,LPCWSTR install_sec,LPCWSTR working_dir,DWORD flags,ADVInfo * info)441 static HRESULT install_init(LPCWSTR inf_filename, LPCWSTR install_sec,
442 LPCWSTR working_dir, DWORD flags, ADVInfo *info)
443 {
444 DWORD len;
445 HRESULT hr;
446 LPCWSTR ptr, path;
447
448 static const WCHAR backslash[] = {'\\',0};
449 static const WCHAR default_install[] = {
450 'D','e','f','a','u','l','t','I','n','s','t','a','l','l',0
451 };
452
453 if (!(ptr = wcsrchr(inf_filename, '\\')))
454 ptr = inf_filename;
455
456 len = lstrlenW(ptr);
457
458 info->inf_filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
459 if (!info->inf_filename)
460 return E_OUTOFMEMORY;
461
462 lstrcpyW(info->inf_filename, ptr);
463
464 /* FIXME: determine the proper platform to install (NTx86, etc) */
465 if (!install_sec || !*install_sec)
466 {
467 len = sizeof(default_install) - 1;
468 ptr = default_install;
469 }
470 else
471 {
472 len = lstrlenW(install_sec);
473 ptr = install_sec;
474 }
475
476 info->install_sec = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
477 if (!info->install_sec)
478 return E_OUTOFMEMORY;
479
480 lstrcpyW(info->install_sec, ptr);
481
482 hr = get_working_dir(info, inf_filename, working_dir);
483 if (FAILED(hr))
484 return hr;
485
486 len = lstrlenW(info->working_dir) + lstrlenW(info->inf_filename) + 2;
487 info->inf_path = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
488 if (!info->inf_path)
489 return E_OUTOFMEMORY;
490
491 lstrcpyW(info->inf_path, info->working_dir);
492 lstrcatW(info->inf_path, backslash);
493 lstrcatW(info->inf_path, info->inf_filename);
494
495 /* RunSetupCommand opens unmodified filename parameter */
496 if (flags & RSC_FLAG_INF)
497 path = inf_filename;
498 else
499 path = info->inf_path;
500
501 info->hinf = SetupOpenInfFileW(path, NULL, INF_STYLE_WIN4, NULL);
502 if (info->hinf == INVALID_HANDLE_VALUE)
503 return ADV_HRESULT(GetLastError());
504
505 set_ldids(info->hinf, info->install_sec, info->working_dir);
506
507 /* FIXME: check that the INF is advanced */
508
509 info->flags = flags;
510 info->need_reboot = FALSE;
511
512 return S_OK;
513 }
514
515 /* release the install instance information */
install_release(const ADVInfo * info)516 static void install_release(const ADVInfo *info)
517 {
518 SetupCloseInfFile(info->hinf);
519
520 HeapFree(GetProcessHeap(), 0, info->inf_path);
521 HeapFree(GetProcessHeap(), 0, info->inf_filename);
522 HeapFree(GetProcessHeap(), 0, info->install_sec);
523 HeapFree(GetProcessHeap(), 0, info->working_dir);
524 }
525
526 /* this structure very closely resembles parameters of RunSetupCommand() */
527 typedef struct
528 {
529 HWND hwnd;
530 LPCSTR title;
531 LPCSTR inf_name;
532 LPCSTR dir;
533 LPCSTR section_name;
534 } SETUPCOMMAND_PARAMS;
535
536 typedef struct
537 {
538 HWND hwnd;
539 LPCWSTR title;
540 LPCWSTR inf_name;
541 LPCWSTR dir;
542 LPCWSTR section_name;
543 } SETUPCOMMAND_PARAMSW;
544
545 /* internal: see DoInfInstall */
DoInfInstallW(const SETUPCOMMAND_PARAMSW * setup)546 static HRESULT DoInfInstallW(const SETUPCOMMAND_PARAMSW *setup)
547 {
548 ADVInfo info;
549 HRESULT hr;
550
551 TRACE("(%p)\n", setup);
552
553 ZeroMemory(&info, sizeof(ADVInfo));
554
555 hr = install_init(setup->inf_name, setup->section_name, setup->dir, 0, &info);
556 if (hr != S_OK)
557 goto done;
558
559 hr = spapi_install(&info);
560 if (hr != S_OK)
561 goto done;
562
563 hr = adv_install(&info);
564
565 done:
566 install_release(&info);
567
568 return S_OK;
569 }
570
571 /***********************************************************************
572 * DoInfInstall (ADVPACK.@)
573 *
574 * Install an INF section.
575 *
576 * PARAMS
577 * setup [I] Structure containing install information.
578 *
579 * RETURNS
580 * S_OK Everything OK
581 * HRESULT_FROM_WIN32(GetLastError()) Some other error
582 */
DoInfInstall(const SETUPCOMMAND_PARAMS * setup)583 HRESULT WINAPI DoInfInstall(const SETUPCOMMAND_PARAMS *setup)
584 {
585 UNICODE_STRING title, inf, section, dir;
586 SETUPCOMMAND_PARAMSW params;
587 HRESULT hr;
588
589 if (!setup)
590 return E_INVALIDARG;
591
592 RtlCreateUnicodeStringFromAsciiz(&title, setup->title);
593 RtlCreateUnicodeStringFromAsciiz(&inf, setup->inf_name);
594 RtlCreateUnicodeStringFromAsciiz(§ion, setup->section_name);
595 RtlCreateUnicodeStringFromAsciiz(&dir, setup->dir);
596
597 params.title = title.Buffer;
598 params.inf_name = inf.Buffer;
599 params.section_name = section.Buffer;
600 params.dir = dir.Buffer;
601 params.hwnd = setup->hwnd;
602
603 hr = DoInfInstallW(¶ms);
604
605 RtlFreeUnicodeString(&title);
606 RtlFreeUnicodeString(&inf);
607 RtlFreeUnicodeString(§ion);
608 RtlFreeUnicodeString(&dir);
609
610 return hr;
611 }
612
613 /***********************************************************************
614 * ExecuteCabA (ADVPACK.@)
615 *
616 * See ExecuteCabW.
617 */
ExecuteCabA(HWND hwnd,CABINFOA * pCab,LPVOID pReserved)618 HRESULT WINAPI ExecuteCabA(HWND hwnd, CABINFOA* pCab, LPVOID pReserved)
619 {
620 UNICODE_STRING cab, inf, section;
621 CABINFOW cabinfo;
622 HRESULT hr;
623
624 TRACE("(%p, %p, %p)\n", hwnd, pCab, pReserved);
625
626 if (!pCab)
627 return E_INVALIDARG;
628
629 if (pCab->pszCab)
630 {
631 RtlCreateUnicodeStringFromAsciiz(&cab, pCab->pszCab);
632 cabinfo.pszCab = cab.Buffer;
633 }
634 else
635 cabinfo.pszCab = NULL;
636
637 RtlCreateUnicodeStringFromAsciiz(&inf, pCab->pszInf);
638 RtlCreateUnicodeStringFromAsciiz(§ion, pCab->pszSection);
639
640 MultiByteToWideChar(CP_ACP, 0, pCab->szSrcPath, -1, cabinfo.szSrcPath, ARRAY_SIZE(cabinfo.szSrcPath));
641
642 cabinfo.pszInf = inf.Buffer;
643 cabinfo.pszSection = section.Buffer;
644 cabinfo.dwFlags = pCab->dwFlags;
645
646 hr = ExecuteCabW(hwnd, &cabinfo, pReserved);
647
648 if (pCab->pszCab)
649 RtlFreeUnicodeString(&cab);
650
651 RtlFreeUnicodeString(&inf);
652 RtlFreeUnicodeString(§ion);
653
654 return hr;
655 }
656
657 /***********************************************************************
658 * ExecuteCabW (ADVPACK.@)
659 *
660 * Installs the INF file extracted from a specified cabinet file.
661 *
662 * PARAMS
663 * hwnd [I] Handle to the window used for the display.
664 * pCab [I] Information about the cabinet file.
665 * pReserved [I] Reserved. Must be NULL.
666 *
667 * RETURNS
668 * Success: S_OK.
669 * Failure: E_FAIL.
670 */
ExecuteCabW(HWND hwnd,CABINFOW * pCab,LPVOID pReserved)671 HRESULT WINAPI ExecuteCabW(HWND hwnd, CABINFOW* pCab, LPVOID pReserved)
672 {
673 ADVInfo info;
674 HRESULT hr;
675
676 TRACE("(%p, %p, %p)\n", hwnd, pCab, pReserved);
677
678 ZeroMemory(&info, sizeof(ADVInfo));
679
680 if (pCab->pszCab && *pCab->pszCab)
681 FIXME("Cab archive not extracted!\n");
682
683 hr = install_init(pCab->pszInf, pCab->pszSection, pCab->szSrcPath, pCab->dwFlags, &info);
684 if (hr != S_OK)
685 goto done;
686
687 hr = spapi_install(&info);
688 if (hr != S_OK)
689 goto done;
690
691 hr = adv_install(&info);
692
693 done:
694 install_release(&info);
695
696 return hr;
697 }
698
699 /***********************************************************************
700 * LaunchINFSectionA (ADVPACK.@)
701 *
702 * See LaunchINFSectionW.
703 */
LaunchINFSectionA(HWND hWnd,HINSTANCE hInst,LPSTR cmdline,INT show)704 INT WINAPI LaunchINFSectionA(HWND hWnd, HINSTANCE hInst, LPSTR cmdline, INT show)
705 {
706 UNICODE_STRING cmd;
707 HRESULT hr;
708
709 TRACE("(%p, %p, %s, %i)\n", hWnd, hInst, debugstr_a(cmdline), show);
710
711 if (!cmdline)
712 return ADV_FAILURE;
713
714 RtlCreateUnicodeStringFromAsciiz(&cmd, cmdline);
715
716 hr = LaunchINFSectionW(hWnd, hInst, cmd.Buffer, show);
717
718 RtlFreeUnicodeString(&cmd);
719
720 return hr;
721 }
722
723 /***********************************************************************
724 * LaunchINFSectionW (ADVPACK.@)
725 *
726 * Installs an INF section without BACKUP/ROLLBACK capabilities.
727 *
728 * PARAMS
729 * hWnd [I] Handle to parent window, NULL for desktop.
730 * hInst [I] Instance of the process.
731 * cmdline [I] Contains parameters in the order INF,section,flags,reboot.
732 * show [I] How the window should be shown.
733 *
734 * RETURNS
735 * Success: ADV_SUCCESS.
736 * Failure: ADV_FAILURE.
737 *
738 * NOTES
739 * INF - Filename of the INF to launch.
740 * section - INF section to install.
741 * flags - see advpub.h.
742 * reboot - smart reboot behavior
743 * 'A' Always reboot.
744 * 'I' Reboot if needed (default).
745 * 'N' No reboot.
746 */
LaunchINFSectionW(HWND hWnd,HINSTANCE hInst,LPWSTR cmdline,INT show)747 INT WINAPI LaunchINFSectionW(HWND hWnd, HINSTANCE hInst, LPWSTR cmdline, INT show)
748 {
749 ADVInfo info;
750 LPWSTR cmdline_copy, cmdline_ptr;
751 LPWSTR inf_filename, install_sec;
752 LPWSTR str_flags;
753 DWORD flags = 0;
754 HRESULT hr = S_OK;
755
756 TRACE("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_w(cmdline), show);
757
758 if (!cmdline)
759 return ADV_FAILURE;
760
761 cmdline_copy = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(cmdline) + 1) * sizeof(WCHAR));
762 cmdline_ptr = cmdline_copy;
763 lstrcpyW(cmdline_copy, cmdline);
764
765 inf_filename = get_parameter(&cmdline_ptr, ',', TRUE);
766 install_sec = get_parameter(&cmdline_ptr, ',', TRUE);
767
768 str_flags = get_parameter(&cmdline_ptr, ',', TRUE);
769 if (str_flags)
770 {
771 DWORD inf_flags = wcstol(str_flags, NULL, 10);
772 if (inf_flags & LIS_QUIET) flags |= RSC_FLAG_QUIET;
773 if (inf_flags & LIS_NOGRPCONV) flags |= RSC_FLAG_NGCONV;
774 }
775
776 ZeroMemory(&info, sizeof(ADVInfo));
777
778 hr = install_init(inf_filename, install_sec, NULL, flags, &info);
779 if (hr != S_OK)
780 goto done;
781
782 hr = spapi_install(&info);
783 if (hr != S_OK)
784 goto done;
785
786 hr = adv_install(&info);
787
788 done:
789 install_release(&info);
790 HeapFree(GetProcessHeap(), 0, cmdline_copy);
791
792 return SUCCEEDED(hr) ? ADV_SUCCESS : ADV_FAILURE;
793 }
794
795 /***********************************************************************
796 * LaunchINFSectionExA (ADVPACK.@)
797 *
798 * See LaunchINFSectionExW.
799 */
LaunchINFSectionExA(HWND hWnd,HINSTANCE hInst,LPSTR cmdline,INT show)800 HRESULT WINAPI LaunchINFSectionExA(HWND hWnd, HINSTANCE hInst, LPSTR cmdline, INT show)
801 {
802 UNICODE_STRING cmd;
803 HRESULT hr;
804
805 TRACE("(%p, %p, %s, %i)\n", hWnd, hInst, debugstr_a(cmdline), show);
806
807 if (!cmdline)
808 return ADV_FAILURE;
809
810 RtlCreateUnicodeStringFromAsciiz(&cmd, cmdline);
811
812 hr = LaunchINFSectionExW(hWnd, hInst, cmd.Buffer, show);
813
814 RtlFreeUnicodeString(&cmd);
815
816 return hr;
817 }
818
819 /***********************************************************************
820 * LaunchINFSectionExW (ADVPACK.@)
821 *
822 * Installs an INF section with BACKUP/ROLLBACK capabilities.
823 *
824 * PARAMS
825 * hWnd [I] Handle to parent window, NULL for desktop.
826 * hInst [I] Instance of the process.
827 * cmdline [I] Contains parameters in the order INF,section,CAB,flags,reboot.
828 * show [I] How the window should be shown.
829 *
830 * RETURNS
831 * Success: ADV_SUCCESS.
832 * Failure: ADV_FAILURE.
833 *
834 * NOTES
835 * INF - Filename of the INF to launch.
836 * section - INF section to install.
837 * flags - see advpub.h.
838 * reboot - smart reboot behavior
839 * 'A' Always reboot.
840 * 'I' Reboot if needed (default).
841 * 'N' No reboot.
842 *
843 * BUGS
844 * Doesn't handle the reboot flag.
845 */
LaunchINFSectionExW(HWND hWnd,HINSTANCE hInst,LPWSTR cmdline,INT show)846 HRESULT WINAPI LaunchINFSectionExW(HWND hWnd, HINSTANCE hInst, LPWSTR cmdline, INT show)
847 {
848 LPWSTR cmdline_copy, cmdline_ptr;
849 LPWSTR flags, ptr;
850 CABINFOW cabinfo;
851 HRESULT hr;
852
853 TRACE("(%p, %p, %s, %d)\n", hWnd, hInst, debugstr_w(cmdline), show);
854
855 if (!cmdline)
856 return ADV_FAILURE;
857
858 cmdline_copy = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(cmdline) + 1) * sizeof(WCHAR));
859 cmdline_ptr = cmdline_copy;
860 lstrcpyW(cmdline_copy, cmdline);
861
862 cabinfo.pszInf = get_parameter(&cmdline_ptr, ',', TRUE);
863 cabinfo.pszSection = get_parameter(&cmdline_ptr, ',', TRUE);
864 cabinfo.pszCab = get_parameter(&cmdline_ptr, ',', TRUE);
865 *cabinfo.szSrcPath = '\0';
866
867 flags = get_parameter(&cmdline_ptr, ',', TRUE);
868 if (flags)
869 cabinfo.dwFlags = wcstol(flags, NULL, 10);
870
871 if (!is_full_path(cabinfo.pszCab) && !is_full_path(cabinfo.pszInf))
872 {
873 HeapFree(GetProcessHeap(), 0, cmdline_copy);
874 return E_INVALIDARG;
875 }
876
877 /* get the source path from the cab filename */
878 if (cabinfo.pszCab && *cabinfo.pszCab)
879 {
880 if (!is_full_path(cabinfo.pszCab))
881 lstrcpyW(cabinfo.szSrcPath, cabinfo.pszInf);
882 else
883 lstrcpyW(cabinfo.szSrcPath, cabinfo.pszCab);
884
885 ptr = wcsrchr(cabinfo.szSrcPath, '\\');
886 *(++ptr) = '\0';
887 }
888
889 hr = ExecuteCabW(hWnd, &cabinfo, NULL);
890 HeapFree(GetProcessHeap(), 0, cmdline_copy);
891 return SUCCEEDED(hr) ? ADV_SUCCESS : ADV_FAILURE;
892 }
893
launch_exe(LPCWSTR cmd,LPCWSTR dir,HANDLE * phEXE)894 HRESULT launch_exe(LPCWSTR cmd, LPCWSTR dir, HANDLE *phEXE)
895 {
896 STARTUPINFOW si;
897 PROCESS_INFORMATION pi;
898
899 if (phEXE) *phEXE = NULL;
900
901 ZeroMemory(&pi, sizeof(pi));
902 ZeroMemory(&si, sizeof(si));
903 si.cb = sizeof(si);
904
905 if (!CreateProcessW(NULL, (LPWSTR)cmd, NULL, NULL, FALSE,
906 CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_PROCESS_GROUP,
907 NULL, dir, &si, &pi))
908 {
909 return HRESULT_FROM_WIN32(GetLastError());
910 }
911
912 CloseHandle(pi.hThread);
913
914 if (phEXE)
915 {
916 *phEXE = pi.hProcess;
917 return S_ASYNCHRONOUS;
918 }
919
920 /* wait for the child process to finish */
921 WaitForSingleObject(pi.hProcess, INFINITE);
922 CloseHandle(pi.hProcess);
923
924 return S_OK;
925 }
926
927 /***********************************************************************
928 * RunSetupCommandA (ADVPACK.@)
929 *
930 * See RunSetupCommandW.
931 */
RunSetupCommandA(HWND hWnd,LPCSTR szCmdName,LPCSTR szInfSection,LPCSTR szDir,LPCSTR lpszTitle,HANDLE * phEXE,DWORD dwFlags,LPVOID pvReserved)932 HRESULT WINAPI RunSetupCommandA(HWND hWnd, LPCSTR szCmdName,
933 LPCSTR szInfSection, LPCSTR szDir,
934 LPCSTR lpszTitle, HANDLE *phEXE,
935 DWORD dwFlags, LPVOID pvReserved)
936 {
937 UNICODE_STRING cmdname, infsec;
938 UNICODE_STRING dir, title;
939 HRESULT hr;
940
941 TRACE("(%p, %s, %s, %s, %s, %p, %d, %p)\n",
942 hWnd, debugstr_a(szCmdName), debugstr_a(szInfSection),
943 debugstr_a(szDir), debugstr_a(lpszTitle),
944 phEXE, dwFlags, pvReserved);
945
946 if (!szCmdName || !szDir)
947 return E_INVALIDARG;
948
949 RtlCreateUnicodeStringFromAsciiz(&cmdname, szCmdName);
950 RtlCreateUnicodeStringFromAsciiz(&infsec, szInfSection);
951 RtlCreateUnicodeStringFromAsciiz(&dir, szDir);
952 RtlCreateUnicodeStringFromAsciiz(&title, lpszTitle);
953
954 hr = RunSetupCommandW(hWnd, cmdname.Buffer, infsec.Buffer, dir.Buffer,
955 title.Buffer, phEXE, dwFlags, pvReserved);
956
957 RtlFreeUnicodeString(&cmdname);
958 RtlFreeUnicodeString(&infsec);
959 RtlFreeUnicodeString(&dir);
960 RtlFreeUnicodeString(&title);
961
962 return hr;
963 }
964
965 /***********************************************************************
966 * RunSetupCommandW (ADVPACK.@)
967 *
968 * Executes an install section in an INF file or a program.
969 *
970 * PARAMS
971 * hWnd [I] Handle to parent window, NULL for quiet mode
972 * szCmdName [I] Inf or EXE filename to execute
973 * szInfSection [I] Inf section to install, NULL for DefaultInstall
974 * szDir [I] Path to extracted files
975 * szTitle [I] Title of all dialogs
976 * phEXE [O] Handle of EXE to wait for
977 * dwFlags [I] Flags; see include/advpub.h
978 * pvReserved [I] Reserved
979 *
980 * RETURNS
981 * S_OK Everything OK
982 * S_ASYNCHRONOUS OK, required to wait on phEXE
983 * ERROR_SUCCESS_REBOOT_REQUIRED Reboot required
984 * E_INVALIDARG Invalid argument given
985 * HRESULT_FROM_WIN32(ERROR_OLD_WIN_VERSION)
986 * Not supported on this Windows version
987 * E_UNEXPECTED Unexpected error
988 * HRESULT_FROM_WIN32(GetLastError()) Some other error
989 */
RunSetupCommandW(HWND hWnd,LPCWSTR szCmdName,LPCWSTR szInfSection,LPCWSTR szDir,LPCWSTR lpszTitle,HANDLE * phEXE,DWORD dwFlags,LPVOID pvReserved)990 HRESULT WINAPI RunSetupCommandW(HWND hWnd, LPCWSTR szCmdName,
991 LPCWSTR szInfSection, LPCWSTR szDir,
992 LPCWSTR lpszTitle, HANDLE *phEXE,
993 DWORD dwFlags, LPVOID pvReserved)
994 {
995 ADVInfo info;
996 HRESULT hr;
997
998 TRACE("(%p, %s, %s, %s, %s, %p, %d, %p)\n",
999 hWnd, debugstr_w(szCmdName), debugstr_w(szInfSection),
1000 debugstr_w(szDir), debugstr_w(lpszTitle),
1001 phEXE, dwFlags, pvReserved);
1002
1003 if (dwFlags & RSC_FLAG_UPDHLPDLLS)
1004 FIXME("Unhandled flag: RSC_FLAG_UPDHLPDLLS\n");
1005
1006 if (!szCmdName || !szDir)
1007 return E_INVALIDARG;
1008
1009 if (!(dwFlags & RSC_FLAG_INF))
1010 return launch_exe(szCmdName, szDir, phEXE);
1011
1012 ZeroMemory(&info, sizeof(ADVInfo));
1013
1014 hr = install_init(szCmdName, szInfSection, szDir, dwFlags, &info);
1015 if (hr != S_OK)
1016 goto done;
1017
1018 hr = spapi_install(&info);
1019 if (hr != S_OK)
1020 goto done;
1021
1022 hr = adv_install(&info);
1023
1024 done:
1025 install_release(&info);
1026
1027 return hr;
1028 }
1029