Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

461 lines
13 KiB

  1. /*++
  2. Copyright (c) 1989-2001 Microsoft Corporation
  3. Module Name:
  4. lockmem.cpp
  5. Abstract:
  6. This utility locks the memory of all the modules currently
  7. mapped in the process address space.
  8. Author:
  9. Vijay Jayaseelan (vijayj@microsoft.com) 26'July'2001
  10. Revision History:
  11. --*/
  12. #include <iostream>
  13. #include <string>
  14. #include <exception>
  15. #include <windows.h>
  16. #include <psapi.h>
  17. using namespace std;
  18. //
  19. // class abstracting the process with module
  20. // details
  21. //
  22. class Process {
  23. public:
  24. //
  25. // constructor
  26. //
  27. Process(ULONG Pid = 0) {
  28. //
  29. // enable the required privileges
  30. //
  31. if (!PrivilegeEnabled) {
  32. EnableRequiredPrivileges();
  33. PrivilegeEnabled = TRUE;
  34. }
  35. if (Pid) {
  36. ProcessID = Pid;
  37. } else {
  38. ProcessID = GetCurrentProcessId();
  39. }
  40. SelfProcess = (ProcessID == GetCurrentProcessId());
  41. hProcess = 0;
  42. ::ZeroMemory(&hLoadedModules, sizeof(hLoadedModules));
  43. //
  44. // Open the process
  45. //
  46. hProcess = ::OpenProcess(PROCESS_ALL_ACCESS,
  47. FALSE, ProcessID);
  48. if (!hProcess)
  49. throw new InvalidProcessID(ProcessID, ::GetLastError());
  50. DWORD cbNeeded = 0;
  51. //
  52. // Get the module details
  53. //
  54. if (!::EnumProcessModules(hProcess, hLoadedModules,
  55. sizeof(hLoadedModules), &cbNeeded)) {
  56. ::CloseHandle(hProcess);
  57. hProcess = 0;
  58. throw new EnumerationError(::GetLastError());
  59. }
  60. }
  61. //
  62. // destructor
  63. //
  64. ~Process() {
  65. if (hProcess) {
  66. ::CloseHandle(hProcess);
  67. }
  68. }
  69. DWORD GetTotalWSSize(VOID) const {
  70. DWORD TotalSize = 0;
  71. for (int Index=0;
  72. ((Index < sizeof(hLoadedModules)/sizeof(HMODULE)) &&
  73. hLoadedModules[Index]);
  74. Index++ ) {
  75. MODULEINFO ModuleInformation = {0};
  76. if (GetModuleInformation(hProcess,
  77. hLoadedModules[Index],
  78. &ModuleInformation,
  79. sizeof(MODULEINFO))) {
  80. TotalSize += ModuleInformation.SizeOfImage;
  81. }
  82. }
  83. return TotalSize;
  84. }
  85. DWORD
  86. GetWSSizeLimits(
  87. SIZE_T &MinimumSize,
  88. SIZE_T &MaximumSize
  89. )
  90. {
  91. GetProcessWorkingSetSize(hProcess,
  92. &MinimumSize,
  93. &MaximumSize);
  94. return ::GetLastError();
  95. }
  96. DWORD LockMemory(DWORD &LockedMemorySize) {
  97. DWORD Result = ERROR_SUCCESS;
  98. DWORD TotalSize = GetTotalWSSize();
  99. LockedMemorySize = 0;
  100. //
  101. // just make the WS limit twice the size of the
  102. // total module size
  103. //
  104. if (SetProcessWorkingSetSize(hProcess,
  105. TotalSize * 2,
  106. TotalSize * 2)) {
  107. if (SelfProcess) {
  108. for (int Index=0;
  109. ((Index < sizeof(hLoadedModules)/sizeof(HMODULE)) &&
  110. hLoadedModules[Index]);
  111. Index++ ) {
  112. MODULEINFO ModuleInformation = {0};
  113. if (GetModuleInformation(hProcess,
  114. hLoadedModules[Index],
  115. &ModuleInformation,
  116. sizeof(MODULEINFO))) {
  117. if (!IsBadCodePtr((FARPROC)ModuleInformation.lpBaseOfDll)) {
  118. if (!VirtualLock(ModuleInformation.lpBaseOfDll,
  119. ModuleInformation.SizeOfImage)) {
  120. Result = ::GetLastError();
  121. } else {
  122. LockedMemorySize += ModuleInformation.SizeOfImage;
  123. }
  124. } else {
  125. Result = ERROR_ACCESS_DENIED;
  126. }
  127. }
  128. }
  129. }
  130. } else {
  131. Result = ::GetLastError();
  132. }
  133. return Result;
  134. }
  135. //
  136. // dump utility
  137. //
  138. friend ostream& operator<<(ostream &os, const Process& rhs) {
  139. char ModuleName[MAX_PATH] = {0};
  140. os << "Process ID: " << rhs.ProcessID << endl;
  141. os << "Loaded Modules: " << endl;
  142. for ( int Index=0;
  143. ((Index < sizeof(rhs.hLoadedModules)/sizeof(HMODULE)) &&
  144. rhs.hLoadedModules[Index]);
  145. Index++ ) {
  146. if (::GetModuleFileNameExA(rhs.hProcess, rhs.hLoadedModules[Index],
  147. ModuleName, sizeof(ModuleName))) {
  148. MODULEINFO ModuleInformation = {0};
  149. if (GetModuleInformation(rhs.hProcess,
  150. rhs.hLoadedModules[Index],
  151. &ModuleInformation,
  152. sizeof(MODULEINFO))) {
  153. os << ModuleName << " (" << ModuleInformation.lpBaseOfDll
  154. << "," << ModuleInformation.SizeOfImage << ")" << endl;
  155. } else {
  156. os << ModuleName << endl;
  157. }
  158. }
  159. }
  160. DWORD TotalSize = rhs.GetTotalWSSize();
  161. os << "Total Size: " << dec << TotalSize << " Bytes = "
  162. << dec << TotalSize / 1024 << " KB = "
  163. << dec << TotalSize / (1024 * 1024) << " MB." << endl;
  164. return os;
  165. }
  166. protected:
  167. //
  168. // data members
  169. //
  170. HANDLE hProcess;
  171. HMODULE hLoadedModules[1024];
  172. ULONG ProcessID;
  173. BOOLEAN SelfProcess;
  174. static BOOLEAN PrivilegeEnabled;
  175. public:
  176. //
  177. // exceptions
  178. //
  179. struct ProcessException{
  180. ULONG ErrCode;
  181. virtual void dump(ostream &os) = 0;
  182. };
  183. struct InvalidProcessID : public ProcessException {
  184. ULONG ProcessID;
  185. InvalidProcessID(ULONG Pid, ULONG Err) : ProcessID(Pid){
  186. ErrCode = Err;
  187. }
  188. void dump(ostream &os) {
  189. os << *this;
  190. }
  191. friend ostream& operator<<(ostream& os, const InvalidProcessID& rhs) {
  192. os << "Invalid Process ID : " << rhs.ProcessID
  193. << " Error Code : " << rhs.ErrCode << endl;
  194. return os;
  195. }
  196. };
  197. struct EnumerationError : public ProcessException {
  198. EnumerationError(ULONG Err) {
  199. ErrCode=Err;
  200. }
  201. void dump(ostream &os) {
  202. os << *this;
  203. }
  204. friend ostream& operator<<(ostream& os, const EnumerationError& rhs) {
  205. os << "Enumeration Error : " << rhs.ErrCode << endl;
  206. return os;
  207. }
  208. };
  209. //
  210. // gives the process the required privileges
  211. //
  212. DWORD
  213. EnableRequiredPrivileges(
  214. VOID
  215. )
  216. {
  217. HANDLE Token ;
  218. UCHAR Buf[ sizeof( TOKEN_PRIVILEGES ) +
  219. (sizeof( LUID_AND_ATTRIBUTES ) * 3) ] = {0};
  220. PTOKEN_PRIVILEGES Privs;
  221. DWORD Result = ERROR_SUCCESS;
  222. if (::OpenProcessToken(hProcess,
  223. MAXIMUM_ALLOWED,
  224. &Token))
  225. {
  226. Privs = (PTOKEN_PRIVILEGES) Buf ;
  227. Privs->PrivilegeCount = 3 ;
  228. LookupPrivilegeValue(NULL,
  229. SE_DEBUG_NAME,
  230. &(Privs->Privileges[0].Luid));
  231. Privs->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED ;
  232. LookupPrivilegeValue(NULL,
  233. SE_INC_BASE_PRIORITY_NAME,
  234. &(Privs->Privileges[1].Luid));
  235. Privs->Privileges[1].Attributes = SE_PRIVILEGE_ENABLED ;
  236. LookupPrivilegeValue(NULL,
  237. SE_LOCK_MEMORY_NAME,
  238. &(Privs->Privileges[2].Luid));
  239. Privs->Privileges[2].Attributes = SE_PRIVILEGE_ENABLED ;
  240. ::AdjustTokenPrivileges(Token,
  241. FALSE,
  242. Privs,
  243. NULL,
  244. NULL,
  245. NULL);
  246. Result = ::GetLastError();
  247. ::CloseHandle(Token);
  248. } else {
  249. Result = ::GetLastError();
  250. }
  251. return Result;
  252. }
  253. };
  254. struct UsageException{};
  255. //
  256. // static data member
  257. //
  258. BOOLEAN Process::PrivilegeEnabled = FALSE;
  259. DWORD
  260. LockModules(
  261. VOID
  262. )
  263. {
  264. Process SelfProcess;
  265. DWORD LockedMemorySize = 0;
  266. return SelfProcess.LockMemory(LockedMemorySize);
  267. }
  268. #ifdef _CONOSOLE_VERSION
  269. //
  270. // global data
  271. //
  272. const string Usage = "Usage: lm.exe [process-to-execute]\n";
  273. const int MinimumArgs = 2;
  274. const string ShowHelp1 = "/?";
  275. const string ShowHelp2 = "-h";
  276. const string SelfProcess = "-self";
  277. /*
  278. /* main() entry point
  279. */
  280. int
  281. __cdecl
  282. main(
  283. int Argc,
  284. char *Argv[]
  285. )
  286. {
  287. int Result = 0;
  288. try {
  289. if (Argc == MinimumArgs) {
  290. char *EndPtr = 0;
  291. string Arg1(Argv[1]);
  292. //
  293. // verify arguments
  294. //
  295. if (Arg1 == ShowHelp1 || Arg1 == ShowHelp2)
  296. throw UsageException();
  297. DWORD LastError = ERROR_SUCCESS;
  298. SIZE_T Min = 0, Max = 0;
  299. DWORD LockedMemorySize = 0;
  300. DWORD WSSize = 0;
  301. if (Arg1 != SelfProcess) {
  302. PROCESS_INFORMATION ProcessInfo = {0};
  303. STARTUPINFOA StartupInfo = {0};
  304. char ExecutableName[MAX_PATH];
  305. strcpy(ExecutableName, Arg1.c_str());
  306. BOOL CreateResult = CreateProcessA(NULL,
  307. ExecutableName,
  308. NULL,
  309. NULL,
  310. FALSE,
  311. 0,
  312. NULL,
  313. NULL,
  314. &StartupInfo,
  315. &ProcessInfo);
  316. if (CreateResult) {
  317. cout << "Waiting for : " << ExecutableName
  318. << "..." << endl;
  319. WaitForSingleObject(ProcessInfo.hProcess,
  320. 2000);
  321. Process ExecedProcess(ProcessInfo.dwProcessId);
  322. cout << ExecedProcess << endl;
  323. ExecedProcess.GetWSSizeLimits(Min, Max);
  324. cout << "Existing WS Limits : " << dec << Min
  325. << ", " << Max << endl;
  326. LastError = ExecedProcess.LockMemory(LockedMemorySize);
  327. ExecedProcess.GetWSSizeLimits(Min, Max);
  328. cout << "New WS Limits : " << dec << Min
  329. << ", " << Max << endl;
  330. cout << "Locked " << dec << LockedMemorySize << " / "
  331. << ExecedProcess.GetTotalWSSize() << " Bytes" << endl;
  332. } else {
  333. LastError = GetLastError();
  334. }
  335. } else {
  336. Process SelfProcess;
  337. cout << SelfProcess << endl;
  338. SelfProcess.GetWSSizeLimits(Min, Max);
  339. cout << "Existing WS Limits : " << dec << Min
  340. << ", " << Max << endl;
  341. LastError = SelfProcess.LockMemory(LockedMemorySize);
  342. SelfProcess.GetWSSizeLimits(Min, Max);
  343. cout << "New WS Limits : " << dec << Min
  344. << ", " << Max << endl;
  345. cout << "Locked " << dec << LockedMemorySize << " / "
  346. << SelfProcess.GetTotalWSSize() << " Bytes" << endl;
  347. }
  348. if (ERROR_SUCCESS != LastError) {
  349. cout << "Error : " << dec << LastError << endl;
  350. }
  351. } else {
  352. cerr << Usage;
  353. Result = 1;
  354. }
  355. } catch(Process::ProcessException *pExp) {
  356. pExp->dump(cerr);
  357. delete pExp;
  358. } catch (...) {
  359. cerr << Usage;
  360. Result = 1;
  361. }
  362. return Result;
  363. }
  364. #endif // _CONSOLE_VERSION