reshuffling of dlls
[reactos.git] / reactos / dll / psapi / psapi.c
1 /* $Id$
2 */
3 /*
4 * COPYRIGHT: See COPYING in the top level directory
5 * LICENSE: See LGPL.txt in the top level directory
6 * PROJECT: ReactOS system libraries
7 * FILE: reactos/lib/psapi/misc/win32.c
8 * PURPOSE: Win32 interfaces for PSAPI
9 * PROGRAMMER: KJK::Hyperion <noog@libero.it>
10 * Thomas Weidenmueller <w3seek@reactos.com>
11 * UPDATE HISTORY:
12 * 10/06/2002: Created
13 */
14
15 #include "precomp.h"
16
17 #define NDEBUG
18 #include <debug.h>
19
20 BOOLEAN
21 WINAPI
22 DllMain(HINSTANCE hDllHandle,
23 DWORD nReason,
24 LPVOID Reserved)
25 {
26 switch(nReason)
27 {
28 case DLL_PROCESS_ATTACH:
29 DisableThreadLibraryCalls(hDllHandle);
30 break;
31 }
32
33 return TRUE;
34 }
35
36 /* INTERNAL *******************************************************************/
37
38 typedef struct _ENUM_DEVICE_DRIVERS_CONTEXT
39 {
40 LPVOID *lpImageBase;
41 DWORD nCount;
42 } ENUM_DEVICE_DRIVERS_CONTEXT, *PENUM_DEVICE_DRIVERS_CONTEXT;
43
44 NTSTATUS STDCALL
45 EnumDeviceDriversCallback(IN PSYSTEM_MODULE_INFORMATION_ENTRY CurrentModule,
46 IN OUT PVOID CallbackContext)
47 {
48 PENUM_DEVICE_DRIVERS_CONTEXT Context = (PENUM_DEVICE_DRIVERS_CONTEXT)CallbackContext;
49
50 /* no more buffer space */
51 if(Context->nCount == 0)
52 {
53 return STATUS_INFO_LENGTH_MISMATCH;
54 }
55
56 /* return current module */
57 *Context->lpImageBase = CurrentModule->Base;
58
59 /* go to next array slot */
60 Context->lpImageBase++;
61 Context->nCount--;
62
63 return STATUS_SUCCESS;
64 }
65
66
67 typedef struct _ENUM_PROCESSES_CONTEXT
68 {
69 DWORD *lpidProcess;
70 DWORD nCount;
71 } ENUM_PROCESSES_CONTEXT, *PENUM_PROCESSES_CONTEXT;
72
73 NTSTATUS STDCALL
74 EnumProcessesCallback(IN PSYSTEM_PROCESS_INFORMATION CurrentProcess,
75 IN OUT PVOID CallbackContext)
76 {
77 PENUM_PROCESSES_CONTEXT Context = (PENUM_PROCESSES_CONTEXT)CallbackContext;
78
79 /* no more buffer space */
80 if(Context->nCount == 0)
81 {
82 return STATUS_INFO_LENGTH_MISMATCH;
83 }
84
85 /* return current process */
86 *Context->lpidProcess = (DWORD)CurrentProcess->UniqueProcessId;
87
88 /* go to next array slot */
89 Context->lpidProcess++;
90 Context->nCount--;
91
92 return STATUS_SUCCESS;
93 }
94
95
96 typedef struct _ENUM_PROCESS_MODULES_CONTEXT
97 {
98 HMODULE *lphModule;
99 DWORD nCount;
100 } ENUM_PROCESS_MODULES_CONTEXT, *PENUM_PROCESS_MODULES_CONTEXT;
101
102 NTSTATUS STDCALL
103 EnumProcessModulesCallback(IN HANDLE ProcessHandle,
104 IN PLDR_DATA_TABLE_ENTRY CurrentModule,
105 IN OUT PVOID CallbackContext)
106 {
107 PENUM_PROCESS_MODULES_CONTEXT Context = (PENUM_PROCESS_MODULES_CONTEXT)CallbackContext;
108
109 /* no more buffer space */
110 if(Context->nCount == 0)
111 {
112 return STATUS_INFO_LENGTH_MISMATCH;
113 }
114
115 /* return current process */
116 *Context->lphModule = CurrentModule->DllBase;
117
118 /* go to next array slot */
119 Context->lphModule++;
120 Context->nCount--;
121
122 return STATUS_SUCCESS;
123 }
124
125
126 typedef struct _GET_DEVICE_DRIVER_NAME_CONTEXT
127 {
128 LPVOID ImageBase;
129 struct
130 {
131 ULONG bFullName : sizeof(ULONG) * 8 / 2;
132 ULONG bUnicode : sizeof(ULONG) * 8 / 2;
133 };
134 DWORD nSize;
135 union
136 {
137 LPVOID lpName;
138 LPSTR lpAnsiName;
139 LPWSTR lpUnicodeName;
140 };
141 } GET_DEVICE_DRIVER_NAME_CONTEXT, *PGET_DEVICE_DRIVER_NAME_CONTEXT;
142
143 NTSTATUS STDCALL
144 GetDeviceDriverNameCallback(IN PSYSTEM_MODULE_INFORMATION_ENTRY CurrentModule,
145 IN OUT PVOID CallbackContext)
146 {
147 PGET_DEVICE_DRIVER_NAME_CONTEXT Context = (PGET_DEVICE_DRIVER_NAME_CONTEXT)CallbackContext;
148
149 /* module found */
150 if(Context->ImageBase == CurrentModule->Base)
151 {
152 PCHAR pcModuleName;
153 ULONG l;
154
155 /* get the full name or just the filename part */
156 if(Context->bFullName)
157 pcModuleName = &CurrentModule->ImageName[0];
158 else
159 pcModuleName = &CurrentModule->ImageName[CurrentModule->PathLength];
160
161 /* get the length of the name */
162 l = strlen(pcModuleName);
163
164 if(Context->nSize <= l)
165 {
166 /* use the user buffer's length */
167 l = Context->nSize;
168 }
169 else
170 {
171 /* enough space for the null terminator */
172 Context->nSize = ++l;
173 }
174
175 /* copy the string */
176 if(Context->bUnicode)
177 {
178 ANSI_STRING AnsiString;
179 UNICODE_STRING UnicodeString;
180
181 UnicodeString.Length = 0;
182 UnicodeString.MaximumLength = l * sizeof(WCHAR);
183 UnicodeString.Buffer = Context->lpUnicodeName;
184
185 RtlInitAnsiString(&AnsiString, pcModuleName);
186 /* driver names should always be in language-neutral ASCII, so we don't
187 bother calling AreFileApisANSI() */
188 RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, FALSE);
189 }
190 else
191 {
192 memcpy(Context->lpAnsiName, pcModuleName, l);
193 }
194
195 /* terminate the enumeration */
196 return STATUS_NO_MORE_FILES;
197 }
198 else
199 {
200 /* continue searching */
201 return STATUS_SUCCESS;
202 }
203 }
204
205
206 static DWORD
207 InternalGetDeviceDriverName(BOOLEAN bUnicode,
208 BOOLEAN bFullName,
209 LPVOID ImageBase,
210 LPVOID lpName,
211 DWORD nSize)
212 {
213 GET_DEVICE_DRIVER_NAME_CONTEXT Context;
214 NTSTATUS Status;
215
216 if(lpName == NULL || nSize == 0)
217 {
218 return 0;
219 }
220
221 if(ImageBase == NULL)
222 {
223 SetLastError(ERROR_INVALID_HANDLE);
224 return 0;
225 }
226
227 Context.ImageBase = ImageBase;
228 Context.bFullName = bFullName;
229 Context.bUnicode = bUnicode;
230 Context.nSize = nSize;
231 Context.lpName = lpName;
232
233 /* start the enumeration */
234 Status = PsaEnumerateSystemModules(GetDeviceDriverNameCallback, &Context);
235
236 if(Status == STATUS_NO_MORE_FILES)
237 {
238 /* module was found, return string size */
239 return Context.nSize;
240 }
241 else if(NT_SUCCESS(Status))
242 {
243 /* module was not found */
244 SetLastError(ERROR_INVALID_HANDLE);
245 }
246 else
247 {
248 /* an error occurred */
249 SetLastErrorByStatus(Status);
250 }
251 return 0;
252 }
253
254
255 static DWORD
256 InternalGetMappedFileName(BOOLEAN bUnicode,
257 HANDLE hProcess,
258 LPVOID lpv,
259 LPVOID lpName,
260 DWORD nSize)
261 {
262 PMEMORY_SECTION_NAME pmsnName;
263 ULONG nBufSize;
264 NTSTATUS Status;
265
266 if(nSize == 0 || lpName == NULL)
267 {
268 return 0;
269 }
270
271 if(nSize > (0xFFFF / sizeof(WCHAR)))
272 {
273 /* if the user buffer contains more characters than would fit in an
274 UNICODE_STRING, limit the buffer size. RATIONALE: we don't limit buffer
275 size elsewhere because here superfluous buffer size will mean a larger
276 temporary buffer */
277 nBufSize = 0xFFFF / sizeof(WCHAR);
278 }
279 else
280 {
281 nBufSize = nSize * sizeof(WCHAR);
282 }
283
284 /* allocate the memory */
285 pmsnName = PsaiMalloc(nBufSize + sizeof(MEMORY_SECTION_NAME));
286
287 if(pmsnName == NULL)
288 {
289 SetLastError(ERROR_OUTOFMEMORY);
290 return 0;
291 }
292
293 /* initialize the destination buffer */
294 pmsnName->SectionFileName.Length = 0;
295 pmsnName->SectionFileName.Length = nBufSize;
296
297 #if 0
298 __try
299 {
300 #endif
301 /* query the name */
302 Status = NtQueryVirtualMemory(hProcess,
303 lpv,
304 MemorySectionName,
305 pmsnName,
306 nBufSize,
307 NULL);
308 if(!NT_SUCCESS(Status))
309 {
310 PsaiFree(pmsnName);
311 SetLastErrorByStatus(Status);
312 return 0;
313 }
314
315 if(bUnicode)
316 {
317 /* destination is an Unicode string: direct copy */
318 memcpy((LPWSTR)lpName, pmsnName + 1, pmsnName->SectionFileName.Length);
319
320 PsaiFree(pmsnName);
321
322 if(pmsnName->SectionFileName.Length < nSize)
323 {
324 /* null-terminate the string */
325 ((LPWSTR)lpName)[pmsnName->SectionFileName.Length] = 0;
326 return pmsnName->SectionFileName.Length + 1;
327 }
328
329 return pmsnName->SectionFileName.Length;
330 }
331 else
332 {
333 ANSI_STRING AnsiString;
334
335 AnsiString.Length = 0;
336 AnsiString.MaximumLength = nSize;
337 AnsiString.Buffer = (LPSTR)lpName;
338
339 if(AreFileApisANSI())
340 RtlUnicodeStringToAnsiString(&AnsiString, &pmsnName->SectionFileName, FALSE);
341 else
342 RtlUnicodeStringToOemString(&AnsiString, &pmsnName->SectionFileName, FALSE);
343
344 PsaiFree(pmsnName);
345
346 if(AnsiString.Length < nSize)
347 {
348 /* null-terminate the string */
349 ((LPSTR)lpName)[AnsiString.Length] = 0;
350 return AnsiString.Length + 1;
351 }
352
353 return AnsiString.Length;
354 }
355
356 #if 0
357 }
358 __finally
359 {
360 PsaiFree(pmsnName);
361 }
362 #endif
363 }
364
365
366 typedef struct _GET_MODULE_INFORMATION_FLAGS
367 {
368 ULONG bWantName : sizeof(ULONG) * 8 / 4;
369 ULONG bUnicode : sizeof(ULONG) * 8 / 4;
370 ULONG bFullName : sizeof(ULONG) * 8 / 4;
371 } GET_MODULE_INFORMATION_FLAGS, *PGET_MODULE_INFORMATION_FLAGS;
372
373 typedef struct _GET_MODULE_INFORMATION_CONTEXT
374 {
375 HMODULE hModule;
376 GET_MODULE_INFORMATION_FLAGS Flags;
377 DWORD nBufSize;
378 union
379 {
380 LPWSTR lpUnicodeName;
381 LPSTR lpAnsiName;
382 LPMODULEINFO lpmodinfo;
383 LPVOID lpBuffer;
384 };
385 } GET_MODULE_INFORMATION_CONTEXT, *PGET_MODULE_INFORMATION_CONTEXT;
386
387 NTSTATUS STDCALL
388 GetModuleInformationCallback(IN HANDLE ProcessHandle,
389 IN PLDR_DATA_TABLE_ENTRY CurrentModule,
390 IN OUT PVOID CallbackContext)
391 {
392 PGET_MODULE_INFORMATION_CONTEXT Context = (PGET_MODULE_INFORMATION_CONTEXT)CallbackContext;
393
394 /* found the module we were looking for */
395 if(CurrentModule->DllBase == Context->hModule)
396 {
397 /* we want the module name */
398 if(Context->Flags.bWantName)
399 {
400 PUNICODE_STRING SourceString;
401 ULONG l;
402 NTSTATUS Status;
403
404 if(Context->Flags.bFullName)
405 SourceString = &(CurrentModule->FullDllName);
406 else
407 SourceString = &(CurrentModule->BaseDllName);
408
409 SourceString->Length -= SourceString->Length % sizeof(WCHAR);
410
411 /* l is the byte size of the user buffer */
412 l = Context->nBufSize * sizeof(WCHAR);
413
414 /* if the user buffer has room for the string and a null terminator */
415 if(l >= (SourceString->Length + sizeof(WCHAR)))
416 {
417 /* limit the buffer size */
418 l = SourceString->Length;
419
420 /* null-terminate the string */
421 if(Context->Flags.bUnicode)
422 Context->lpUnicodeName[l / sizeof(WCHAR)] = 0;
423 else
424 Context->lpAnsiName[l / sizeof(WCHAR)] = 0;
425 }
426
427 if(Context->Flags.bUnicode)
428 {
429 /* Unicode: direct copy */
430 /* NOTE: I've chosen not to check for ProcessHandle == NtCurrentProcess(),
431 this function is complicated enough as it is */
432 Status = NtReadVirtualMemory(ProcessHandle,
433 SourceString->Buffer,
434 Context->lpUnicodeName,
435 l,
436 NULL);
437
438 if(!NT_SUCCESS(Status))
439 {
440 Context->nBufSize = 0;
441 return Status;
442 }
443
444 Context->nBufSize = l / sizeof(WCHAR);
445 }
446 else
447 {
448 /* ANSI/OEM: convert and copy */
449 LPWSTR pwcUnicodeBuf;
450 ANSI_STRING AnsiString;
451 UNICODE_STRING UnicodeString;
452
453 AnsiString.Length = 0;
454 AnsiString.MaximumLength = Context->nBufSize;
455 AnsiString.Buffer = Context->lpAnsiName;
456
457 /* allocate the local buffer */
458 pwcUnicodeBuf = PsaiMalloc(SourceString->Length);
459
460 #if 0
461 __try
462 {
463 #endif
464 if(pwcUnicodeBuf == NULL)
465 {
466 Status = STATUS_NO_MEMORY;
467 goto exitWithStatus;
468 }
469
470 /* copy the string in the local buffer */
471 Status = NtReadVirtualMemory(ProcessHandle,
472 SourceString->Buffer,
473 pwcUnicodeBuf,
474 l,
475 NULL);
476
477 if(!NT_SUCCESS(Status))
478 {
479 goto exitWithStatus;
480 }
481
482 /* initialize Unicode string buffer */
483 UnicodeString.Length = UnicodeString.MaximumLength = l;
484 UnicodeString.Buffer = pwcUnicodeBuf;
485
486 /* convert and copy */
487 if(AreFileApisANSI())
488 RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE);
489 else
490 RtlUnicodeStringToOemString(&AnsiString, &UnicodeString, FALSE);
491
492 /* return the string size */
493 Context->nBufSize = AnsiString.Length;
494 #if 0
495 }
496 __finally
497 {
498 /* free the buffer */
499 PsaiFree(pwcUnicodeBuf);
500 }
501 #else
502 Status = STATUS_NO_MORE_FILES;
503
504 exitWithStatus:
505 /* free the buffer */
506 PsaiFree(pwcUnicodeBuf);
507 return Status;
508 #endif
509 }
510 }
511 else
512 {
513 /* we want other module information */
514 ULONG nSize = Context->nBufSize;
515
516 /* base address */
517 if(nSize >= sizeof(CurrentModule->DllBase))
518 {
519 Context->lpmodinfo->lpBaseOfDll = CurrentModule->DllBase;
520 nSize -= sizeof(CurrentModule->DllBase);
521 }
522
523 /* image size */
524 if(nSize >= sizeof(CurrentModule->SizeOfImage))
525 {
526 Context->lpmodinfo->SizeOfImage = CurrentModule->SizeOfImage;
527 nSize -= sizeof(CurrentModule->SizeOfImage);
528 }
529
530 /* entry point */
531 if(nSize >= sizeof(CurrentModule->EntryPoint))
532 {
533 /* ??? FIXME? is "EntryPoint" just the offset, or the real address? */
534 Context->lpmodinfo->EntryPoint = (PVOID)CurrentModule->EntryPoint;
535 }
536
537 Context->nBufSize = TRUE;
538 }
539
540 return STATUS_NO_MORE_FILES;
541 }
542
543 return STATUS_SUCCESS;
544 }
545
546
547 static DWORD
548 InternalGetModuleInformation(HANDLE hProcess,
549 HMODULE hModule,
550 GET_MODULE_INFORMATION_FLAGS Flags,
551 LPVOID lpBuffer,
552 DWORD nBufSize)
553 {
554 GET_MODULE_INFORMATION_CONTEXT Context;
555 NTSTATUS Status;
556
557 Context.hModule = hModule;
558 Context.Flags = Flags;
559 Context.nBufSize = nBufSize;
560 Context.lpBuffer = lpBuffer;
561
562 Status = PsaEnumerateProcessModules(hProcess, GetModuleInformationCallback, &Context);
563
564 if(Status == STATUS_NO_MORE_FILES)
565 {
566 /* module was found, return string size */
567 return Context.nBufSize;
568 }
569 else if(NT_SUCCESS(Status))
570 {
571 /* module was not found */
572 SetLastError(ERROR_INVALID_HANDLE);
573 }
574 else
575 {
576 /* an error occurred */
577 SetLastErrorByStatus(Status);
578 }
579 return 0;
580 }
581
582
583 typedef struct _INTERNAL_ENUM_PAGE_FILES_CONTEXT
584 {
585 PENUM_PAGE_FILE_CALLBACKA pCallbackRoutine;
586 LPVOID lpContext;
587 } INTERNAL_ENUM_PAGE_FILES_CONTEXT, *PINTERNAL_ENUM_PAGE_FILES_CONTEXT;
588
589
590 static BOOL
591 InternalAnsiPageFileCallback(LPVOID pContext,
592 PENUM_PAGE_FILE_INFORMATION pPageFileInfo,
593 LPCWSTR lpFilename)
594 {
595 size_t slen;
596 LPSTR AnsiFileName;
597 PINTERNAL_ENUM_PAGE_FILES_CONTEXT Context = (PINTERNAL_ENUM_PAGE_FILES_CONTEXT)pContext;
598
599 slen = wcslen(lpFilename);
600
601 AnsiFileName = (LPSTR)LocalAlloc(LMEM_FIXED, (slen + 1) * sizeof(CHAR));
602 if(AnsiFileName != NULL)
603 {
604 BOOL Ret;
605
606 WideCharToMultiByte(CP_ACP,
607 0,
608 lpFilename,
609 -1, /* only works if the string is NULL-terminated!!! */
610 AnsiFileName,
611 (slen + 1) * sizeof(CHAR),
612 NULL,
613 NULL);
614
615 Ret = Context->pCallbackRoutine(Context->lpContext, pPageFileInfo, AnsiFileName);
616
617 LocalFree((HLOCAL)AnsiFileName);
618
619 return Ret;
620 }
621
622 return FALSE;
623 }
624
625 /* PUBLIC *********************************************************************/
626
627 /*
628 * @implemented
629 */
630 BOOL
631 STDCALL
632 EmptyWorkingSet(HANDLE hProcess)
633 {
634 QUOTA_LIMITS QuotaLimits;
635 NTSTATUS Status;
636
637 /* query the working set */
638 Status = NtQueryInformationProcess(hProcess,
639 ProcessQuotaLimits,
640 &QuotaLimits,
641 sizeof(QuotaLimits),
642 NULL);
643
644 if(!NT_SUCCESS(Status))
645 {
646 SetLastErrorByStatus(Status);
647 return FALSE;
648 }
649
650 /* empty the working set */
651 QuotaLimits.MinimumWorkingSetSize = -1;
652 QuotaLimits.MaximumWorkingSetSize = -1;
653
654 /* set the working set */
655 Status = NtSetInformationProcess(hProcess,
656 ProcessQuotaLimits,
657 &QuotaLimits,
658 sizeof(QuotaLimits));
659 if(!NT_SUCCESS(Status))
660 {
661 SetLastErrorByStatus(Status);
662 return FALSE;
663 }
664
665 return TRUE;
666 }
667
668
669 /*
670 * @implemented
671 */
672 BOOL
673 STDCALL
674 EnumDeviceDrivers(LPVOID *lpImageBase,
675 DWORD cb,
676 LPDWORD lpcbNeeded)
677 {
678 ENUM_DEVICE_DRIVERS_CONTEXT Context;
679 NTSTATUS Status;
680
681 if(cb == 0 || lpImageBase == NULL)
682 {
683 *lpcbNeeded = 0;
684 return TRUE;
685 }
686
687 cb /= sizeof(PVOID);
688
689 Context.lpImageBase = lpImageBase;
690 Context.nCount = cb;
691
692 Status = PsaEnumerateSystemModules(EnumDeviceDriversCallback, &Context);
693
694 /* return the count of bytes returned */
695 *lpcbNeeded = (cb - Context.nCount) * sizeof(PVOID);
696
697 if(!NT_SUCCESS(Status) && (Status != STATUS_INFO_LENGTH_MISMATCH))
698 {
699 SetLastErrorByStatus(Status);
700 return FALSE;
701 }
702
703 return TRUE;
704 }
705
706
707 /*
708 * @implemented
709 */
710 BOOL
711 STDCALL
712 EnumProcesses(DWORD *lpidProcess,
713 DWORD cb,
714 LPDWORD lpcbNeeded)
715 {
716 ENUM_PROCESSES_CONTEXT Context;
717 NTSTATUS Status;
718
719 cb /= sizeof(DWORD);
720
721 if(cb == 0 || lpidProcess == NULL)
722 {
723 *lpcbNeeded = 0;
724 return TRUE;
725 }
726
727 Context.lpidProcess = lpidProcess;
728 Context.nCount = cb;
729
730 /* enumerate the process ids */
731 Status = PsaEnumerateProcesses(EnumProcessesCallback, &Context);
732
733 *lpcbNeeded = (cb - Context.nCount) * sizeof(DWORD);
734
735 if(!NT_SUCCESS(Status) && (Status != STATUS_INFO_LENGTH_MISMATCH))
736 {
737 SetLastErrorByStatus(Status);
738 return FALSE;
739 }
740
741 return TRUE;
742 }
743
744
745 /*
746 * @implemented
747 */
748 BOOL
749 STDCALL
750 EnumProcessModules(HANDLE hProcess,
751 HMODULE *lphModule,
752 DWORD cb,
753 LPDWORD lpcbNeeded)
754 {
755 ENUM_PROCESS_MODULES_CONTEXT Context;
756 NTSTATUS Status;
757
758 cb /= sizeof(HMODULE);
759
760 if(cb == 0 || lphModule == NULL)
761 {
762 *lpcbNeeded = 0;
763 return TRUE;
764 }
765
766 Context.lphModule = lphModule;
767 Context.nCount = cb;
768
769 /* enumerate the process modules */
770 Status = PsaEnumerateProcessModules(hProcess, EnumProcessModulesCallback, &Context);
771
772 *lpcbNeeded = (cb - Context.nCount) * sizeof(DWORD);
773
774 if(!NT_SUCCESS(Status) && (Status != STATUS_INFO_LENGTH_MISMATCH))
775 {
776 SetLastErrorByStatus(Status);
777 return FALSE;
778 }
779
780 return TRUE;
781 }
782
783
784 /*
785 * @implemented
786 */
787 DWORD
788 STDCALL
789 GetDeviceDriverBaseNameA(LPVOID ImageBase,
790 LPSTR lpBaseName,
791 DWORD nSize)
792 {
793 return InternalGetDeviceDriverName(FALSE, FALSE, ImageBase, lpBaseName, nSize);
794 }
795
796
797 /*
798 * @implemented
799 */
800 DWORD
801 STDCALL
802 GetDeviceDriverFileNameA(LPVOID ImageBase,
803 LPSTR lpFilename,
804 DWORD nSize)
805 {
806 return InternalGetDeviceDriverName(FALSE, TRUE, ImageBase, lpFilename, nSize);
807 }
808
809
810 /*
811 * @implemented
812 */
813 DWORD
814 STDCALL
815 GetDeviceDriverBaseNameW(LPVOID ImageBase,
816 LPWSTR lpBaseName,
817 DWORD nSize)
818 {
819 return InternalGetDeviceDriverName(TRUE, FALSE, ImageBase, lpBaseName, nSize);
820 }
821
822
823 /*
824 * @implemented
825 */
826 DWORD
827 STDCALL
828 GetDeviceDriverFileNameW(LPVOID ImageBase,
829 LPWSTR lpFilename,
830 DWORD nSize)
831 {
832 return InternalGetDeviceDriverName(TRUE, TRUE, ImageBase, lpFilename, nSize);
833 }
834
835
836 /*
837 * @implemented
838 */
839 DWORD
840 STDCALL
841 GetMappedFileNameA(HANDLE hProcess,
842 LPVOID lpv,
843 LPSTR lpFilename,
844 DWORD nSize)
845 {
846 return InternalGetMappedFileName(FALSE, hProcess, lpv, lpFilename, nSize);
847 }
848
849
850 /*
851 * @implemented
852 */
853 DWORD
854 STDCALL
855 GetMappedFileNameW(HANDLE hProcess,
856 LPVOID lpv,
857 LPWSTR lpFilename,
858 DWORD nSize)
859 {
860 return InternalGetMappedFileName(TRUE, hProcess, lpv, lpFilename, nSize);
861 }
862
863
864 /*
865 * @implemented
866 */
867 DWORD
868 STDCALL
869 GetModuleBaseNameA(HANDLE hProcess,
870 HMODULE hModule,
871 LPSTR lpBaseName,
872 DWORD nSize)
873 {
874 GET_MODULE_INFORMATION_FLAGS Flags = {TRUE, FALSE, FALSE};
875 return InternalGetModuleInformation(hProcess, hModule, Flags, lpBaseName, nSize);
876 }
877
878
879 /*
880 * @implemented
881 */
882 DWORD
883 STDCALL
884 GetModuleBaseNameW(HANDLE hProcess,
885 HMODULE hModule,
886 LPWSTR lpBaseName,
887 DWORD nSize)
888 {
889 GET_MODULE_INFORMATION_FLAGS Flags = {TRUE, TRUE, FALSE};
890 return InternalGetModuleInformation(hProcess, hModule, Flags, lpBaseName, nSize);
891 }
892
893
894 /*
895 * @implemented
896 */
897 DWORD
898 STDCALL
899 GetModuleFileNameExA(HANDLE hProcess,
900 HMODULE hModule,
901 LPSTR lpFilename,
902 DWORD nSize)
903 {
904 GET_MODULE_INFORMATION_FLAGS Flags = {TRUE, FALSE, TRUE};
905 return InternalGetModuleInformation(hProcess, hModule, Flags, lpFilename, nSize);
906 }
907
908
909 /*
910 * @implemented
911 */
912 DWORD
913 STDCALL
914 GetModuleFileNameExW(HANDLE hProcess,
915 HMODULE hModule,
916 LPWSTR lpFilename,
917 DWORD nSize)
918 {
919 GET_MODULE_INFORMATION_FLAGS Flags = {TRUE, TRUE, TRUE};
920 return InternalGetModuleInformation(hProcess, hModule, Flags, lpFilename, nSize);
921 }
922
923
924 /*
925 * @implemented
926 */
927 BOOL
928 STDCALL
929 GetModuleInformation(HANDLE hProcess,
930 HMODULE hModule,
931 LPMODULEINFO lpmodinfo,
932 DWORD cb)
933 {
934 GET_MODULE_INFORMATION_FLAGS Flags = {FALSE, FALSE, FALSE};
935 return (BOOL)InternalGetModuleInformation(hProcess, hModule, Flags, lpmodinfo, cb);
936 }
937
938
939 /*
940 * @implemented
941 */
942 BOOL
943 STDCALL
944 InitializeProcessForWsWatch(HANDLE hProcess)
945 {
946 NTSTATUS Status;
947
948 Status = NtSetInformationProcess(hProcess,
949 ProcessWorkingSetWatch,
950 NULL,
951 0);
952 if(!NT_SUCCESS(Status))
953 {
954 SetLastErrorByStatus(Status);
955 return FALSE;
956 }
957
958 return TRUE;
959 }
960
961
962 /*
963 * @implemented
964 */
965 BOOL
966 STDCALL
967 GetWsChanges(HANDLE hProcess,
968 PPSAPI_WS_WATCH_INFORMATION lpWatchInfo,
969 DWORD cb)
970 {
971 NTSTATUS Status;
972
973 Status = NtQueryInformationProcess(hProcess,
974 ProcessWorkingSetWatch,
975 (PVOID)lpWatchInfo,
976 cb,
977 NULL);
978 if(!NT_SUCCESS(Status))
979 {
980 SetLastErrorByStatus(Status);
981 return FALSE;
982 }
983
984 return TRUE;
985 }
986
987
988 /*
989 * @implemented
990 */
991 DWORD
992 STDCALL
993 GetProcessImageFileNameW(HANDLE hProcess,
994 LPWSTR lpImageFileName,
995 DWORD nSize)
996 {
997 PUNICODE_STRING ImageFileName;
998 SIZE_T BufferSize;
999 NTSTATUS Status;
1000 DWORD Ret = 0;
1001
1002 BufferSize = sizeof(UNICODE_STRING) + (nSize * sizeof(WCHAR));
1003
1004 ImageFileName = (PUNICODE_STRING)LocalAlloc(LMEM_FIXED, BufferSize);
1005 if(ImageFileName != NULL)
1006 {
1007 Status = NtQueryInformationProcess(hProcess,
1008 ProcessImageFileName,
1009 ImageFileName,
1010 BufferSize,
1011 NULL);
1012 if(NT_SUCCESS(Status))
1013 {
1014 memcpy(lpImageFileName, ImageFileName->Buffer, ImageFileName->Length);
1015
1016 /* make sure the string is null-terminated! */
1017 lpImageFileName[ImageFileName->Length / sizeof(WCHAR)] = L'\0';
1018 Ret = ImageFileName->Length / sizeof(WCHAR);
1019 }
1020 else if(Status == STATUS_INFO_LENGTH_MISMATCH)
1021 {
1022 /* XP sets this error code for some reason if the buffer is too small */
1023 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1024 }
1025 else
1026 {
1027 SetLastErrorByStatus(Status);
1028 }
1029
1030 LocalFree((HLOCAL)ImageFileName);
1031 }
1032
1033 return Ret;
1034 }
1035
1036
1037 /*
1038 * @implemented
1039 */
1040 DWORD
1041 STDCALL
1042 GetProcessImageFileNameA(HANDLE hProcess,
1043 LPSTR lpImageFileName,
1044 DWORD nSize)
1045 {
1046 PUNICODE_STRING ImageFileName;
1047 SIZE_T BufferSize;
1048 NTSTATUS Status;
1049 DWORD Ret = 0;
1050
1051 BufferSize = sizeof(UNICODE_STRING) + (nSize * sizeof(WCHAR));
1052
1053 ImageFileName = (PUNICODE_STRING)LocalAlloc(LMEM_FIXED, BufferSize);
1054 if(ImageFileName != NULL)
1055 {
1056 Status = NtQueryInformationProcess(hProcess,
1057 ProcessImageFileName,
1058 ImageFileName,
1059 BufferSize,
1060 NULL);
1061 if(NT_SUCCESS(Status))
1062 {
1063 WideCharToMultiByte(CP_ACP,
1064 0,
1065 ImageFileName->Buffer,
1066 ImageFileName->Length / sizeof(WCHAR),
1067 lpImageFileName,
1068 nSize,
1069 NULL,
1070 NULL);
1071
1072 /* make sure the string is null-terminated! */
1073 lpImageFileName[ImageFileName->Length / sizeof(WCHAR)] = '\0';
1074 Ret = ImageFileName->Length / sizeof(WCHAR);
1075 }
1076 else if(Status == STATUS_INFO_LENGTH_MISMATCH)
1077 {
1078 /* XP sets this error code for some reason if the buffer is too small */
1079 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1080 }
1081 else
1082 {
1083 SetLastErrorByStatus(Status);
1084 }
1085
1086 LocalFree((HLOCAL)ImageFileName);
1087 }
1088
1089 return Ret;
1090 }
1091
1092
1093 /*
1094 * @implemented
1095 */
1096 BOOL
1097 STDCALL
1098 EnumPageFilesA(PENUM_PAGE_FILE_CALLBACKA pCallbackRoutine,
1099 LPVOID lpContext)
1100 {
1101 INTERNAL_ENUM_PAGE_FILES_CONTEXT Context;
1102
1103 Context.pCallbackRoutine = pCallbackRoutine;
1104 Context.lpContext = lpContext;
1105
1106 return EnumPageFilesW(InternalAnsiPageFileCallback, &Context);
1107 }
1108
1109
1110 /*
1111 * @implemented
1112 */
1113 BOOL
1114 STDCALL
1115 EnumPageFilesW(PENUM_PAGE_FILE_CALLBACKW pCallbackRoutine,
1116 LPVOID lpContext)
1117 {
1118 NTSTATUS Status;
1119 PVOID Buffer;
1120 ULONG BufferSize = 0;
1121 BOOL Ret = FALSE;
1122
1123 for(;;)
1124 {
1125 BufferSize += 0x1000;
1126 Buffer = LocalAlloc(LMEM_FIXED, BufferSize);
1127 if(Buffer == NULL)
1128 {
1129 return FALSE;
1130 }
1131
1132 Status = NtQuerySystemInformation(SystemPageFileInformation,
1133 Buffer,
1134 BufferSize,
1135 NULL);
1136 if(Status == STATUS_INFO_LENGTH_MISMATCH)
1137 {
1138 LocalFree((HLOCAL)Buffer);
1139 }
1140 else
1141 {
1142 break;
1143 }
1144 }
1145
1146 if(NT_SUCCESS(Status))
1147 {
1148 ENUM_PAGE_FILE_INFORMATION Information;
1149 PSYSTEM_PAGEFILE_INFORMATION pfi = (PSYSTEM_PAGEFILE_INFORMATION)Buffer;
1150 ULONG Offset = 0;
1151
1152 do
1153 {
1154 PWCHAR Colon;
1155
1156 pfi = (PSYSTEM_PAGEFILE_INFORMATION)((ULONG_PTR)pfi + Offset);
1157
1158 Information.cb = sizeof(Information);
1159 Information.Reserved = 0;
1160 Information.TotalSize = pfi->TotalSize;
1161 Information.TotalInUse = pfi->TotalInUse;
1162 Information.PeakUsage = pfi->PeakUsage;
1163
1164 /* strip the \??\ prefix from the file name. We do this by searching for the first
1165 : character and then just change Buffer to point to the previous character. */
1166
1167 Colon = wcschr(pfi->PageFileName.Buffer, L':');
1168 if(Colon != NULL)
1169 {
1170 pfi->PageFileName.Buffer = --Colon;
1171 }
1172
1173 /* FIXME - looks like the PageFileName string is always NULL-terminated on win.
1174 At least I haven't encountered a different case so far, we should
1175 propably manually NULL-terminate the string here... */
1176
1177 if(!pCallbackRoutine(lpContext, &Information, pfi->PageFileName.Buffer))
1178 {
1179 break;
1180 }
1181
1182 Offset = pfi->NextEntryOffset;
1183 } while(Offset != 0);
1184
1185 Ret = TRUE;
1186 }
1187 else
1188 {
1189 SetLastErrorByStatus(Status);
1190 }
1191
1192 LocalFree((HLOCAL)Buffer);
1193
1194 return Ret;
1195 }
1196
1197
1198 /*
1199 * @implemented
1200 */
1201 BOOL
1202 STDCALL
1203 GetPerformanceInfo(PPERFORMANCE_INFORMATION pPerformanceInformation,
1204 DWORD cb)
1205 {
1206 SYSTEM_PERFORMANCE_INFORMATION spi;
1207 SYSTEM_BASIC_INFORMATION sbi;
1208 SYSTEM_HANDLE_INFORMATION shi;
1209 PSYSTEM_PROCESS_INFORMATION ProcessInfo;
1210 ULONG BufferSize, ProcOffset, ProcessCount, ThreadCount;
1211 PVOID Buffer;
1212 NTSTATUS Status;
1213
1214 Status = NtQuerySystemInformation(SystemPerformanceInformation,
1215 &spi,
1216 sizeof(spi),
1217 NULL);
1218 if(!NT_SUCCESS(Status))
1219 {
1220 SetLastErrorByStatus(Status);
1221 return FALSE;
1222 }
1223
1224 Status = NtQuerySystemInformation(SystemBasicInformation,
1225 &sbi,
1226 sizeof(sbi),
1227 NULL);
1228 if(!NT_SUCCESS(Status))
1229 {
1230 SetLastErrorByStatus(Status);
1231 return FALSE;
1232 }
1233
1234 /*
1235 * allocate enough memory to get a dump of all processes and threads
1236 */
1237 BufferSize = 0;
1238 for(;;)
1239 {
1240 BufferSize += 0x10000;
1241 Buffer = (PVOID)LocalAlloc(LMEM_FIXED, BufferSize);
1242 if(Buffer == NULL)
1243 {
1244 return FALSE;
1245 }
1246
1247 Status = NtQuerySystemInformation(SystemProcessInformation,
1248 Buffer,
1249 BufferSize,
1250 NULL);
1251 if(Status == STATUS_INFO_LENGTH_MISMATCH)
1252 {
1253 LocalFree((HLOCAL)Buffer);
1254 }
1255 else
1256 {
1257 break;
1258 }
1259 }
1260
1261 if(!NT_SUCCESS(Status))
1262 {
1263 LocalFree((HLOCAL)Buffer);
1264 SetLastErrorByStatus(Status);
1265 return FALSE;
1266 }
1267
1268 /*
1269 * determine the process and thread count
1270 */
1271 ProcessCount = ThreadCount = ProcOffset = 0;
1272 ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)Buffer;
1273 do
1274 {
1275 ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)((ULONG_PTR)ProcessInfo + ProcOffset);
1276 ProcessCount++;
1277 ThreadCount += ProcessInfo->NumberOfThreads;
1278
1279 ProcOffset = ProcessInfo->NextEntryOffset;
1280 } while(ProcOffset != 0);
1281
1282 LocalFree((HLOCAL)Buffer);
1283
1284 /*
1285 * it's enough to supply a SYSTEM_HANDLE_INFORMATION structure as buffer. Even
1286 * though it returns STATUS_INFO_LENGTH_MISMATCH, it already sets the NumberOfHandles
1287 * field which is all we're looking for anyway.
1288 */
1289 Status = NtQuerySystemInformation(SystemHandleInformation,
1290 &shi,
1291 sizeof(shi),
1292 NULL);
1293 if(!NT_SUCCESS(Status) && (Status != STATUS_INFO_LENGTH_MISMATCH))
1294 {
1295 SetLastErrorByStatus(Status);
1296 return FALSE;
1297 }
1298
1299 /*
1300 * all required information collected, fill the structure
1301 */
1302
1303 pPerformanceInformation->cb = sizeof(PERFORMANCE_INFORMATION);
1304 pPerformanceInformation->CommitTotal = spi.CommittedPages;
1305 pPerformanceInformation->CommitLimit = spi.CommitLimit;
1306 pPerformanceInformation->CommitPeak = spi.PeakCommitment;
1307 pPerformanceInformation->PhysicalTotal = sbi.NumberOfPhysicalPages;
1308 pPerformanceInformation->PhysicalAvailable = spi.AvailablePages;
1309 pPerformanceInformation->SystemCache = 0; /* FIXME - where to get this information from? */
1310 pPerformanceInformation->KernelTotal = spi.PagedPoolPages + spi.NonPagedPoolPages;
1311 pPerformanceInformation->KernelPaged = spi.PagedPoolPages;
1312 pPerformanceInformation->KernelNonpaged = spi.NonPagedPoolPages;
1313 pPerformanceInformation->PageSize = sbi.PageSize;
1314 pPerformanceInformation->HandleCount = shi.NumberOfHandles;
1315 pPerformanceInformation->ProcessCount = ProcessCount;
1316 pPerformanceInformation->ThreadCount = ThreadCount;
1317
1318 return TRUE;
1319 }
1320
1321
1322 /*
1323 * @implemented
1324 */
1325 BOOL
1326 STDCALL
1327 GetProcessMemoryInfo(HANDLE Process,
1328 PPROCESS_MEMORY_COUNTERS ppsmemCounters,
1329 DWORD cb)
1330 {
1331 NTSTATUS Status;
1332 VM_COUNTERS vmc;
1333 BOOL Ret = FALSE;
1334
1335 /* XP's implementation secures access to ppsmemCounters in SEH, we should behave
1336 similar so we can return the proper error codes when bad pointers are passed
1337 to this function! */
1338
1339 _SEH_TRY
1340 {
1341 if(cb < sizeof(PROCESS_MEMORY_COUNTERS))
1342 {
1343 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1344 _SEH_LEAVE;
1345 }
1346
1347 /* ppsmemCounters->cb isn't checked at all! */
1348
1349 Status = NtQueryInformationProcess(Process,
1350 ProcessVmCounters,
1351 &vmc,
1352 sizeof(vmc),
1353 NULL);
1354 if(!NT_SUCCESS(Status))
1355 {
1356 SetLastErrorByStatus(Status);
1357 _SEH_LEAVE;
1358 }
1359
1360 /* fill the structure with the collected information, in case of bad pointers
1361 SEH will catch the exception and set the appropriate error code */
1362 ppsmemCounters->cb = sizeof(PROCESS_MEMORY_COUNTERS);
1363 ppsmemCounters->PageFaultCount = vmc.PageFaultCount;
1364 ppsmemCounters->PeakWorkingSetSize = vmc.PeakWorkingSetSize;
1365 ppsmemCounters->WorkingSetSize = vmc.WorkingSetSize;
1366 ppsmemCounters->QuotaPeakPagedPoolUsage = vmc.QuotaPeakPagedPoolUsage;
1367 ppsmemCounters->QuotaPagedPoolUsage = vmc.QuotaPagedPoolUsage;
1368 ppsmemCounters->QuotaPeakNonPagedPoolUsage = vmc.QuotaPeakNonPagedPoolUsage;
1369 ppsmemCounters->QuotaNonPagedPoolUsage = vmc.QuotaNonPagedPoolUsage;
1370 ppsmemCounters->PagefileUsage = vmc.PagefileUsage;
1371 ppsmemCounters->PeakPagefileUsage = vmc.PeakPagefileUsage;
1372
1373 Ret = TRUE;
1374 }
1375 _SEH_HANDLE
1376 {
1377 SetLastErrorByStatus(_SEH_GetExceptionCode());
1378 }
1379 _SEH_END;
1380
1381 return Ret;
1382 }
1383
1384
1385 /*
1386 * @implemented
1387 */
1388 BOOL
1389 STDCALL
1390 QueryWorkingSet(HANDLE hProcess,
1391 PVOID pv,
1392 DWORD cb)
1393 {
1394 NTSTATUS Status;
1395
1396 Status = NtQueryVirtualMemory(hProcess,
1397 NULL,
1398 MemoryWorkingSetList,
1399 pv,
1400 cb,
1401 NULL);
1402 if(!NT_SUCCESS(Status))
1403 {
1404 SetLastErrorByStatus(Status);
1405 return FALSE;
1406 }
1407
1408 return TRUE;
1409 }
1410
1411 /* EOF */