tags:

views:

480

answers:

3

Is is possible to detect if a Python script was started from the command prompt or by a user "double clicking" a .py file in the file explorer on Windows?

+3  A: 

The command-prompt started script has a parent process named cmd.exe (or a non-existent process, in case the console has been closed in the mean time).

The doubleclick-started script should have a parent process named explorer.exe.

Tomalak
Clever. How would you do that?
grammar31
From http://docs.python.org/library/os.html#os.getppid it seems I can get the process id, but not the name.
pkit
It depends. What tools do you have available? Do you want to check from within the python script or from outside? In any case, "How do I find out Win32 process information using Python" is good material for a separate question.
Tomalak
After a brief Googling it seems that the win32pdh module is just what you need. It looks quite promising. WMI should also be perfectly capable of answering such a question
Tomalak
+1  A: 

Good question. One thing you could do is create a shortcut to the script in Windows, and pass arguments (using the shortcut's Target property) that would denote the script was launched by double-clicking (in this case, a shortcut).

jcoon
+3  A: 

Here is an example of how to obtain the parent process id and name of the current running script. As suggested by Tomalak this can be used to detect if the script was started from the command prompt or by double clicking in explorer.

import win32pdh
import os

def getPIDInfo():
    """ 
    Return a dictionary with keys the PID of all running processes.
    The values are dictionaries with the following key-value pairs:
        - name: <Name of the process PID>
        - parent_id: <PID of this process parent>
    """

    # get the names and occurences of all running process names
    items, instances = win32pdh.EnumObjectItems(None, None, 'Process', win32pdh.PERF_DETAIL_WIZARD)
    instance_dict = {}
    for instance in instances:
        instance_dict[instance] = instance_dict.get(instance, 0) + 1

    # define the info to obtain 
    counter_items =  ['ID Process', 'Creating Process ID']

    # output dict
    pid_dict = {}

    # loop over each program (multiple instances might be running)
    for instance, max_instances in instance_dict.items():
        for inum in xrange(max_instances):
            # define the counters for the query 
            hq = win32pdh.OpenQuery()
            hcs = {}
            for item in counter_items:
                path = win32pdh.MakeCounterPath((None,'Process',instance, None,inum,item))
                hcs[item] = win32pdh.AddCounter(hq,path)
            win32pdh.CollectQueryData(hq)

            # store the values in a temporary dict
            hc_dict = {}
            for item, hc in hcs.items():
                type,val=win32pdh.GetFormattedCounterValue(hc,win32pdh.PDH_FMT_LONG)
                hc_dict[item] = val
                win32pdh.RemoveCounter(hc)
            win32pdh.CloseQuery(hq)

            # obtain the pid and ppid of the current instance
            # and store it in the output dict
            pid, ppid = (hc_dict[item] for item in counter_items) 
            pid_dict[pid] = {'name': instance, 'parent_id': ppid}

    return pid_dict

def getParentInfo(pid):
    """
    Returns a PID, Name tuple of the parent process for the argument pid process.
    """
    pid_info = getPIDInfo()
    ppid = pid_info[pid]['parent_id']
    return ppid, pid_info[ppid]['name']

if __name__ == "__main__":
    """
    Print the current PID and information of the parent process.
    """
    pid = os.getpid()
    ppid, ppname = getParentInfo(pid)

    print "This PID: %s. Parent PID: %s, Parent process name: %s" % (pid, ppid, ppname)
    dummy = raw_input()

When run from the command prompt this outputs:

This PID: 148. Parent PID: 4660, Parent process name: cmd

When started by double clicking in explorer this outputs:

This PID: 1896. Parent PID: 3788, Parent process name: explorer

pkit