Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

Psapi and Windows

Moderators: larsivi kris

Posted: 11/10/08 23:07:36

Hello,

I need help. I'm starting to write a Windows pgm which can list all processes on the system (option 'l') There's also an option to list modules on a specifique process (option 'm [PID]') But this function return a object.Exception and I really really don't find why... :-(

Thanks, TSalm

Here is the code :

module system.ProcessEnvVars;

private
{
    import tango.sys.win32.Types;
    import tango.sys.win32.UserGdi;
    import SharedLib = tango.sys.SharedLib;
    
    import tango.io.Stdout;
    
    import tango.io.FilePath;
    
    import tango.stdc.stringz;
    
    import tango.text.convert.Layout;
    
    import tango.io.Console;
    
    import tango.text.Util;

    import tango.text.Regex;
    
    import Utf = tango.text.convert.Utf;
    
    import Integer = tango.text.convert.Integer;
    
    import tango.core.Memory;
    
}

void main()
{
    new Commands;
}

class Commands
{
    align(1) struct CommandeInfo
    {
        char[]  description;
        bool delegate (char[] argLn) func;
        
        public static CommandeInfo opCall( char[] d , bool delegate (char[] args) f )
        {
            CommandeInfo c;
            
            c.description = d;
            c.func = f;
            
            return c;
        }
        
    }
    
    CommandeInfo[char[]] commandes;
    
    bool doNotQuit;
    
    static char[] INFO_BASE = ">> ";
    char[] info;

    // Le processus en cours
    Process currentProc ;
    
    this()
    {
        commandes = [
                          "?"[]:CommandeInfo(   "Aide"     ,&usage)
                         ,"q":CommandeInfo(   "Quitter"  ,&quit)
                         ,"l":CommandeInfo( "Lister les processus. Arg: [regexp]", &listProc)
                         ,"o":CommandeInfo( "Entrer dans un processus specifique. Arg: [PID]" , &openProc)
                         ,"k":CommandeInfo( "Tuer un processus. Arg: [PID]|aucun" , &killProc )
                         ,"m":CommandeInfo( "Lister les modules. Arg: [PID]|aucun" , &listModules)
                     ];
        
        doNotQuit = true;
        info = INFO_BASE;
        
        while(doNotQuit)
        {
            // "before-cmd" info
            Stdout(info)();
            
            // Get command...
            char[] cmd;
            Cin.readln(cmd);
            
            // Interpret it !
            size_t posSpace = indexOf( cmd.ptr , ' ' , cmd.length);
            
            if (posSpace)
            {
                char[] c = trim( cmd[0..posSpace] );
                char[] a;
                if (posSpace != cmd.length)
                    a = trim( cmd[posSpace..$] );
                else
                    a = "";

                
                if ( c in commandes )
                    commandes[ c ].func(a);
                else
                    Stdout("\a " ~ c ~ " : commande inconnue !\n Utiliser '?' pour afficher l'aide\n")();

            }
        }
    }
    
    /***
     * Usage
     * Returns:
     */
    bool usage(char[] argLn)
    {
        char[] _out;
        foreach (cK,cV;commandes)
        {
            _out ~= (new Layout!(char)).convert("{,4} : {}\n",cK,cV.description); 
        }
        
        Stdout(_out)();

        return true;
    }
    
    /***
     * Quit
     * Params:
     *     args = 
     * Returns:
     */
    bool quit(char[] argLn)
    {
        doNotQuit = false;
        
        return true;
    }
    
    
    /***
     * Liste les processus et leurs ID
     * Params:
     *     argLn = 
     * Returns:
     */
    bool listProc(char[] argLn)
    {
        auto ps = new Processes ;
        
        foreach ( p ; ps.list )
        {
            auto pid = p.pid;
            wchar[] filename;
            try {
                filename = p.filename;
            } catch(ApiException)
            {
                filename = "[unknow]";
            }
            
            
            // filter ?
            if (argLn.length)
                if (! RegExpT!(wchar)(  Utf.toString16(argLn)  ).test( filename ) )
                    continue;
            
            Stdout.format("{0,4} : {}\n",pid,filename );
                
        }
        
        return true;
    }
    
    bool openProc(char[] argLn)
    {
        
        // Vérifie les paramètres
        try 
            currentProc =  new Process( Integer.toInt(argLn) );
        catch (IllegalArgumentException)
        {
            Stdout.format(" Erreur : '{}' n'est pas un nombre valide.\n",argLn)();
            return false;
        }
        
        info = (new Layout!(char)).convert("{}({}){}",currentProc.filename ,currentProc.pid , INFO_BASE );        
        
        
        return true;
    }
    
    bool killProc(char[] argLn)
    {
        if (currentProc is null)
        {
            if (argLn.length == 0)
            {
                Stdout(" Erreur : Aucun processus en cours\n")();
                return false;
            }
                
            try 
                (new Process( Integer.toInt(argLn) ) ).kill(0) ;
            catch (IllegalArgumentException)
            {
                Stdout.format(" Erreur : '{}' n'est pas un nombre valide.\n",argLn)();
                return false;
            }
            
            return true;
        } else{
            currentProc.kill(0);
        }
        
        return true;
    }

    bool listModules(char[] argLn)
    {
        wchar[][] lstModules;
        
        if (currentProc is null)
        {
            if (argLn.length == 0)
            {
                Stdout(" Erreur : Aucun processus en cours\n")();
                return false;   
            }
            
            try 
                lstModules = (new Process( Integer.toInt(argLn) )).listModulesFileName  ;
            catch (IllegalArgumentException)
            {
                Stdout.format(" Erreur : '{}' n'est pas un nombre valide.\n",argLn)();
                return false;
            }
        } else {
            lstModules = currentProc.listModulesFileName();
        }
           
        foreach(mStr;lstModules)
        {
            Stdout.format("  {}\n",mStr)();
        }
        
        Stdout.format(" {} module(s)\n",lstModules.length)();
        
        return true;
    }
    
}


  
public extern (C) BOOL function (
                                 DWORD *pProcessIds,
                                 DWORD cb,
                                 DWORD *pBytesReturned
                               ) EnumProcesses;
                

