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>
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
76 IN PSYSTEM_MODULE_INFORMATION CurrentModule,
77 IN OUT PVOID CallbackContext
80 register PENUM_DEVICE_DRIVERS_CONTEXT peddcContext =
81 (PENUM_DEVICE_DRIVERS_CONTEXT)CallbackContext;
83 /* no more buffer space */
84 if(peddcContext->nCount == 0)
85 return STATUS_INFO_LENGTH_MISMATCH;
87 /* return current module */
88 *(peddcContext->lpImageBase) = CurrentModule->Base;
90 /* go to next array slot */
91 (peddcContext->lpImageBase) ++;
92 (peddcContext->nCount) --;
94 return STATUS_SUCCESS;
97 /* exported interface */
98 BOOL STDCALL EnumDeviceDrivers
105 register NTSTATUS nErrCode;
106 ENUM_DEVICE_DRIVERS_CONTEXT eddcContext = {lpImageBase, cb / sizeof(PVOID)};
110 /* do nothing if the buffer is empty */
111 if(cb == 0 || lpImageBase == NULL)
117 /* enumerate the system modules */
118 nErrCode = PsaEnumerateSystemModules(&EnumDeviceDriversCallback, &eddcContext);
120 /* return the count of bytes returned */
121 *lpcbNeeded = (cb - eddcContext.nCount) * sizeof(PVOID);
124 if(NT_SUCCESS(nErrCode) || nErrCode == STATUS_INFO_LENGTH_MISMATCH)
129 SetLastError(RtlNtStatusToDosError(nErrCode));
135 /* callback context */
136 typedef struct _ENUM_PROCESSES_CONTEXT
140 } ENUM_PROCESSES_CONTEXT, *PENUM_PROCESSES_CONTEXT;
142 /* callback routine */
143 NTSTATUS STDCALL EnumProcessesCallback
145 IN PSYSTEM_PROCESSES CurrentProcess,
146 IN OUT PVOID CallbackContext
149 register PENUM_PROCESSES_CONTEXT pepcContext =
150 (PENUM_PROCESSES_CONTEXT)CallbackContext;
152 /* no more buffer space */
153 if(pepcContext->nCount == 0)
154 return STATUS_INFO_LENGTH_MISMATCH;
156 /* return current process */
157 *(pepcContext->lpidProcess) = CurrentProcess->ProcessId;
159 /* go to next array slot */
160 (pepcContext->lpidProcess) ++;
161 (pepcContext->nCount) --;
163 return STATUS_SUCCESS;
166 /* exported interface */
168 @brief Enumerate the process identifiers of the currently active processes
170 @param lpidProcess Array that receives the list of process identifiers
171 @param cb Size of the @p lpidProcess array, in bytes
172 @param lpcbNeeded Number of bytes returned in the @p lpidProcess array
176 BOOL STDCALL EnumProcesses
183 register NTSTATUS nErrCode;
184 ENUM_PROCESSES_CONTEXT epcContext = {lpidProcess, cb / sizeof(DWORD)};
188 /* do nothing if the buffer is empty */
189 if(cb == 0 || lpidProcess == NULL)
195 /* enumerate the process ids */
196 nErrCode = PsaEnumerateProcesses
198 &EnumProcessesCallback,
202 *lpcbNeeded = (cb - epcContext.nCount) * sizeof(DWORD);
205 if(NT_SUCCESS(nErrCode) || nErrCode == STATUS_INFO_LENGTH_MISMATCH)
210 SetLastError(RtlNtStatusToDosError(nErrCode));
215 /* EnumProcessModules */
216 /* callback context */
217 typedef struct _ENUM_PROCESS_MODULES_CONTEXT
221 } ENUM_PROCESS_MODULES_CONTEXT, *PENUM_PROCESS_MODULES_CONTEXT;
223 /* callback routine */
224 NTSTATUS STDCALL EnumProcessModulesCallback
226 IN HANDLE ProcessHandle,
227 IN PLDR_MODULE CurrentModule,
228 IN OUT PVOID CallbackContext
231 register PENUM_PROCESS_MODULES_CONTEXT pepmcContext =
232 (PENUM_PROCESS_MODULES_CONTEXT)CallbackContext;
234 /* no more buffer space */
235 if(pepmcContext->nCount == 0)
236 return STATUS_INFO_LENGTH_MISMATCH;
238 /* return current process */
239 *(pepmcContext->lphModule) = CurrentModule->BaseAddress;
241 /* go to next array slot */
242 (pepmcContext->lphModule) ++;
243 (pepmcContext->nCount) --;
245 return STATUS_SUCCESS;
248 /* exported interface */
249 BOOL STDCALL EnumProcessModules(
256 register NTSTATUS nErrCode;
257 ENUM_PROCESS_MODULES_CONTEXT epmcContext = {lphModule, cb / sizeof(HMODULE)};
261 /* do nothing if the buffer is empty */
262 if(cb == 0 || lphModule == NULL)
268 /* enumerate the process modules */
269 nErrCode = PsaEnumerateProcessModules
272 &EnumProcessModulesCallback,
276 *lpcbNeeded = (cb - epmcContext.nCount) * sizeof(DWORD);
279 if(NT_SUCCESS(nErrCode) || nErrCode == STATUS_INFO_LENGTH_MISMATCH)
284 SetLastError(RtlNtStatusToDosError(nErrCode));
289 /* GetDeviceDriverBase/FileName */
290 /* common callback context */
291 typedef struct _GET_DEVICE_DRIVER_NAME_CONTEXT
296 ULONG bFullName:sizeof(ULONG) * 8 / 2;
297 ULONG bUnicode:sizeof(ULONG) * 8 / 2;
304 LPWSTR lpUnicodeName;
306 } GET_DEVICE_DRIVER_NAME_CONTEXT, *PGET_DEVICE_DRIVER_NAME_CONTEXT;
308 /* common callback routine */
309 NTSTATUS STDCALL GetDeviceDriverNameCallback
311 IN PSYSTEM_MODULE_INFORMATION CurrentModule,
312 IN OUT PVOID CallbackContext
315 register PGET_DEVICE_DRIVER_NAME_CONTEXT pgddncContext =
316 (PGET_DEVICE_DRIVER_NAME_CONTEXT) CallbackContext;
319 if(pgddncContext->ImageBase == CurrentModule->Base)
321 register PCHAR pcModuleName;
324 /* get the full name or just the filename part */
325 if(pgddncContext->bFullName)
326 pcModuleName = &CurrentModule->ImageName[0];
328 pcModuleName = &CurrentModule->ImageName[CurrentModule->ModuleNameOffset];
330 /* get the length of the name */
331 l = strlen(pcModuleName);
333 /* if user buffer smaller than the name */
334 if(pgddncContext->nSize <= l)
335 /* use the user buffer's length */
336 l = pgddncContext->nSize;
337 /* if user buffer larger than the name */
340 /* enough space for the null terminator */
342 pgddncContext->nSize = l;
345 /* copy the string */
346 if(pgddncContext->bUnicode)
348 /* Unicode: convert and copy */
349 ANSI_STRING strAnsi = {l, l, pcModuleName};
350 UNICODE_STRING wstrUnicode =
354 pgddncContext->lpUnicodeName
356 /* driver names should always be in language-neutral ASCII, so we don't
357 bother calling AreFileApisANSI() */
358 RtlAnsiStringToUnicodeString(&wstrUnicode, &strAnsi, FALSE);
361 /* ANSI/OEM: direct copy */
362 memcpy(pgddncContext->lpAnsiName, pcModuleName, l);
364 /* terminate the enumeration */
365 return STATUS_NO_MORE_FILES;
367 /* continue searching */
369 return STATUS_SUCCESS;
372 /* common internal implementation */
373 DWORD FASTCALL internalGetDeviceDriverName(
381 register NTSTATUS nErrCode;
382 GET_DEVICE_DRIVER_NAME_CONTEXT gddncContext =
385 { bFullName, bUnicode },
391 if(lpName == NULL || nSize == 0)
394 /* invalid image base */
395 if(ImageBase == NULL)
397 SetLastError(ERROR_INVALID_HANDLE);
401 /* start the enumeration */
402 nErrCode = PsaEnumerateSystemModules
404 &GetDeviceDriverNameCallback,
408 if(nErrCode == STATUS_NO_MORE_FILES)
409 /* module was found, return string size */
410 return gddncContext.nSize;
413 if(NT_SUCCESS(nErrCode))
414 /* module was not found */
415 SetLastError(ERROR_INVALID_HANDLE);
417 /* an error occurred */
418 SetLastError(RtlNtStatusToDosError(nErrCode));
425 /* exported interfaces */
428 - nSize is not, as stated by Microsoft's documentation, the byte size, but the
429 count of characters in the buffer
430 - the return value is the count of characters copied into the buffer
431 - the functions don't attempt to null-terminate the string
433 DWORD STDCALL GetDeviceDriverBaseNameA(
439 return internalGetDeviceDriverName(FALSE, FALSE, ImageBase, lpBaseName, nSize);
442 DWORD STDCALL GetDeviceDriverFileNameA(
448 return internalGetDeviceDriverName(FALSE, TRUE, ImageBase, lpFilename, nSize);
451 DWORD STDCALL GetDeviceDriverBaseNameW(
457 return internalGetDeviceDriverName(TRUE, FALSE, ImageBase, lpBaseName, nSize);
460 DWORD STDCALL GetDeviceDriverFileNameW(
466 return internalGetDeviceDriverName(TRUE, TRUE, ImageBase, lpFilename, nSize);
469 /* GetMappedFileName */
470 /* common internal implementation */
471 DWORD FASTCALL internalGetMappedFileName(
479 register NTSTATUS nErrCode;
480 register ULONG nBufSize;
481 PMEMORY_SECTION_NAME pmsnName;
484 if(nSize == 0 || (LPSTR)lpName == NULL)
487 if(nSize > (0xFFFF / sizeof(WCHAR)))
488 /* if the user buffer contains more characters than would fit in an
489 UNICODE_STRING, limit the buffer size. RATIONALE: we don't limit buffer
490 size elsewhere because here superfluous buffer size will mean a larger
492 nBufSize = 0xFFFF / sizeof(WCHAR);
494 nBufSize = nSize * sizeof(WCHAR);
496 /* allocate the memory */
497 pmsnName = PsaiMalloc(nBufSize + offsetof(MEMORY_SECTION_NAME, NameBuffer));
502 SetLastError(ERROR_OUTOFMEMORY);
506 /* initialize the destination buffer */
507 pmsnName->SectionFileName.Length = 0;
508 pmsnName->SectionFileName.Length = nBufSize;
515 nErrCode = NtQueryVirtualMemory
525 if(!NT_SUCCESS(nErrCode))
528 SetLastError(RtlNtStatusToDosError(nErrCode));
531 /* free the buffer */
540 /* destination is an Unicode string: direct copy */
544 pmsnName->NameBuffer,
545 pmsnName->SectionFileName.Length
550 /* free the buffer */
554 if(pmsnName->SectionFileName.Length < nSize)
556 /* null-terminate the string */
557 ((LPWSTR)lpName)[pmsnName->SectionFileName.Length] = 0;
558 return pmsnName->SectionFileName.Length + 1;
561 return pmsnName->SectionFileName.Length;
565 ANSI_STRING strAnsi = {0, nSize, (LPSTR)lpName};
567 if(AreFileApisANSI())
568 /* destination is an ANSI string: convert and copy */
569 RtlUnicodeStringToAnsiString(&strAnsi, &pmsnName->SectionFileName, FALSE);
571 /* destination is an OEM string: convert and copy */
572 RtlUnicodeStringToOemString(&strAnsi, &pmsnName->SectionFileName, FALSE);
576 /* free the buffer */
580 if(strAnsi.Length < nSize)
582 /* null-terminate the string */
583 ((LPSTR)lpName)[strAnsi.Length] = 0;
584 return strAnsi.Length + 1;
587 return strAnsi.Length;
599 /* exported interfaces */
600 DWORD STDCALL GetMappedFileNameA(
607 return internalGetMappedFileName(FALSE, hProcess, lpv, lpFilename, nSize);
610 DWORD STDCALL GetMappedFileNameW(
617 return internalGetMappedFileName(TRUE, hProcess, lpv, lpFilename, nSize);
620 /* GetModuleInformation */
621 /* common callback context */
622 typedef struct _GET_MODULE_INFORMATION_FLAGS
624 ULONG bWantName:sizeof(ULONG) * 8 / 4;
625 ULONG bUnicode:sizeof(ULONG) * 8 / 4;
626 ULONG bFullName:sizeof(ULONG) * 8 / 4;
627 } GET_MODULE_INFORMATION_FLAGS, *PGET_MODULE_INFORMATION_FLAGS;
629 typedef struct _GET_MODULE_INFORMATION_CONTEXT
632 GET_MODULE_INFORMATION_FLAGS Flags;
636 LPWSTR lpUnicodeName;
638 LPMODULEINFO lpmodinfo;
641 } GET_MODULE_INFORMATION_CONTEXT, *PGET_MODULE_INFORMATION_CONTEXT;
643 /* common callback */
644 NTSTATUS STDCALL GetModuleInformationCallback
646 IN HANDLE ProcessHandle,
647 IN PLDR_MODULE CurrentModule,
648 IN OUT PVOID CallbackContext
651 register PGET_MODULE_INFORMATION_CONTEXT pgmicContext =
652 (PGET_MODULE_INFORMATION_CONTEXT)CallbackContext;
654 /* found the module we were looking for */
655 if(CurrentModule->BaseAddress == pgmicContext->hModule)
657 /* we want the module name */
658 if(pgmicContext->Flags.bWantName)
660 register NTSTATUS nErrCode;
661 register PUNICODE_STRING pwstrSource;
664 if(pgmicContext->Flags.bFullName)
666 pwstrSource = &(CurrentModule->FullDllName);
669 pwstrSource = &(CurrentModule->BaseDllName);
672 pwstrSource->Length -= pwstrSource->Length % sizeof(WCHAR);
674 /* l is the byte size of the user buffer */
675 l = pgmicContext->nBufSize * sizeof(WCHAR);
677 /* if the user buffer has room for the string and a null terminator */
678 if(l >= (pwstrSource->Length + sizeof(WCHAR)))
680 /* limit the buffer size */
681 l = pwstrSource->Length;
683 /* null-terminate the string */
684 if(pgmicContext->Flags.bUnicode)
685 pgmicContext->lpUnicodeName[l / sizeof(WCHAR)] = 0;
687 pgmicContext->lpAnsiName[l / sizeof(WCHAR)] = 0;
690 if(pgmicContext->Flags.bUnicode)
692 /* Unicode: direct copy */
693 /* NOTE: I've chosen not to check for ProcessHandle == NtCurrentProcess(),
694 this function is complicated enough as it is */
695 nErrCode = NtReadVirtualMemory
699 pgmicContext->lpUnicodeName,
704 if(NT_SUCCESS(nErrCode))
705 pgmicContext->nBufSize = l / sizeof(WCHAR);
708 pgmicContext->nBufSize = 0;
714 /* ANSI/OEM: convert and copy */
715 register LPWSTR pwcUnicodeBuf;
716 ANSI_STRING strAnsi = {0, pgmicContext->nBufSize, pgmicContext->lpAnsiName};
717 UNICODE_STRING wstrUnicodeBuf;
719 /* allocate the local buffer */
720 pwcUnicodeBuf = PsaiMalloc(pwstrSource->Length);
726 if(pwcUnicodeBuf == NULL)
729 return STATUS_NO_MEMORY;
732 nErrCode = STATUS_NO_MEMORY;
737 /* copy the string in the local buffer */
738 nErrCode = NtReadVirtualMemory
747 if(!NT_SUCCESS(nErrCode))
755 /* initialize Unicode string buffer */
756 wstrUnicodeBuf.Length = wstrUnicodeBuf.MaximumLength = l;
757 wstrUnicodeBuf.Buffer = pwcUnicodeBuf;
759 /* convert and copy */
760 if(AreFileApisANSI())
761 RtlUnicodeStringToAnsiString(&strAnsi, &wstrUnicodeBuf, FALSE);
763 RtlUnicodeStringToOemString(&strAnsi, &wstrUnicodeBuf, FALSE);
765 /* return the string size */
766 pgmicContext->nBufSize = strAnsi.Length;
771 /* free the buffer */
772 PsaiFree(pwcUnicodeBuf);
776 nErrCode = STATUS_NO_MORE_FILES;
779 /* free the buffer */
780 PsaiFree(pwcUnicodeBuf);
786 /* we want other module information */
789 register ULONG nSize = pgmicContext->nBufSize;
792 if(nSize >= sizeof(CurrentModule->BaseAddress))
794 pgmicContext->lpmodinfo->lpBaseOfDll = CurrentModule->BaseAddress;
795 nSize -= sizeof(CurrentModule->BaseAddress);
799 if(nSize >= sizeof(CurrentModule->SizeOfImage))
801 pgmicContext->lpmodinfo->SizeOfImage = CurrentModule->SizeOfImage;
802 nSize -= sizeof(CurrentModule->SizeOfImage);
806 if(nSize >= sizeof(CurrentModule->EntryPoint))
807 /* ??? FIXME? is "EntryPoint" just the offset, or the real address? */
808 pgmicContext->lpmodinfo->EntryPoint = (PVOID)CurrentModule->EntryPoint;
810 pgmicContext->nBufSize = TRUE;
813 return STATUS_NO_MORE_FILES;
816 return STATUS_SUCCESS;
819 /* common internal implementation */
820 DWORD FASTCALL internalGetModuleInformation(
823 GET_MODULE_INFORMATION_FLAGS Flags,
828 register NTSTATUS nErrCode;
829 GET_MODULE_INFORMATION_CONTEXT gmicContext =
838 nErrCode = PsaEnumerateProcessModules
841 &GetModuleInformationCallback,
845 if(nErrCode == STATUS_NO_MORE_FILES)
846 return gmicContext.nBufSize;
849 if(NT_SUCCESS(nErrCode))
850 SetLastError(ERROR_INVALID_HANDLE);
852 SetLastError(RtlNtStatusToDosError(nErrCode));
858 /* exported interfaces */
859 DWORD STDCALL GetModuleBaseNameA(
860 HANDLE hProcess, // handle to process
861 HMODULE hModule, // handle to module
862 LPSTR lpBaseName, // base name buffer
863 DWORD nSize // maximum characters to retrieve
866 register GET_MODULE_INFORMATION_FLAGS Flags = {TRUE, FALSE, FALSE};
867 return internalGetModuleInformation
877 DWORD STDCALL GetModuleBaseNameW(
878 HANDLE hProcess, // handle to process
879 HMODULE hModule, // handle to module
880 LPWSTR lpBaseName, // base name buffer
881 DWORD nSize // maximum characters to retrieve
884 register GET_MODULE_INFORMATION_FLAGS Flags = {TRUE, TRUE, FALSE};
885 return internalGetModuleInformation
895 DWORD STDCALL GetModuleFileNameExA(
896 HANDLE hProcess, // handle to process
897 HMODULE hModule, // handle to module
898 LPSTR lpFilename, // path buffer
899 DWORD nSize // maximum characters to retrieve
902 register GET_MODULE_INFORMATION_FLAGS Flags = {TRUE, FALSE, TRUE};
903 return internalGetModuleInformation
913 DWORD STDCALL GetModuleFileNameExW(
914 HANDLE hProcess, // handle to process
915 HMODULE hModule, // handle to module
916 LPWSTR lpFilename, // path buffer
917 DWORD nSize // maximum characters to retrieve
920 register GET_MODULE_INFORMATION_FLAGS Flags = {TRUE, TRUE, TRUE};
921 return internalGetModuleInformation
931 BOOL STDCALL GetModuleInformation(
932 HANDLE hProcess, // handle to process
933 HMODULE hModule, // handle to module
934 LPMODULEINFO lpmodinfo, // information buffer
935 DWORD cb // size of buffer
938 register GET_MODULE_INFORMATION_FLAGS Flags = {FALSE, FALSE, FALSE};
939 return (BOOL)internalGetModuleInformation