summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiampaolo Rodola <g.rodola@gmail.com>2019-02-21 07:39:54 -0800
committerGitHub <noreply@github.com>2019-02-21 07:39:54 -0800
commit0a30dc9dc2693ffe9aa54126eb684711d950c3f1 (patch)
treec163b5492c33bee1a57145a81ce2a89cdc405032
parentba649e832140fd69e0adb3958ad298b8f7434e69 (diff)
downloadpsutil-0a30dc9dc2693ffe9aa54126eb684711d950c3f1.tar.gz
Windows / speeup: dynamically load libraries on startup and never again (#1422)
Windows / speeup: dynamically load libraries on startup and never again.
-rw-r--r--psutil/_psutil_windows.c289
-rw-r--r--psutil/arch/windows/global.c129
-rw-r--r--psutil/arch/windows/global.h11
-rw-r--r--psutil/arch/windows/ntextapi.h293
-rw-r--r--psutil/arch/windows/process_handles.c198
-rw-r--r--psutil/arch/windows/process_handles.h101
-rw-r--r--psutil/arch/windows/process_info.c183
-rw-r--r--psutil/arch/windows/process_info.h2
-rwxr-xr-xpsutil/tests/test_windows.py5
-rwxr-xr-xsetup.py1
10 files changed, 581 insertions, 631 deletions
diff --git a/psutil/_psutil_windows.c b/psutil/_psutil_windows.c
index d6058b8b..3908884e 100644
--- a/psutil/_psutil_windows.c
+++ b/psutil/_psutil_windows.c
@@ -22,6 +22,8 @@
#include <ws2tcpip.h>
#endif
#include <iphlpapi.h>
+#include <iprtrmib.h>
+#include <udpmib.h>
#include <wtsapi32.h>
#include <Winsvc.h>
#include <PowrProf.h>
@@ -30,13 +32,14 @@
// Link with Iphlpapi.lib
#pragma comment(lib, "IPHLPAPI.lib")
-#include "_psutil_common.h"
+#include "arch/windows/ntextapi.h"
+#include "arch/windows/global.h"
#include "arch/windows/security.h"
#include "arch/windows/process_info.h"
#include "arch/windows/process_handles.h"
-#include "arch/windows/ntextapi.h"
#include "arch/windows/inet_ntop.h"
#include "arch/windows/services.h"
+#include "_psutil_common.h"
/*
@@ -53,109 +56,6 @@
#ifndef AF_INET6
#define AF_INET6 23
#endif
-#define _psutil_conn_decref_objs() \
- Py_DECREF(_AF_INET); \
- Py_DECREF(_AF_INET6);\
- Py_DECREF(_SOCK_STREAM);\
- Py_DECREF(_SOCK_DGRAM);
-
-#if (_WIN32_WINNT >= 0x0601) // Windows 7
-typedef BOOL (WINAPI *PFN_GETLOGICALPROCESSORINFORMATIONEX)(
- LOGICAL_PROCESSOR_RELATIONSHIP relationship,
- PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX Buffer,
- PDWORD ReturnLength);
-static PFN_GETLOGICALPROCESSORINFORMATIONEX _GetLogicalProcessorInformationEx;
-#endif
-
-// Fix for mingw32, see:
-// https://github.com/giampaolo/psutil/issues/351#c2
-// This is actually a DISK_PERFORMANCE struct:
-// https://msdn.microsoft.com/en-us/library/windows/desktop/
-// aa363991(v=vs.85).aspx
-typedef struct _DISK_PERFORMANCE_WIN_2008 {
- LARGE_INTEGER BytesRead;
- LARGE_INTEGER BytesWritten;
- LARGE_INTEGER ReadTime;
- LARGE_INTEGER WriteTime;
- LARGE_INTEGER IdleTime;
- DWORD ReadCount;
- DWORD WriteCount;
- DWORD QueueDepth;
- DWORD SplitCount;
- LARGE_INTEGER QueryTime;
- DWORD StorageDeviceNumber;
- WCHAR StorageManagerName[8];
-} DISK_PERFORMANCE_WIN_2008;
-
-// --- network connections mingw32 support
-#ifndef _IPRTRMIB_H
-#if (_WIN32_WINNT < 0x0600) // Windows XP
-typedef struct _MIB_TCP6ROW_OWNER_PID {
- UCHAR ucLocalAddr[16];
- DWORD dwLocalScopeId;
- DWORD dwLocalPort;
- UCHAR ucRemoteAddr[16];
- DWORD dwRemoteScopeId;
- DWORD dwRemotePort;
- DWORD dwState;
- DWORD dwOwningPid;
-} MIB_TCP6ROW_OWNER_PID, *PMIB_TCP6ROW_OWNER_PID;
-
-typedef struct _MIB_TCP6TABLE_OWNER_PID {
- DWORD dwNumEntries;
- MIB_TCP6ROW_OWNER_PID table[ANY_SIZE];
-} MIB_TCP6TABLE_OWNER_PID, *PMIB_TCP6TABLE_OWNER_PID;
-#endif
-#endif
-
-#ifndef __IPHLPAPI_H__
-typedef struct in6_addr {
- union {
- UCHAR Byte[16];
- USHORT Word[8];
- } u;
-} IN6_ADDR, *PIN6_ADDR, FAR *LPIN6_ADDR;
-
-typedef enum _UDP_TABLE_CLASS {
- UDP_TABLE_BASIC,
- UDP_TABLE_OWNER_PID,
- UDP_TABLE_OWNER_MODULE
-} UDP_TABLE_CLASS, *PUDP_TABLE_CLASS;
-
-typedef struct _MIB_UDPROW_OWNER_PID {
- DWORD dwLocalAddr;
- DWORD dwLocalPort;
- DWORD dwOwningPid;
-} MIB_UDPROW_OWNER_PID, *PMIB_UDPROW_OWNER_PID;
-
-typedef struct _MIB_UDPTABLE_OWNER_PID {
- DWORD dwNumEntries;
- MIB_UDPROW_OWNER_PID table[ANY_SIZE];
-} MIB_UDPTABLE_OWNER_PID, *PMIB_UDPTABLE_OWNER_PID;
-#endif
-
-#if (_WIN32_WINNT < 0x0600) // Windows XP
-typedef struct _MIB_UDP6ROW_OWNER_PID {
- UCHAR ucLocalAddr[16];
- DWORD dwLocalScopeId;
- DWORD dwLocalPort;
- DWORD dwOwningPid;
-} MIB_UDP6ROW_OWNER_PID, *PMIB_UDP6ROW_OWNER_PID;
-
-typedef struct _MIB_UDP6TABLE_OWNER_PID {
- DWORD dwNumEntries;
- MIB_UDP6ROW_OWNER_PID table[ANY_SIZE];
-} MIB_UDP6TABLE_OWNER_PID, *PMIB_UDP6TABLE_OWNER_PID;
-#endif
-
-typedef struct _PROCESSOR_POWER_INFORMATION {
- ULONG Number;
- ULONG MaxMhz;
- ULONG CurrentMhz;
- ULONG MhzLimit;
- ULONG MaxIdleState;
- ULONG CurrentIdleState;
-} PROCESSOR_POWER_INFORMATION, *PPROCESSOR_POWER_INFORMATION;
PIP_ADAPTER_ADDRESSES
@@ -204,15 +104,10 @@ unsigned int
psutil_get_num_cpus(int fail_on_err) {
unsigned int ncpus = 0;
SYSTEM_INFO sysinfo;
- static DWORD(CALLBACK *_GetActiveProcessorCount)(WORD) = NULL;
-
- // GetActiveProcessorCount is available only on 64 bit versions
- // of Windows from Windows 7 onward.
- // Windows Vista 64 bit and Windows XP don't have it.
- _GetActiveProcessorCount = \
- psutil_GetProcAddress("kernel32", "GetActiveProcessorCount");
- if (_GetActiveProcessorCount != NULL) {
- ncpus = _GetActiveProcessorCount(ALL_PROCESSOR_GROUPS);
+
+ // Minimum requirement: Windows 7
+ if (psutil_GetActiveProcessorCount != NULL) {
+ ncpus = psutil_GetActiveProcessorCount(ALL_PROCESSOR_GROUPS);
if ((ncpus == 0) && (fail_on_err == 1)) {
PyErr_SetFromWindowsErr(0);
}
@@ -242,8 +137,6 @@ psutil_get_num_cpus(int fail_on_err) {
static PyObject *TimeoutExpired;
static PyObject *TimeoutAbandoned;
-static ULONGLONG (*psutil_GetTickCount64)(void) = NULL;
-
/*
* Return a Python float representing the system uptime expressed in seconds
* since the epoch.
@@ -258,7 +151,6 @@ psutil_boot_time(PyObject *self, PyObject *args) {
time_t pt;
FILETIME fileTime;
long long ll;
- psutil_GetTickCount64;
GetSystemTimeAsFileTime(&fileTime);
/*
@@ -287,7 +179,6 @@ psutil_boot_time(PyObject *self, PyObject *args) {
// "#if (_WIN32_WINNT >= 0x0600)" pre-processor but that way
// the produced exe/wheels cannot be used on Windows XP, see:
// https://github.com/giampaolo/psutil/issues/811#issuecomment-230639178
- psutil_GetTickCount64 = psutil_GetProcAddress("kernel32", "GetTickCount64");
if (psutil_GetTickCount64 != NULL) {
// Windows >= Vista
uptime = psutil_GetTickCount64() / (ULONGLONG)1000.00f;
@@ -297,6 +188,8 @@ psutil_boot_time(PyObject *self, PyObject *args) {
// Windows XP.
// GetTickCount() time will wrap around to zero if the
// system is run continuously for 49.7 days.
+ psutil_debug("Windows < Vista; using GetTickCount() instead of "
+ "GetTickCount64()");
uptime = GetTickCount() / (LONGLONG)1000.00f;
return Py_BuildValue("L", pt - uptime);
}
@@ -611,17 +504,6 @@ psutil_cpu_count_logical(PyObject *self, PyObject *args) {
* Return the number of physical CPU cores (hyper-thread CPUs count
* is excluded).
*/
-#if (_WIN32_WINNT < 0x0601) // < Windows 7 (namely Vista and XP)
-static PyObject *
-psutil_cpu_count_phys(PyObject *self, PyObject *args) {
- // Note: we may have used GetLogicalProcessorInformation()
- // but I don't want to prolong support for Windows XP and Vista.
- // On such old systems psutil will compile but this API will
- // just return None.
- psutil_debug("Win < 7; cpu_count_phys() forced to None");
- Py_RETURN_NONE;
-}
-#else // Windows >= 7
static PyObject *
psutil_cpu_count_phys(PyObject *self, PyObject *args) {
DWORD rc;
@@ -636,13 +518,13 @@ psutil_cpu_count_phys(PyObject *self, PyObject *args) {
// it supports process groups, meaning this is able to report more
// than 64 CPUs. See:
// https://bugs.python.org/issue33166
- _GetLogicalProcessorInformationEx = psutil_GetProcAddressFromLib(
- "kernel32", "GetLogicalProcessorInformationEx");
- if (_GetLogicalProcessorInformationEx == NULL)
- return NULL;
+ if (psutil_GetLogicalProcessorInformationEx == NULL) {
+ psutil_debug("Win < 7; cpu_count_phys() forced to None");
+ Py_RETURN_NONE;
+ }
while (1) {
- rc = _GetLogicalProcessorInformationEx(
+ rc = psutil_GetLogicalProcessorInformationEx(
RelationAll, buffer, &length);
if (rc == FALSE) {
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
@@ -691,7 +573,6 @@ return_none:
free(buffer);
Py_RETURN_NONE;
}
-#endif
/*
@@ -1044,10 +925,6 @@ psutil_cpu_times(PyObject *self, PyObject *args) {
*/
static PyObject *
psutil_per_cpu_times(PyObject *self, PyObject *args) {
- // NtQuerySystemInformation stuff
- typedef DWORD (_stdcall * NTQSI_PROC) (int, PVOID, ULONG, PULONG);
- NTQSI_PROC NtQuerySystemInformation;
-
double idle, kernel, systemt, user, interrupt, dpc;
NTSTATUS status;
_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *sppi = NULL;
@@ -1058,10 +935,6 @@ psutil_per_cpu_times(PyObject *self, PyObject *args) {
if (py_retlist == NULL)
return NULL;
- NtQuerySystemInformation = \
- psutil_GetProcAddressFromLib("ntdll.dll", "NtQuerySystemInformation");
- if (NtQuerySystemInformation == NULL)
- goto error;
// retrieves number of processors
ncpus = psutil_get_num_cpus(1);
@@ -1078,7 +951,7 @@ psutil_per_cpu_times(PyObject *self, PyObject *args) {
}
// gets cpu time informations
- status = NtQuerySystemInformation(
+ status = psutil_NtQuerySystemInformation(
SystemProcessorPerformanceInformation,
sppi,
ncpus * sizeof(_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION),
@@ -1537,10 +1410,6 @@ error:
}
-typedef DWORD (WINAPI * _GetExtendedTcpTable)(PVOID, PDWORD, BOOL, ULONG,
- TCP_TABLE_CLASS, ULONG);
-
-
// https://msdn.microsoft.com/library/aa365928.aspx
static DWORD __GetExtendedTcpTable(_GetExtendedTcpTable call,
ULONG address_family,
@@ -1575,10 +1444,6 @@ static DWORD __GetExtendedTcpTable(_GetExtendedTcpTable call,
}
-typedef DWORD (WINAPI * _GetExtendedUdpTable)(PVOID, PDWORD, BOOL, ULONG,
- UDP_TABLE_CLASS, ULONG);
-
-
// https://msdn.microsoft.com/library/aa365930.aspx
static DWORD __GetExtendedUdpTable(_GetExtendedUdpTable call,
ULONG address_family,
@@ -1613,6 +1478,13 @@ static DWORD __GetExtendedUdpTable(_GetExtendedUdpTable call,
}
+#define psutil_conn_decref_objs() \
+ Py_DECREF(_AF_INET); \
+ Py_DECREF(_AF_INET6);\
+ Py_DECREF(_SOCK_STREAM);\
+ Py_DECREF(_SOCK_DGRAM);
+
+
/*
* Return a list of network connections opened by a process
*/
@@ -1621,12 +1493,6 @@ psutil_net_connections(PyObject *self, PyObject *args) {
static long null_address[4] = { 0, 0, 0, 0 };
unsigned long pid;
int pid_return;
- typedef PSTR (NTAPI * _RtlIpv4AddressToStringA)(struct in_addr *, PSTR);
- _RtlIpv4AddressToStringA rtlIpv4AddressToStringA;
- typedef PSTR (NTAPI * _RtlIpv6AddressToStringA)(struct in6_addr *, PSTR);
- _RtlIpv6AddressToStringA rtlIpv6AddressToStringA;
- _GetExtendedTcpTable getExtendedTcpTable;
- _GetExtendedUdpTable getExtendedUdpTable;
PVOID table = NULL;
DWORD tableSize;
DWORD error;
@@ -1650,28 +1516,11 @@ psutil_net_connections(PyObject *self, PyObject *args) {
PyObject *_SOCK_DGRAM = PyLong_FromLong((long)SOCK_DGRAM);
// Import some functions.
- rtlIpv4AddressToStringA = psutil_GetProcAddressFromLib(
- "ntdll.dll", "RtlIpv4AddressToStringA");
- if (rtlIpv4AddressToStringA == NULL)
- goto error;
- rtlIpv6AddressToStringA = psutil_GetProcAddressFromLib(
- "ntdll.dll", "RtlIpv6AddressToStringA");
- if (rtlIpv6AddressToStringA == NULL)
- goto error;
- getExtendedTcpTable = psutil_GetProcAddressFromLib(
- "iphlpapi.dll", "GetExtendedTcpTable");
- if (getExtendedTcpTable == NULL)
- goto error;
- getExtendedUdpTable = psutil_GetProcAddressFromLib(
- "iphlpapi.dll", "GetExtendedUdpTable");
- if (getExtendedUdpTable == NULL)
- goto error;
-
if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter))
goto error;
if (!PySequence_Check(py_af_filter) || !PySequence_Check(py_type_filter)) {
- _psutil_conn_decref_objs();
+ psutil_conn_decref_objs();
PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence");
return NULL;
}
@@ -1679,25 +1528,18 @@ psutil_net_connections(PyObject *self, PyObject *args) {
if (pid != -1) {
pid_return = psutil_pid_is_running(pid);
if (pid_return == 0) {
- _psutil_conn_decref_objs();
+ psutil_conn_decref_objs();
return NoSuchProcess("");
}
else if (pid_return == -1) {
- _psutil_conn_decref_objs();
+ psutil_conn_decref_objs();
return NULL;
}
}
- if ((getExtendedTcpTable == NULL) || (getExtendedUdpTable == NULL)) {
- PyErr_SetString(PyExc_NotImplementedError,
- "feature not supported on this Windows version");
- _psutil_conn_decref_objs();
- return NULL;
- }
-
py_retlist = PyList_New(0);
if (py_retlist == NULL) {
- _psutil_conn_decref_objs();
+ psutil_conn_decref_objs();
return NULL;
}
@@ -1712,7 +1554,7 @@ psutil_net_connections(PyObject *self, PyObject *args) {
py_addr_tuple_remote = NULL;
tableSize = 0;
- error = __GetExtendedTcpTable(getExtendedTcpTable,
+ error = __GetExtendedTcpTable(psutil_GetExtendedTcpTable,
AF_INET, &table, &tableSize);
if (error == ERROR_NOT_ENOUGH_MEMORY) {
PyErr_NoMemory();
@@ -1737,7 +1579,7 @@ psutil_net_connections(PyObject *self, PyObject *args) {
struct in_addr addr;
addr.S_un.S_addr = tcp4Table->table[i].dwLocalAddr;
- rtlIpv4AddressToStringA(&addr, addressBufferLocal);
+ psutil_rtlIpv4AddressToStringA(&addr, addressBufferLocal);
py_addr_tuple_local = Py_BuildValue(
"(si)",
addressBufferLocal,
@@ -1759,7 +1601,7 @@ psutil_net_connections(PyObject *self, PyObject *args) {
struct in_addr addr;
addr.S_un.S_addr = tcp4Table->table[i].dwRemoteAddr;
- rtlIpv4AddressToStringA(&addr, addressBufferRemote);
+ psutil_rtlIpv4AddressToStringA(&addr, addressBufferRemote);
py_addr_tuple_remote = Py_BuildValue(
"(si)",
addressBufferRemote,
@@ -1809,7 +1651,7 @@ psutil_net_connections(PyObject *self, PyObject *args) {
py_addr_tuple_remote = NULL;
tableSize = 0;
- error = __GetExtendedTcpTable(getExtendedTcpTable,
+ error = __GetExtendedTcpTable(psutil_GetExtendedTcpTable,
AF_INET6, &table, &tableSize);
if (error == ERROR_NOT_ENOUGH_MEMORY) {
PyErr_NoMemory();
@@ -1834,7 +1676,7 @@ psutil_net_connections(PyObject *self, PyObject *args) {
struct in6_addr addr;
memcpy(&addr, tcp6Table->table[i].ucLocalAddr, 16);
- rtlIpv6AddressToStringA(&addr, addressBufferLocal);
+ psutil_rtlIpv6AddressToStringA(&addr, addressBufferLocal);
py_addr_tuple_local = Py_BuildValue(
"(si)",
addressBufferLocal,
@@ -1857,7 +1699,7 @@ psutil_net_connections(PyObject *self, PyObject *args) {
struct in6_addr addr;
memcpy(&addr, tcp6Table->table[i].ucRemoteAddr, 16);
- rtlIpv6AddressToStringA(&addr, addressBufferRemote);
+ psutil_rtlIpv6AddressToStringA(&addr, addressBufferRemote);
py_addr_tuple_remote = Py_BuildValue(
"(si)",
addressBufferRemote,
@@ -1906,7 +1748,7 @@ psutil_net_connections(PyObject *self, PyObject *args) {
py_addr_tuple_local = NULL;
py_addr_tuple_remote = NULL;
tableSize = 0;
- error = __GetExtendedUdpTable(getExtendedUdpTable,
+ error = __GetExtendedUdpTable(psutil_GetExtendedUdpTable,
AF_INET, &table, &tableSize);
if (error == ERROR_NOT_ENOUGH_MEMORY) {
PyErr_NoMemory();
@@ -1931,7 +1773,7 @@ psutil_net_connections(PyObject *self, PyObject *args) {
struct in_addr addr;
addr.S_un.S_addr = udp4Table->table[i].dwLocalAddr;
- rtlIpv4AddressToStringA(&addr, addressBufferLocal);
+ psutil_rtlIpv4AddressToStringA(&addr, addressBufferLocal);
py_addr_tuple_local = Py_BuildValue(
"(si)",
addressBufferLocal,
@@ -1980,7 +1822,7 @@ psutil_net_connections(PyObject *self, PyObject *args) {
py_addr_tuple_local = NULL;
py_addr_tuple_remote = NULL;
tableSize = 0;
- error = __GetExtendedUdpTable(getExtendedUdpTable,
+ error = __GetExtendedUdpTable(psutil_GetExtendedUdpTable,
AF_INET6, &table, &tableSize);
if (error == ERROR_NOT_ENOUGH_MEMORY) {
PyErr_NoMemory();
@@ -2004,7 +1846,7 @@ psutil_net_connections(PyObject *self, PyObject *args) {
struct in6_addr addr;
memcpy(&addr, udp6Table->table[i].ucLocalAddr, 16);
- rtlIpv6AddressToStringA(&addr, addressBufferLocal);
+ psutil_rtlIpv6AddressToStringA(&addr, addressBufferLocal);
py_addr_tuple_local = Py_BuildValue(
"(si)",
addressBufferLocal,
@@ -2043,11 +1885,11 @@ psutil_net_connections(PyObject *self, PyObject *args) {
tableSize = 0;
}
- _psutil_conn_decref_objs();
+ psutil_conn_decref_objs();
return py_retlist;
error:
- _psutil_conn_decref_objs();
+ psutil_conn_decref_objs();
Py_XDECREF(py_conn_tuple);
Py_XDECREF(py_addr_tuple_local);
Py_XDECREF(py_addr_tuple_remote);
@@ -2123,19 +1965,13 @@ psutil_proc_io_priority_get(PyObject *self, PyObject *args) {
long pid;
HANDLE hProcess;
DWORD IoPriority;
- _NtQueryInformationProcess NtQueryInformationProcess;
- NtQueryInformationProcess = \
- psutil_GetProcAddress("ntdll.dll", "NtQueryInformationProcess");
- if (NtQueryInformationProcess == NULL)
- return NULL;
if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
hProcess = psutil_handle_from_pid(pid, PROCESS_QUERY_LIMITED_INFORMATION);
if (hProcess == NULL)
return NULL;
-
- NtQueryInformationProcess(
+ psutil_NtQueryInformationProcess(
hProcess,
ProcessIoPriority,
&IoPriority,
@@ -2156,19 +1992,14 @@ psutil_proc_io_priority_set(PyObject *self, PyObject *args) {
DWORD prio;
HANDLE hProcess;
DWORD access = PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION;
- _NtSetInformationProcess NtSetInformationProcess;
- NtSetInformationProcess = \
- psutil_GetProcAddress("ntdll.dll", "NtSetInformationProcess");
- if (NtSetInformationProcess == NULL)
- return NULL;
if (! PyArg_ParseTuple(args, "li", &pid, &prio))
return NULL;
hProcess = psutil_handle_from_pid(pid, access);
if (hProcess == NULL)
return NULL;
- NtSetInformationProcess(
+ psutil_NtSetInformationProcess(
hProcess,
ProcessIoPriority,
(PVOID)&prio,
@@ -2461,7 +2292,7 @@ error:
*/
static PyObject *
psutil_disk_io_counters(PyObject *self, PyObject *args) {
- DISK_PERFORMANCE_WIN_2008 diskPerformance;
+ DISK_PERFORMANCE diskPerformance;
DWORD dwSize;
HANDLE hDevice = NULL;
char szDevice[MAX_PATH];
@@ -2764,7 +2595,6 @@ psutil_users(PyObject *self, PyObject *args) {
PWTS_CLIENT_ADDRESS address;
char address_str[50];
long long unix_time;
- PWINSTATIONQUERYINFORMATIONW WinStationQueryInformationW;
WINSTATION_INFO station_info;
ULONG returnLen;
PyObject *py_tuple = NULL;
@@ -2775,11 +2605,6 @@ psutil_users(PyObject *self, PyObject *args) {
if (py_retlist == NULL)
return NULL;
- WinStationQueryInformationW = psutil_GetProcAddressFromLib(
- "winsta.dll", "WinStationQueryInformationW");
- if (WinStationQueryInformationW == NULL)
- goto error;
-
if (WTSEnumerateSessions(hServer, 0, 1, &sessions, &count) == 0) {
PyErr_SetFromWindowsErr(0);
goto error;
@@ -2833,12 +2658,13 @@ psutil_users(PyObject *self, PyObject *args) {
}
// login time
- if (!WinStationQueryInformationW(hServer,
- sessionId,
- WinStationInformation,
- &station_info,
- sizeof(station_info),
- &returnLen))
+ if (! psutil_WinStationQueryInformationW(
+ hServer,
+ sessionId,
+ WinStationInformation,
+ &station_info,
+ sizeof(station_info),
+ &returnLen))
{
goto error;
}
@@ -3478,8 +3304,6 @@ error:
*/
static PyObject *
psutil_cpu_stats(PyObject *self, PyObject *args) {
- typedef DWORD (_stdcall * NTQSI_PROC) (int, PVOID, ULONG, PULONG);
- NTQSI_PROC NtQuerySystemInformation;
NTSTATUS status;
_SYSTEM_PERFORMANCE_INFORMATION *spi = NULL;
_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *sppi = NULL;
@@ -3489,11 +3313,6 @@ psutil_cpu_stats(PyObject *self, PyObject *args) {
ULONG64 dpcs = 0;
ULONG interrupts = 0;
- NtQuerySystemInformation = \
- psutil_GetProcAddressFromLib("ntdll.dll", "NtQuerySystemInformation");
- if (NtQuerySystemInformation == NULL)
- return NULL;
-
// retrieves number of processors
ncpus = psutil_get_num_cpus(1);
if (ncpus == 0)
@@ -3506,7 +3325,7 @@ psutil_cpu_stats(PyObject *self, PyObject *args) {
PyErr_NoMemory();
goto error;
}
- status = NtQuerySystemInformation(
+ status = psutil_NtQuerySystemInformation(
SystemPerformanceInformation,
spi,
ncpus * sizeof(_SYSTEM_PERFORMANCE_INFORMATION),
@@ -3524,7 +3343,7 @@ psutil_cpu_stats(PyObject *self, PyObject *args) {
goto error;
}
- status = NtQuerySystemInformation(
+ status = psutil_NtQuerySystemInformation(
SystemInterruptInformation,
InterruptInformation,
ncpus * sizeof(SYSTEM_INTERRUPT_INFORMATION),
@@ -3545,7 +3364,7 @@ psutil_cpu_stats(PyObject *self, PyObject *args) {
goto error;
}
- status = NtQuerySystemInformation(
+ status = psutil_NtQuerySystemInformation(
SystemProcessorPerformanceInformation,
sppi,
ncpus * sizeof(_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION),
@@ -3939,6 +3758,8 @@ void init_psutil_windows(void)
// set SeDebug for the current process
psutil_set_se_debug();
psutil_setup();
+ if (psutil_loadlibs() != 0)
+ return NULL;
#if PY_MAJOR_VERSION >= 3
return module;
diff --git a/psutil/arch/windows/global.c b/psutil/arch/windows/global.c
new file mode 100644
index 00000000..bb9970fe
--- /dev/null
+++ b/psutil/arch/windows/global.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <windows.h>
+#include <Python.h>
+#include "ntextapi.h"
+#include "global.h"
+
+
+// A wrapper around GetModuleHandle and GetProcAddress.
+PVOID
+psutil_GetProcAddress(LPCSTR libname, LPCSTR procname) {
+ HMODULE mod;
+ FARPROC addr;
+
+ if ((mod = GetModuleHandleA(libname)) == NULL) {
+ PyErr_SetFromWindowsErrWithFilename(0, libname);
+ return NULL;
+ }
+ if ((addr = GetProcAddress(mod, procname)) == NULL) {
+ PyErr_SetFromWindowsErrWithFilename(0, procname);
+ return NULL;
+ }
+ return addr;
+}
+
+
+// A wrapper around LoadLibrary and GetProcAddress.
+PVOID
+psutil_GetProcAddressFromLib(LPCSTR libname, LPCSTR procname) {
+ HMODULE mod;
+ FARPROC addr;
+
+ Py_BEGIN_ALLOW_THREADS
+ mod = LoadLibraryA(libname);
+ Py_END_ALLOW_THREADS
+ if (mod == NULL) {
+ PyErr_SetFromWindowsErrWithFilename(0, libname);
+ return NULL;
+ }
+ if ((addr = GetProcAddress(mod, procname)) == NULL) {
+ PyErr_SetFromWindowsErrWithFilename(0, procname);
+ FreeLibrary(mod);
+ return NULL;
+ }
+ // Causes crash.
+ // FreeLibrary(mod);
+ return addr;
+}
+
+
+/*
+ * This is executed on import and loads Windows APIs so that they
+ * are available globally.
+ */
+psutil_loadlibs() {
+ /*
+ * Mandatory.
+ */
+
+ psutil_NtQuerySystemInformation = psutil_GetProcAddressFromLib(
+ "ntdll.dll", "NtQuerySystemInformation");
+ if (psutil_NtQuerySystemInformation == NULL)
+ return 1;
+
+ psutil_NtQueryInformationProcess = psutil_GetProcAddress(
+ "ntdll.dll", "NtQueryInformationProcess");
+ if (! psutil_NtQueryInformationProcess)
+ return 1;
+
+ psutil_NtSetInformationProcess = psutil_GetProcAddress(
+ "ntdll.dll", "NtSetInformationProcess");
+ if (! psutil_NtSetInformationProcess)
+ return 1;
+
+ psutil_WinStationQueryInformationW = psutil_GetProcAddressFromLib(
+ "winsta.dll", "WinStationQueryInformationW");
+ if (! psutil_WinStationQueryInformationW)
+ return 1;
+
+ psutil_NtQueryObject = psutil_GetProcAddressFromLib(
+ "ntdll.dll", "NtQueryObject");
+ if (! psutil_NtQueryObject)
+ return 1;
+
+ psutil_rtlIpv4AddressToStringA = psutil_GetProcAddressFromLib(
+ "ntdll.dll", "RtlIpv4AddressToStringA");
+ if (! psutil_rtlIpv4AddressToStringA)
+ return 1;
+
+ psutil_rtlIpv6AddressToStringA = psutil_GetProcAddressFromLib(
+ "ntdll.dll", "RtlIpv6AddressToStringA");
+ if (! psutil_rtlIpv6AddressToStringA)
+ return 1;
+
+ // minimum requirement: Win XP SP3
+ psutil_GetExtendedTcpTable = psutil_GetProcAddressFromLib(
+ "iphlpapi.dll", "GetExtendedTcpTable");
+ if (! psutil_GetExtendedTcpTable)
+ return 1;
+
+ // minimum requirement: Win XP SP3
+ psutil_GetExtendedUdpTable = psutil_GetProcAddressFromLib(
+ "iphlpapi.dll", "GetExtendedUdpTable");
+ if (! psutil_GetExtendedUdpTable)
+ return 1;
+
+ /*
+ * Optional.
+ */
+
+ // minimum requirement: Win Vista
+ psutil_GetTickCount64 = psutil_GetProcAddress(
+ "kernel32", "GetTickCount64");
+
+ // minimum requirement: Win 7
+ psutil_GetActiveProcessorCount = psutil_GetProcAddress(
+ "kernel32", "GetActiveProcessorCount");
+
+ // minumum requirement: Win 7
+ psutil_GetLogicalProcessorInformationEx = psutil_GetProcAddressFromLib(
+ "kernel32", "GetLogicalProcessorInformationEx");
+
+ PyErr_Clear();
+ return 0;
+}
diff --git a/psutil/arch/windows/global.h b/psutil/arch/windows/global.h
new file mode 100644
index 00000000..8d828776
--- /dev/null
+++ b/psutil/arch/windows/global.h
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <windows.h>
+
+int psutil_loadlibs();
+PVOID psutil_GetProcAddress(LPCSTR libname, LPCSTR procname);
+PVOID psutil_GetProcAddressFromLib(LPCSTR libname, LPCSTR procname);
diff --git a/psutil/arch/windows/ntextapi.h b/psutil/arch/windows/ntextapi.h
index ea23ddb7..e0006c7b 100644
--- a/psutil/arch/windows/ntextapi.h
+++ b/psutil/arch/windows/ntextapi.h
@@ -6,7 +6,75 @@
#if !defined(__NTEXTAPI_H__)
#define __NTEXTAPI_H__
#include <winternl.h>
+#include <iphlpapi.h>
+typedef LONG NTSTATUS;
+
+#define STATUS_INFO_LENGTH_MISMATCH 0xc0000004
+#define STATUS_BUFFER_TOO_SMALL 0xC0000023L
+#define SystemExtendedHandleInformation 64
+
+/*
+ * ================================================================
+ * Enums.
+ * ================================================================
+ */
+
+typedef enum _PROCESSINFOCLASS2 {
+ _ProcessBasicInformation,
+ ProcessQuotaLimits,
+ ProcessIoCounters,
+ ProcessVmCounters,
+ ProcessTimes,
+ ProcessBasePriority,
+ ProcessRaisePriority,
+ _ProcessDebugPort,
+ ProcessExceptionPort,
+ ProcessAccessToken,
+ ProcessLdtInformation,
+ ProcessLdtSize,
+ ProcessDefaultHardErrorMode,
+ ProcessIoPortHandlers,
+ ProcessPooledUsageAndLimits,
+ ProcessWorkingSetWatch,
+ ProcessUserModeIOPL,
+ ProcessEnableAlignmentFaultFixup,
+ ProcessPriorityClass,
+ ProcessWx86Information,
+ ProcessHandleCount,
+ ProcessAffinityMask,
+ ProcessPriorityBoost,
+ ProcessDeviceMap,
+ ProcessSessionInformation,
+ ProcessForegroundInformation,
+ _ProcessWow64Information,
+ /* added after XP+ */
+ _ProcessImageFileName,
+ ProcessLUIDDeviceMapsEnabled,
+ _ProcessBreakOnTermination,
+ ProcessDebugObjectHandle,
+ ProcessDebugFlags,
+ ProcessHandleTracing,
+ ProcessIoPriority,
+ ProcessExecuteFlags,
+ ProcessResourceManagement,
+ ProcessCookie,
+ ProcessImageInformation,
+ MaxProcessInfoClass
+} PROCESSINFOCLASS2;
+
+#define PROCESSINFOCLASS PROCESSINFOCLASS2
+#define ProcessBasicInformation _ProcessBasicInformation
+#define ProcessWow64Information _ProcessWow64Information
+#define ProcessDebugPort _ProcessDebugPort
+#define ProcessImageFileName _ProcessImageFileName
+#define ProcessBreakOnTermination _ProcessBreakOnTermination
+
+/*
+ * ================================================================
+ * Structs.
+ * ================================================================
+ */
typedef struct {
LARGE_INTEGER IdleTime;
@@ -17,7 +85,6 @@ typedef struct {
ULONG InterruptCount;
} _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;
-
typedef struct {
LARGE_INTEGER IdleProcessTime;
LARGE_INTEGER IoReadTransferCount;
@@ -93,10 +160,8 @@ typedef struct {
ULONG FirstLevelTbFills;
ULONG SecondLevelTbFills;
ULONG SystemCalls;
-
} _SYSTEM_PERFORMANCE_INFORMATION;
-
typedef struct {
ULONG ContextSwitches;
ULONG DpcCount;
@@ -106,7 +171,6 @@ typedef struct {
ULONG ApcBypassCount;
} _SYSTEM_INTERRUPT_INFORMATION;
-
typedef enum _KTHREAD_STATE {
Initialized,
Ready,
@@ -120,7 +184,6 @@ typedef enum _KTHREAD_STATE {
MaximumThreadState
} KTHREAD_STATE, *PKTHREAD_STATE;
-
typedef enum _KWAIT_REASON {
Executive = 0,
FreePage = 1,
@@ -162,6 +225,22 @@ typedef enum _KWAIT_REASON {
MaximumWaitReason = 37
} KWAIT_REASON, *PKWAIT_REASON;
+typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX {
+ PVOID Object;
+ HANDLE UniqueProcessId;
+ HANDLE HandleValue;
+ ULONG GrantedAccess;
+ USHORT CreatorBackTraceIndex;
+ USHORT ObjectTypeIndex;
+ ULONG HandleAttributes;
+ ULONG Reserved;
+} SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX;
+
+typedef struct _SYSTEM_HANDLE_INFORMATION_EX {
+ ULONG_PTR NumberOfHandles;
+ ULONG_PTR Reserved;
+ SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1];
+} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX;
typedef struct _CLIENT_ID2 {
HANDLE UniqueProcess;
@@ -190,8 +269,6 @@ typedef struct _SYSTEM_THREAD_INFORMATION2 {
typedef struct _TEB *PTEB;
-
-// private
typedef struct _SYSTEM_EXTENDED_THREAD_INFORMATION {
SYSTEM_THREAD_INFORMATION ThreadInfo;
PVOID StackBase;
@@ -203,7 +280,6 @@ typedef struct _SYSTEM_EXTENDED_THREAD_INFORMATION {
ULONG_PTR Reserved4;
} SYSTEM_EXTENDED_THREAD_INFORMATION, *PSYSTEM_EXTENDED_THREAD_INFORMATION;
-
typedef struct _SYSTEM_PROCESS_INFORMATION2 {
ULONG NextEntryOffset;
ULONG NumberOfThreads;
@@ -244,10 +320,35 @@ typedef struct _SYSTEM_PROCESS_INFORMATION2 {
#define SYSTEM_PROCESS_INFORMATION SYSTEM_PROCESS_INFORMATION2
#define PSYSTEM_PROCESS_INFORMATION PSYSTEM_PROCESS_INFORMATION2
-
-// ================================================
-// psutil.users() support
-// ================================================
+typedef struct _PROCESSOR_POWER_INFORMATION {
+ ULONG Number;
+ ULONG MaxMhz;
+ ULONG CurrentMhz;
+ ULONG MhzLimit;
+ ULONG MaxIdleState;
+ ULONG CurrentIdleState;
+} PROCESSOR_POWER_INFORMATION, *PPROCESSOR_POWER_INFORMATION;
+
+#ifndef __IPHLPAPI_H__
+typedef struct in6_addr {
+ union {
+ UCHAR Byte[16];
+ USHORT Word[8];
+ } u;
+} IN6_ADDR, *PIN6_ADDR, FAR *LPIN6_ADDR;
+#endif
+
+// http://msdn.microsoft.com/en-us/library/aa813741(VS.85).aspx
+typedef struct {
+ BYTE Reserved1[16];
+ PVOID Reserved2[5];
+ UNICODE_STRING CurrentDirectoryPath;
+ PVOID CurrentDirectoryHandle;
+ UNICODE_STRING DllPath;
+ UNICODE_STRING ImagePathName;
+ UNICODE_STRING CommandLine;
+ LPCWSTR env;
+} RTL_USER_PROCESS_PARAMETERS_, *PRTL_USER_PROCESS_PARAMETERS_;
typedef struct _WINSTATION_INFO {
BYTE Reserved1[72];
@@ -261,18 +362,38 @@ typedef struct _WINSTATION_INFO {
FILETIME CurrentTime;
} WINSTATION_INFO, *PWINSTATION_INFO;
-
-typedef BOOLEAN (WINAPI * PWINSTATIONQUERYINFORMATIONW)
- (HANDLE,ULONG,WINSTATIONINFOCLASS,PVOID,ULONG,PULONG);
-
+#if (_WIN32_WINNT < 0x0601) // Windows < 7 (Vista and XP)
+typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX {
+ LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
+ DWORD Size;
+ _ANONYMOUS_UNION
+ union {
+ PROCESSOR_RELATIONSHIP Processor;
+ NUMA_NODE_RELATIONSHIP NumaNode;
+ CACHE_RELATIONSHIP Cache;
+ GROUP_RELATIONSHIP Group;
+ } DUMMYUNIONNAME;
+} SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, *PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX;
+#endif
/*
- * NtQueryInformationProcess code taken from
- * http://wj32.wordpress.com/2009/01/24/howto-get-the-command-line-of-processes/
- * typedefs needed to compile against ntdll functions not exposted in the API
+ * ================================================================
+ * Type defs for modules loaded at runtime.
+ * ================================================================
*/
-typedef LONG NTSTATUS;
+typedef BOOL (WINAPI *_GetLogicalProcessorInformationEx)(
+ LOGICAL_PROCESSOR_RELATIONSHIP relationship,
+ PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX Buffer,
+ PDWORD ReturnLength);
+
+typedef BOOLEAN (WINAPI * _WinStationQueryInformationW)(
+ HANDLE ServerHandle,
+ ULONG SessionId,
+ WINSTATIONINFOCLASS WinStationInformationClass,
+ PVOID pWinStationInformation,
+ ULONG WinStationInformationLength,
+ PULONG pReturnLength);
typedef NTSTATUS (NTAPI *_NtQueryInformationProcess)(
HANDLE ProcessHandle,
@@ -282,6 +403,12 @@ typedef NTSTATUS (NTAPI *_NtQueryInformationProcess)(
PDWORD ReturnLength
);
+typedef NTSTATUS (NTAPI *_NtQuerySystemInformation)(
+ ULONG SystemInformationClass,
+ PVOID SystemInformation,
+ ULONG SystemInformationLength,
+ PULONG ReturnLength
+);
typedef NTSTATUS (NTAPI *_NtSetInformationProcess)(
HANDLE ProcessHandle,
@@ -290,56 +417,86 @@ typedef NTSTATUS (NTAPI *_NtSetInformationProcess)(
DWORD ProcessInformationLength
);
+typedef PSTR (NTAPI * _RtlIpv4AddressToStringA)(
+ struct in_addr *Addr,
+ PSTR S);
+
+typedef PSTR (NTAPI * _RtlIpv6AddressToStringA)(
+ struct in6_addr *Addr,
+ PSTR P);
+
+typedef DWORD (WINAPI * _GetExtendedTcpTable)(
+ PVOID pTcpTable,
+ PDWORD pdwSize,
+ BOOL bOrder,
+ ULONG ulAf,
+ TCP_TABLE_CLASS TableClass,
+ ULONG Reserved
+);
-typedef enum _PROCESSINFOCLASS2 {
- _ProcessBasicInformation,
- ProcessQuotaLimits,
- ProcessIoCounters,
- ProcessVmCounters,
- ProcessTimes,
- ProcessBasePriority,
- ProcessRaisePriority,
- _ProcessDebugPort,
- ProcessExceptionPort,
- ProcessAccessToken,
- ProcessLdtInformation,
- ProcessLdtSize,
- ProcessDefaultHardErrorMode,
- ProcessIoPortHandlers,
- ProcessPooledUsageAndLimits,
- ProcessWorkingSetWatch,
- ProcessUserModeIOPL,
- ProcessEnableAlignmentFaultFixup,
- ProcessPriorityClass,
- ProcessWx86Information,
- ProcessHandleCount,
- ProcessAffinityMask,
- ProcessPriorityBoost,
- ProcessDeviceMap,
- ProcessSessionInformation,
- ProcessForegroundInformation,
- _ProcessWow64Information,
- /* added after XP+ */
- _ProcessImageFileName,
- ProcessLUIDDeviceMapsEnabled,
- _ProcessBreakOnTermination,
- ProcessDebugObjectHandle,
- ProcessDebugFlags,
- ProcessHandleTracing,
- ProcessIoPriority,
- ProcessExecuteFlags,
- ProcessResourceManagement,
- ProcessCookie,
- ProcessImageInformation,
- MaxProcessInfoClass
-} PROCESSINFOCLASS2;
+typedef DWORD (WINAPI * _GetExtendedUdpTable)(
+ PVOID pUdpTable,
+ PDWORD pdwSize,
+ BOOL bOrder,
+ ULONG ulAf,
+ UDP_TABLE_CLASS TableClass,
+ ULONG Reserved
+);
+typedef DWORD (CALLBACK *_GetActiveProcessorCount)(
+ WORD GroupNumber);
-#define PROCESSINFOCLASS PROCESSINFOCLASS2
-#define ProcessBasicInformation _ProcessBasicInformation
-#define ProcessWow64Information _ProcessWow64Information
-#define ProcessDebugPort _ProcessDebugPort
-#define ProcessImageFileName _ProcessImageFileName
-#define ProcessBreakOnTermination _ProcessBreakOnTermination
+typedef ULONGLONG (CALLBACK *_GetTickCount64)(
+ void);
+
+typedef NTSTATUS (NTAPI *_NtQueryObject)(
+ HANDLE Handle,
+ OBJECT_INFORMATION_CLASS ObjectInformationClass,
+ PVOID ObjectInformation,
+ ULONG ObjectInformationLength,
+ PULONG ReturnLength
+);
+
+/*
+ * ================================================================
+ * Custom psutil definitions for modules loaded at runtime.
+ * ================================================================
+ */
+
+_NtQuerySystemInformation \
+ psutil_NtQuerySystemInformation;
+
+_NtQueryInformationProcess \
+ psutil_NtQueryInformationProcess;
+
+_NtSetInformationProcess
+ psutil_NtSetInformationProcess;
+
+_WinStationQueryInformationW \
+ psutil_WinStationQueryInformationW;
+
+_RtlIpv4AddressToStringA \
+ psutil_rtlIpv4AddressToStringA;
+
+_RtlIpv6AddressToStringA \
+ psutil_rtlIpv6AddressToStringA;
+
+_GetExtendedTcpTable \
+ psutil_GetExtendedTcpTable;
+
+_GetExtendedUdpTable \
+ psutil_GetExtendedUdpTable;
+
+_GetActiveProcessorCount \
+ psutil_GetActiveProcessorCount;
+
+_GetTickCount64 \
+ psutil_GetTickCount64;
+
+_NtQueryObject \
+ psutil_NtQueryObject;
+
+_GetLogicalProcessorInformationEx \
+ psutil_GetLogicalProcessorInformationEx;
#endif // __NTEXTAPI_H__
diff --git a/psutil/arch/windows/process_handles.c b/psutil/arch/windows/process_handles.c
index 4ac02b91..f295f18d 100644
--- a/psutil/arch/windows/process_handles.c
+++ b/psutil/arch/windows/process_handles.c
@@ -4,13 +4,16 @@
* found in the LICENSE file.
*
*/
+
+#include <windows.h>
+#include <Psapi.h>
+#include <Python.h>
+#include "ntextapi.h"
+#include "global.h"
#include "process_handles.h"
#include "process_info.h"
#include "../../_psutil_common.h"
-static _NtQuerySystemInformation __NtQuerySystemInformation = NULL;
-static _NtQueryObject __NtQueryObject = NULL;
-
CRITICAL_SECTION g_cs;
BOOL g_initialized = FALSE;
NTSTATUS g_status;
@@ -23,33 +26,15 @@ ULONG g_dwSize = 0;
ULONG g_dwLength = 0;
-PyObject *
-psutil_get_open_files(long dwPid, HANDLE hProcess) {
- OSVERSIONINFO osvi;
-
- ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
- osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
- GetVersionEx(&osvi);
-
- // Threaded version only works for Vista+
- if (osvi.dwMajorVersion >= 6)
- return psutil_get_open_files_ntqueryobject(dwPid, hProcess);
- else
- return psutil_get_open_files_getmappedfilename(dwPid, hProcess);
-}
+#define ObjectNameInformation 1
+#define NTQO_TIMEOUT 100
-VOID
+static VOID
psutil_get_open_files_init(BOOL threaded) {
if (g_initialized == TRUE)
return;
- // Resolve the Windows API calls
- __NtQuerySystemInformation = psutil_GetProcAddressFromLib(
- "ntdll.dll", "NtQuerySystemInformation");
- __NtQueryObject = psutil_GetProcAddressFromLib(
- "ntdll.dll", "NtQueryObject");
-
// Create events for signalling work between threads
if (threaded == TRUE) {
g_hEvtStart = CreateEvent(NULL, FALSE, FALSE, NULL);
@@ -61,7 +46,59 @@ psutil_get_open_files_init(BOOL threaded) {
}
-PyObject *
+static DWORD WINAPI
+psutil_wait_thread(LPVOID lpvParam) {
+ // Loop infinitely waiting for work
+ while (TRUE) {
+ WaitForSingleObject(g_hEvtStart, INFINITE);
+
+ g_status = psutil_NtQueryObject(
+ g_hFile,
+ ObjectNameInformation,
+ g_pNameBuffer,
+ g_dwSize,
+ &g_dwLength);
+ SetEvent(g_hEvtFinish);
+ }
+}
+
+
+static DWORD
+psutil_create_thread() {
+ DWORD dwWait = 0;
+
+ if (g_hThread == NULL)
+ g_hThread = CreateThread(
+ NULL,
+ 0,
+ psutil_wait_thread,
+ NULL,
+ 0,
+ NULL);
+ if (g_hThread == NULL)
+ return GetLastError();
+
+ // Signal the worker thread to start
+ SetEvent(g_hEvtStart);
+
+ // Wait for the worker thread to finish
+ dwWait = WaitForSingleObject(g_hEvtFinish, NTQO_TIMEOUT);
+
+ // If the thread hangs, kill it and cleanup
+ if (dwWait == WAIT_TIMEOUT) {
+ SuspendThread(g_hThread);
+ TerminateThread(g_hThread, 1);
+ WaitForSingleObject(g_hThread, INFINITE);
+ CloseHandle(g_hThread);
+
+ g_hThread = NULL;
+ }
+
+ return dwWait;
+}
+
+
+static PyObject *
psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess) {
NTSTATUS status;
PSYSTEM_HANDLE_INFORMATION_EX pHandleInfo = NULL;
@@ -81,9 +118,7 @@ psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess) {
// to psutil_get_open_files() is running
EnterCriticalSection(&g_cs);
- if (__NtQuerySystemInformation == NULL ||
- __NtQueryObject == NULL ||
- g_hEvtStart == NULL ||
+ if (g_hEvtStart == NULL ||
g_hEvtFinish == NULL)
{
@@ -117,7 +152,7 @@ psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess) {
error = TRUE;
goto cleanup;
}
- } while ((status = __NtQuerySystemInformation(
+ } while ((status = psutil_NtQuerySystemInformation(
SystemExtendedHandleInformation,
pHandleInfo,
dwInfoSize,
@@ -180,7 +215,7 @@ psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess) {
goto loop_cleanup;
}
- dwWait = psutil_NtQueryObject();
+ dwWait = psutil_create_thread();
// If the call does not return, skip this handle
if (dwWait != WAIT_OBJECT_0)
@@ -228,19 +263,19 @@ psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess) {
}
loop_cleanup:
- Py_XDECREF(py_path);
- py_path = NULL;
+ Py_XDECREF(py_path);
+ py_path = NULL;
- if (g_pNameBuffer != NULL)
- HeapFree(GetProcessHeap(), 0, g_pNameBuffer);
- g_pNameBuffer = NULL;
- g_dwSize = 0;
- g_dwLength = 0;
+ if (g_pNameBuffer != NULL)
+ HeapFree(GetProcessHeap(), 0, g_pNameBuffer);
+ g_pNameBuffer = NULL;
+ g_dwSize = 0;
+ g_dwLength = 0;
- if (g_hFile != NULL)
- CloseHandle(g_hFile);
- g_hFile = NULL;
- }
+ if (g_hFile != NULL)
+ CloseHandle(g_hFile);
+ g_hFile = NULL;
+}
cleanup:
if (g_pNameBuffer != NULL)
@@ -268,58 +303,7 @@ cleanup:
}
-DWORD
-psutil_NtQueryObject() {
- DWORD dwWait = 0;
-
- if (g_hThread == NULL)
- g_hThread = CreateThread(
- NULL,
- 0,
- psutil_NtQueryObjectThread,
- NULL,
- 0,
- NULL);
- if (g_hThread == NULL)
- return GetLastError();
-
- // Signal the worker thread to start
- SetEvent(g_hEvtStart);
-
- // Wait for the worker thread to finish
- dwWait = WaitForSingleObject(g_hEvtFinish, NTQO_TIMEOUT);
-
- // If the thread hangs, kill it and cleanup
- if (dwWait == WAIT_TIMEOUT) {
- SuspendThread(g_hThread);
- TerminateThread(g_hThread, 1);
- WaitForSingleObject(g_hThread, INFINITE);
- CloseHandle(g_hThread);
-
- g_hThread = NULL;
- }
-
- return dwWait;
-}
-
-
-DWORD WINAPI
-psutil_NtQueryObjectThread(LPVOID lpvParam) {
- // Loop infinitely waiting for work
- while (TRUE) {
- WaitForSingleObject(g_hEvtStart, INFINITE);
-
- g_status = __NtQueryObject(g_hFile,
- ObjectNameInformation,
- g_pNameBuffer,
- g_dwSize,
- &g_dwLength);
- SetEvent(g_hEvtFinish);
- }
-}
-
-
-PyObject *
+static PyObject *
psutil_get_open_files_getmappedfilename(long dwPid, HANDLE hProcess) {
NTSTATUS status;
PSYSTEM_HANDLE_INFORMATION_EX pHandleInfo = NULL;
@@ -339,12 +323,6 @@ psutil_get_open_files_getmappedfilename(long dwPid, HANDLE hProcess) {
if (g_initialized == FALSE)
psutil_get_open_files_init(FALSE);
- if (__NtQuerySystemInformation == NULL || __NtQueryObject == NULL) {
- PyErr_SetFromWindowsErr(0);
- error = TRUE;
- goto cleanup;
- }
-
// Py_BuildValue raises an exception if NULL is returned
py_retlist = PyList_New(0);
if (py_retlist == NULL) {
@@ -370,7 +348,7 @@ psutil_get_open_files_getmappedfilename(long dwPid, HANDLE hProcess) {
error = TRUE;
goto cleanup;
}
- } while ((status = __NtQuerySystemInformation(
+ } while ((status = psutil_NtQuerySystemInformation(
SystemExtendedHandleInformation,
pHandleInfo,
dwInfoSize,
@@ -517,3 +495,23 @@ cleanup:
return py_retlist;
}
+
+
+/*
+ * The public function.
+ */
+PyObject *
+psutil_get_open_files(long dwPid, HANDLE hProcess) {
+ OSVERSIONINFO osvi;
+
+ ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&osvi);
+
+ // Threaded version only works for Vista+
+ if (osvi.dwMajorVersion >= 6)
+ return psutil_get_open_files_ntqueryobject(dwPid, hProcess);
+ else
+ return psutil_get_open_files_getmappedfilename(dwPid, hProcess);
+}
+
diff --git a/psutil/arch/windows/process_handles.h b/psutil/arch/windows/process_handles.h
index 4a022c1c..342ce8fd 100644
--- a/psutil/arch/windows/process_handles.h
+++ b/psutil/arch/windows/process_handles.h
@@ -4,108 +4,7 @@
* found in the LICENSE file.
*/
-#ifndef __PROCESS_HANDLES_H__
-#define __PROCESS_HANDLES_H__
-
-#ifndef UNICODE
-#define UNICODE
-#endif
-
#include <Python.h>
-#include <stdio.h>
#include <windows.h>
-#include <strsafe.h>
-#include <winternl.h>
-#include <psapi.h>
-
-
-#ifndef NT_SUCCESS
-#define NT_SUCCESS(x) ((x) >= 0)
-#endif
-
-#define STATUS_INFO_LENGTH_MISMATCH 0xc0000004
-#define ObjectBasicInformation 0
-#define ObjectNameInformation 1
-#define ObjectTypeInformation 2
-#define HANDLE_TYPE_FILE 28
-#define NTQO_TIMEOUT 100
-
-typedef NTSTATUS (NTAPI *_NtQuerySystemInformation)(
- ULONG SystemInformationClass,
- PVOID SystemInformation,
- ULONG SystemInformationLength,
- PULONG ReturnLength
-);
-
-typedef NTSTATUS (NTAPI *_NtQueryObject)(
- HANDLE ObjectHandle,
- ULONG ObjectInformationClass,
- PVOID ObjectInformation,
- ULONG ObjectInformationLength,
- PULONG ReturnLength
-);
-// Undocumented FILE_INFORMATION_CLASS: FileNameInformation
-static const SYSTEM_INFORMATION_CLASS SystemExtendedHandleInformation = (SYSTEM_INFORMATION_CLASS)64;
-
-typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX {
- PVOID Object;
- HANDLE UniqueProcessId;
- HANDLE HandleValue;
- ULONG GrantedAccess;
- USHORT CreatorBackTraceIndex;
- USHORT ObjectTypeIndex;
- ULONG HandleAttributes;
- ULONG Reserved;
-} SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX;
-
-typedef struct _SYSTEM_HANDLE_INFORMATION_EX {
- ULONG_PTR NumberOfHandles;
- ULONG_PTR Reserved;
- SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1];
-} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX;
-
-typedef enum _POOL_TYPE {
- NonPagedPool,
- PagedPool,
- NonPagedPoolMustSucceed,
- DontUseThisType,
- NonPagedPoolCacheAligned,
- PagedPoolCacheAligned,
- NonPagedPoolCacheAlignedMustS
-} POOL_TYPE, *PPOOL_TYPE;
-
-typedef struct _OBJECT_TYPE_INFORMATION {
- UNICODE_STRING Name;
- ULONG TotalNumberOfObjects;
- ULONG TotalNumberOfHandles;
- ULONG TotalPagedPoolUsage;
- ULONG TotalNonPagedPoolUsage;
- ULONG TotalNamePoolUsage;
- ULONG TotalHandleTableUsage;
- ULONG HighWaterNumberOfObjects;
- ULONG HighWaterNumberOfHandles;
- ULONG HighWaterPagedPoolUsage;
- ULONG HighWaterNonPagedPoolUsage;
- ULONG HighWaterNamePoolUsage;
- ULONG HighWaterHandleTableUsage;
- ULONG InvalidAttributes;
- GENERIC_MAPPING GenericMapping;
- ULONG ValidAccess;
- BOOLEAN SecurityRequired;
- BOOLEAN MaintainHandleCount;
- USHORT MaintainTypeList;
- POOL_TYPE PoolType;
- ULONG PagedPoolUsage;
- ULONG NonPagedPoolUsage;
-} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
-
-PVOID GetLibraryProcAddress(PSTR LibraryName, PSTR ProcName);
-VOID psutil_get_open_files_init(BOOL threaded);
PyObject* psutil_get_open_files(long pid, HANDLE processHandle);
-PyObject* psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess);
-PyObject* psutil_get_open_files_getmappedfilename(long dwPid, HANDLE hProcess);
-DWORD psutil_NtQueryObject(void);
-DWORD WINAPI psutil_NtQueryObjectThread(LPVOID lpvParam);
-
-#endif // __PROCESS_HANDLES_H__
diff --git a/psutil/arch/windows/process_info.c b/psutil/arch/windows/process_info.c
index a2edca58..9a698e42 100644
--- a/psutil/arch/windows/process_info.c
+++ b/psutil/arch/windows/process_info.c
@@ -12,9 +12,10 @@
#include <Psapi.h>
#include <tlhelp32.h>
+#include "ntextapi.h"
+#include "global.h"
#include "security.h"
#include "process_info.h"
-#include "ntextapi.h"
#include "../../_psutil_common.h"
@@ -24,23 +25,6 @@
// but unfortunately not in a usable way.
// ====================================================================
-// see http://msdn2.microsoft.com/en-us/library/aa489609.aspx
-#ifndef NT_SUCCESS
-#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
-#endif
-
-// http://msdn.microsoft.com/en-us/library/aa813741(VS.85).aspx
-typedef struct {
- BYTE Reserved1[16];
- PVOID Reserved2[5];
- UNICODE_STRING CurrentDirectoryPath;
- PVOID CurrentDirectoryHandle;
- UNICODE_STRING DllPath;
- UNICODE_STRING ImagePathName;
- UNICODE_STRING CommandLine;
- LPCWSTR env;
-} RTL_USER_PROCESS_PARAMETERS_, *PRTL_USER_PROCESS_PARAMETERS_;
-
// https://msdn.microsoft.com/en-us/library/aa813706(v=vs.85).aspx
#ifdef _WIN64
typedef struct {
@@ -97,15 +81,11 @@ typedef struct {
use the 64 bit structure layout and a special function to read its memory.
*/
typedef NTSTATUS (NTAPI *_NtWow64ReadVirtualMemory64)(
- IN HANDLE ProcessHandle,
- IN PVOID64 BaseAddress,
- OUT PVOID Buffer,
- IN ULONG64 Size,
- OUT PULONG64 NumberOfBytesRead);
-
-typedef enum {
- MemoryInformationBasic
-} MEMORY_INFORMATION_CLASS;
+ HANDLE ProcessHandle,
+ PVOID64 BaseAddress,
+ PVOID Buffer,
+ ULONG64 Size,
+ PULONG64 NumberOfBytesRead);
typedef struct {
PVOID Reserved1[2];
@@ -150,47 +130,6 @@ typedef struct {
(PSYSTEM_PROCESS_INFORMATION)((PCHAR)(Process) + \
((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset) : NULL)
-const int STATUS_INFO_LENGTH_MISMATCH = 0xC0000004;
-const int STATUS_BUFFER_TOO_SMALL = 0xC0000023L;
-
-
-// A wrapper around GetModuleHandle and GetProcAddress.
-PVOID
-psutil_GetProcAddress(LPCSTR libname, LPCSTR procname) {
- HMODULE mod;
- FARPROC addr;
-
- if ((mod = GetModuleHandleA(libname)) == NULL) {
- PyErr_SetFromWindowsErrWithFilename(0, libname);
- return NULL;
- }
- if ((addr = GetProcAddress(mod, procname)) == NULL) {
- PyErr_SetFromWindowsErrWithFilename(0, procname);
- return NULL;
- }
- return addr;
-}
-
-
-// A wrapper around LoadLibrary and GetProcAddress.
-PVOID
-psutil_GetProcAddressFromLib(LPCSTR libname, LPCSTR procname) {
- HMODULE mod;
- FARPROC addr;
-
- if ((mod = LoadLibraryA(libname)) == NULL) {
- PyErr_SetFromWindowsErrWithFilename(0, libname);
- return NULL;
- }
- if ((addr = GetProcAddress(mod, procname)) == NULL) {
- PyErr_SetFromWindowsErrWithFilename(0, procname);
- FreeLibrary(mod);
- return NULL;
- }
- FreeLibrary(mod);
- return addr;
-}
-
// ====================================================================
// Process and PIDs utiilties.
@@ -535,11 +474,6 @@ psutil_get_process_data(long pid,
#endif
DWORD access = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ;
- NtQueryInformationProcess = \
- psutil_GetProcAddress("ntdll.dll", "NtQueryInformationProcess");
- if (NtQueryInformationProcess == NULL)
- return -1;
-
hProcess = psutil_handle_from_pid(pid, access);
if (hProcess == NULL)
return -1;
@@ -547,11 +481,13 @@ psutil_get_process_data(long pid,
#ifdef _WIN64
/* 64 bit case. Check if the target is a 32 bit process running in WoW64
* mode. */
- if (!NT_SUCCESS(NtQueryInformationProcess(hProcess,
- ProcessWow64Information,
- &ppeb32,
- sizeof(LPVOID),
- NULL))) {
+ if (! NT_SUCCESS(psutil_NtQueryInformationProcess(
+ hProcess,
+ ProcessWow64Information,
+ &ppeb32,
+ sizeof(LPVOID),
+ NULL)))
+ {
PyErr_SetFromWindowsErr(0);
goto error;
}
@@ -610,7 +546,7 @@ psutil_get_process_data(long pid,
psutil_GetProcAddressFromLib(
"ntdll.dll", "NtWow64QueryInformationProcess64");
if (NtWow64QueryInformationProcess64 == NULL) {
- // Too complicated. Give up.
+ PyErr_Clear();
AccessDenied("can't query 64-bit process in 32-bit-WoW mode");
goto error;
}
@@ -620,38 +556,44 @@ psutil_get_process_data(long pid,
psutil_GetProcAddressFromLib(
"ntdll.dll", "NtWow64ReadVirtualMemory64");
if (NtWow64ReadVirtualMemory64 == NULL) {
- // Too complicated. Give up.
+ PyErr_Clear();
AccessDenied("can't query 64-bit process in 32-bit-WoW mode");
goto error;
}
}
- if (!NT_SUCCESS(NtWow64QueryInformationProcess64(
- hProcess,
- ProcessBasicInformation,
- &pbi64,
- sizeof(pbi64),
- NULL))) {
+ if (! NT_SUCCESS(
+ NtWow64QueryInformationProcess64(
+ hProcess,
+ ProcessBasicInformation,
+ &pbi64,
+ sizeof(pbi64),
+ NULL)))
+ {
PyErr_SetFromWindowsErr(0);
goto error;
}
// read peb
- if (!NT_SUCCESS(NtWow64ReadVirtualMemory64(hProcess,
- pbi64.PebBaseAddress,
- &peb64,
- sizeof(peb64),
- NULL))) {
+ if (! NT_SUCCESS(NtWow64ReadVirtualMemory64(
+ hProcess,
+ pbi64.PebBaseAddress,
+ &peb64,
+ sizeof(peb64),
+ NULL)))
+ {
PyErr_SetFromWindowsErr(0);
goto error;
}
// read process parameters
- if (!NT_SUCCESS(NtWow64ReadVirtualMemory64(hProcess,
- peb64.ProcessParameters,
- &procParameters64,
- sizeof(procParameters64),
- NULL))) {
+ if (! NT_SUCCESS(NtWow64ReadVirtualMemory64(
+ hProcess,
+ peb64.ProcessParameters,
+ &procParameters64,
+ sizeof(procParameters64),
+ NULL)))
+ {
PyErr_SetFromWindowsErr(0);
goto error;
}
@@ -671,18 +613,19 @@ psutil_get_process_data(long pid,
}
} else
#endif
-
/* Target process is of the same bitness as us. */
{
PROCESS_BASIC_INFORMATION pbi;
PEB_ peb;
RTL_USER_PROCESS_PARAMETERS_ procParameters;
- if (!NT_SUCCESS(NtQueryInformationProcess(hProcess,
- ProcessBasicInformation,
- &pbi,
- sizeof(pbi),
- NULL))) {
+ if (! NT_SUCCESS(psutil_NtQueryInformationProcess(
+ hProcess,
+ ProcessBasicInformation,
+ &pbi,
+ sizeof(pbi),
+ NULL)))
+ {
PyErr_SetFromWindowsErr(0);
goto error;
}
@@ -743,11 +686,13 @@ psutil_get_process_data(long pid,
#ifndef _WIN64
if (weAreWow64 && !theyAreWow64) {
- if (!NT_SUCCESS(NtWow64ReadVirtualMemory64(hProcess,
- src64,
- buffer,
- size,
- NULL))) {
+ if (! NT_SUCCESS(NtWow64ReadVirtualMemory64(
+ hProcess,
+ src64,
+ buffer,
+ size,
+ NULL)))
+ {
PyErr_SetFromWindowsErr(0);
goto error;
}
@@ -788,12 +733,6 @@ psutil_get_cmdline_data(long pid, WCHAR **pdata, SIZE_T *psize) {
WCHAR * cmdline_buffer_wchar = NULL;
PUNICODE_STRING tmp = NULL;
DWORD string_size;
- _NtQueryInformationProcess NtQueryInformationProcess;
-
- NtQueryInformationProcess = \
- psutil_GetProcAddress("ntdll.dll", "NtQueryInformationProcess");
- if (NtQueryInformationProcess == NULL)
- goto error;
cmdline_buffer = calloc(ret_length, 1);
if (cmdline_buffer == NULL) {
@@ -804,14 +743,14 @@ psutil_get_cmdline_data(long pid, WCHAR **pdata, SIZE_T *psize) {
hProcess = psutil_handle_from_pid(pid, PROCESS_QUERY_LIMITED_INFORMATION);
if (hProcess == NULL)
goto error;
- status = NtQueryInformationProcess(
+ status = psutil_NtQueryInformationProcess(
hProcess,
60, // ProcessCommandLineInformation
cmdline_buffer,
ret_length,
&ret_length
);
- if (!NT_SUCCESS(status)) {
+ if (! NT_SUCCESS(status)) {
PyErr_SetFromWindowsErr(0);
goto error;
}
@@ -971,13 +910,6 @@ psutil_get_proc_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess,
PVOID buffer;
ULONG bufferSize;
PSYSTEM_PROCESS_INFORMATION process;
- typedef DWORD (_stdcall * NTQSI_PROC) (int, PVOID, ULONG, PULONG);
- NTQSI_PROC NtQuerySystemInformation;
-
- NtQuerySystemInformation = \
- psutil_GetProcAddressFromLib("ntdll.dll", "NtQuerySystemInformation");
- if (NtQuerySystemInformation == NULL)
- goto error;
bufferSize = initialBufferSize;
buffer = malloc(bufferSize);
@@ -987,8 +919,11 @@ psutil_get_proc_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess,
}
while (TRUE) {
- status = NtQuerySystemInformation(SystemProcessInformation, buffer,
- bufferSize, &bufferSize);
+ status = psutil_NtQuerySystemInformation(
+ SystemProcessInformation,
+ buffer,
+ bufferSize,
+ &bufferSize);
if (status == STATUS_BUFFER_TOO_SMALL ||
status == STATUS_INFO_LENGTH_MISMATCH)
{
diff --git a/psutil/arch/windows/process_info.h b/psutil/arch/windows/process_info.h
index d2e60b7c..4278c4df 100644
--- a/psutil/arch/windows/process_info.h
+++ b/psutil/arch/windows/process_info.h
@@ -23,8 +23,6 @@ int psutil_get_proc_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess,
int psutil_assert_pid_exists(DWORD pid, char *err);
int psutil_assert_pid_not_exists(DWORD pid, char *err);
-PVOID psutil_GetProcAddress(LPCSTR libname, LPCSTR procname);
-PVOID psutil_GetProcAddressFromLib(LPCSTR libname, LPCSTR procname);
PyObject* psutil_get_cmdline(long pid, int use_peb);
PyObject* psutil_get_cwd(long pid);
diff --git a/psutil/tests/test_windows.py b/psutil/tests/test_windows.py
index 7be12d9c..c98d892c 100755
--- a/psutil/tests/test_windows.py
+++ b/psutil/tests/test_windows.py
@@ -778,10 +778,11 @@ class RemoteProcessTestCase(unittest.TestCase):
self.assertEquals(e["THINK_OF_A_NUMBER"], str(os.getpid()))
def test_environ_64(self):
- # Environ 32 is not supported.
p = psutil.Process(self.proc64.pid)
- with self.assertRaises(psutil.AccessDenied):
+ try:
p.environ()
+ except psutil.AccessDenied:
+ pass
# ===================================================================
diff --git a/setup.py b/setup.py
index e2853236..764f8b31 100755
--- a/setup.py
+++ b/setup.py
@@ -134,6 +134,7 @@ if WINDOWS:
'psutil/arch/windows/security.c',
'psutil/arch/windows/inet_ntop.c',
'psutil/arch/windows/services.c',
+ 'psutil/arch/windows/global.c',
],
define_macros=macros,
libraries=[