www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Multiple-OS Header Access

reply "Malkierian" <rhydonj gmail.com> writes:
Alright, so I'm making a little utility, and it looks like I'm 
going to need to access OS-specific header functions on each 
operating system in order to make it work, because 1) I want to 
get a list of all active processes and their names and 2) I want 
to periodically check which window currently has focus.  I've 
already found SetWinEventHook and GetForegroundWindow (for 
checking the foreground window and setting an event hook for 
focus change), and also EnumProcesses for getting the list, but 
these are all Windows specific, not to mention C++ specific on 
Windows, and I can't see any way of making one set of functions 
that would work on Windows, Mac and Linux.

So anyway, my question is, does D have the capability of 
interfacing with Linux and Mac such that those functions are 
accessible, and/or would I be better of working in C++ for this 
particular venture?  How would I go about accessing those 
functions, and using the information they provide in D?
Feb 12 2014
next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Wednesday, 12 February 2014 at 17:21:52 UTC, Malkierian wrote:
 not to mention C++ specific on Windows
They aren't really C++ specific, you can use them from a lot of languages, including C and D.
 So anyway, my question is, does D have the capability of 
 interfacing with Linux and Mac such that those functions are 
 accessible
Not those specific functions, since they are part of Windows. Similar functions on Linux would be... I think you'd have to read the /proc directory for directories with numeric names, then inside there, you can read a file called cmdline to get the process name (sort of, it is the command line used to launch it) and other stuff. The name of the directory is the process id. To get the currently focused window on linux, you could do it by asking the X server. The functions XGetInputFocus or fetching the _NET_ACTIVE_WINDOW atom should give a usable window id. Tying window IDs to process IDs is a bit harder, you might be able to get it by looking for a _NET_WM_PID atom... which is opt-in by the application, I don't think the X server necessarily knows the pid of the owner (indeed, the owner might be running on a different computer anyway). So yeah, kinda in depth low level stuff. I don't know if there's any library to help with this. I have no idea about Mac (or even other unixes for that matter). , and/or would I be better of working in C++ for this
 particular venture?
Linux is a pain in the ass to program for in any language... but if you can do it in C or C++, you can mostly just to the same thing in D. Might have to copy/paste function prototypes though.
Feb 12 2014
next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
version(linux)
void EnumProcessesLinux(void delegate(long) forEach) {
         import std.file;
         import std.algorithm;
         import std.ascii;
         import std.conv;
         foreach(string name; dirEntries("/proc/", 
SpanMode.shallow)) {
                 name = name["/proc/".length .. $];
                 if(all!isDigit(name))
                         forEach(to!long(name));
         }
}

void main() {
         import std.stdio;
         EnumProcessesLinux((n) => writeln(n));
}


Not the same signature as the Windows function (the windows one 
is weird imo) but the same functionality - this will print the 
process ID of everything on the system.
Feb 12 2014
prev sibling next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
Here's some more functions:

version(linux)
string getProcessCommandLine(long pid) {
         import std.file;
         import std.conv;
         return readText("/proc/" ~ to!string(pid) ~ "/cmdline");
}


And for looking at windows, you'll want my simpledisplay.d and 
color.d from here:
https://github.com/adamdruppe/misc-stuff-including-D-programming-language-web-stuff


Then use these two functions:

import simpledisplay;
Window getActiveWindow() {
         auto display = XDisplayConnection.get();
         auto focusedAtom = GetAtom!"_NET_ACTIVE_WINDOW"(display);

         Atom target;
         int format;
         arch_ulong bytesafter, length;
         char* value;
         XGetWindowProperty(
                 display,
                 RootWindow(display, DefaultScreen(display)),
                 focusedAtom,
                 0,
                 100000 /* length */,
                 false,
                 0 /*AnyPropertyType*/,
                 &target, &format, &length, &bytesafter, &value);

         assert(format == 32);

         auto activeWindowId = *cast(uint*) value;

         XFree(value);

         return cast(Window) activeWindowId;
}

long getWindowPid(Window w) {
         auto display = XDisplayConnection.get();
         auto atom = GetAtom!"_NET_WM_PID"(display);

         Atom target;
         int format;
         arch_ulong bytesafter, length;
         char* value;
         XGetWindowProperty(
                 display,
                 w,
                 atom,
                 0,
                 100000 /* length */,
                 false,
                 0 /*AnyPropertyType*/,
                 &target, &format, &length, &bytesafter, &value);

         long pid;

         if(format == 32)
                 pid = *cast(uint*) value;
         if(format == 64)
                 pid = *cast(long*) value;

         XFree(value);

         return pid;
}



(You might notice they are substantially similar... perhaps I'll 
add a generic wrapper of some sort to simpledisplay.d for this 
stuff.)


Then you can use it:

void main() {
         auto activeWindow = getActiveWindow();
         auto pid = getWindowPid(activeWindow);
         writeln(pid);
         if(pid)
                 writeln(getProcessCommandLine(pid));
}


pid might not be available, so be sure to check that it is 
non-zero before trying to use it.

But I compiled this program:

dmd processes.d simpledisplay.d color.d

And ran it:

