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>
19 #include <ddk/ntddk.h>
20 #include <internal/psapi.h>
23 BOOL STDCALL EmptyWorkingSet(HANDLE hProcess)
26 QUOTA_LIMITS qlProcessQuota;
28 /* query the working set */
29 nErrCode = NtQueryInformationProcess
34 sizeof(qlProcessQuota),
39 if(!NT_SUCCESS(nErrCode))
42 /* empty the working set */
43 qlProcessQuota.MinimumWorkingSetSize = -1;
44 qlProcessQuota.MaximumWorkingSetSize = -1;
46 /* set the working set */
47 nErrCode = NtSetInformationProcess
52 sizeof(qlProcessQuota)
56 if(NT_SUCCESS(nErrCode))
61 SetLastError(RtlNtStatusToDosError(nErrCode));
65 /* EnumDeviceDrivers */
66 /* callback context */
67 typedef struct _ENUM_DEVICE_DRIVERS_CONTEXT
71 } ENUM_DEVICE_DRIVERS_CONTEXT, *PENUM_DEVICE_DRIVERS_CONTEXT;
73 /* callback routine */
74 NTSTATUS STDCALL EnumDeviceDriversCallback
77 IN PSYSTEM_MODULE_ENTRY CurrentModule,
78 IN OUT PVOID CallbackContext
81 register PENUM_DEVICE_DRIVERS_CONTEXT peddcContext =
82 (PENUM_DEVICE_DRIVERS_CONTEXT)CallbackContext;
84 /* no more buffer space */
85 if(peddcContext->nCount == 0)
86 return STATUS_INFO_LENGTH_MISMATCH;
88 /* return current module */
89 *(peddcContext->lpImageBase) = CurrentModule->BaseAddress;
91 /* go to next array slot */
92 (peddcContext->lpImageBase) ++;
93 (peddcContext->nCount) --;
95 return STATUS_SUCCESS;
98 /* exported interface */
99 BOOL STDCALL EnumDeviceDrivers
106 register NTSTATUS nErrCode;
107 ENUM_DEVICE_DRIVERS_CONTEXT eddcContext = {lpImageBase, cb / sizeof(PVOID)};
111 /* do nothing if the buffer is empty */
112 if(cb == 0 || lpImageBase == NULL)
118 /* enumerate the system modules */
119 nErrCode = PsaEnumerateSystemModules(&EnumDeviceDriversCallback, &eddcContext);
121 /* return the count of bytes returned */
122 *lpcbNeeded = (cb - eddcContext.nCount) * sizeof(PVOID);
125 if(NT_SUCCESS(nErrCode) || nErrCode == STATUS_INFO_LENGTH_MISMATCH)
130 SetLastError(RtlNtStatusToDosError(nErrCode));
136 /* callback context */
137 typedef struct _ENUM_PROCESSES_CONTEXT
141 } ENUM_PROCESSES_CONTEXT, *PENUM_PROCESSES_CONTEXT;
143 /* callback routine */
144 NTSTATUS STDCALL EnumProcessesCallback
146 IN PSYSTEM_PROCESS_INFORMATION CurrentProcess,
147 IN OUT PVOID CallbackContext
150 register PENUM_PROCESSES_CONTEXT pepcContext =
151 (PENUM_PROCESSES_CONTEXT)CallbackContext;
153 /* no more buffer space */
154 if(pepcContext->nCount == 0)
155 return STATUS_INFO_LENGTH_MISMATCH;
157 /* return current process */
158 *(pepcContext->lpidProcess) = CurrentProcess->ProcessId;
160 /* go to next array slot */
161 (pepcContext->lpidProcess) ++;
162 (pepcContext->nCount) --;
164 return STATUS_SUCCESS;
167 /* exported interface */
168 BOOL STDCALL EnumProcesses
175 register NTSTATUS nErrCode;
176 ENUM_PROCESSES_CONTEXT epcContext = {lpidProcess, cb / sizeof(DWORD)};
180 /* do nothing if the buffer is empty */
181 if(cb == 0 || lpidProcess == NULL)
187 /* enumerate the process ids */
188 nErrCode = PsaEnumerateProcesses(&EnumProcessesCallback, &epcContext);
190 *lpcbNeeded = (cb - epcContext.nCount) * sizeof(DWORD);
193 if(NT_SUCCESS(nErrCode) || nErrCode == STATUS_INFO_LENGTH_MISMATCH)
198 SetLastError(RtlNtStatusToDosError(nErrCode));
203 /* EnumProcessModules */
204 /* callback context */
205 typedef struct _ENUM_PROCESS_MODULES_CONTEXT
209 } ENUM_PROCESS_MODULES_CONTEXT, *PENUM_PROCESS_MODULES_CONTEXT;
211 /* callback routine */
212 NTSTATUS STDCALL EnumProcessModulesCallback
214 IN HANDLE ProcessHandle,
215 IN PLDR_MODULE CurrentModule,
216 IN OUT PVOID CallbackContext
219 register PENUM_PROCESS_MODULES_CONTEXT pepmcContext =
220 (PENUM_PROCESS_MODULES_CONTEXT)CallbackContext;
222 /* no more buffer space */
223 if(pepmcContext->nCount == 0)
224 return STATUS_INFO_LENGTH_MISMATCH;
226 /* return current process */
227 *(pepmcContext->lphModule) = CurrentModule->BaseAddress;
229 /* go to next array slot */
230 (pepmcContext->lphModule) ++;
231 (pepmcContext->nCount) --;
233 return STATUS_SUCCESS;
236 /* exported interface */
237 BOOL STDCALL EnumProcessModules(
244 register NTSTATUS nErrCode;
245 ENUM_PROCESS_MODULES_CONTEXT epmcContext = {lphModule, cb / sizeof(HMODULE)};
249 /* do nothing if the buffer is empty */
250 if(cb == 0 || lphModule == NULL)
256 /* enumerate the process modules */
257 nErrCode = PsaEnumerateProcessModules
260 &EnumProcessModulesCallback,
264 *lpcbNeeded = (cb - epmcContext.nCount) * sizeof(DWORD);
267 if(NT_SUCCESS(nErrCode) || nErrCode == STATUS_INFO_LENGTH_MISMATCH)
272 SetLastError(RtlNtStatusToDosError(nErrCode));
277 /* GetDeviceDriverBase/FileName */
278 /* common callback context */
279 typedef struct _GET_DEVICE_DRIVER_NAME_CONTEXT
284 ULONG bFullName:sizeof(ULONG) * 8 / 2;
285 ULONG bUnicode:sizeof(ULONG) * 8 / 2;
292 LPWSTR lpUnicodeName;
294 } GET_DEVICE_DRIVER_NAME_CONTEXT, *PGET_DEVICE_DRIVER_NAME_CONTEXT;
296 /* common callback routine */
297 NTSTATUS STDCALL GetDeviceDriverNameCallback
299 IN ULONG ModuleCount,
300 IN PSYSTEM_MODULE_ENTRY CurrentModule,
301 IN OUT PVOID CallbackContext
304 register PGET_DEVICE_DRIVER_NAME_CONTEXT pgddncContext =
305 (PGET_DEVICE_DRIVER_NAME_CONTEXT) CallbackContext;
308 if(pgddncContext->ImageBase == CurrentModule->BaseAddress)
310 register PCHAR pcModuleName;
313 /* get the full name or just the filename part */
314 if(pgddncContext->bFullName)
315 pcModuleName = &CurrentModule->Name[0];
317 pcModuleName = &CurrentModule->Name[CurrentModule->PathLength];
319 /* get the length of the name */
320 l = strlen(pcModuleName);
322 /* if user buffer smaller than the name */
323 if(pgddncContext->nSize <= l)
324 /* use the user buffer's length */
325 l = pgddncContext->nSize;
326 /* if user buffer larger than the name */
329 /* enough space for the null terminator */
331 pgddncContext->nSize = l;
334 /* copy the string */
335 if(pgddncContext->bUnicode)
337 /* Unicode: convert and copy */
338 ANSI_STRING strAnsi = {l, l, pcModuleName};
339 UNICODE_STRING wstrUnicode =
343 pgddncContext->lpUnicodeName
345 /* driver names should always be in language-neutral ASCII, so we don't
346 bother calling AreFileApisANSI() */
347 RtlAnsiStringToUnicodeString(&wstrUnicode, &strAnsi, FALSE);
350 /* ANSI/OEM: direct copy */
351 memcpy(pgddncContext->lpAnsiName, pcModuleName, l);
353 /* terminate the enumeration */
354 return STATUS_NO_MORE_FILES;
356 /* continue searching */
358 return STATUS_SUCCESS;
361 /* common internal implementation */
362 DWORD FASTCALL internalGetDeviceDriverName(
370 register NTSTATUS nErrCode;
371 GET_DEVICE_DRIVER_NAME_CONTEXT gddncContext =
374 { bFullName, bUnicode },
380 if(lpName == NULL || nSize == 0)
383 /* invalid image base */
384 if(ImageBase == NULL)
386 SetLastError(ERROR_INVALID_HANDLE);
390 /* start the enumeration */
391 nErrCode = PsaEnumerateSystemModules
393 &GetDeviceDriverNameCallback,
397 if(nErrCode == STATUS_NO_MORE_FILES)
398 /* module was found, return string size */
399 return gddncContext.nSize;
402 if(NT_SUCCESS(nErrCode))
403 /* module was not found */
404 SetLastError(ERROR_INVALID_HANDLE);
406 /* an error occurred */
407 SetLastError(RtlNtStatusToDosError(nErrCode));
414 /* exported interfaces */
417 - nSize is not, as stated by Microsoft's documentation, the byte size, but the
418 count of characters in the buffer
419 - the return value is the count of characters copied into the buffer
420 - the functions don't attempt to null-terminate the string
422 DWORD STDCALL GetDeviceDriverBaseNameA(
428 return internalGetDeviceDriverName(FALSE, FALSE, ImageBase, lpBaseName, nSize);
431 DWORD STDCALL GetDeviceDriverFileNameA(
437 return internalGetDeviceDriverName(FALSE, TRUE, ImageBase, lpFilename, nSize);
440 DWORD STDCALL GetDeviceDriverBaseNameW(
446 return internalGetDeviceDriverName(TRUE, FALSE, ImageBase, lpBaseName, nSize);
449 DWORD STDCALL GetDeviceDriverFileNameW(
455 return internalGetDeviceDriverName(TRUE, TRUE, ImageBase, lpFilename, nSize);
458 /* GetMappedFileName */
459 /* common internal implementation */
460 DWORD FASTCALL internalGetMappedFileName(
468 register NTSTATUS nErrCode;
469 register ULONG nBufSize;
470 PMEMORY_SECTION_NAME pmsnName;
473 if(nSize == 0 || (LPSTR)lpName == NULL)
476 if(nSize > (0xFFFF / sizeof(WCHAR)))
477 /* if the user buffer contains more characters than would fit in an
478 UNICODE_STRING, limit the buffer size. RATIONALE: we don't limit buffer
479 size elsewhere because here superfluous buffer size will mean a larger
481 nBufSize = 0xFFFF / sizeof(WCHAR);
483 nBufSize = nSize * sizeof(WCHAR);
485 /* allocate the memory */
486 pmsnName = malloc(nBufSize + offsetof(MEMORY_SECTION_NAME, NameBuffer));
491 SetLastError(ERROR_OUTOFMEMORY);
495 /* initialize the destination buffer */
496 pmsnName->SectionFileName.Length = 0;
497 pmsnName->SectionFileName.Length = nBufSize;
504 nErrCode = NtQueryVirtualMemory
514 if(!NT_SUCCESS(nErrCode))
517 SetLastError(RtlNtStatusToDosError(nErrCode));
520 /* free the buffer */
529 /* destination is an Unicode string: direct copy */
533 pmsnName->NameBuffer,
534 pmsnName->SectionFileName.Length
539 /* free the buffer */
543 if(pmsnName->SectionFileName.Length < nSize)
545 /* null-terminate the string */
546 ((LPWSTR)lpName)[pmsnName->SectionFileName.Length] = 0;
547 return pmsnName->SectionFileName.Length + 1;
550 return pmsnName->SectionFileName.Length;
554 ANSI_STRING strAnsi = {0, nSize, (LPSTR)lpName};
556 if(AreFileApisANSI())
557 /* destination is an ANSI string: convert and copy */
558 RtlUnicodeStringToAnsiString(&strAnsi, &pmsnName->SectionFileName, FALSE);
560 /* destination is an OEM string: convert and copy */
561 RtlUnicodeStringToOemString(&strAnsi, &pmsnName->SectionFileName, FALSE);
565 /* free the buffer */
569 if(strAnsi.Length < nSize)
571 /* null-terminate the string */
572 ((LPSTR)lpName)[strAnsi.Length] = 0;
573 return strAnsi.Length + 1;
576 return strAnsi.Length;
588 /* exported interfaces */
589 DWORD STDCALL GetMappedFileNameA(
596 return internalGetMappedFileName(FALSE, hProcess, lpv, lpFilename, nSize);
599 DWORD STDCALL GetMappedFileNameW(
606 return internalGetMappedFileName(TRUE, hProcess, lpv, lpFilename, nSize);
609 /* GetModuleInformation */
610 /* common callback context */
611 typedef struct _GET_MODULE_INFORMATION_FLAGS
613 ULONG bWantName:sizeof(ULONG) * 8 / 4;
614 ULONG bUnicode:sizeof(ULONG) * 8 / 4;
615 ULONG bFullName:sizeof(ULONG) * 8 / 4;
616 } GET_MODULE_INFORMATION_FLAGS, *PGET_MODULE_INFORMATION_FLAGS;
618 typedef struct _GET_MODULE_INFORMATION_CONTEXT
621 GET_MODULE_INFORMATION_FLAGS Flags;
625 LPWSTR lpUnicodeName;
627 LPMODULEINFO lpmodinfo;
630 } GET_MODULE_INFORMATION_CONTEXT, *PGET_MODULE_INFORMATION_CONTEXT;
632 /* common callback */
633 NTSTATUS STDCALL GetModuleInformationCallback
635 IN HANDLE ProcessHandle,
636 IN PLDR_MODULE CurrentModule,
637 IN OUT PVOID CallbackContext
640 register PGET_MODULE_INFORMATION_CONTEXT pgmicContext =
641 (PGET_MODULE_INFORMATION_CONTEXT)CallbackContext;
643 /* found the module we were looking for */
644 if(CurrentModule->BaseAddress == pgmicContext->hModule)
646 /* we want the module name */
647 if(pgmicContext->Flags.bWantName)
649 register NTSTATUS nErrCode;
650 register PUNICODE_STRING pwstrSource;
653 if(pgmicContext->Flags.bFullName)
655 pwstrSource = &(CurrentModule->FullDllName);
658 pwstrSource = &(CurrentModule->BaseDllName);
661 pwstrSource->Length -= pwstrSource->Length % sizeof(WCHAR);
663 /* l is the byte size of the user buffer */
664 l = pgmicContext->nBufSize * sizeof(WCHAR);
666 /* if the user buffer has room for the string and a null terminator */
667 if(l >= (pwstrSource->Length + sizeof(WCHAR)))
669 /* limit the buffer size */
670 l = pwstrSource->Length;
672 /* null-terminate the string */
673 if(pgmicContext->Flags.bUnicode)
674 pgmicContext->lpUnicodeName[l / sizeof(WCHAR)] = 0;
676 pgmicContext->lpAnsiName[l / sizeof(WCHAR)] = 0;
679 if(pgmicContext->Flags.bUnicode)
681 /* Unicode: direct copy */
682 /* NOTE: I've chosen not to check for ProcessHandle == NtCurrentProcess(),
683 this function is complicated enough as it is */
684 nErrCode = NtReadVirtualMemory
688 pgmicContext->lpUnicodeName,
693 if(NT_SUCCESS(nErrCode))
694 pgmicContext->nBufSize = l / sizeof(WCHAR);
697 pgmicContext->nBufSize = 0;
703 /* ANSI/OEM: convert and copy */
704 register LPWSTR pwcUnicodeBuf;
705 ANSI_STRING strAnsi = {0, pgmicContext->nBufSize, pgmicContext->lpAnsiName};
706 UNICODE_STRING wstrUnicodeBuf;
708 /* allocate the local buffer */
709 pwcUnicodeBuf = malloc(pwstrSource->Length);
715 if(pwcUnicodeBuf == NULL)
718 return STATUS_NO_MEMORY;
721 nErrCode = STATUS_NO_MEMORY;
726 /* copy the string in the local buffer */
727 nErrCode = NtReadVirtualMemory
736 if(!NT_SUCCESS(nErrCode))
744 /* initialize Unicode string buffer */
745 wstrUnicodeBuf.Length = wstrUnicodeBuf.MaximumLength = l;
746 wstrUnicodeBuf.Buffer = pwcUnicodeBuf;
748 /* convert and copy */
749 if(AreFileApisANSI())
750 RtlUnicodeStringToAnsiString(&strAnsi, &wstrUnicodeBuf, FALSE);
752 RtlUnicodeStringToOemString(&strAnsi, &wstrUnicodeBuf, FALSE);
754 /* return the string size */
755 pgmicContext->nBufSize = strAnsi.Length;
760 /* free the buffer */
765 nErrCode = STATUS_NO_MORE_FILES;
768 /* free the buffer */
775 /* we want other module information */
778 register ULONG nSize = pgmicContext->nBufSize;
781 if(nSize >= sizeof(CurrentModule->BaseAddress))
783 pgmicContext->lpmodinfo->lpBaseOfDll = CurrentModule->BaseAddress;
784 nSize -= sizeof(CurrentModule->BaseAddress);
788 if(nSize >= sizeof(CurrentModule->SizeOfImage))
790 pgmicContext->lpmodinfo->SizeOfImage = CurrentModule->SizeOfImage;
791 nSize -= sizeof(CurrentModule->SizeOfImage);
795 if(nSize >= sizeof(CurrentModule->EntryPoint))
796 /* ??? FIXME? is "EntryPoint" just the offset, or the real address? */
797 pgmicContext->lpmodinfo->EntryPoint = (PVOID)CurrentModule->EntryPoint;
799 pgmicContext->nBufSize = TRUE;
802 return STATUS_NO_MORE_FILES;
805 return STATUS_SUCCESS;
808 /* common internal implementation */
809 DWORD FASTCALL internalGetModuleInformation(
812 GET_MODULE_INFORMATION_FLAGS Flags,
817 register NTSTATUS nErrCode;
818 GET_MODULE_INFORMATION_CONTEXT gmicContext =
827 nErrCode = PsaEnumerateProcessModules
830 &GetModuleInformationCallback,
834 if(nErrCode == STATUS_NO_MORE_FILES)
835 return gmicContext.nBufSize;
838 if(NT_SUCCESS(nErrCode))
839 SetLastError(ERROR_INVALID_HANDLE);
841 SetLastError(RtlNtStatusToDosError(nErrCode));
847 /* exported interfaces */
848 DWORD STDCALL GetModuleBaseNameA(
849 HANDLE hProcess, // handle to process
850 HMODULE hModule, // handle to module
851 LPSTR lpBaseName, // base name buffer
852 DWORD nSize // maximum characters to retrieve
855 register GET_MODULE_INFORMATION_FLAGS Flags = {TRUE, FALSE, FALSE};
856 return internalGetModuleInformation
866 DWORD STDCALL GetModuleBaseNameW(
867 HANDLE hProcess, // handle to process
868 HMODULE hModule, // handle to module
869 LPWSTR lpBaseName, // base name buffer
870 DWORD nSize // maximum characters to retrieve
873 register GET_MODULE_INFORMATION_FLAGS Flags = {TRUE, TRUE, FALSE};
874 return internalGetModuleInformation
884 DWORD STDCALL GetModuleFileNameExA(
885 HANDLE hProcess, // handle to process
886 HMODULE hModule, // handle to module
887 LPSTR lpFilename, // path buffer
888 DWORD nSize // maximum characters to retrieve
891 register GET_MODULE_INFORMATION_FLAGS Flags = {TRUE, FALSE, TRUE};
892 return internalGetModuleInformation
902 DWORD STDCALL GetModuleFileNameExW(
903 HANDLE hProcess, // handle to process
904 HMODULE hModule, // handle to module
905 LPWSTR lpFilename, // path buffer
906 DWORD nSize // maximum characters to retrieve
909 register GET_MODULE_INFORMATION_FLAGS Flags = {TRUE, TRUE, TRUE};
910 return internalGetModuleInformation
920 BOOL STDCALL GetModuleInformation(
921 HANDLE hProcess, // handle to process
922 HMODULE hModule, // handle to module
923 LPMODULEINFO lpmodinfo, // information buffer
924 DWORD cb // size of buffer
927 register GET_MODULE_INFORMATION_FLAGS Flags = {FALSE, FALSE, FALSE};
928 return (BOOL)internalGetModuleInformation