8c6481e5a1276b29b829d6782691e529d2f0de37
[sdk] / ide / src / debugger / process.ec
1 default:
2 #define uint _uint
3 #define String String_
4
5 #include <unistd.h>
6 #ifdef __WIN32__
7 #define WIN32_LEAN_AND_MEAN
8 #include <windows.h>
9 #include <stdio.h>
10 #include <tlhelp32.h>
11 #else
12
13 #define uint _uint
14 #define property _property
15 #define new _new
16 #define class _class
17 #define Window    X11Window
18 #define Cursor    X11Cursor
19 #define Font      X11Font
20 #define Display   X11Display
21 #define Time      X11Time
22 #define KeyCode   X11KeyCode
23
24 #include <signal.h>
25
26 #include <X11/Xatom.h>
27 #include <X11/Xlib.h>
28 #include <X11/Xresource.h>
29 #include <X11/Xutil.h>
30 #include <fcntl.h>
31
32 #undef Window
33 #undef Cursor
34 #undef Font
35 #undef Display
36 #undef Time
37 #undef KeyCode
38 #undef uint
39 #undef new
40 #undef property
41 #undef class
42
43 #endif
44 #undef uint
45 #undef String
46
47 private:
48
49 import "ecere"
50
51 #ifdef __WIN32__
52 static bool CALLBACK EnumWindowsBringToTop(HWND hwnd, LPARAM lParam)
53 {
54    DWORD pid;
55    GetWindowThreadProcessId(hwnd, &pid);
56    if(pid == lParam)
57       BringWindowToTop(hwnd);
58    return true;
59 }
60
61 static bool CALLBACK EnumWindowsSetForeground(HWND hwnd, LPARAM lParam)
62 {
63    DWORD pid;
64    GetWindowThreadProcessId(hwnd, &pid);
65    if(pid == lParam)
66    {
67       for(;;)
68       {
69          HWND parent = GetParent(hwnd);
70          if(parent) hwnd = parent; else break;
71       }
72       SetForegroundWindow(hwnd); //SetForegroundWindow( GetAncestor(hwnd, GA_ROOTOWNER));
73       return false;
74    }
75    return true;
76 }
77
78 class ShowProcessWindowsThread : Thread
79 {
80    int processId;
81    unsigned int Main()
82    {
83       if(processId)
84       {
85          EnumWindows(EnumWindowsSetForeground, processId);
86          EnumWindows(EnumWindowsBringToTop, processId);
87       }
88       return 0;
89    }
90 }
91 #else
92
93 extern void * IS_XGetDisplay();
94 static Atom xa_NET_WM_PID, xa_activeWindow;
95
96 static void WaitForViewableWindow(X11Display * xGlobalDisplay, X11Window window)
97 {
98    int c;
99    XFlush(xGlobalDisplay);
100    for(c = 0; c<4; c++)
101    // while(true)
102    {
103       XWindowAttributes attributes = { 0 };
104       XGetWindowAttributes(xGlobalDisplay, window, &attributes);
105       if(attributes.map_state == IsViewable)
106          break;
107       else
108          Sleep(1.0 / 18.2);
109    }
110 }
111
112 static void EnumWindowBringToTop(X11Display * xGlobalDisplay, X11Window window, int processId)
113 {
114    Atom xa_type;
115    X11Window root = 0, parent = 0, * children = null;
116    uint numWindows = 0;
117    int format;
118    unsigned long len, fill;
119
120    if(XQueryTree(xGlobalDisplay, window, &root, &parent, &children, &numWindows))
121    {
122       int c;
123       for(c = 0; c<numWindows; c++)
124       {
125          byte * data;
126          if(XGetWindowProperty(xGlobalDisplay, children[c], xa_NET_WM_PID, 0, 1, False,
127                                XA_CARDINAL, &xa_type, &format, &len, &fill,
128                                &data) != Success)
129          {
130             // printf("cant get _NET_WM_PID property\n");
131             break;
132          }
133
134          if(data)
135          {
136             int pid = *(int *)data;
137             //printf("pid: %d\n", pid);
138             if(pid == processId)
139             {
140                // printf("Found one window with processID\n");
141                {
142                   XRaiseWindow(xGlobalDisplay, children[c]);
143                   WaitForViewableWindow(xGlobalDisplay, children[c]);
144                   if(xa_activeWindow)
145                   {
146                      XClientMessageEvent event = { 0 };
147                      event.type = ClientMessage;
148                      event.message_type = xa_activeWindow;
149                      event.display = xGlobalDisplay;
150                      event.serial = 0;
151                      event.window = children[c];
152                      event.send_event = 1;
153                      event.format = 32;
154                      event.data.l[0] = 0;
155
156                      XSendEvent(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), bool::false, SubstructureRedirectMask | SubstructureNotifyMask, (union _XEvent *)&event);
157                   }
158                   else
159                      XSetInputFocus(xGlobalDisplay, children[c], RevertToPointerRoot, CurrentTime);
160                }
161             }
162          }
163          else
164             EnumWindowBringToTop(xGlobalDisplay, children[c], processId);
165       }
166    }
167    if(children)
168       XFree(children);
169 }
170
171 #endif
172
173 void Process_ShowWindows(int processId)
174 {
175 #ifdef __WIN32__
176    ShowProcessWindowsThread thread { processId = processId };
177    thread.Create();
178 #else
179    if(processId)
180    {
181       X11Display * xGlobalDisplay = IS_XGetDisplay();
182       xa_NET_WM_PID = XInternAtom(xGlobalDisplay, "_NET_WM_PID", True);
183       xa_activeWindow = XInternAtom(xGlobalDisplay, "_NET_ACTIVE_WINDOW", True);
184       EnumWindowBringToTop(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), processId);
185    }
186 #endif
187 }
188
189 bool Process_Break(int processId)
190 {
191    bool result = false;
192 #ifdef __WIN32__
193    HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId);
194    if(handle)
195    {
196       DWORD remoteThreadId;
197       HANDLE hRemoteThread;
198       static void * debugBreakAddress;
199       if(!debugBreakAddress)
200       {
201          HINSTANCE hDll = LoadLibrary("kernel32");
202          debugBreakAddress = GetProcAddress(hDll, "DebugBreak");
203          FreeLibrary(hDll);
204       }
205       hRemoteThread = CreateRemoteThread(handle, null, 0, debugBreakAddress, 0, 0, &remoteThreadId);
206       if(hRemoteThread)
207       {
208          //DebugBreakProcess(handle);  // this worked only in winxp, right?
209          //GenerateConsoleCtrlEvent(CTRL_C_EVENT, processId);  // this had no effect, right?
210          result = true;
211          CloseHandle(hRemoteThread);
212       }
213       CloseHandle(handle);
214    }
215 #else
216    kill(processId, SIGTRAP);
217    result = true;
218 #endif
219    return result;
220 }
221
222 int Process_GetCurrentProcessId()
223 {
224 #ifdef __WIN32__
225    DWORD currentProcessId = GetCurrentProcessId();
226    return currentProcessId;
227 #else
228    return (int)getpid();
229 #endif
230 }
231
232 int Process_GetChildExeProcessId(const int parentProcessId, const char * exeFile)
233 {
234 #ifdef __WIN32__
235    HANDLE hProcessSnap;
236    PROCESSENTRY32 pe32;
237
238    int childProcessId = 0;
239
240    hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
241
242    if(hProcessSnap != INVALID_HANDLE_VALUE)
243    {
244       pe32.dwSize = sizeof(PROCESSENTRY32);
245
246       if(Process32First(hProcessSnap, &pe32))
247       {
248          do
249          {
250             if(pe32.th32ParentProcessID == parentProcessId)
251             {
252                //if(strstr(exeFile, pe32.szExeFile) == exeFile)
253                if(SearchString(exeFile, 0, pe32.szExeFile, false, false) == exeFile)
254                {
255                   childProcessId = pe32.th32ProcessID;
256                   break;
257                }
258             }
259          } while(Process32Next(hProcessSnap, &pe32));
260       }
261       CloseHandle(hProcessSnap);
262    }
263    return childProcessId;
264 #elif defined(__linux__)
265    char exeFileTruncated[16];
266    FileListing listing { "/proc/" };
267    // Names is limited to 15 characters in /proc/pid/status
268    strncpy(exeFileTruncated, exeFile, 15);
269    exeFileTruncated[15] = 0;
270    while(listing.Find())
271    {
272       if(listing.stats.attribs.isDirectory)
273       {
274          int process = atoi(listing.name);
275          if(process)
276          {
277             int ppid = 0;
278             bool found = false;
279             char fileName[256];
280             File f;
281             strcpy(fileName, listing.path);
282             PathCat(fileName, "status");
283             if((f = FileOpen(fileName, read)))
284             {
285                char buffer[256];
286                while(f.GetLine(buffer, 256))
287                {
288                   if(!strncmp(buffer, "Name:", 5))
289                   {
290                      char * string = strstr(buffer + 6, exeFileTruncated);
291                      if(!string || strcmp(string, exeFileTruncated))
292                         break;
293                      found = true;
294                   }
295                   else if(!strncmp(buffer, "PPid:", 5))
296                   {
297                      ppid = atoi(buffer + 6);
298                      break;
299                   }
300                }
301                delete f;
302             }
303             if(found && ppid == parentProcessId)
304             {
305                listing.Stop();
306                return process;
307             }
308          }
309       }
310    }
311    return 0;
312 #else
313    // This is the current OS X implementation
314    uint pid = 0;
315    File f = DualPipeOpen({ output = true }, "ps -ajx");
316    if(f)
317    {
318       bool firstLine = true;
319       int pidColumn = -1;
320       int ppidColumn = -1;
321       while(!f.eof)
322       {
323          char line[1024];
324          char * tokens[128];
325          if(f.GetLine(line,sizeof(line)))
326          {
327             uint count = Tokenize(line, sizeof(tokens)/sizeof(tokens[0]), tokens,false);
328             int i;
329             if(firstLine)
330             {
331                for(i = 0; i < count; i++)
332                {
333                   if(!strcmpi(tokens[i], "pid"))
334                      pidColumn = i;
335                   else if(!strcmpi(tokens[i], "ppid"))
336                      ppidColumn = i;
337                }
338                if(pidColumn > 0 && ppidColumn > 0)
339                   firstLine = false;
340                else
341                   break;
342             }
343             else
344             {
345                if(count > pidColumn && count > ppidColumn && strtoul(tokens[ppidColumn], null, 0) == parentProcessId)
346                {
347                   pid = (uint)strtoul(tokens[pidColumn], null, 0);
348                   break;
349                }
350             }
351          }
352       }
353       delete f;
354    }
355    return pid;
356 #endif
357 }
358
359 void setEcereLanguageInWinRegEnvironment(const char * languageCode)
360 {
361 #ifdef __WIN32__
362    HKEY key = null;
363    uint16 wLanguage[256];
364    DWORD status;
365    wLanguage[0] = 0;
366
367    RegCreateKeyEx(HKEY_CURRENT_USER, "Environment", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
368    if(key)
369    {
370       UTF8toUTF16Buffer(languageCode, wLanguage, sizeof(wLanguage) / sizeof(uint16));
371       RegSetValueExW(key, L"ECERE_LANGUAGE", 0, REG_EXPAND_SZ, (byte *)wLanguage, (uint)(wcslen(wLanguage)+1) * 2);
372       RegCloseKey(key);
373    }
374 #endif
375 }