-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for Windows Nano Server #1768
Conversation
… winsta.dll with wtsapi. (cherry picked from commit 7728eac066e6576d2971f2c94a4caf55bd12d4c2)
(cherry picked from commit 93a5d2ca55dc548ed8563c3733bfcc77a4084fb2)
…ween wide char and multi-byte functions.
VOID(CALLBACK *_WTSFreeMemory)( | ||
IN PVOID pMemory | ||
); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since these names are available on other Windows systems, I think there should be something like:
#ifdef WINDOWS_NANO_OR_SOMETHING
...
#endif
There's no need of the _
prefix. Look at how other declarations are done. E.g.:
PSTR (NTAPI * _RtlIpv6AddressToStringA) (
struct in6_addr *Addr,
PSTR P);
#define RtlIpv6AddressToStringA _RtlIpv6AddressToStringA
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not entirely sure I understand what you mean with the names being available on other Windows systems.
I think the function names are still available when compiling for Windows Nano, but the library is not present on the target system (i.e. Windows Nano is not a separate compilation target with a separate SDK).
If we're worried about name conflicts, what about using a distinctive name for the functions, like so:
BOOL(CALLBACK *psutil_WTSQuerySessionInformation) (
HANDLE hServer,
DWORD SessionId,
WTS_INFO_CLASS WTSInfoClass,
LPTSTR* ppBuffer,
DWORD* pBytesReturned
);
BOOL(CALLBACK *psutil_WTSEnumerateSessions)(
HANDLE hServer,
DWORD Reserved,
DWORD Version,
PWTS_SESSION_INFO* ppSessionInfo,
DWORD* pCount
);
VOID(CALLBACK *psutil_WTSFreeMemory)(
IN PVOID pMemory
);
...
psutil_WTSEnumerateSessions = psutil_GetProcAddressFromLib(
"wtsapi32.dll", "WTSEnumerateSessionsW");
psutil_WTSQuerySessionInformation = psutil_GetProcAddressFromLib(
"wtsapi32.dll", "WTSQuerySessionInformationW");
psutil_WTSFreeMemory = psutil_GetProcAddressFromLib(
"wtsapi32.dll", "WTSFreeMemory");
This way we also removes the need for the _
prefix.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not entirely sure I understand what you mean
It's OK, let me try to rephrase it differently.
What I am aiming at is using the original API names, without the _
or psutil_
prefix (the original version of this file did exactly that, then I changed it).
In order to do that you first have to "declare" the API name, like this:
psutil/psutil/arch/windows/ntextapi.h
Lines 501 to 507 in 96cc7ea
NTSTATUS (NTAPI *_NtQuerySystemInformation) ( | |
ULONG SystemInformationClass, | |
PVOID SystemInformation, | |
ULONG SystemInformationLength, | |
PULONG ReturnLength); | |
#define NtQuerySystemInformation _NtQuerySystemInformation |
Then you'll have to "load" the API, in here, like this:
psutil/psutil/_psutil_common.c
Lines 217 to 220 in 96cc7ea
NtQuerySystemInformation = psutil_GetProcAddressFromLib( | |
"ntdll.dll", "NtQuerySystemInformation"); | |
if (! NtQuerySystemInformation) | |
return 1; |
Is it more clear?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not tested, but it should be something like this:
// ntextapi.h
BOOL (CALLBACK *_WTSQuerySessionInformation) (
HANDLE hServer,
DWORD SessionId,
WTS_INFO_CLASS WTSInfoClass,
LPTSTR* ppBuffer,
DWORD* pBytesReturned
);
#define WTSQuerySessionInformation _WTSQuerySessionInformation
// _psutil_common.c
WTSEnumerateSessions = psutil_GetProcAddressFromLib(
"wtsapi32.dll", "WTSEnumerateSessions");
if (! WTSEnumerateSessions)
return 1;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, MS doc says:
The wtsapi32.h header defines WTSEnumerateSessions as an alias which automatically selects the ANSI or Unicode version of this function based on the definition of the UNICODE preprocessor constant.
...so I think you should keep using WTSEnumerateSessions
instead of WTSEnumerateSessionsW
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the explanation, I think I see what you're aiming for.
I included the header Wtsapi32.h
in ntextapi.h
to use the existing structures definition, but the point of ntextapi.h
is to be independent of such header, right ?
So I should remove that #include
and copy over all the definitions required to make it look like we are using the original header, correct ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you can fix the issue just by adding that new header (or from setup.py) there is no need to redefine anything in ntextapi.h.
Just define them explicitly in ntextapi.h only if you can’t solve it otherwise, in which case you should put the definition inside an “#ifdef nanoserver” because I think it will break other windows versions (but the CI tests should break)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAIK there is no way to distinguish Windows Nano via preprocessor definitions - I think it is still using the same _WIN32_WINNT
and WINVER
as a regular Windows.
If we introduce a new prepocessor flag for Windows Nano, then we would have to maintain 2 versions of psutil, one linked with WtsApi32.lib
and one that loads dynamically the DLL at runtime.
Why not just keep the dynamically loaded version for all version of Windows and avoid that issue altogether ?
You mention it will break other Windows version, do you have something specific in mind ?
To me it seems the dynamic loading will also work on other Windows version (I ran my tests on many versions of Windows actually - I should probably update the PR description).
psutil/_psutil_common.c
Outdated
@@ -320,6 +316,20 @@ psutil_loadlibs() { | |||
// minumum requirement: Win 7 | |||
GetLogicalProcessorInformationEx = psutil_GetProcAddressFromLib( | |||
"kernel32", "GetLogicalProcessorInformationEx"); | |||
// minimum requirements: Windows Server Core | |||
#ifdef UNICODE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mmm. Is this necessary? Is it possible for a system to not have unicode support?
Regardless from that, we already use other unicode "W" functions in many other places. If this is broken then they are all broken (in which case it should be a separate fix).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't sure if psutil
was ever compiled with UNICODE unset, so I provided both "A" and "W". I will simplify this to just use the unicode methods.
Only provide UNICODE variants of WTSQuerySessionInformation and WTSEnumerateSessions. Copy definitions from WtsApi32.h in ntextapi.h to prevent conflicting name definitions. Removed _ prefix for WTS* api calls.
WTSFreeMemory == NULL) { | ||
PyErr_SetString(PyExc_RuntimeError, "wtsapi32.dll cannot be found."); | ||
goto error; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand. Are these names available on Windows Nano? Does this function (users()
) work at all?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, those names are not available on Windows Nano, and consequently users
does not work. If you try to run psutil.users
in Windows Nano, that is what you get:
OSError: [WinError 120] This function is not supported on this system: '(originated from WTSEnumerateSessions)'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But by loading those symbols dynamically, at least psutil
can be used on Windows Nano. Previously it would simply try to load WtsApi32.dll
and fail even if you never called users()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If Windows Nano does not support users at all then I think it makes more sense to just return an empty list. It's less disruptive than an error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think return Py_BuildValue("[]");
should do it.
psutil/_psutil_windows.c
Outdated
|
||
// username | ||
bytes = 0; | ||
if (WTSQuerySessionInformationW(hServer, sessionId, WTSUserName, | ||
if (WTSQuerySessionInformation(hServer, sessionId, WTSUserName, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it makes more sense to keep the old unicode name.
psutil/_psutil_windows.c
Outdated
{ | ||
PyErr_SetFromOSErrnoWithSyscall("WinStationQueryInformationW"); | ||
bytes = 0; | ||
if (WTSQuerySessionInformation(hServer, sessionId, WTSSessionInfo, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here, keep the old name
(cherry picked from commit 1c82c6a1d64c47c94e85e59b54d3737228d245af)
(cherry picked from commit 6013def71d72455994e6949156d8f16687ac96b4)
(cherry picked from commit e6a7d4ca81e6983a05916bb4ae0df7ed25db674f) (cherry picked from commit 11108cce06ddf28f656b809d64aa7f9c6a32cc96)
(cherry picked from commit c7569a85893e83801473cd6e12bacf08c97d5160)
(cherry picked from commit cf330cb9579ef250c57d22ec91cd5557df89896e)
dcc970f
to
12982a6
Compare
Merged. Glad to see a new platform being supported. |
Purpose
The purpose of this PR is to address #693 so that psutil can be used with Windows Nano Server containers.
Additional notes
ConnectTime
I changed the call that obtains the
ConnectTime
to usewtsapi
sinceWinStationQueryInformationW
seems deprecated (see Microsoft documentation).Dynamic module loading
The API from
wtsapi32.lib
is loaded dynamically as recommended hereTesting
I wrote some Dockerfile that will build a custom server nano image with python and then copy psutil into that container and ran a few commands:
Nano Server Dockerfile
Server Core Dockerfile
Test code
In
winmake.py