1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
|
#include <Windows.h>
#include <stdio.h>
#include <strsafe.h>
#include <wuerror.h>
//
// These defines control which packages need to be updated. In order to
// to customize this for your drivers needs, edit needed packages to 1 and
// unneeded packages to 0.
//
// If your UMDF driver uses USB functionality, you also need KMDF and WinUSB
//
#define INSTALL_KMDF (TRUE)
#define INSTALL_WINUSB (TRUE)
#define INSTALL_UMDF (TRUE)
//
// Reference strings that are used to build our MSU package name. These will
// change between releases of the framework and will need to be updated
//
#define WINUSB_UPDATE_NAME L"WinUSB_1.9.msu"
//
// MSU names are of the format:
// <kmdf|umdf>-<wdf major version>.<wdf minor version>-
// Win-<windows major version>.<windows minor version>.msu
//
#define MSU_FORMAT_STRING L"%s-%d.%d-Win-%d.%d.msu"
#define WUSA_EXE L"%windir%\\system32\\wusa.exe"
#define WUSA_EXE_ARGUMENTS L"/quiet /norestart"
#define WDF_MAJOR_VERSION 1
#define WDF_MINOR_VERSION 11
DWORD
ApplyUpdate(
PCWSTR MSUName
)
{
DWORD error = ERROR_SUCCESS;
size_t cmdLengthBytes;
size_t applicationLengthBytes;
BOOL ok;
PROCESS_INFORMATION pInfo;
STARTUPINFOW startInfo;
PWCHAR applicationName = NULL;
PWCHAR commandLine = NULL;
HRESULT hr;
ZeroMemory(&startInfo,sizeof(startInfo)) ;
startInfo.cb = sizeof(STARTUPINFO) ;
ZeroMemory(&pInfo,sizeof(pInfo));
//
// Check that the update package exists
//
error = GetFileAttributes(MSUName);
if (error == INVALID_FILE_ATTRIBUTES) {
error = GetLastError();
wprintf(L"Error: Could not find update file %s; error %x\n", MSUName, error);
goto exit;
}
//
// Invoke wusa
//
applicationName = (PWCHAR) LocalAlloc(LPTR, (MAX_PATH + 1)*sizeof(WCHAR));
if (applicationName == NULL) {
error = ERROR_INSTALL_FAILURE;
wprintf(L"Failed to allocate applicationName buffer\n");
goto exit;
}
applicationName[0] = L'\0';
applicationLengthBytes = ExpandEnvironmentStrings(WUSA_EXE,
applicationName,
MAX_PATH+1);
if ((applicationLengthBytes == 0) ||
(applicationLengthBytes > MAX_PATH+1)) {
wprintf(L"Could not expland %s\n", WUSA_EXE);
error = ERROR_INSTALL_FAILURE;
goto exit;
}
applicationLengthBytes = sizeof(WCHAR) * applicationLengthBytes;
hr = StringCbLength(MSUName,
MAX_PATH * sizeof(WCHAR),
&cmdLengthBytes);
if (hr != S_OK) {
error = ERROR_INSTALL_FAILURE;
wprintf(L"StringCbLength failed MSUName, %x\n",
hr);
goto exit;
}
//
// Add enough padding for 2 \". The size returned by sizeof() includes
// the terminating L'\0'
//
cmdLengthBytes = applicationLengthBytes + cmdLengthBytes + sizeof(WUSA_EXE_ARGUMENTS) + 3*sizeof(WCHAR);
commandLine = (PWCHAR) LocalAlloc(LPTR, cmdLengthBytes );
if (commandLine == NULL) {
wprintf(L"Failed to allocate applicationName buffer\n");
error = ERROR_INSTALL_FAILURE;
goto exit;
}
hr = StringCbPrintf(commandLine,
cmdLengthBytes,
L"%s \"%s\" %s",
applicationName,
MSUName,
WUSA_EXE_ARGUMENTS);
if (hr != S_OK) {
error = ERROR_INSTALL_FAILURE;
wprintf(L"StringCbPrintf failed for applicationParameters, %x\n",
hr);
goto exit;
}
wprintf(L"Invoking: %s\n", commandLine);
ok = CreateProcess(applicationName, // name of executable module
commandLine, // command line string
NULL, // SD
NULL, // SD
TRUE, // handle inheritance option
0, // creation flags CREATE_NO_WINDOW
NULL, // new environment block
NULL, // current directory name
&startInfo, // startup information
&pInfo // process information
);
if (ok == FALSE) {
error = GetLastError();
wprintf(L"Create process failed : %x\n",
error);
goto exit;
} else {
//
// Wait until child process exits.
//
error = WaitForSingleObject( pInfo.hProcess, INFINITE );
if ( error != WAIT_OBJECT_0 ) {
//
// It can't hurt to add this
//
TerminateProcess(pInfo.hProcess, (UINT)-1);
}
GetExitCodeProcess(pInfo.hProcess, &error);
//
// The possible return values for wusa.exe are:
// 1)ERROR_SUCCESS (0) : installation was successfull
// 2)ERROR_SUCCESS_REBOOT_REQUIRED (3010) : installation was successful,
// however a reboot is required, so that the binaries will be
// loaded to memory
// 3)S_FALSE (1) (Vista) OR WU_S_ALREADY_INSTALLED (240006) (Win7):
// No action was taken (i.e. files were already installed)
// 4)Everything else (e.g. ERROR_INSTALL_FAILURE) is an error
//
switch (error) {
case S_FALSE:
case WU_S_ALREADY_INSTALLED:
wprintf(L"The package was already installed in the system\n");
error = ERROR_SUCCESS;
break;
case ERROR_SUCCESS:
wprintf(L"The package was installed successfully\n");
break;
case ERROR_SUCCESS_REBOOT_REQUIRED:
wprintf(L"The package was installed successfully but requires a reboot\n");
break;
case ERROR_SERVICE_DISABLED:
case WU_E_WU_DISABLED:
//
// If the "Windows Update" service is disabled, then wusa
// returns ERROR_SERVICE_DISABLED
//
wprintf(L"The \"Windows Update\" service is disabled. It "
L"has to be enabled for the installation to succeed."
L"\n");
break;
default:
wprintf(L"The update process returned error code :%x. ",
error);
wprintf(L"For additional information please look at the log "
L"files %%windir%%\\windowsupdate.log and "
L"%%windir%%\\Logs\\CBS\\CBS.log\n");
break;
}
CloseHandle(pInfo.hProcess);
CloseHandle(pInfo.hThread);
}
exit:
if (commandLine != NULL) {
LocalFree(commandLine);
commandLine = NULL;
}
if (applicationName != NULL) {
LocalFree(applicationName);
applicationName = NULL;
}
return error;
}
BOOL
PromptRestart()
{
HANDLE hToken; // handle to process token
TOKEN_PRIVILEGES tkp; // pointer to token structure
BOOL fResult; // system shutdown flag
// Get the current process token handle so we can get shutdown
// privilege.
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
return FALSE;
// Get the LUID for shutdown privilege.
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,
&tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1; // one privilege to set
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// Get shutdown privilege for this process.
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
(PTOKEN_PRIVILEGES) NULL, 0);
// Cannot test the return value of AdjustTokenPrivileges.
if (GetLastError() != ERROR_SUCCESS) {
return FALSE;
}
// Display the shutdown dialog box and start the countdown.
#pragma prefast(suppress:28159, "Ignore the suggestion against system shutdown.")
fResult = InitiateSystemShutdownEx(
NULL, // shut down local computer
NULL, // message for user
0, // time-out period, in seconds
FALSE, // ask user to close apps
TRUE, // reboot after shutdown
SHTDN_REASON_FLAG_PLANNED // shutdown reason
| SHTDN_REASON_MAJOR_SOFTWARE
| SHTDN_REASON_MINOR_UPGRADE);
// Disable shutdown privilege.
tkp.Privileges[0].Attributes = 0;
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
(PTOKEN_PRIVILEGES) NULL, 0);
return fResult;
}
DWORD
UpdateWdf(
VOID
)
{
BOOL ok;
OSVERSIONINFO curOsvi;
OSVERSIONINFOEX targetOsvi;
DWORDLONG dwlConditionMask = 0;
WCHAR MSUName[MAX_PATH];
BOOL rebootNeeded = FALSE;
DWORD error = ERROR_SUCCESS;
HRESULT hr;
//
// Make sure updates are valid for this operating system.
// Vista SP1/SP2; Win7 RTM
// TODO: what happens on Vista RTM/SP3+/Win7 SP1+
//
ZeroMemory(&targetOsvi, sizeof(OSVERSIONINFOEX));
dwlConditionMask = 0;
targetOsvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
targetOsvi.dwMajorVersion = 6;
targetOsvi.dwMinorVersion = 0;
targetOsvi.wServicePackMajor = 0;
VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, VER_LESS_EQUAL );
VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, VER_LESS_EQUAL );
VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, VER_LESS_EQUAL );
ok = VerifyVersionInfo( &targetOsvi,
VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR,
dwlConditionMask);
if (ok) {
wprintf(L"Error: Updates are not supported on OS before Vista or Vista RTM\n");
error = ERROR_OLD_WIN_VERSION;
goto exit;
}
//
// No need to update on Win8+
//
ZeroMemory(&targetOsvi, sizeof(OSVERSIONINFOEX));
dwlConditionMask = 0;
targetOsvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
targetOsvi.dwMajorVersion = 6;
targetOsvi.dwMinorVersion = 2;
VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL );
VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL );
ok = VerifyVersionInfo( &targetOsvi,
VER_MAJORVERSION | VER_MINORVERSION,
dwlConditionMask);
if (ok) {
wprintf(L"Updates are not needed to Windows 8, they are already inbox\n");
error = ERROR_SUCCESS;
goto exit;
}
//
// Create MSU name
//
ZeroMemory(&curOsvi, sizeof(OSVERSIONINFO));
curOsvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
#pragma warning( push )
#pragma warning( disable : 4996 ) // 'GetVersionEx': was declared deprecated
ok = GetVersionEx(&curOsvi);
if (ok == FALSE) {
error = GetLastError();
wprintf(L"GetVersionEx failed: %x\n", error);
goto exit;
}
//
// We want to apply the updates in a specific order. This is because UMDF
// is potentially dependent on WinUSB. WinUSB is dependent on KMDF. If we
// fail to apply an update, we want to make sure the machine is in a good
// state. This we apply required framework updates first.
// KMDF > WinUSB > UMDF
//
#if INSTALL_KMDF
hr = StringCchPrintf(MSUName,
MAX_PATH,
MSU_FORMAT_STRING,
L"kmdf",
WDF_MAJOR_VERSION,
WDF_MINOR_VERSION,
curOsvi.dwMajorVersion,
curOsvi.dwMinorVersion);
if (hr != S_OK) {
wprintf(L"StringCchPrintf for KMDF MSU failed: %x\n", hr);
error = ERROR_INSTALL_FAILURE;
goto exit;
}
error = ApplyUpdate(MSUName);
if (error == ERROR_SUCCESS_REBOOT_REQUIRED) {
rebootNeeded = TRUE;
} else if (error != ERROR_SUCCESS) {
goto exit;
}
#endif // INSTALL_KMDF
#pragma warning( pop ) // 'GetVersionEx': was declared deprecated
#if (INSTALL_WINUSB)
//
// WinUSB update only applies to Vista
//
ZeroMemory(&targetOsvi, sizeof(OSVERSIONINFOEX));
dwlConditionMask = 0;
targetOsvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
targetOsvi.dwMajorVersion = 6;
targetOsvi.dwMinorVersion = 0;
VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, VER_EQUAL );
VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, VER_EQUAL );
ok = VerifyVersionInfo( &targetOsvi,
VER_MAJORVERSION | VER_MINORVERSION,
dwlConditionMask);
if (ok) {
error = ApplyUpdate(WINUSB_UPDATE_NAME);
if (error == ERROR_SUCCESS_REBOOT_REQUIRED) {
rebootNeeded = TRUE;
} else if (error != ERROR_SUCCESS) {
goto exit;
}
}
#endif // INSTALL_WINUSB
#if INSTALL_UMDF
hr = StringCchPrintf(MSUName,
MAX_PATH,
MSU_FORMAT_STRING,
L"umdf",
WDF_MAJOR_VERSION,
WDF_MINOR_VERSION,
curOsvi.dwMajorVersion,
curOsvi.dwMinorVersion);
if (hr != S_OK) {
wprintf(L"StringCchPrintf for UMDF MSU failed: %x\n", hr);
error = ERROR_INSTALL_FAILURE;
goto exit;
}
error = ApplyUpdate(MSUName);
if (error == ERROR_SUCCESS_REBOOT_REQUIRED) {
rebootNeeded = TRUE;
} else if (error != ERROR_SUCCESS) {
goto exit;
}
#endif // INSTALL_UMDF
//
// If we have made it to this point there have been no fatal errors. If
// there were fatal errors, these should be caught and we would've jumped
// to exit.
//
// We must account for the fact the latest update applied did not require
// a reboot but earlier updates did.
//
if (rebootNeeded == TRUE) {
error = ERROR_SUCCESS_REBOOT_REQUIRED;
goto exit;
}
error = ERROR_SUCCESS;
exit:
return error;
}
int __cdecl
wmain(
_In_ int argc,
_In_reads_(argc) char* argv[]
)
{
DWORD updateStatus;
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(argv);
updateStatus = UpdateWdf();
if (updateStatus == ERROR_SUCCESS_REBOOT_REQUIRED) {
int msgboxID = MessageBox(
NULL,
L"A restart is needed for these changes to take effect\nRestart now?",
L"Restart Required",
MB_ICONEXCLAMATION | MB_YESNO
);
if (msgboxID == IDYES)
{
PromptRestart();
}
}
return updateStatus;
}
|