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