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