48 using namespace basis;
59 const astring NTVDM_NAME =
"ntvdm.exe";
73 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
77 class process_implementation_hider
94 BOOL (WINAPI *first_process)(
HANDLE,LPPROCESSENTRY32);
95 BOOL (WINAPI *next_process)(
HANDLE,LPPROCESSENTRY32);
100 process_implementation_hider()
109 ~process_implementation_hider() {
110 if (psapi_dll) FreeLibrary(psapi_dll);
111 if (vdm_dll) FreeLibrary(vdm_dll);
112 if (kernel32_dll) FreeLibrary(kernel32_dll);
122 class process_info_clump
126 process_entry_array &_to_fill;
128 process_info_clump(
basis::un_int id, process_entry_array &to_fill)
129 : _process_id(id), _to_fill(to_fill) {}
136 process_control::process_control()
137 : _ptrs(new process_implementation_hider),
146 version osver = application_configuration::get_OS_version();
149 if (osver.
v_revision() == VER_PLATFORM_WIN32_WINDOWS) {
152 }
else if (osver.
v_major() >= 5) {
157 _healthy = initialize_psapi_support();
159 _healthy = initialize_toolhelp_support();
176 for (
int gap = v.
length() / 2; gap > 0; gap /= 2)
177 for (
int i = gap; i < v.
length(); i++)
178 for (
int j = i - gap; j >= 0
182 { temp = v[j]; v[j] = v[j + gap]; v[j + gap] = temp; }
188 for (
int gap = v.
length() / 2; gap > 0; gap /= 2)
189 for (
int i = gap; i < v.
length(); i++)
190 for (
int j = i - gap; j >= 0 && (v[j]._process_id
191 > v[j + gap]._process_id); j = j - gap)
192 { temp = v[j]; v[j] = v[j + gap]; v[j + gap] = temp; }
197 if (!_healthy)
return false;
202 return get_processes_with_toolhelp(to_fill);
205 return get_processes_with_psapi(to_fill);
208 return get_processes_with_ps(to_fill);
213 bool process_control::initialize_psapi_support()
218 _ptrs->psapi_dll = LoadLibraryA(
"psapi.dll");
219 if (!_ptrs->psapi_dll)
return false;
220 _ptrs->vdm_dll = LoadLibraryA(
"vdmdbg.dll");
221 if (!_ptrs->vdm_dll)
return false;
225 GetProcAddress(_ptrs->psapi_dll,
"EnumProcesses");
226 _ptrs->enumerate_modules
228 GetProcAddress(_ptrs->psapi_dll,
"EnumProcessModules");
229 _ptrs->get_module_name
231 GetProcAddress(_ptrs->psapi_dll,
"GetModuleFileNameExA");
236 if (!_ptrs->enumerate_processes || !_ptrs->enumerate_modules
237 || !_ptrs->get_module_name
246 bool process_control::initialize_toolhelp_support()
249 _ptrs->kernel32_dll = LoadLibraryA(
"Kernel32.DLL");
250 if (!_ptrs->kernel32_dll)
return false;
254 GetProcAddress(_ptrs->kernel32_dll,
"CreateToolhelp32Snapshot");
255 _ptrs->first_process = (BOOL(WINAPI *)(
HANDLE,LPPROCESSENTRY32))
256 GetProcAddress(_ptrs->kernel32_dll,
"Process32First");
257 _ptrs->next_process = (BOOL(WINAPI *)(
HANDLE,LPPROCESSENTRY32))
258 GetProcAddress(_ptrs->kernel32_dll,
"Process32Next");
259 if (!_ptrs->next_process || !_ptrs->first_process
260 || !_ptrs->create_snapshot)
return false;
268 #ifdef DEBUG_PROCESS_CONTROL
271 if (!_healthy)
return false;
273 int ret = kill(to_zap, 9);
277 HANDLE h = OpenProcess(PROCESS_TERMINATE,
false, to_zap);
279 #ifdef DEBUG_PROCESS_CONTROL
280 int err = critical_events::system_error();
282 + critical_events::system_error_text(err));
287 BOOL ret = TerminateProcess(h, exit_code);
300 if (!got_em)
return to_return;
302 for (
int i = 0; i < to_fill.
length(); i++) {
303 if (to_fill[i]._process_id == to_query)
320 #ifdef DEBUG_PROCESS_CONTROL
321 FUNCDEF(
"find_process_in_list");
326 version os_ver = application_configuration::get_OS_version();
328 bool compare_prefix = (os_ver.
v_major() == 5) && (os_ver.
v_minor() == 0);
334 for (
int i = 0; i <
processes.length(); i++) {
340 if ( (compare_prefix && (base.
compare(app_name, 0, 0, 15,
false)))
341 || (base == app_name) ) {
346 #ifdef DEBUG_PROCESS_CONTROL
348 LOG(
astring(
"failed to find the program called ") + app_name);
359 BOOL WINAPI process_16bit(
basis::un_int dwThreadId, WORD module_handle16, WORD hTask16,
360 PSZ pszModName, PSZ pszFileName, LPARAM lpUserDefined)
362 process_info_clump *to_stuff = (process_info_clump *)lpUserDefined;
366 to_add.
path(pszFileName);
368 to_stuff->_to_fill += to_add;
372 bool process_control::get_processes_with_psapi(process_entry_array &to_fill)
379 bool got_all =
false;
384 pid_list = (
basis::un_int *)HeapAlloc(GetProcessHeap(), 0, max_size);
385 if (!pid_list)
return false;
386 if (!_ptrs->enumerate_processes(pid_list, max_size, &actual_size)) {
387 HeapFree(GetProcessHeap(), 0, pid_list);
390 if (actual_size == max_size) {
392 HeapFree(GetProcessHeap(), 0, pid_list);
394 }
else got_all =
true;
404 HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
413 HMODULE *module_handles =
new HMODULE[max_size + 1];
414 if (!module_handles) {
415 CloseHandle(hProcess);
416 HeapFree(GetProcessHeap(), 0, pid_list);
419 if (_ptrs->enumerate_modules(hProcess, module_handles, max_size,
422 if (!_ptrs->get_module_name(hProcess, *module_handles, process_name,
423 sizeof(process_name)))
426 WHACK(module_handles);
427 CloseHandle(hProcess);
431 process_entry new_entry;
432 new_entry._process_id = pid_list[i];
433 astring converted_name = from_unicode_temp(process_name);
434 new_entry.path(converted_name);
438 to_fill += new_entry;
442 if (new_entry.path().length() >= NTVDM_NAME.
length()) {
444 (new_entry.path().end() - NTVDM_NAME.
length() + 1,
445 new_entry.path().end());
459 if (pid_list) HeapFree(GetProcessHeap(), 0, pid_list);
467 bool process_control::get_processes_with_toolhelp(process_entry_array &to_fill)
474 hSnapShot = _ptrs->create_snapshot(TH32CS_SNAPPROCESS, 0);
475 if (hSnapShot == INVALID_HANDLE_VALUE)
return false;
478 PROCESSENTRY32 entry;
479 entry.dwSize =
sizeof(PROCESSENTRY32);
480 BOOL keep_going = _ptrs->first_process(hSnapShot, &entry);
485 process_entry new_entry;
486 new_entry._process_id = entry.th32ProcessID;
487 new_entry._references = entry.cntUsage;
488 new_entry._threads = entry.cntThreads;
489 new_entry._parent_process_id = entry.th32ParentProcessID;
490 astring exe_file = from_unicode_temp(entry.szExeFile);
491 new_entry.path(exe_file);
492 to_fill += new_entry;
493 entry.dwSize =
sizeof(PROCESSENTRY32);
494 keep_going = _ptrs->next_process(hSnapShot, &entry);
497 CloseHandle(hSnapShot);
504 #define CLOSE_TEMPORARY_FILE { \
508 unlink(tmpfile.s()); \
512 bool process_control::get_processes_with_ps(process_entry_array &to_fill)
514 FUNCDEF(
"get_processes_with_ps");
517 a_sprintf tmpfile(
"/tmp/proc_list_%d_%d.txt", application_configuration::process_id(),
519 a_sprintf cmd(
"ps wax --format \"%%p %%a\" >%s", tmpfile.
s());
522 int sysret = system(cmd.
s());
524 LOG(
"got negative return from system()!");
528 output = fopen(tmpfile.
s(),
"r");
530 LOG(
"failed to open process list file!");
534 const int max_buff = 10000;
536 size_t size_read = 1;
538 while (size_read > 0) {
540 size_read = fread(buff, 1, max_buff, output);
543 accumulator +=
astring(astring::UNTERMINATED, buff, size_read);
547 bool first_line =
true;
548 while (accumulator.
length()) {
552 int cr_indy = accumulator.
find(
'\n');
553 accumulator.
zap(0, cr_indy);
554 if (accumulator[accumulator.
end()] ==
'\r')
555 accumulator.
zap(accumulator.
end(), accumulator.
end());
559 while (accumulator.
length() && (accumulator[0] ==
' '))
560 accumulator.
zap(0, 0);
562 int num_indy = accumulator.
find(
' ');
565 accumulator.
zap(0, num_indy);
566 int cr_indy = accumulator.
find(
'\n');
568 cr_indy = accumulator.
end() + 1;
570 if (proc_name[proc_name.
end()] ==
'\r')
571 proc_name.
zap(proc_name.
end(), proc_name.
end());
572 accumulator.
zap(0, cr_indy);
573 int space_indy = proc_name.
find(
' ');
576 space_indy = proc_name.
end() + 1;
577 process_entry to_add;
582 for (
int i = 0; i <
path.length(); i++) {
583 if (
path[i] ==
'[') brackets_in++;
584 else if (
path[i] ==
']') brackets_in--;
588 if ( (
path[i] ==
'/') || (
path[i] ==
'\\') )
a_sprintf is a specialization of astring that provides printf style support.
int length() const
Returns the current reported length of the allocated C array.
Provides a dynamically resizable ASCII character string.
const char * s() const
synonym for observe. the 's' stands for "string", if that helps.
astring lower() const
like to_lower(), but returns a new string rather than modifying this.
virtual void zap(int start, int end)
Deletes the characters between "start" and "end" inclusively.
bool substring(astring &target, int start, int end) const
a version that stores the substring in an existing "target" string.
int end() const
returns the index of the last (non-null) character in the string.
int length() const
Returns the current length of the string.
bool compare(const astring &to_compare, int start_first, int start_second, int count, bool case_sensitive) const
Compares "this" string with "to_compare".
int find(char to_find, int position=0, bool reverse=false) const
Locates "to_find" in "this".
void to_lower()
to_lower modifies "this" by replacing capitals with lower-case.
Provides operations commonly needed on file names.
const basis::astring & raw() const
returns the astring that we're holding onto for the path.
filename basename() const
returns the base of the filename; no directory.
a platform-independent way to acquire random numbers in a specific range.
int inclusive(int low, int high) const
< Returns a pseudo-random number r, such that "low" <= r <= "high".
static bool find_process_in_list(const process_entry_array &processes, const basis::astring &app_name, structures::int_set &pids)
uses a pre-existing list of "processes" to search for the "app_name".
void sort_by_pid(process_entry_array &to_sort)
process_entry query_process(basis::un_int to_query)
returns the information for just one process.
bool zap_process(basis::un_int to_zap)
preemptively zaps the process "to_zap".
void sort_by_name(process_entry_array &to_sort)
bool query_processes(process_entry_array &to_fill)
finds the processes that are running and drops them into "to_fill".
virtual ~process_control()
a handy class that implements an array of process entries.
Encapsulates information about OS processes.
basis::un_int _process_id
the OS identifier of this process.
basis::un_short _module16
non-zero if this process is a 16-bit application.
const basis::astring & path() const
A simple object that wraps a templated set of ints.
bool add(const contents &to_add)
Adds a new element "to_add" to the set.
void clear()
Empties out this set.
Holds a file's version identifier.
int v_minor() const
minor version number.
int v_major() const
major version number.
int v_revision() const
revision level.
#define NULL_POINTER
The value representing a pointer to nothing.
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
The guards collection helps in testing preconditions and reporting errors.
void WHACK(contents *&ptr)
deletion with clearing of the pointer.
unsigned int un_int
Abbreviated name for unsigned integers.
bool negative(const type &a)
negative returns true if "a" is less than zero.
A platform independent way to obtain the timestamp of a file.
A logger that sends to the console screen using the standard output device.
An extension to floating point primitives providing approximate equality.
A dynamic container class that holds any kind of object via pointers.
#define CLOSE_TEMPORARY_FILE
Support for unicode builds.
Aids in achievement of platform independence.
void * application_instance