- Introduce GetNTDDIVersion() to get NTDDI version at runtime for apitests.
- Introduce GetMajorNTVersion() and GetMinorNTVersion() macros and use them for GetNTVersion()
- Introduce GENERATE_NTDDI() macro to construct NTDDI values from major, minor, service pack, and subversion values.
- Introduce NTDDI_MIN and NTDDI_MAX macros for tests that use NTDDI ranges.
Note: the build number in KUSER_SHARED_DATA is only populated on Windows 10 RTM and later. On older Windows versions, this field is reserved and is usually 0. For this reason, I chose not to expose it as a macro.
- Let it be `"NDIS"`, instead of variations of `"SIMN"`.
- Use matching `ExFreePoolWithTag()`.
- Remove a redundant `KeyInformation = NULL;`.
Addendum to commits e8861acfb2 (r12196) and 5658b2154c (r53045).
CORE-18791
- Remove unused idedma.def
Addendum to commit 1daf74908e (r29256).
- Convert a few files to UTF-8 from ANSI
Plus, 2 tiny formatting fixes.
- id_ata.cpp: Unmark a ReactOS own diff
Addendum to commit 7fdf078134.
- id_init.cpp: Mark a diff
Addendum to commit 09dde2cff9.
- Upgrade to v0.47b from v0.47a
CORE-17876
- The single default button in the "Shutdown Computer" and "GINA failed
to load" dialogs will be automatically focused by the dialog manager,
so there is no need to invoke `SetFocus()` in their `WM_INITDIALOG`
handler -- which also erroneously returned `TRUE`, thus ignoring any
focus set by the caller :D
- Use `DeleteMenu()` instead of `RemoveMenu()` so that it'll free any
memory resources.
Fix some erroneous `SetFocus()` invocations in dialog procedures:
- In `WM_INITDIALOG`, don't return `TRUE` if focus is changed to a
control, otherwise any focus set by the caller would be ignored;
- In other handlers, `SetFocus()` would generate an inconsistent
behaviour with the dialog push-buttons, as mentioned in:
https://devblogs.microsoft.com/oldnewthing/20040802-00/?p=38283
This allows pressing ENTER or ESC on the keyboard and have the correct
action done. The equivalent dialog in shell32.dll was already using that.
Simplify the associated code as well.
Also: remove the unused `", 400, 0, 1"` `FONT` resource specification info.
And add missing keyboard accelerators to the dialog buttons
(except for Hebrew where it's not clear what the preferred way
of specifying accelerators is).
Some partition entries (such as those added by the CreateInsertBlankRegion function) may not have their Volume member allocated. This fixes the USETUP crash when such partitions are handled.
- Both 3rd-party modules and GINA shutdown notifications should be
called just when shutdown is being started.
Addendum to commit d3b9c68d22 (r66252)
CORE-8322
- Factor the two `DisplayStatusMessage()` calls for shutdown vs. reboot.
- The `LogonHandler` notification should be invoked only once for a
given logon operation. It is invoked in `HandleLogon()` after access
to the window station (and desktop) is allowed for the user logging in.
And so, it must not be invoked elsewhere, when no user is logged in
(or a logon failure happened), like after a call to `WlxDisplaySASNotice()`...
- Invoke the `StartShellHandler` notification **before** starting the
shell, and the `PostShellHandler` notification **after** the shell
started.
- Invoke the `LogoffHandler` notification on the application desktop,
just after having terminated all the user's programs, and before
switching back to Winlogon's desktop.
- Add and show the 'Logging off' status message.
- When performing the following actions:
`WLX_SAS_ACTION_LOGOFF`, `WLX_SAS_ACTION_FORCE_LOGOFF`,
as well as:
`WLX_SAS_ACTION_SHUTDOWN`, `WLX_SAS_ACTION_SHUTDOWN_POWER_OFF`,
`WLX_SAS_ACTION_SHUTDOWN_REBOOT`,
ensure that Winlogon is in a correct LogonState for doing the logoff
sequence.
----
Test results for Winlogon notifications, after fix:
- `Asynchronous: FALSE, Impersonation: FALSE`
```
WLEventStartup: 30 tests executed (0 marked as todo, 1 failure), 0 skipped.
WLEventLogon: 32 tests executed (0 marked as todo, 1 failure), 0 skipped.
WLEventStartShell: 32 tests executed (0 marked as todo, 1 failure), 0 skipped.
WLEventPostShell: 32 tests executed (0 marked as todo, 1 failure), 0 skipped.
WLEventLock: 32 tests executed (0 marked as todo, 1 failure), 0 skipped.
WLEventUnlock: 32 tests executed (0 marked as todo, 1 failure), 0 skipped.
WLEventStartScreenSaver: 32 tests executed (0 marked as todo, 6 failures), 0 skipped.
WLEventStopScreenSaver: 32 tests executed (0 marked as todo, 5 failures), 0 skipped.
WLEventLogoff: 32 tests executed (0 marked as todo, 1 failure), 0 skipped.
WLEventShutdown: 31 tests executed (0 marked as todo, 3 failures), 0 skipped.
```
- `Asynchronous: FALSE, Impersonation: TRUE`
```
WLEventStartup: 30 tests executed (0 marked as todo, 1 failure), 0 skipped.
WLEventLogon: 33 tests executed (0 marked as todo, 3 failures), 0 skipped.
WLEventStartShell: 33 tests executed (0 marked as todo, 3 failures), 0 skipped.
WLEventPostShell: 33 tests executed (0 marked as todo, 3 failures), 0 skipped.
WLEventLock: 33 tests executed (0 marked as todo, 3 failures), 0 skipped.
WLEventUnlock: 33 tests executed (0 marked as todo, 3 failures), 0 skipped.
WLEventStartScreenSaver: 34 tests executed (0 marked as todo, 3 failures), 0 skipped.
WLEventStopScreenSaver: 34 tests executed (0 marked as todo, 2 failures), 0 skipped.
WLEventLogoff: 34 tests executed (0 marked as todo, 1 failure), 0 skipped.
WLEventShutdown: 31 tests executed (0 marked as todo, 3 failures), 0 skipped.
```
Per-user network connections (to shared drives...) are restored at user
logon: `HandleLogon() -> RestoreAllConnections()`.
These connections should be closed only at user logoff, in `HandleLogoff()`,
instead of inside the common logoff/shutdown thread, which is also invoked
at... shutdown!
- Isolate the network connections closing inside a `CloseAllConnections()`
helper (which also performs the necessary user thread impersonation).
- Invoke this helper directly inside `HandleLogoff()`, and also re-enable
the `IDS_CLOSINGNETWORKCONNECTIONS` message display.
Test results:
- Test 1a: `Asynchronous: FALSE, Impersonation: FALSE`
BEFORE the fix:
OK, the thread isn't impersonated:
```
Thread Token : 0x00000000 - User: '(null)\(null)'
```
BUT these two WLX notify info fields aren't set when the user is logged in:
```
Info.UserName : '(null)'
Info.Domain : '(null)'
```
Results:
```
WLEventStartup: 30 tests executed (0 marked as todo, 1 failure), 0 skipped.
WLEventLogon: 30 tests executed (0 marked as todo, 3 failures), 2 skipped.
WLEventStartShell: 30 tests executed (0 marked as todo, 3 failures), 2 skipped.
(NOTE: WLEventPostShell isn't yet implemented in ReactOS)
WLEventLock: 30 tests executed (0 marked as todo, 4 failures), 2 skipped.
WLEventUnlock: 30 tests executed (0 marked as todo, 3 failures), 2 skipped.
WLEventStartScreenSaver: 30 tests executed (0 marked as todo, 9 failures), 2 skipped.
WLEventStopScreenSaver: 30 tests executed (0 marked as todo, 7 failures), 2 skipped.
WLEventLogoff: 30 tests executed (0 marked as todo, 4 failures), 2 skipped.
WLEventShutdown: 31 tests executed (0 marked as todo, 3 failures), 0 skipped.
```
- Test 1b: `Asynchronous: FALSE, Impersonation: FALSE`
AFTER the fix:
OK, the thread isn't impersonated:
```
Thread Token : 0x00000000 - User: '(null)\(null)'
```
OK, these two WLX notify info fields are now set when the user is logged in:
```
Info.UserName : 'Administrator'
Info.Domain : 'MYCOMPUTERNAME'
```
Results:
```
WLEventStartup: 30 tests executed (0 marked as todo, 1 failure), 0 skipped.
WLEventLogon: 32 tests executed (0 marked as todo, 1 failure), 0 skipped.
WLEventStartShell: 32 tests executed (0 marked as todo, 1 failure), 0 skipped.
(NOTE: WLEventPostShell isn't yet implemented in ReactOS)
WLEventLock: 32 tests executed (0 marked as todo, 2 failures), 0 skipped.
WLEventUnlock: 32 tests executed (0 marked as todo, 1 failure), 0 skipped.
WLEventStartScreenSaver: 32 tests executed (0 marked as todo, 7 failures), 0 skipped.
WLEventStopScreenSaver: 32 tests executed (0 marked as todo, 5 failures), 0 skipped.
WLEventLogoff: 32 tests executed (0 marked as todo, 2 failures), 0 skipped.
WLEventShutdown: 31 tests executed (0 marked as todo, 3 failures), 0 skipped.
```
Less failed tests and none skipped anymore.
- Test 2a: `Asynchronous: FALSE, Impersonation: TRUE`
BEFORE the fix:
OK, the thread impersonates the user when (s)he is logged in:
```
Thread Token : 0x00000360 - User: 'MYCOMPUTERNAME\Administrator'
```
BUT these two WLX notify info fields aren't set when the user is logged in:
```
Info.UserName : '(null)'
Info.Domain : '(null)'
```
Results:
```
WLEventStartup: 30 tests executed (0 marked as todo, 1 failure), 0 skipped.
WLEventLogon: 31 tests executed (0 marked as todo, 5 failures), 2 skipped.
WLEventStartShell: 31 tests executed (0 marked as todo, 5 failures), 2 skipped.
(NOTE: WLEventPostShell isn't yet implemented in ReactOS)
WLEventLock: 31 tests executed (0 marked as todo, 6 failures), 2 skipped.
WLEventUnlock: 31 tests executed (0 marked as todo, 5 failures), 2 skipped.
WLEventStartScreenSaver: 32 tests executed (0 marked as todo, 6 failures), 2 skipped.
WLEventStopScreenSaver: 32 tests executed (0 marked as todo, 4 failures), 2 skipped.
WLEventLogoff: 32 tests executed (0 marked as todo, 4 failures), 2 skipped.
WLEventShutdown: 31 tests executed (0 marked as todo, 3 failures), 0 skipped.
```
- Test 2b: `Asynchronous: FALSE, Impersonation: TRUE`
AFTER the fix:
OK, the thread impersonates the user when (s)he is logged in:
```
Thread Token : 0x00000360 - User: 'MYCOMPUTERNAME\Administrator'
```
OK, these two WLX notify info fields are now set when the user is logged in:
```
Info.UserName : 'Administrator'
Info.Domain : 'MYCOMPUTERNAME'
```
Results:
```
WLEventStartup: 30 tests executed (0 marked as todo, 1 failure), 0 skipped.
WLEventLogon: 33 tests executed (0 marked as todo, 3 failures), 0 skipped.
WLEventStartShell: 33 tests executed (0 marked as todo, 3 failures), 0 skipped.
(NOTE: WLEventPostShell isn't yet implemented in ReactOS)
WLEventLock: 33 tests executed (0 marked as todo, 4 failures), 0 skipped.
WLEventUnlock: 33 tests executed (0 marked as todo, 3 failures), 0 skipped.
WLEventStartScreenSaver: 34 tests executed (0 marked as todo, 4 failures), 0 skipped.
WLEventStopScreenSaver: 34 tests executed (0 marked as todo, 2 failures), 0 skipped.
WLEventLogoff: 34 tests executed (0 marked as todo, 2 failures), 0 skipped.
WLEventShutdown: 31 tests executed (0 marked as todo, 3 failures), 0 skipped.
```
As well, less failed tests and none skipped anymore.
- As mentioned in the previous MSGINA commit aa67222595,
`lpProfilePath` specifies the path to a *roaming* user profile,
for example on a domain server, if any. It is then used to create
a local image (copy) of the profile on the local computer.
HOWEVER (ReactOS HACK):
We currently don't implement this in ReactOS; instead, we use it
directly as *the* user's profile path, without doing any copy...
- Yes, MS Windows allows `lpProfileInfo->lpProfilePath` to be NULL :)
The following members of the returned `WLX_PROFILE_V2_0` structure:
`pszProfile`, `pszPolicy`, `pszNetworkDefaultUserProfile`, and
`pszServerName`, have a specific meaning and are used when logging
to (NT4, Active Directory...) domains.
See the added code comments for details.
In particular, `pszProfile` specifies the path to a *roaming* user
profile[^1] on a domain server, if any. It **DOES NOT** specify the local
`"C:\Documents and Settings"` path (got via `GetProfilesDirectoryW()`).
Since we don't really support user login on domains, set these pointers to NULL.
----
Enabling UserEnv debug logging[^2] on Windows 2003, one can observe such
following traces, for a `TestUser` roaming user profile:
```
USERENV(148.14c) 20:24:59:821 LoadUserProfile: Entering, hToken = <0x8bc>, lpProfileInfo = 0x6e5d8
USERENV(148.14c) 20:24:59:875 LoadUserProfile: lpProfileInfo->dwFlags = <0x0>
USERENV(148.14c) 20:24:59:912 LoadUserProfile: lpProfileInfo->lpUserName = <TestUser>
USERENV(148.14c) 20:24:59:966 LoadUserProfile: lpProfileInfo->lpProfilePath = <C:\Documents and Settings\TestUser_Roaming>
USERENV(148.14c) 20:25:00:021 LoadUserProfile: lpProfileInfo->lpDefaultPath = <\\PC-H\netlogon\Default User>
USERENV(148.14c) 20:25:00:075 LoadUserProfile: NULL server name
...
USERENV(148.14c) 20:25:06:177 CopyProfileDirectoryEx: Found hive file NTUSER.DAT
USERENV(148.14c) 20:25:06:395 ReconcileFile: C:\Documents and Settings\TestUser_Roaming\NTUSER.DAT ==> C:\Documents and Settings\TestUser\NTUSER.DAT [OK]
...
```
The `lpProfilePath` specifies a roaming profile directory (`"TestUser_Roaming"`)
for a user named named `TestUser`, and UserEnv proceeds to image the roaming
profile into the directory (`"TestUser"`) in the local computer.
However, when the user has a local profile, the `lpProfilePath` is set to
NULL in this case, and one observes instead:
```
USERENV(148.14c) 20:21:22:644 LoadUserProfile: NULL central profile path
```
----
[^1]: The following links explain this, also demonstrating UserEnv debug logging:
- https://web.archive.org/web/20130319204738/http://blogs.technet.com/b/askds/archive/2008/11/11/understanding-how-to-read-a-userenv-log-part-2.aspx
- https://web.archive.org/web/20150405040409/http://blogs.technet.com/b/ad/archive/2007/08/20/tracking-user-environment-creation.aspx
[^2]: For more details, see:
https://www.betaarchive.com/wiki/index.php?title=Microsoft_KB_Archive/221833
(archived from: http://support.microsoft.com/kb/221833)
UserEnv debug logging is achieved by adding a `REG_DWORD` value named
`UserEnvDebugLevel` in the following registry sub-key:
`HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon`
with a non-zero value.
To view the output in a debugger (e.g. WinDbg when kernel-debugging
Windows), set the value to `0x00020002`.