Starting external offline programm via Phyton

Hy!

How can i open external programm (*.exe / htlm) via phyton.
Can i start it directly with an short operator?

Thank for help

I found something like that…


import bpy
import os, sys
import subprocess

# snippet by saidenka / meta-androcto
class OpenExternal(bpy.types.Operator):
    bl_idname = "wm.open_external"
    bl_label = "Open External"
    bl_description = "open external files or programm"
    bl_options = {'REGISTER'}
    
    def execute(self, context):
        exe = os.path.join(os.path.dirname(__file__), "console_toggle.py")
        filepath = bpy.data.filepath
        if (filepath != ""):
            subprocess.Popen([sys.argv[0], filepath, '-P', exe])
        else:
            subprocess.Popen([sys.argv[0],'-P', exe])
        return {'FINISHED'}



def menu_func(self, context):
    layout = self.layout
    layout.separator()
    layout.operator(OpenExternal.bl_idname, icon="PLUGIN")
    layout.separator()


def register():
    bpy.utils.register_module(__name__)
    bpy.types.INFO_MT_file.prepend(menu_func)

def unregister():
    bpy.utils.register_module(__name__)
    bpy.types.INFO_MT_file.remove(menu_func)


if __name__ == "__main__":
    register()

…this, i think it a bit to far…


import os
import string

def run(program, *args):
    # find executable
    for path in string.split(os.environ["PATH"], os.pathsep):
        file = os.path.join(path, program) + ".exe"
        try:
            return os.spawnv(os.P_WAIT, file, (file,) + args)
        except os.error:
            pass
    raise os.error, "cannot find executable"

run("python", "hello.py")

print "goodbye"

Here are the site: http://effbot.org/librarybook/os.htm

This might give you a clue

I think subprocess is the best option


>>> import subprocess as s
>>> s.Popen("notepad.exe")
<subprocess.Popen object at 0x00000004E3379080>



It is hard for me to figure out what to do…Can you explain it a little more?

Here is the example, it works well either way with os.system or subprocess. Only one problem I found was that Blender would stuck as long as the external program is open. This command os.system/subprocess.call won’t finish until the external program is closed, so this will make Blender stuck because it won’t do anything else until the script is finished.

If the external program won’t remain open too long (say about 1 to 5 seconds) you might call directly the external program otherwise you will need to use threading. I don’t know what errors multi threading will bring but at least it will solve the stuck.


import bpy
import threading

def run_program():
    # import os
    # os.system("notepad.exe")
    import subprocess
    subprocess.call("notepad.exe")

class RunExternalProgramOperator(bpy.types.Operator):
    bl_idname = "wm.run_ext_program"
    bl_label = "Run External Program Operator"

    def execute(self, context):
        t = threading.Thread(target=run_program)
        t.start()
        return {'FINISHED'}

def register():
    bpy.utils.register_class(RunExternalProgramOperator)

def unregister():
    bpy.utils.unregister_class(RunExternalProgramOperator)

if __name__ == "__main__":
    register()
    bpy.ops.wm.run_ext_program()



Thank you!
This work well for the installed accessories programms in windows > system32!
eg.: SnippingTool.exe / mspaint.exe / StikyNot.exe / xpsrchvw.exe / psr.exe / etc.

Is there a way to start portal programms on a relativ path?

If you want to see from where the script is loaded you can do this:

print(__file__)

and see how you can manage this filepath.

I tried this also and seemed like a good alternative, the deal is that you will create an environment variable and use that instead to get a proper path.


def environment_path():
    import os
    return os.environ.get("MY_APP_DIR")
def run_program():
    import subprocess
    subprocess.call(environment_path() + "/hello.bat") #or whatever file

You could try this approach:
put the program I want to call in same folder as plugin, and then locate it using the dirname of file.
make a list containing the abspath to the program as first entry, and any other parameters as next entries


from os import path
#fetch absolute path to the folder where this script, and the program, are
working_dir = path.dirname(__file__)
program_path = path.join(working_dir, 'myprogram.exe')
params = [program_path, 'any_parameter_you_want', 'as many as you like']
proc = subprocess.Popen(args=args , cwd=self.working_dir)
#if you want to wait till process has finished, call proc.wait() here

You can actually do the following (at least on Windows):

bpy.ops.wm.url_open(url=“notepad.exe”)

If the url leads to a file, it will open in the standard application.

Here is a small result collection:


import bpy

from bpy import*
import threading

def current_path():
    import os
    import sys
    return os.path.dirname(__file__)

def run_program():
    # import os
    # os.system("notepad.exe")
    import subprocess
    subprocess.call("notepad.exe")
    #import webbrowser
    #webbrowser.open(current_path() + '/manual.html')


class RunExternalProgramOperator(bpy.types.Operator):
    """Run External Programm or Websides"""
    bl_idname = "wm.run_ext_program"
    bl_label = "Run External Program Operator"

    def execute(self, context):
        t = threading.Thread(target=run_program)
        t.start()
        return {'FINISHED'}


class DocuPanel(bpy.types.Panel):
    bl_label = "Documentation"
    bl_idname = "OBJECT_PT_Docu"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'
    bl_category = 'Info'
    bl_options =  {'DEFAULT_CLOSED'}   

    def draw(self, context):
        layout = self.layout

        row = layout.column()
        row.operator("wm.run_ext_program","Notepad", icon='FILE_TEXT')
        row.operator('wm.path_open',  text = 'Open Documents', icon='HELP').filepath = "C:\\Users\Public\Documents"
        row.operator('wm.url_open',  text = 'Open Manuel Html', icon = 'FILESEL').url = "C:\\Users\Public\Documents\xxx.html"
        


def register():
    bpy.utils.register_class(RunExternalProgramOperator)
    bpy.utils.register_class(DocuPanel)

def unregister():
    bpy.utils.unregister_class(RunExternalProgramOperator)
    bpy.utils.unregister_class(DocuPanel)


if __name__ == "__main__":
    register()
    #bpy.ops.wm.run_ext_program()