$ sleep 2; ./processes
9412
/home/me/firefox9/firefox/firefox


(The sleep was to give me a chance to focus another window before 
the program ran, here I went to firefox and it successfully 
showed that, or xterm if I go there, and so on. My rxvt does not 
set this property though... nor does my own simpledisplay.d 
windows!)



Anywho this is linux/X11 code, if you version them out you should 
be able to make a generic Windows function too.
Feb 12 2014
prev sibling parent reply "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Wednesday, 12 February 2014 at 17:40:01 UTC, Adam D. Ruppe 
wrote:
 Linux is a pain in the ass to program for in any language... 
 but if you can do it in C or C++, you can mostly just to the 
 same thing in D. Might have to copy/paste function prototypes 
 though.
How so? I find POSIX much more palatable than the Windows API. Though I guess GUI programming can be a little more involved, having to figure out which libraries to code against.
Feb 12 2014
parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Wednesday, 12 February 2014 at 18:26:45 UTC, Jakob Ovrum wrote:
 I find POSIX much more palatable than the Windows API.
POSIX is ok for what it does, but it doesn't actually do very much. The topics here, for example, are not standardized (I'm pretty sure anyway). Even de-facto standards like X11 is pretty minimal; you end having to do things yourself or get random third party libraries (which are often poorly documented and the user may not have installed!). Biggest examples are GTK and Qt for doing gui widgets since X doesn't do that, but even for basic drawing, X is pretty minimal... yet pretty complex in the stuff you have to get right to do that minimal amount of work. An example that irks me is the lack of "draw this image sized for this rectangle"; there's nothing like StretchBlt from Windows. Instead, you need to create an image (being sure to get the right format) and resize it yourself before sending those bits down to the display. (which btw cannot be compressed in the X protocol itself!) But generally, I find when I have a task I need to get done, Win32 offers some kind of function to do it and it doesn't take too long to find it on MSDN. It might be an ugly function with a dozen arguments wrapped up in a struct, but it gets the job done and just works for the user. On Linux, gotta go hunting for third party libraries... which might not work on the user's environment... or cannot complete the task at all (terminal emulators SUCK! want a key up notification? too bad) or can only very inefficiently (anti-aliased text on X for example... you get a screenshot, draw the text, then draw the modified image. The network won't be very transparent through that process, I tell you what.)
 Though I guess GUI programming can be a little more involved, 
 having to figure out which libraries to code against.
Yeah, that's a big problem too.
Feb 12 2014
prev sibling parent Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
On 2/12/2014 12:21 PM, Malkierian wrote:
 Alright, so I'm making a little utility, and it looks like I'm going to
 need to access OS-specific header functions on each operating system in
 order to make it work, because 1) I want to get a list of all active
 processes and their names and 2) I want to periodically check which
 window currently has focus.  I've already found SetWinEventHook and
 GetForegroundWindow (for checking the foreground window and setting an
 event hook for focus change), and also EnumProcesses for getting the
 list, but these are all Windows specific, not to mention C++ specific on
 Windows, and I can't see any way of making one set of functions that
 would work on Windows, Mac and Linux.

 So anyway, my question is, does D have the capability of interfacing
 with Linux and Mac such that those functions are accessible, and/or
 would I be better of working in C++ for this particular venture?  How
 would I go about accessing those functions, and using the information
 they provide in D?
Regarding actually accessing system libraries: ------------------------------------------- The system APIs on Windows and Linux are in C (and sometimes some C++ on Windows), and D is perfectly capable of linking with C (and a certain subset of C++), so yes this is possible. All you have to do to access these system libraries from D is write the extern declarations as described here: http://dlang.org/interfaceToC.html (C, for most system calls) http://dlang.org/cpp_interface.html (C++, in case you happen to need it) All in all, it's actually quite simple. There's also a really good series of articles out somewhere that explains more about it. Unfortunately I don't have a link to it handy right now, but you could maybe search for it, or maybe someone else knows. OSX might be a little trickier since a lot of its libs are in Objective-C instead of straight C, but Objective-C is still link-compatible with C just like D is, so it's definitely possible. Also, keep in mind that a lot of OS-specific calls are already available through D's standard library. See std.windows, std.linux, std.c.windows, std.c.posix, and I think there's some others. As for dealing with differences between OSes: ------------------------------------------- In C/C++, you'd do this with something like #ifdef. In D you use version(). //One way to do it: version(Windows) void myOwnWrapperFunction(blah blah blah) { // Use the Windows API } version(linux) void myOwnWrapperFunction(blah blah blah) { // Use the Linux API } version(OSX) void myOwnWrapperFunction(blah blah blah) { // Use the OSX API } //Another way to do it: void myOwnWrapperFunction(blah blah blah) { version(windows) { // Do it the Windows way } else version(OSX) { // Do it the Mac way } else version(Posix) { // Do it the Posix way } else static assert(0, "This OS not supported.") } Or any combination of the above. This way all the OS-specific differences are hidden inside your "myOwnWrapperFunction", and you can call it from any OS you've supported. As for knowing what OS-specific functions to use: ------------------------------------------- For that, you'd have to look at the documentation for the OS's API.
Feb 12 2014