1 |
/* rndw32.c - W32 entropy gatherer |
2 |
* Copyright (C) 1999, 2000 Free Software Foundation, Inc. |
3 |
* Copyright Peter Gutmann, Matt Thomlinson and Blake Coverett 1996-1999 |
4 |
* |
5 |
* This file is part of Libgcrypt. |
6 |
* |
7 |
* Libgcrypt is free software; you can redistribute it and/or modify |
8 |
* it under the terms of the GNU General Public License as published by |
9 |
* the Free Software Foundation; either version 2 of the License, or |
10 |
* (at your option) any later version. |
11 |
* |
12 |
* Libgcrypt is distributed in the hope that it will be useful, |
13 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 |
* GNU General Public License for more details. |
16 |
* |
17 |
* You should have received a copy of the GNU General Public License |
18 |
* along with this program; if not, write to the Free Software |
19 |
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA |
20 |
* |
21 |
************************************************************************* |
22 |
* The code here is based on code from Cryptlib 3.0 beta by Peter Gutmann. |
23 |
* Source file misc/rndwin32.c "Win32 Randomness-Gathering Code" with this |
24 |
* copyright notice: |
25 |
* |
26 |
* This module is part of the cryptlib continuously seeded pseudorandom |
27 |
* number generator. For usage conditions, see lib_rand.c |
28 |
* |
29 |
* [Here is the notice from lib_rand.c, which is now called dev_sys.c] |
30 |
* |
31 |
* This module and the misc/rnd*.c modules represent the cryptlib |
32 |
* continuously seeded pseudorandom number generator (CSPRNG) as described in |
33 |
* my 1998 Usenix Security Symposium paper "The generation of random numbers |
34 |
* for cryptographic purposes". |
35 |
* |
36 |
* The CSPRNG code is copyright Peter Gutmann (and various others) 1996, |
37 |
* 1997, 1998, 1999, all rights reserved. Redistribution of the CSPRNG |
38 |
* modules and use in source and binary forms, with or without modification, |
39 |
* are permitted provided that the following conditions are met: |
40 |
* |
41 |
* 1. Redistributions of source code must retain the above copyright notice |
42 |
* and this permission notice in its entirety. |
43 |
* |
44 |
* 2. Redistributions in binary form must reproduce the copyright notice in |
45 |
* the documentation and/or other materials provided with the distribution. |
46 |
* |
47 |
* 3. A copy of any bugfixes or enhancements made must be provided to the |
48 |
* author, <[email protected]> to allow them to be added to the |
49 |
* baseline version of the code. |
50 |
* |
51 |
* ALTERNATIVELY, the code may be distributed under the terms of the GNU |
52 |
* General Public License, version 2 or any later version published by the |
53 |
* Free Software Foundation, in which case the provisions of the GNU GPL are |
54 |
* required INSTEAD OF the above restrictions. |
55 |
* |
56 |
* Although not required under the terms of the GPL, it would still be nice if |
57 |
* you could make any changes available to the author to allow a consistent |
58 |
* code base to be maintained |
59 |
************************************************************************* |
60 |
* Heavily modified by Timo Schulz to fit into WinPT, 2001. |
61 |
*/ |
62 |
|
63 |
#include <stdio.h> |
64 |
#include <stdlib.h> |
65 |
#include <assert.h> |
66 |
#include <errno.h> |
67 |
#include <string.h> |
68 |
|
69 |
#include <windows.h> |
70 |
#include <tlhelp32.h> |
71 |
#include <winioctl.h> |
72 |
|
73 |
|
74 |
/* Type definitions for function pointers to call Toolhelp32 functions |
75 |
* used with the windows95 gatherer */ |
76 |
typedef BOOL (WINAPI * MODULEWALK) (HANDLE hSnapshot, MODULEENTRY32 *lpme); |
77 |
typedef BOOL (WINAPI * THREADWALK) (HANDLE hSnapshot, THREADENTRY32 *lpte); |
78 |
typedef BOOL (WINAPI * PROCESSWALK) (HANDLE hSnapshot, PROCESSENTRY32 *lppe); |
79 |
typedef BOOL (WINAPI * HEAPLISTWALK) (HANDLE hSnapshot, HEAPLIST32 *lphl); |
80 |
typedef BOOL (WINAPI * HEAPFIRST) (HEAPENTRY32 *lphe, DWORD th32ProcessID, |
81 |
DWORD th32HeapID); |
82 |
typedef BOOL (WINAPI * HEAPNEXT) (HEAPENTRY32 *lphe); |
83 |
typedef HANDLE (WINAPI * CREATESNAPSHOT) (DWORD dwFlags, DWORD th32ProcessID); |
84 |
|
85 |
/* Type definitions for function pointers to call NetAPI32 functions */ |
86 |
typedef DWORD (WINAPI * NETSTATISTICSGET) (LPWSTR szServer, LPWSTR szService, |
87 |
DWORD dwLevel, DWORD dwOptions, |
88 |
LPBYTE * lpBuffer); |
89 |
typedef DWORD (WINAPI * NETAPIBUFFERSIZE) (LPVOID lpBuffer, LPDWORD cbBuffer); |
90 |
typedef DWORD (WINAPI * NETAPIBUFFERFREE) (LPVOID lpBuffer); |
91 |
|
92 |
|
93 |
/* When we query the performance counters, we allocate an initial buffer and |
94 |
* then reallocate it as required until RegQueryValueEx() stops returning |
95 |
* ERROR_MORE_DATA. The following values define the initial buffer size and |
96 |
* step size by which the buffer is increased |
97 |
*/ |
98 |
#define PERFORMANCE_BUFFER_SIZE 65536 /* Start at 64K */ |
99 |
#define PERFORMANCE_BUFFER_STEP 16384 /* Step by 16K */ |
100 |
|
101 |
|
102 |
static void |
103 |
random_w32_err( const char *format, ... ) |
104 |
{ |
105 |
char log[8192]; |
106 |
va_list arg_ptr; |
107 |
|
108 |
va_start( arg_ptr, format ); |
109 |
_vsnprintf( log, sizeof log-1, format, arg_ptr ); |
110 |
MessageBox( NULL, log, "Crypto RNG", MB_ICONERROR|MB_OK ); |
111 |
va_end( arg_ptr ); |
112 |
} /* log_box */ |
113 |
|
114 |
|
115 |
static void |
116 |
slow_gatherer_windows95( void (*add)(const void*, size_t, int), int requester ) |
117 |
{ |
118 |
static CREATESNAPSHOT pCreateToolhelp32Snapshot = NULL; |
119 |
static MODULEWALK pModule32First = NULL; |
120 |
static MODULEWALK pModule32Next = NULL; |
121 |
static PROCESSWALK pProcess32First = NULL; |
122 |
static PROCESSWALK pProcess32Next = NULL; |
123 |
static THREADWALK pThread32First = NULL; |
124 |
static THREADWALK pThread32Next = NULL; |
125 |
static HEAPLISTWALK pHeap32ListFirst = NULL; |
126 |
static HEAPLISTWALK pHeap32ListNext = NULL; |
127 |
static HEAPFIRST pHeap32First = NULL; |
128 |
static HEAPNEXT pHeap32Next = NULL; |
129 |
HANDLE hSnapshot; |
130 |
|
131 |
|
132 |
/* initialize the Toolhelp32 function pointers */ |
133 |
if ( !pCreateToolhelp32Snapshot ) { |
134 |
HANDLE hKernel; |
135 |
|
136 |
/* Obtain the module handle of the kernel to retrieve the addresses |
137 |
* of the Toolhelp32 functions */ |
138 |
if ( ( !(hKernel = GetModuleHandle ("KERNEL32.DLL"))) ) { |
139 |
random_w32_err( "rndw32: can't get module handle" ); |
140 |
return; |
141 |
} |
142 |
|
143 |
/* Now get pointers to the functions */ |
144 |
pCreateToolhelp32Snapshot = (CREATESNAPSHOT) GetProcAddress (hKernel, |
145 |
"CreateToolhelp32Snapshot"); |
146 |
pModule32First = (MODULEWALK) GetProcAddress (hKernel, "Module32First"); |
147 |
pModule32Next = (MODULEWALK) GetProcAddress (hKernel, "Module32Next"); |
148 |
pProcess32First = (PROCESSWALK) GetProcAddress (hKernel, |
149 |
"Process32First"); |
150 |
pProcess32Next = (PROCESSWALK) GetProcAddress (hKernel, |
151 |
"Process32Next"); |
152 |
pThread32First = (THREADWALK) GetProcAddress (hKernel, "Thread32First"); |
153 |
pThread32Next = (THREADWALK) GetProcAddress (hKernel, "Thread32Next"); |
154 |
pHeap32ListFirst = (HEAPLISTWALK) GetProcAddress (hKernel, |
155 |
"Heap32ListFirst"); |
156 |
pHeap32ListNext = (HEAPLISTWALK) GetProcAddress (hKernel, |
157 |
"Heap32ListNext"); |
158 |
pHeap32First = (HEAPFIRST) GetProcAddress (hKernel, "Heap32First"); |
159 |
pHeap32Next = (HEAPNEXT) GetProcAddress (hKernel, "Heap32Next"); |
160 |
|
161 |
if ( !pCreateToolhelp32Snapshot |
162 |
|| !pModule32First || !pModule32Next |
163 |
|| !pProcess32First || !pProcess32Next |
164 |
|| !pThread32First || !pThread32Next |
165 |
|| !pHeap32ListFirst || !pHeap32ListNext |
166 |
|| !pHeap32First || !pHeap32Next ) { |
167 |
random_w32_err( "rndw32: failed to get a toolhep function" ); |
168 |
return; |
169 |
} |
170 |
} |
171 |
|
172 |
/* Take a snapshot of everything we can get to which is currently |
173 |
* in the system */ |
174 |
if ( !(hSnapshot = pCreateToolhelp32Snapshot (TH32CS_SNAPALL, 0)) ) { |
175 |
random_w32_err( "rndw32: failed to take a toolhelp snapshot" ); |
176 |
return; |
177 |
} |
178 |
|
179 |
/* Walk through the local heap */ |
180 |
{ HEAPLIST32 hl32; |
181 |
hl32.dwSize = sizeof (HEAPLIST32); |
182 |
if (pHeap32ListFirst (hSnapshot, &hl32)) { |
183 |
do { |
184 |
HEAPENTRY32 he32; |
185 |
|
186 |
/* First add the information from the basic Heaplist32 struct */ |
187 |
(*add) ( &hl32, sizeof (hl32), requester ); |
188 |
|
189 |
/* Now walk through the heap blocks getting information |
190 |
* on each of them */ |
191 |
he32.dwSize = sizeof (HEAPENTRY32); |
192 |
if (pHeap32First (&he32, hl32.th32ProcessID, hl32.th32HeapID)){ |
193 |
do { |
194 |
(*add) ( &he32, sizeof (he32), requester ); |
195 |
} while (pHeap32Next (&he32)); |
196 |
} |
197 |
} while (pHeap32ListNext (hSnapshot, &hl32)); |
198 |
} |
199 |
} |
200 |
|
201 |
|
202 |
/* Walk through all processes */ |
203 |
{ PROCESSENTRY32 pe32; |
204 |
pe32.dwSize = sizeof (PROCESSENTRY32); |
205 |
if (pProcess32First (hSnapshot, &pe32)) { |
206 |
do { |
207 |
(*add) ( &pe32, sizeof (pe32), requester ); |
208 |
} while (pProcess32Next (hSnapshot, &pe32)); |
209 |
} |
210 |
} |
211 |
|
212 |
/* Walk through all threads */ |
213 |
{ THREADENTRY32 te32; |
214 |
te32.dwSize = sizeof (THREADENTRY32); |
215 |
if (pThread32First (hSnapshot, &te32)) { |
216 |
do { |
217 |
(*add) ( &te32, sizeof (te32), requester ); |
218 |
} while (pThread32Next (hSnapshot, &te32)); |
219 |
} |
220 |
} |
221 |
|
222 |
/* Walk through all modules associated with the process */ |
223 |
{ MODULEENTRY32 me32; |
224 |
me32.dwSize = sizeof (MODULEENTRY32); |
225 |
if (pModule32First (hSnapshot, &me32)) { |
226 |
do { |
227 |
(*add) ( &me32, sizeof (me32), requester ); |
228 |
} while (pModule32Next (hSnapshot, &me32)); |
229 |
} |
230 |
} |
231 |
|
232 |
CloseHandle (hSnapshot); |
233 |
} |
234 |
|
235 |
|
236 |
|
237 |
|
238 |
|
239 |
static void |
240 |
slow_gatherer_windowsNT( void (*add)(const void*, size_t, int), int requester ) |
241 |
{ |
242 |
static int is_initialized = 0; |
243 |
static NETSTATISTICSGET pNetStatisticsGet = NULL; |
244 |
static NETAPIBUFFERSIZE pNetApiBufferSize = NULL; |
245 |
static NETAPIBUFFERFREE pNetApiBufferFree = NULL; |
246 |
static int is_workstation = 1; |
247 |
static int diskperf_warning = 0; |
248 |
|
249 |
static int cbPerfData = PERFORMANCE_BUFFER_SIZE; |
250 |
PERF_DATA_BLOCK *pPerfData; |
251 |
HANDLE hDevice, hNetAPI32 = NULL; |
252 |
DWORD dwSize, status; |
253 |
int nDrive; |
254 |
|
255 |
if ( !is_initialized ) { |
256 |
HKEY hKey; |
257 |
|
258 |
/* Find out whether this is an NT server or workstation if necessary */ |
259 |
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, |
260 |
"SYSTEM\\CurrentControlSet\\Control\\ProductOptions", |
261 |
0, KEY_READ, &hKey) == ERROR_SUCCESS) { |
262 |
BYTE szValue[32]; |
263 |
dwSize = sizeof (szValue); |
264 |
|
265 |
status = RegQueryValueEx (hKey, "ProductType", 0, NULL, |
266 |
szValue, &dwSize); |
267 |
if (status == ERROR_SUCCESS && stricmp (szValue, "WinNT")) { |
268 |
/* Note: There are (at least) three cases for ProductType: |
269 |
* WinNT = NT Workstation, ServerNT = NT Server, LanmanNT = |
270 |
* NT Server acting as a Domain Controller */ |
271 |
is_workstation = 0; |
272 |
} |
273 |
RegCloseKey (hKey); |
274 |
} |
275 |
|
276 |
/* Initialize the NetAPI32 function pointers if necessary */ |
277 |
if ( (hNetAPI32 = LoadLibrary ("NETAPI32.DLL")) ) { |
278 |
pNetStatisticsGet = (NETSTATISTICSGET) GetProcAddress (hNetAPI32, |
279 |
"NetStatisticsGet"); |
280 |
pNetApiBufferSize = (NETAPIBUFFERSIZE) GetProcAddress (hNetAPI32, |
281 |
"NetApiBufferSize"); |
282 |
pNetApiBufferFree = (NETAPIBUFFERFREE) GetProcAddress (hNetAPI32, |
283 |
"NetApiBufferFree"); |
284 |
|
285 |
if ( !pNetStatisticsGet |
286 |
|| !pNetApiBufferSize || !pNetApiBufferFree ) { |
287 |
FreeLibrary (hNetAPI32); |
288 |
hNetAPI32 = NULL; |
289 |
} |
290 |
} |
291 |
|
292 |
is_initialized = 1; |
293 |
} |
294 |
|
295 |
/* Get network statistics. Note: Both NT Workstation and NT Server by |
296 |
* default will be running both the workstation and server services. The |
297 |
* heuristic below is probably useful though on the assumption that the |
298 |
* majority of the network traffic will be via the appropriate service. |
299 |
* In any case the network statistics return almost no randomness */ |
300 |
{ LPBYTE lpBuffer; |
301 |
if (hNetAPI32 && !pNetStatisticsGet (NULL, |
302 |
is_workstation ? L"LanmanWorkstation" : |
303 |
L"LanmanServer", 0, 0, &lpBuffer) ) { |
304 |
pNetApiBufferSize (lpBuffer, &dwSize); |
305 |
(*add) ( lpBuffer, dwSize,requester ); |
306 |
pNetApiBufferFree (lpBuffer); |
307 |
} |
308 |
} |
309 |
|
310 |
/* Get disk I/O statistics for all the hard drives */ |
311 |
for (nDrive = 0;; nDrive++) { |
312 |
DISK_PERFORMANCE diskPerformance; |
313 |
char szDevice[50]; |
314 |
|
315 |
/* Check whether we can access this device */ |
316 |
sprintf (szDevice, "\\\\.\\PhysicalDrive%d", nDrive); |
317 |
hDevice = CreateFile (szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, |
318 |
NULL, OPEN_EXISTING, 0, NULL); |
319 |
if (hDevice == INVALID_HANDLE_VALUE) |
320 |
break; |
321 |
|
322 |
/* Note: This only works if you have turned on the disk performance |
323 |
* counters with 'diskperf -y'. These counters are off by default */ |
324 |
if (DeviceIoControl (hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0, |
325 |
&diskPerformance, sizeof (DISK_PERFORMANCE), |
326 |
&dwSize, NULL)) |
327 |
{ |
328 |
(*add) ( &diskPerformance, dwSize, requester ); |
329 |
} |
330 |
CloseHandle (hDevice); |
331 |
} |
332 |
|
333 |
/* Get information from the system performance counters. This can take |
334 |
* a few seconds to do. In some environments the call to |
335 |
* RegQueryValueEx() can produce an access violation at some random time |
336 |
* in the future, adding a short delay after the following code block |
337 |
* makes the problem go away. This problem is extremely difficult to |
338 |
* reproduce, I haven't been able to get it to occur despite running it |
339 |
* on a number of machines. The best explanation for the problem is that |
340 |
* on the machine where it did occur, it was caused by an external driver |
341 |
* or other program which adds its own values under the |
342 |
* HKEY_PERFORMANCE_DATA key. The NT kernel calls the required external |
343 |
* modules to map in the data, if there's a synchronisation problem the |
344 |
* external module would write its data at an inappropriate moment, |
345 |
* causing the access violation. A low-level memory checker indicated |
346 |
* that ExpandEnvironmentStrings() in KERNEL32.DLL, called an |
347 |
* interminable number of calls down inside RegQueryValueEx(), was |
348 |
* overwriting memory (it wrote twice the allocated size of a buffer to a |
349 |
* buffer allocated by the NT kernel). This may be what's causing the |
350 |
* problem, but since it's in the kernel there isn't much which can be |
351 |
* done. |
352 |
* |
353 |
* In addition to these problems the code in RegQueryValueEx() which |
354 |
* estimates the amount of memory required to return the performance |
355 |
* counter information isn't very accurate, since it always returns a |
356 |
* worst-case estimate which is usually nowhere near the actual amount |
357 |
* required. For example it may report that 128K of memory is required, |
358 |
* but only return 64K of data */ |
359 |
{ pPerfData = malloc (cbPerfData); |
360 |
for (;;) { |
361 |
dwSize = cbPerfData; |
362 |
status = RegQueryValueEx (HKEY_PERFORMANCE_DATA, "Global", NULL, |
363 |
NULL, (LPBYTE) pPerfData, &dwSize); |
364 |
if (status == ERROR_SUCCESS) { |
365 |
if (!memcmp (pPerfData->Signature, L"PERF", 8)) { |
366 |
(*add) ( pPerfData, dwSize, requester ); |
367 |
} |
368 |
break; |
369 |
} |
370 |
else if (status == ERROR_MORE_DATA) { |
371 |
cbPerfData += PERFORMANCE_BUFFER_STEP; |
372 |
pPerfData = realloc (pPerfData, cbPerfData); |
373 |
} |
374 |
else { |
375 |
random_w32_err ( "rndw32: get performance data problem"); |
376 |
break; |
377 |
} |
378 |
} |
379 |
free (pPerfData); |
380 |
} |
381 |
/* Although this isn't documented in the Win32 API docs, it's necessary |
382 |
to explicitly close the HKEY_PERFORMANCE_DATA key after use (it's |
383 |
implicitly opened on the first call to RegQueryValueEx()). If this |
384 |
isn't done then any system components which provide performance data |
385 |
can't be removed or changed while the handle remains active */ |
386 |
RegCloseKey (HKEY_PERFORMANCE_DATA); |
387 |
} |
388 |
|
389 |
|
390 |
int |
391 |
gather_random( void (*add)(const void*, size_t, int), int requester, |
392 |
size_t length, int level ) |
393 |
{ |
394 |
static int is_initialized; |
395 |
static int is_windows95; |
396 |
|
397 |
|
398 |
if( !level ) |
399 |
return 0; |
400 |
/* We don't differentiate between level 1 and 2 here because |
401 |
* there is no nternal entropy pool as a scary resource. It may |
402 |
* all work slower, but because our entropy source will never |
403 |
* block but deliver some not easy to measure entropy, we assume level 2 |
404 |
*/ |
405 |
|
406 |
|
407 |
if ( !is_initialized ) { |
408 |
OSVERSIONINFO osvi = { sizeof( osvi ) }; |
409 |
DWORD platform; |
410 |
|
411 |
GetVersionEx( &osvi ); |
412 |
platform = osvi.dwPlatformId; |
413 |
is_windows95 = platform == VER_PLATFORM_WIN32_WINDOWS; |
414 |
|
415 |
if ( platform == VER_PLATFORM_WIN32s ) { |
416 |
random_w32_err("can't run on a W32s platform" ); |
417 |
return 0; |
418 |
} |
419 |
is_initialized = 1; |
420 |
} |
421 |
|
422 |
if (is_windows95 ) { |
423 |
slow_gatherer_windows95( add, requester ); |
424 |
} |
425 |
else { |
426 |
slow_gatherer_windowsNT( add, requester ); |
427 |
} |
428 |
|
429 |
return 0; |
430 |
} |
431 |
|
432 |
|
433 |
|
434 |
int |
435 |
gather_random_fast( void (*add)(const void*, size_t, int), int requester ) |
436 |
{ |
437 |
static int addedFixedItems = 0; |
438 |
|
439 |
/* Get various basic pieces of system information: Handle of active |
440 |
* window, handle of window with mouse capture, handle of clipboard owner |
441 |
* handle of start of clpboard viewer list, pseudohandle of current |
442 |
* process, current process ID, pseudohandle of current thread, current |
443 |
* thread ID, handle of desktop window, handle of window with keyboard |
444 |
* focus, whether system queue has any events, cursor position for last |
445 |
* message, 1 ms time for last message, handle of window with clipboard |
446 |
* open, handle of process heap, handle of procs window station, types of |
447 |
* events in input queue, and milliseconds since Windows was started */ |
448 |
{ BYTE buffer[20*sizeof(DWORD)], *bufptr; |
449 |
bufptr = buffer; |
450 |
#define ADD(f) do { DWORD along = (DWORD)(f); \ |
451 |
memcpy (bufptr, &along, sizeof (along) ); \ |
452 |
bufptr += sizeof (along); } while (0) |
453 |
ADD ( GetActiveWindow ()); |
454 |
ADD ( GetCapture ()); |
455 |
ADD ( GetClipboardOwner ()); |
456 |
ADD ( GetClipboardViewer ()); |
457 |
ADD ( GetCurrentProcess ()); |
458 |
ADD ( GetCurrentProcessId ()); |
459 |
ADD ( GetCurrentThread ()); |
460 |
ADD ( GetCurrentThreadId ()); |
461 |
ADD ( GetDesktopWindow ()); |
462 |
ADD ( GetFocus ()); |
463 |
ADD ( GetInputState ()); |
464 |
ADD ( GetMessagePos ()); |
465 |
ADD ( GetMessageTime ()); |
466 |
ADD ( GetOpenClipboardWindow ()); |
467 |
ADD ( GetProcessHeap ()); |
468 |
ADD ( GetProcessWindowStation ()); |
469 |
ADD ( GetQueueStatus (QS_ALLEVENTS)); |
470 |
ADD ( GetTickCount ()); |
471 |
|
472 |
assert ( bufptr-buffer < sizeof (buffer) ); |
473 |
(*add) ( buffer, bufptr-buffer, requester ); |
474 |
#undef ADD |
475 |
} |
476 |
|
477 |
/* Get multiword system information: Current caret position, current |
478 |
* mouse cursor position */ |
479 |
{ POINT point; |
480 |
GetCaretPos (&point); |
481 |
(*add) ( &point, sizeof (point), requester ); |
482 |
GetCursorPos (&point); |
483 |
(*add) ( &point, sizeof (point), requester ); |
484 |
} |
485 |
|
486 |
/* Get percent of memory in use, bytes of physical memory, bytes of free |
487 |
* physical memory, bytes in paging file, free bytes in paging file, user |
488 |
* bytes of address space, and free user bytes */ |
489 |
{ MEMORYSTATUS memoryStatus; |
490 |
memoryStatus.dwLength = sizeof (MEMORYSTATUS); |
491 |
GlobalMemoryStatus (&memoryStatus); |
492 |
(*add) ( &memoryStatus, sizeof (memoryStatus), requester ); |
493 |
} |
494 |
|
495 |
/* Get thread and process creation time, exit time, time in kernel mode, |
496 |
and time in user mode in 100ns intervals */ |
497 |
{ HANDLE handle; |
498 |
FILETIME creationTime, exitTime, kernelTime, userTime; |
499 |
DWORD minimumWorkingSetSize, maximumWorkingSetSize; |
500 |
|
501 |
handle = GetCurrentThread (); |
502 |
GetThreadTimes (handle, &creationTime, &exitTime, |
503 |
&kernelTime, &userTime); |
504 |
(*add) ( &creationTime, sizeof (creationTime), requester ); |
505 |
(*add) ( &exitTime, sizeof (exitTime), requester ); |
506 |
(*add) ( &kernelTime, sizeof (kernelTime), requester ); |
507 |
(*add) ( &userTime, sizeof (userTime), requester ); |
508 |
|
509 |
handle = GetCurrentProcess (); |
510 |
GetProcessTimes (handle, &creationTime, &exitTime, |
511 |
&kernelTime, &userTime); |
512 |
(*add) ( &creationTime, sizeof (creationTime), requester ); |
513 |
(*add) ( &exitTime, sizeof (exitTime), requester ); |
514 |
(*add) ( &kernelTime, sizeof (kernelTime), requester ); |
515 |
(*add) ( &userTime, sizeof (userTime), requester ); |
516 |
|
517 |
/* Get the minimum and maximum working set size for the current process */ |
518 |
GetProcessWorkingSetSize (handle, &minimumWorkingSetSize, |
519 |
&maximumWorkingSetSize); |
520 |
(*add) ( &minimumWorkingSetSize, |
521 |
sizeof (&minimumWorkingSetSize), requester ); |
522 |
(*add) ( &maximumWorkingSetSize, |
523 |
sizeof (&maximumWorkingSetSize), requester ); |
524 |
} |
525 |
|
526 |
|
527 |
/* The following are fixed for the lifetime of the process so we only |
528 |
* add them once */ |
529 |
if (!addedFixedItems) { |
530 |
STARTUPINFO startupInfo; |
531 |
|
532 |
/* Get name of desktop, console window title, new window position and |
533 |
* size, window flags, and handles for stdin, stdout, and stderr */ |
534 |
startupInfo.cb = sizeof (STARTUPINFO); |
535 |
GetStartupInfo (&startupInfo); |
536 |
(*add) ( &startupInfo, sizeof (STARTUPINFO), requester ); |
537 |
addedFixedItems = 1; |
538 |
} |
539 |
|
540 |
/* The performance of QPC varies depending on the architecture it's |
541 |
* running on and on the OS. Under NT it reads the CPU's 64-bit timestamp |
542 |
* counter (at least on a Pentium and newer '486's, it hasn't been tested |
543 |
* on anything without a TSC), under Win95 it reads the 1.193180 MHz PIC |
544 |
* timer. There are vague mumblings in the docs that it may fail if the |
545 |
* appropriate hardware isn't available (possibly '386's or MIPS machines |
546 |
* running NT), but who's going to run NT on a '386? */ |
547 |
{ LARGE_INTEGER performanceCount; |
548 |
if (QueryPerformanceCounter (&performanceCount)) { |
549 |
(*add) (&performanceCount, sizeof (&performanceCount), requester); |
550 |
} |
551 |
else { /* Millisecond accuracy at best... */ |
552 |
DWORD aword = GetTickCount (); |
553 |
(*add) (&aword, sizeof (aword), requester ); |
554 |
} |
555 |
} |
556 |
|
557 |
return 0; |
558 |
} |