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