1 /*
   2  * Copyright 2000-2001 Sun Microsystems, Inc.  All Rights Reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  20  * CA 95054 USA or visit www.sun.com if you need additional information or
  21  * have any questions.
  22  *
  23  */
  24 
  25 #include "procList.hpp"
  26 #include "nt4internals.hpp"
  27 #include "isNT4.hpp"
  28 #include "toolHelp.hpp"
  29 #include <assert.h>
  30 
  31 using namespace std;
  32 using namespace NT4;
  33 
  34 typedef void ProcListImplFunc(ProcEntryList& processes);
  35 
  36 void procListImplNT4(ProcEntryList& processes);
  37 void procListImplToolHelp(ProcEntryList& processes);
  38 
  39 ProcEntry::ProcEntry(ULONG pid, USHORT nameLength, WCHAR* name) {
  40   this->pid = pid;
  41   this->nameLength = nameLength;
  42   this->name = new WCHAR[nameLength];
  43   memcpy(this->name, name, nameLength * sizeof(WCHAR));
  44 }
  45 
  46 ProcEntry::ProcEntry(ULONG pid, USHORT nameLength, char* name) {
  47   this->pid = pid;
  48   this->nameLength = nameLength;
  49   this->name = new WCHAR[nameLength];
  50   int j = 0;
  51   for (int i = 0; i < nameLength; i++) {
  52     // FIXME: what is the proper promotion from ASCII to UNICODE?
  53     this->name[i] = name[i] & 0xFF;
  54   }
  55 }
  56 
  57 ProcEntry::ProcEntry(const ProcEntry& arg) {
  58   name = NULL;
  59   copyFrom(arg);
  60 }
  61 
  62 ProcEntry&
  63 ProcEntry::operator=(const ProcEntry& arg) {
  64   copyFrom(arg);
  65   return *this;
  66 }
  67 
  68 ProcEntry::~ProcEntry() {
  69   delete[] name;
  70 }
  71 
  72 void
  73 ProcEntry::copyFrom(const ProcEntry& arg) {
  74   if (name != NULL) {
  75     delete[] name;
  76   }
  77   pid = arg.pid;
  78   nameLength = arg.nameLength;
  79   name = new WCHAR[nameLength];
  80   memcpy(name, arg.name, nameLength * sizeof(WCHAR));
  81 }
  82 
  83 ULONG
  84 ProcEntry::getPid() {
  85   return pid;
  86 }
  87 
  88 USHORT
  89 ProcEntry::getNameLength() {
  90   return nameLength;
  91 }
  92 
  93 WCHAR*
  94 ProcEntry::getName() {
  95   return name;
  96 }
  97 
  98 void
  99 procList(ProcEntryList& processes) {
 100   static ProcListImplFunc* impl = NULL;
 101 
 102   if (impl == NULL) {
 103     // See which operating system we're on
 104     impl = (isNT4() ? &procListImplNT4 : &procListImplToolHelp);
 105   }
 106 
 107   assert(impl != NULL);
 108 
 109   (*impl)(processes);
 110 }
 111 
 112 void
 113 procListImplNT4(ProcEntryList& processes) {
 114   using namespace NT4;
 115 
 116   static ZwQuerySystemInformationFunc* query = NULL;
 117 
 118   if (query == NULL) {
 119     HMODULE ntDLL = loadNTDLL();
 120     query =
 121       (ZwQuerySystemInformationFunc*) GetProcAddress(ntDLL,
 122                                                      "ZwQuerySystemInformation");
 123     assert(query != NULL);
 124   }
 125 
 126   ULONG n = 0x100;
 127   PSYSTEM_PROCESSES sp = new SYSTEM_PROCESSES[n];
 128   while ((*query)(SystemProcessesAndThreadsInformation,
 129                   sp, n * sizeof(SYSTEM_PROCESSES), 0) == STATUS_INFO_LENGTH_MISMATCH) {
 130     delete[] sp;
 131     n *= 2;
 132     sp = new SYSTEM_PROCESSES[n];
 133   }
 134 
 135   bool done = false;
 136   for (PSYSTEM_PROCESSES p = sp; !done;
 137        p = PSYSTEM_PROCESSES(PCHAR(p) + p->NextEntryDelta)) {
 138     processes.push_back(ProcEntry(p->ProcessId,
 139                                   p->ProcessName.Length / 2,
 140                                   p->ProcessName.Buffer));
 141     done = p->NextEntryDelta == 0;
 142   }
 143 }
 144 
 145 void
 146 procListImplToolHelp(ProcEntryList& processes) {
 147   using namespace ToolHelp;
 148 
 149   static CreateToolhelp32SnapshotFunc* snapshotFunc = NULL;
 150   static Process32FirstFunc*           firstFunc    = NULL;
 151   static Process32NextFunc*            nextFunc     = NULL;
 152 
 153   if (snapshotFunc == NULL) {
 154     HMODULE dll = loadDLL();
 155 
 156     snapshotFunc =
 157       (CreateToolhelp32SnapshotFunc*) GetProcAddress(dll,
 158                                                      "CreateToolhelp32Snapshot");
 159 
 160     firstFunc = (Process32FirstFunc*) GetProcAddress(dll,
 161                                                      "Process32First");
 162 
 163     nextFunc = (Process32NextFunc*) GetProcAddress(dll,
 164                                                    "Process32Next");
 165 
 166     assert(snapshotFunc != NULL);
 167     assert(firstFunc    != NULL);
 168     assert(nextFunc     != NULL);
 169   }
 170 
 171   HANDLE snapshot = (*snapshotFunc)(TH32CS_SNAPPROCESS, 0 /* ignored */);
 172   if (snapshot == (HANDLE) -1) {
 173     // Error occurred during snapshot
 174     return;
 175   }
 176 
 177   // Iterate
 178   PROCESSENTRY32 proc;
 179   if ((*firstFunc)(snapshot, &proc)) {
 180     do {
 181       // FIXME: could make this uniform to the NT version by cutting
 182       // off the path name just before the executable name
 183       processes.push_back(ProcEntry(proc.th32ProcessID,
 184                                     strlen(proc.szExeFile),
 185                                     proc.szExeFile));
 186     } while ((*nextFunc)(snapshot, &proc));
 187   }
 188 
 189   CloseHandle(snapshot);
 190 }