public extern (C) DWORD function(
                     HANDLE hProcess,
                     LPTSTR lpImageFileName,
                     DWORD nSize
                   ) GetProcessImageFileNameW;


public extern (C) BOOL function (
                     HANDLE hProcess,
                     HMODULE *lphModule,
                     DWORD cb,
                     LPDWORD dwFilterFlag
                   ) EnumProcessModules ;


public extern (C) DWORD function (
                     HANDLE hProcess,
                     HMODULE hModule,
                     LPTSTR lpFilename,
                     DWORD nSize
                   ) GetModuleFileNameExW;



static class Psapi
{
    private static SharedLib.SharedLib libPsapi ;
    
    static this()
    {
        // Load library
        libPsapi     = SharedLib.SharedLib.load(`psapi.dll`);
        
        // DLL functions
        EnumProcesses = cast(typeof(EnumProcesses)) libPsapi.getSymbol("EnumProcesses") ;
        GetProcessImageFileNameW = cast(typeof(GetProcessImageFileNameW)) libPsapi.getSymbol("GetProcessImageFileNameW") ;
        EnumProcessModules = cast(typeof(EnumProcessModules)) libPsapi.getSymbol("EnumProcessModules") ;
        GetModuleFileNameExW = cast(typeof(GetModuleFileNameExW)) libPsapi.getSymbol("GetModuleFileNameExW") ;
        
    }
    
    static ~this()
    {
        libPsapi.unload;
    }
}

class ApiException:Exception
{
    this(char[] message)
    {
        super(message);
    }
}


class Processes
{

    
    this()
    {
        
    }
    

    
    uint[] listPID()
    {
        DWORD[] pProcessIds = new DWORD[2000];
        DWORD   cb = 2000 * DWORD.sizeof;
        DWORD   pBytesReturned;
        
        if ( EnumProcesses( pProcessIds.ptr , cb , &pBytesReturned ) == 0)
        {
            throw new Exception("Can't get process list");
        }
        
        pProcessIds = pProcessIds[0..(pBytesReturned/DWORD.sizeof)];
        
        return pProcessIds;
    }
    
    Process[] list()
    {
        Process[] pList;
        
        foreach ( pid ; listPID )
        {
            pList ~= new Process(pid);
        }
        
        return pList;
    }
    
}

class Process
{
    private 
    {
        uint _pid;
        HANDLE h;
    }
    
    this(uint pid)
    {
        h = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid);
        this._pid = pid;
    }
    
    
    
    ~this()
    {
        
        Stdout("Close process...\n")();
        CloseHandle(h);
    }
    
    uint pid()
    {
        return _pid;
    }
    
    wchar[] path()
    {
        const DWORD SZ_MAX = 2000;
        LPTSTR lpImageFileName = (new wchar[SZ_MAX]).ptr;
        DWORD sz =  GetProcessImageFileNameW(h,lpImageFileName,SZ_MAX);
        if (sz==0)
            throw new ApiException("GetProcessImageFileName(h,lpImageFileName) in getFileName");

        return lpImageFileName[0..sz].dup;
    }
    
    wchar[] filename()
    {
        wchar[] p = path(); 
        size_t pos_begin = locatePrior( p , cast(wchar)'\\', p.length )+1;
        size_t pos_end   = locate( p , cast(wchar)'.' , pos_begin );
        
        return p[pos_begin..pos_end];
    }
    
    void kill(uint exitCode)
    {
        TerminateProcess(h,exitCode);
    }
    
    private HMODULE[] getModules()
    {
        const MAX_NBR_EL = 1000 ;
        
        BOOL result;
        HMODULE[] hModule = new HMODULE[MAX_NBR_EL];
        DWORD cb = MAX_NBR_EL * HMODULE.sizeof; 
        DWORD cbNeeded;

        
        if (    !
                    EnumProcessModules(
                        h,
                        hModule.ptr,
                        cb,
                        &cbNeeded
                    )
                )
            throw new ApiException("EnumProcessModulesEx in getModules()");

        return hModule[ 0 .. ((cbNeeded)/(HMODULE.sizeof)) ]; 
        
    }
    
    
    public wchar[][] listModulesFileName()
    {        
        static const size_t MAX_STR_SIZE = 2000;
        
        wchar[][] moduleList;

        foreach(hModule;getModules())
        {            

            wchar baseName[MAX_STR_SIZE] ;
            DWORD  size = MAX_STR_SIZE;
            DWORD  szOut = 0;

            szOut = GetModuleFileNameExW(
                             h
                            ,hModule
                            ,baseName.ptr
                            ,MAX_STR_SIZE
                    ); 

            wchar[] name;
            if (szOut == 0)
                name = "[unknow]";
            else
                name = baseName[0..szOut] ;
            
            moduleList ~= name;
            
            
        }
        
        return moduleList;
    }
    
}

Author Message

Posted: 11/10/08 23:58:34

Heya, I haven't read all of your code, but I've noticed that your winapi functions are extern(C) while they should be extern(Windows). If that doesn't help, then perhaps some of the code in my beta profiler for D could: http://team0xf.com:1024/dprof

Posted: 11/11/08 09:27:03

h3r3tic wrote:

Marvellous! change "extern(C)" to "extern(Windows)" resolve the problem.
Thank H3r3tic