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 */
169 @brief Enumerate the process identifiers of the currently active processes
171 @param lpidProcess Array that receives the list of process identifiers
172 @param cb Size of the @p lpidProcess array, in bytes
173 @param lpcbNeeded Number of bytes returned in the @p lpidProcess array
177 BOOL STDCALL EnumProcesses
184 register NTSTATUS nErrCode;
185 ENUM_PROCESSES_CONTEXT epcContext = {lpidProcess, cb / sizeof(DWORD)};
189 /* do nothing if the buffer is empty */
190 if(cb == 0 || lpidProcess == NULL)
196 /* enumerate the process ids */
197 nErrCode = PsaEnumerateProcesses(&EnumProcessesCallback, &epcContext);
199 *lpcbNeeded = (cb - epcContext.nCount) * sizeof(DWORD);
202 if(NT_SUCCESS(nErrCode) || nErrCode == STATUS_INFO_LENGTH_MISMATCH)
207 SetLastError(RtlNtStatusToDosError(nErrCode));
212 /* EnumProcessModules */
213 /* callback context */
214 typedef struct _ENUM_PROCESS_MODULES_CONTEXT
218 } ENUM_PROCESS_MODULES_CONTEXT, *PENUM_PROCESS_MODULES_CONTEXT;
220 /* callback routine */
221 NTSTATUS STDCALL EnumProcessModulesCallback
223 IN HANDLE ProcessHandle,
224 IN PLDR_MODULE CurrentModule,
225 IN OUT PVOID CallbackContext
228 register PENUM_PROCESS_MODULES_CONTEXT pepmcContext =
229 (PENUM_PROCESS_MODULES_CONTEXT)CallbackContext;
231 /* no more buffer space */
232 if(pepmcContext->nCount == 0)
233 return STATUS_INFO_LENGTH_MISMATCH;
235 /* return current process */
236 *(pepmcContext->lphModule) = CurrentModule->BaseAddress;
238 /* go to next array slot */
239 (pepmcContext->lphModule) ++;
240 (pepmcContext->nCount) --;
242 return STATUS_SUCCESS;
245 /* exported interface */
246 BOOL STDCALL EnumProcessModules(
253 register NTSTATUS nErrCode;
254 ENUM_PROCESS_MODULES_CONTEXT epmcContext = {lphModule, cb / sizeof(HMODULE)};
258 /* do nothing if the buffer is empty */
259 if(cb == 0 || lphModule == NULL)
265 /* enumerate the process modules */
266 nErrCode = PsaEnumerateProcessModules
269 &EnumProcessModulesCallback,
273 *lpcbNeeded = (cb - epmcContext.nCount) * sizeof(DWORD);
276 if(NT_SUCCESS(nErrCode) || nErrCode == STATUS_INFO_LENGTH_MISMATCH)
281 SetLastError(RtlNtStatusToDosError(nErrCode));
286 /* GetDeviceDriverBase/FileName */
287 /* common callback context */
288 typedef struct _GET_DEVICE_DRIVER_NAME_CONTEXT
293 ULONG bFullName:sizeof(ULONG) * 8 / 2;
294 ULONG bUnicode:sizeof(ULONG) * 8 / 2;
301 LPWSTR lpUnicodeName;
303 } GET_DEVICE_DRIVER_NAME_CONTEXT, *PGET_DEVICE_DRIVER_NAME_CONTEXT;
305 /* common callback routine */
306 NTSTATUS STDCALL GetDeviceDriverNameCallback
308 IN ULONG ModuleCount,
309 IN PSYSTEM_MODULE_ENTRY CurrentModule,
310 IN OUT PVOID CallbackContext
313 register PGET_DEVICE_DRIVER_NAME_CONTEXT pgddncContext =
314 (PGET_DEVICE_DRIVER_NAME_CONTEXT) CallbackContext;
317 if(pgddncContext->ImageBase == CurrentModule->BaseAddress)
319 register PCHAR pcModuleName;
322 /* get the full name or just the filename part */
323 if(pgddncContext->bFullName)
324 pcModuleName = &CurrentModule->Name[0];
326 pcModuleName = &CurrentModule->Name[CurrentModule->PathLength];
328 /* get the length of the name */
329 l = strlen(pcModuleName);
331 /* if user buffer smaller than the name */
332 if(pgddncContext->nSize <= l)
333 /* use the user buffer's length */
334 l = pgddncContext->nSize;
335 /* if user buffer larger than the name */
338 /* enough space for the null terminator */
340 pgddncContext->nSize = l;
343 /* copy the string */
344 if(pgddncContext->bUnicode)
346 /* Unicode: convert and copy */
347 ANSI_STRING strAnsi = {l, l, pcModuleName};
348 UNICODE_STRING wstrUnicode =
352 pgddncContext->lpUnicodeName
354 /* driver names should always be in language-neutral ASCII, so we don't
355 bother calling AreFileApisANSI() */
356 RtlAnsiStringToUnicodeString(&wstrUnicode, &strAnsi, FALSE);
359 /* ANSI/OEM: direct copy */
360 memcpy(pgddncContext->lpAnsiName, pcModuleName, l);
362 /* terminate the enumeration */
363 return STATUS_NO_MORE_FILES;
365 /* continue searching */
367 return STATUS_SUCCESS;
370 /* common internal implementation */
371 DWORD FASTCALL internalGetDeviceDriverName(
379 register NTSTATUS nErrCode;
380 GET_DEVICE_DRIVER_NAME_CONTEXT gddncContext =
383 { bFullName, bUnicode },
389 if(lpName == NULL || nSize == 0)
392 /* invalid image base */
393 if(ImageBase == NULL)
395 SetLastError(ERROR_INVALID_HANDLE);
399 /* start the enumeration */
400 nErrCode = PsaEnumerateSystemModules
402 &GetDeviceDriverNameCallback,
406 if(nErrCode == STATUS_NO_MORE_FILES)
407 /* module was found, return string size */
408 return gddncContext.nSize;
411 if(NT_SUCCESS(nErrCode))
412 /* module was not found */
413 SetLastError(ERROR_INVALID_HANDLE);
415 /* an error occurred */
416 SetLastError(RtlNtStatusToDosError(nErrCode));
423 /* exported interfaces */
426 - nSize is not, as stated by Microsoft's documentation, the byte size, but the
427 count of characters in the buffer
428 - the return value is the count of characters copied into the buffer
429 - the functions don't attempt to null-terminate the string
431 DWORD STDCALL GetDeviceDriverBaseNameA(
437 return internalGetDeviceDriverName(FALSE, FALSE, ImageBase, lpBaseName, nSize);
440 DWORD STDCALL GetDeviceDriverFileNameA(
446 return internalGetDeviceDriverName(FALSE, TRUE, ImageBase, lpFilename, nSize);
449 DWORD STDCALL GetDeviceDriverBaseNameW(
455 return internalGetDeviceDriverName(TRUE, FALSE, ImageBase, lpBaseName, nSize);
458 DWORD STDCALL GetDeviceDriverFileNameW(
464 return internalGetDeviceDriverName(TRUE, TRUE, ImageBase, lpFilename, nSize);
467 /* GetMappedFileName */
468 /* common internal implementation */
469 DWORD FASTCALL internalGetMappedFileName(
477 register NTSTATUS nErrCode;
478 register ULONG nBufSize;
479 PMEMORY_SECTION_NAME pmsnName;
482 if(nSize == 0 || (LPSTR)lpName == NULL)
485 if(nSize > (0xFFFF / sizeof(WCHAR)))
486 /* if the user buffer contains more characters than would fit in an
487 UNICODE_STRING, limit the buffer size. RATIONALE: we don't limit buffer
488 size elsewhere because here superfluous buffer size will mean a larger
490 nBufSize = 0xFFFF / sizeof(WCHAR);
492 nBufSize = nSize * sizeof(WCHAR);
494 /* allocate the memory */
495 pmsnName = malloc(nBufSize + offsetof(MEMORY_SECTION_NAME, NameBuffer));
500 SetLastError(ERROR_OUTOFMEMORY);
504 /* initialize the destination buffer */
505 pmsnName->SectionFileName.Length = 0;
506 pmsnName->SectionFileName.Length = nBufSize;
513 nErrCode = NtQueryVirtualMemory
523 if(!NT_SUCCESS(nErrCode))
526 SetLastError(RtlNtStatusToDosError(nErrCode));
529 /* free the buffer */
538 /* destination is an Unicode string: direct copy */
542 pmsnName->NameBuffer,
543 pmsnName->SectionFileName.Length
548 /* free the buffer */
552 if(pmsnName->SectionFileName.Length < nSize)
554 /* null-terminate the string */
555 ((LPWSTR)lpName)[pmsnName->SectionFileName.Length] = 0;
556 return pmsnName->SectionFileName.Length + 1;
559 return pmsnName->SectionFileName.Length;
563 ANSI_STRING strAnsi = {0, nSize, (LPSTR)lpName};
565 if(AreFileApisANSI())
566 /* destination is an ANSI string: convert and copy */
567 RtlUnicodeStringToAnsiString(&strAnsi, &pmsnName->SectionFileName, FALSE);
569 /* destination is an OEM string: convert and copy */
570 RtlUnicodeStringToOemString(&strAnsi, &pmsnName->SectionFileName, FALSE);
574 /* free the buffer */
578 if(strAnsi.Length < nSize)
580 /* null-terminate the string */
581 ((LPSTR)lpName)[strAnsi.Length] = 0;
582 return strAnsi.Length + 1;
585 return strAnsi.Length;
597 /* exported interfaces */
598 DWORD STDCALL GetMappedFileNameA(
605 return internalGetMappedFileName(FALSE, hProcess, lpv, lpFilename, nSize);
608 DWORD STDCALL GetMappedFileNameW(
615 return internalGetMappedFileName(TRUE, hProcess, lpv, lpFilename, nSize);
618 /* GetModuleInformation */
619 /* common callback context */
620 typedef struct _GET_MODULE_INFORMATION_FLAGS
622 ULONG bWantName:sizeof(ULONG) * 8 / 4;
623 ULONG bUnicode:sizeof(ULONG) * 8 / 4;
624 ULONG bFullName:sizeof(ULONG) * 8 / 4;
625 } GET_MODULE_INFORMATION_FLAGS, *PGET_MODULE_INFORMATION_FLAGS;
627 typedef struct _GET_MODULE_INFORMATION_CONTEXT
630 GET_MODULE_INFORMATION_FLAGS Flags;
634 LPWSTR lpUnicodeName;
636 LPMODULEINFO lpmodinfo;
639 } GET_MODULE_INFORMATION_CONTEXT, *PGET_MODULE_INFORMATION_CONTEXT;
641 /* common callback */
642 NTSTATUS STDCALL GetModuleInformationCallback
644 IN HANDLE ProcessHandle,
645 IN PLDR_MODULE CurrentModule,
646 IN OUT PVOID CallbackContext
649 register PGET_MODULE_INFORMATION_CONTEXT pgmicContext =
650 (PGET_MODULE_INFORMATION_CONTEXT)CallbackContext;
652 /* found the module we were looking for */
653 if(CurrentModule->BaseAddress == pgmicContext->hModule)
655 /* we want the module name */
656 if(pgmicContext->Flags.bWantName)
658 register NTSTATUS nErrCode;
659 register PUNICODE_STRING pwstrSource;
662 if(pgmicContext->Flags.bFullName)
664 pwstrSource = &(CurrentModule->FullDllName);
667 pwstrSource = &(CurrentModule->BaseDllName);
670 pwstrSource->Length -= pwstrSource->Length % sizeof(WCHAR);
672 /* l is the byte size of the user buffer */
673 l = pgmicContext->nBufSize * sizeof(WCHAR);
675 /* if the user buffer has room for the string and a null terminator */
676 if(l >= (pwstrSource->Length + sizeof(WCHAR)))
678 /* limit the buffer size */
679 l = pwstrSource->Length;
681 /* null-terminate the string */
682 if(pgmicContext->Flags.bUnicode)
683 pgmicContext->lpUnicodeName[l / sizeof(WCHAR)] = 0;
685 pgmicContext->lpAnsiName[l / sizeof(WCHAR)] = 0;
688 if(pgmicContext->Flags.bUnicode)
690 /* Unicode: direct copy */
691 /* NOTE: I've chosen not to check for ProcessHandle == NtCurrentProcess(),
692 this function is complicated enough as it is */
693 nErrCode = NtReadVirtualMemory
697 pgmicContext->lpUnicodeName,
702 if(NT_SUCCESS(nErrCode))
703 pgmicContext->nBufSize = l / sizeof(WCHAR);
706 pgmicContext->nBufSize = 0;
712 /* ANSI/OEM: convert and copy */
713 register LPWSTR pwcUnicodeBuf;
714 ANSI_STRING strAnsi = {0, pgmicContext->nBufSize, pgmicContext->lpAnsiName};
715 UNICODE_STRING wstrUnicodeBuf;
717 /* allocate the local buffer */
718 pwcUnicodeBuf = malloc(pwstrSource->Length);
724 if(pwcUnicodeBuf == NULL)
727 return STATUS_NO_MEMORY;
730 nErrCode = STATUS_NO_MEMORY;
735 /* copy the string in the local buffer */
736 nErrCode = NtReadVirtualMemory
745 if(!NT_SUCCESS(nErrCode))
753 /* initialize Unicode string buffer */
754 wstrUnicodeBuf.Length = wstrUnicodeBuf.MaximumLength = l;
755 wstrUnicodeBuf.Buffer = pwcUnicodeBuf;
757 /* convert and copy */
758 if(AreFileApisANSI())
759 RtlUnicodeStringToAnsiString(&strAnsi, &wstrUnicodeBuf, FALSE);
761 RtlUnicodeStringToOemString(&strAnsi, &wstrUnicodeBuf, FALSE);
763 /* return the string size */
764 pgmicContext->nBufSize = strAnsi.Length;
769 /* free the buffer */
774 nErrCode = STATUS_NO_MORE_FILES;
777 /* free the buffer */
784 /* we want other module information */
787 register ULONG nSize = pgmicContext->nBufSize;
790 if(nSize >= sizeof(CurrentModule->BaseAddress))
792 pgmicContext->lpmodinfo->lpBaseOfDll = CurrentModule->BaseAddress;
793 nSize -= sizeof(CurrentModule->BaseAddress);
797 if(nSize >= sizeof(CurrentModule->SizeOfImage))
799 pgmicContext->lpmodinfo->SizeOfImage = CurrentModule->SizeOfImage;
800 nSize -= sizeof(CurrentModule->SizeOfImage);
804 if(nSize >= sizeof(CurrentModule->EntryPoint))
805 /* ??? FIXME? is "EntryPoint" just the offset, or the real address? */
806 pgmicContext->lpmodinfo->EntryPoint = (PVOID)CurrentModule->EntryPoint;
808 pgmicContext->nBufSize = TRUE;
811 return STATUS_NO_MORE_FILES;
814 return STATUS_SUCCESS;
817 /* common internal implementation */
818 DWORD FASTCALL internalGetModuleInformation(
821 GET_MODULE_INFORMATION_FLAGS Flags,
826 register NTSTATUS nErrCode;
827 GET_MODULE_INFORMATION_CONTEXT gmicContext =
836 nErrCode = PsaEnumerateProcessModules
839 &GetModuleInformationCallback,
843 if(nErrCode == STATUS_NO_MORE_FILES)
844 return gmicContext.nBufSize;
847 if(NT_SUCCESS(nErrCode))
848 SetLastError(ERROR_INVALID_HANDLE);
850 SetLastError(RtlNtStatusToDosError(nErrCode));
856 /* exported interfaces */
857 DWORD STDCALL GetModuleBaseNameA(
858 HANDLE hProcess, // handle to process
859 HMODULE hModule, // handle to module
860 LPSTR lpBaseName, // base name buffer
861 DWORD nSize // maximum characters to retrieve
864 register GET_MODULE_INFORMATION_FLAGS Flags = {TRUE, FALSE, FALSE};
865 return internalGetModuleInformation
875 DWORD STDCALL GetModuleBaseNameW(
876 HANDLE hProcess, // handle to process
877 HMODULE hModule, // handle to module
878 LPWSTR lpBaseName, // base name buffer
879 DWORD nSize // maximum characters to retrieve
882 register GET_MODULE_INFORMATION_FLAGS Flags = {TRUE, TRUE, FALSE};
883 return internalGetModuleInformation
893 DWORD STDCALL GetModuleFileNameExA(
894 HANDLE hProcess, // handle to process
895 HMODULE hModule, // handle to module
896 LPSTR lpFilename, // path buffer
897 DWORD nSize // maximum characters to retrieve
900 register GET_MODULE_INFORMATION_FLAGS Flags = {TRUE, FALSE, TRUE};
901 return internalGetModuleInformation
911 DWORD STDCALL GetModuleFileNameExW(
912 HANDLE hProcess, // handle to process
913 HMODULE hModule, // handle to module
914 LPWSTR lpFilename, // path buffer
915 DWORD nSize // maximum characters to retrieve
918 register GET_MODULE_INFORMATION_FLAGS Flags = {TRUE, TRUE, TRUE};
919 return internalGetModuleInformation
929 BOOL STDCALL GetModuleInformation(
930 HANDLE hProcess, // handle to process
931 HMODULE hModule, // handle to module
932 LPMODULEINFO lpmodinfo, // information buffer
933 DWORD cb // size of buffer
936 register GET_MODULE_INFORMATION_FLAGS Flags = {FALSE, FALSE, FALSE};
937 return (BOOL)internalGetModuleInformation