说明:前面的部分用于打开外部程序.exe;win32gui用于关闭窗口程序(显示最大化最小化)

Python调用(运行)外部程序  2019/3/7

 

在Python中可在脚本中直接使用其他脚本或程序

1 使用os.system(command)运行其他程序

参数

command 要执行的命令,相当于在Windows的cmd窗口中输入的命令。
如果要向程序或者脚本传递参数,可以使用空格分隔程序及多个参数。

实例:

import os,sys

os.system('notepad')          # 使用os.system()函数打开记事本程序
os.system('notepad python.txt')# 向记事本传递参数,打开python.txt文件
os.system('start "" /d  "C:\\Users\\Administrator\\AppData\\Roaming\\Goldminer3\\"  /wait
          "goldminer3.exe" ''--username=131628911xx --password=xxxx')

实例1.1:

def test():

     #base_dir=os.path.dirname("C:\\Users\\Administrator\\AppData\\Roaming\\Goldminer3\\")
     #sys.path.append(base_dir)      #临时修改环境变量
     
     currrent_path=os.getcwd()   
     print('1.current_path=',os.getcwd())#D:\PycharmProjects\test_py36
     os.chdir("C:\\Users\\Administrator\\AppData\\Roaming\\Goldminer3\\")#必须
     print('2.current_path=',os.getcwd()) 
    
     # C:\Users\Administrator\AppData\Roaming\Goldminer3
     os.system('goldminer3.exe --username=13162891176 --password=tcy-1974')
     os.chdir(currrent_path) #改变工作目录    

  test()

显示结果:

1.current_path= D:\PycharmProjects\test_py36
2.current_path= C:\Users\Administrator\AppData\Roaming\Goldminer3 
      [main 下午1:22:38] updatesetState idle
      [main 下午1:22:38] BackendInit { version: '3.10.0',
        commit: '10706b5ff1e4441304cd410756328c5d43e9b548' }
      ...
      [main 下午1:23:24] Backendquit
3.current_path= D:\PycharmProjects\test_py36

2 ShellExecute(hwnd, op , file , params , dir , bShow )相当于在资源管理器中双击文件图标一样:

参数

hwnd:父窗口的句柄,如果没有父窗口,则为0。
op:  要进行的操作,为“open”、“print”或者为空。
file:要运行的程序,或者打开的脚本。
params:要向程序传递的参数,如果打开的为文件,则为空。
dir:   程序初始化的目录。
bShow: 是否显示窗口。

实例2.1:

import win32api

win32api.ShellExecute(0, 'open', 'notepad.exe', '','',0)#打开记事本后台运行

win32api.ShellExecute(0, 'open', 'notepad.exe', '','',1)#前台运行

win32api.ShellExecute(0, 'open', 'notepad.exe', 'python.txt','',1)# 向记事本传递参数,打开python.txt

win32api.ShellExecute(0, 'open', 'http://www.python.org', '','',1)# 在默认浏览器中打开网站

win32api.ShellExecute(0, 'open', 'E:\\song.wma', '','',1) # 在默认的媒体播放器中播放E:\song.wma

win32api.ShellExecute(0, 'open', 'E:\\book\\code\\MessageBox.py', '','',1)# 运行MessageBox.py脚本
def test2():

    # 打开记事本程序,在后台运行,即显示记事本程序的窗口

    win32api.ShellExecute(0, 'open', 'notepad.exe',

           r'C:\ProgramData\MySQL\MySQL Server 8.0\my.ini','',1)

    win32api.ShellExecute(0, 'open', 'notepad.exe', 'my.ini',

           'C:\\ProgramData\\MySQL\\MySQL Server 8.0\\', 1)

    win32api.ShellExecute(0, 'open', 'goldminer3.exe', '--username=131628911xx -- password=xx',

           'C:\\Users\\Administrator\\AppData\\Roaming\\Goldminer3\\', 1)

test2()

 

3 CreateProcess(appName, commandLine , processAttributes , threadAttributes ,

bInheritHandles ,dwCreationFlags , newEnvironment , currentDirectory , startupinfo ):

import win32process,win32event
handle = win32process.CreateProcess('c:\\windows\\notepad.exe', '',None , None , 0 ,
win32process. CREATE_NO_WINDOW , None , None ,win32process.STARTUPINFO())
# 打开记事本获得其句柄
#(<?XML:NAMESPACE PREFIX = PYHANDLE />, , 280, 3076)
# 函数返回进程句柄、线程句柄、进程ID,以及线程ID
win32process.TerminateProcess(handle[0],0) #用TerminateProcess函数终止记事本程序
win32event.WaitForSingleObject(handle[0], -1)# 等待进程结束0进程结束的返回值

 

4 使用ctypes调用kernel32.dll中的函数:

import win32process,win32event

handle = win32process.CreateProcess('c:\\windows\\notepad.exe', '',None , None , 0 ,

win32process. CREATE_NO_WINDOW , None , None ,win32process.STARTUPINFO())

# 打开记事本获得其句柄

#(<?XML:NAMESPACE PREFIX = PYHANDLE />, , 280, 3076)

# 函数返回进程句柄、线程句柄、进程ID,以及线程ID

win32process.TerminateProcess(handle[0],0) #用TerminateProcess函数终止记事本程序

win32event.WaitForSingleObject(handle[0], -1)# 等待进程结束0进程结束的返回值

from ctypes import *

user32 = windll.LoadLibrary('user32.dll')            # 加载动态链接库

user32.MessageBoxA(0, 'Ctypes is cool!', 'Ctypes', 0)# 调用MessageBoxA函数

.

5.os.popen运行dos命令:

print(os.popen('dir').read())

 

6.subprocess:

import sys,os,subprocess
from subprocess import Popen,PIPE


def test2():# 用subprocess.Popen执行.exe程序
    order_name="goldminer3.exe --username=13162891176 --password=tcy-1974"
    path='C:\\Users\\Administrator\\AppData\\Roaming\\Goldminer3\\'

    #cwd指定子进程工作路径
    p=subprocess.Popen(order_name,shell=True,stdout=subprocess.PIPE,cwd=path)#程序阻塞
    s=p.stdout.read()#b"\r\n[main \xe4\xb8\x8b\xe5\x8d\x885:20:25]..."
    s=s.split()

    lst=[i.decode() for i in s]
    print(lst)        #['[main', '下午5:23:17]', 'update#setState', 'idle', ...]

# test2()

 

实例:

def test3(): # 用subprocess.Popen执行系统命令

    p= Popen('cd', shell=True,stdout=subprocess.PIPE)#windows执行cd命令获取当前目录
    print('p=',p.stdout.read())   #b'D:\\PycharmProjects\\test_py36\r\n'
    print(os.popen('cd').read())  # C:\Users\Administrator\AppData\Roaming\Goldminer3

    p = Popen('python c:\b.py', shell=True, stdout=PIPE)  # 运行脚本b.py
    p.wait()   # 获取Popen的返回值及输出
    if (p.returncode == 0): print("当前目录:%s" % p2.stdout.read())

#test3()

 

win32gui

官网:http://timgolden.me.uk/pywin32-docs/win32gui.html

实例1:

import win32gui,win32con,win32api
import time
def test_win32gui():
    hwnd = win32gui.FindWindow("TXGuiFoundation", "TIM")#找主窗口
    print('hwnd=%0x'%hwnd,hwnd)#hwnd=a0b42 658242
    Ex_hwnd=win32gui.FindWindowEx(hwnd,None,'Edit',None)
    print('Ex_hwnd=%0x'%Ex_hwnd)#Ex_hwnd=a0af8
# hhwndChildList = []  # 枚举子窗口
    # win32gui.EnumChildWindows(hwnd, lambda hhwnd, param: param.append(hhwnd),                         
      hhwndChildList)
    # print('hhwndChildList=     ',hhwndChildList) #[789286]

    time.sleep(2)
    win32gui.CloseWindow(hwnd)                                                                         

    #窗口最小化
    time.sleep(2)
    win32gui.SendMessage(hwnd, win32con.WM_CLOSE)              #关闭窗口

test_win32gui()
win32gui.方法:
FindWindow(lpClassName=None, lpWindowName=None) 窗口类名 窗口标题名

方法:

FindWindowEx(hhwndParent=0, hhwndChildAfter=0, lpszClass=None, lpszWindow=None);
描述:搜索类名和窗体名匹配的窗体,并返回这个窗体的句柄。不区分大小写,找不到就返回0。
参数:
hhwndParent: 若不为0,则搜索句柄为hhwndParent窗体的子窗体。
hhwndChildAfter:若不为0,则按照z-index的顺序从hhwndChildAfter向后开始搜索子窗体,
否则从第一个子窗体开始搜索。
lpClassName: 字符型,是窗体的类名,这个可以在Spy++里找到。
lpWindowName:字符型,是窗口名,也就是标题栏上你能看见的那个标题。
说明:找到了主窗口以后就靠它来定位子窗体啦。

 

方法:

left,top,right,bottom=win32gui.GetWindowRect(hnd)# 获取窗口位置-屏幕坐标中窗口的矩形
win32gui.SetWindowPos(hwnd,win32con.HWND_TOPMOST,x,y,400,400,win32con.SWP_SHOWWINDOW)
title = win32gui.GetWindowText(hnd)     #获取某个句柄的标题
clsname = win32gui.GetClassName(hnd)#获取某个句柄的类名
GetClientRect            #在客户端坐标中返回窗口客户区的矩形
SetWindowPos          #设置窗口的位置和大小
SetWindowPlacement#设置窗口位置的RegisterClass
ScreenToClient #将屏幕坐标转换为客户端坐标
ClientToScreen #将客户端坐标转换为屏幕坐标
HCURSOR = win32gui.GetCursor()
win32api.SetCursorPos([30,50])         # 鼠标定位到(30,50)

ctrlid=win32gui.GetDlgCtrlID(hwnd)     #控件的窗口id
ctrl2=win32gui.GetDlgItem(hwnd,ctrlid)#控件句柄
buffer = '0' *50
len = win32gui.SendMessage(hwnd, win32con.WM_GETTEXTLENGTH)+1 #获取edit控件文本长度
win32gui.SendMessage(hwnd, win32con.WM_GETTEXT, len, buffer)          #读取文本
print('buffer=',len,buffer)

方法:

menuHandle = win32gui.GetMenu(subHandle)# 获得窗口的菜单句柄
# 获得子菜单或下拉菜单句柄
subMenuHandle = win32gui.GetSubMenu(menuHandle, 0)# 参数:菜单句柄 子菜单索引号
# 获得菜单项中的的标志符,注意,分隔符是被编入索引的
menuItemHandle = win32gui.GetMenuItemID(subMenuHandle, 0)# 参数:子菜单句柄 项目索引号

方法:

# 发送消息,加入消息队列,无返回
win32gui.postMessage(subHandle,win32con.WM_COMMAND, menuItemHandle, 0)
参数:句柄 消息类型 WParam IParam
       wParam的定义是32位整型,high word就是他的31至16位,low word是它的15至0位。
    当参数超过两个,wParam和lParam不够用时,可以将wParam就给拆成两个int16来使用。
    把HIWORD的常数向左移16位,再加LOWORD,即wParam = HIWORD<<16+LOWORD。

方法:

下选框内容更改
参数:下选框句柄; 消息内容; 参数下选框的哪一个item,以0起始的待选选项的索引;
如果该值为-1,将从组合框列表中删除当前选项,并使当前选项为空;
参数CB_Handle为下选框句柄,PCB_hnd下选框父窗口句柄
win32api.SendMessage(CB_hnd, win32con.CB_SETCURSEL, 1, 0)

方法:

下选框的父窗口命令
参数:父窗口句柄; 命令; 参数:WParam:高位表示类型,低位表示内容;参数IParam,
下选框句柄CBN_SELENDOK当用户选择了有效的列表项时发送,提示父窗体处理用户的选择。
LOWORD为组合框的ID. HIWORD为CBN_SELENDOK的值。
win32api.SendMessage(PCB_hnd, win32con.WM_COMMAND, 0x90000, CB_hnd)

方法:

CBN_SELCHANGE当用户更改了列表项的选择时发送,
不论用户是通过鼠标选择或是通过方向键选择都会发送此通知。
LOWORD为组合框的ID. HIWORD为CBN_SELCHANGE的值。
win32api.SendMessage(PCB_hnd, win32con.WM_COMMAND, 0x10000, CB_hnd)

方法:

# 设置文本框内容,等窗口处理完毕后返回true。中文需编码成gbk
# 参数:句柄;消息类型;参数WParam,无需使用; 参数IParam,要设置的内容,字符串
win32api.SendMessage(hnd,win32con.WM_SETTEXT,0,os.path.abspath(fgFilePath).encode('gbk'))

# 控件点击确定,处理消息后返回0
# 参数:窗口句柄; 消息类型; 参数WParam HIWORD为0(未使用),LOWORD为控件的ID;
 参数IParam  0(未使用),确定控件的句柄
win32api.SendMessage(Mhnd, win32con.WM_COMMAND, 1, confirmBTN_hnd)
# 获取窗口文本不含截尾空字符的长度
# 参数:窗口句柄; 消息类型; 参数WParam; 参数IParam

bufSize = win32api.SendMessage(subHandle, win32con.WM_GETTEXTLENGTH, 0, 0) +1
# 利用api生成Buffer
strBuf = win32gui.PyMakeBuffer(bufSize)
print(strBuf)

# 发送消息获取文本内容
# 参数:窗口句柄; 消息类型;文本大小; 存储位置
length = win32gui.SendMessage(subHandle, win32con.WM_GETTEXT, bufSize, strBuf)
text = str(strBuf[:-1])# 反向内容,转为字符串

address, length = win32gui.PyGetBufferAddressAndLen(strBuf)
text = win32gui.PyGetString(address, length)
win32api.MessageBox(hnd,text,text)
print('text: ', text)
2.鼠标单击事件:
win32api.SetCursorPos([30,50])#鼠标定位到(30,50)
#执行左单键击,若需要双击则延时几毫秒再点击一次即可
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP | win32con.MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0)
#右键单击
win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTUP | win32con.MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0)

实例:

def click1(x,y): #第一种
win32api.SetCursorPos((x,y))
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,x,y,0,0)
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,x,y,0,0)
def click2(x,y):               #第二种
    ctypes.windll.user32.SetCursorPos(x,y)
       ctypes.windll.user32.mouse_event(2,0,0,0,0)
       ctypes.windll.user32.mouse_event(4,0,0,0,0)
def click_it(pos):             #第三种
  hnd= win32gui.WindowFromPoint(pos)
    client_pos =win32gui.ScreenToClient(hnd,pos)
    tmp=win32api.MAKELONG(client_pos[0],client_pos[1])
    win32gui.SendMessage(hnd, win32con.WM_ACTIVATE,win32con.WA_ACTIVE,0)
    win32gui.SendMessage(hnd, win32con.WM_LBUTTONDOWN,win32con.MK_LBUTTON,tmp)
    win32gui.SendMessage(hnd, win32con.WM_LBUTTONUP,win32con.MK_LBUTTON,tmp)

 

实例:

# 发送回车
win32api.keybd_event(13,0,0,0)
win32api.keybd_event(13,0,win32con.KEYEVENTF_KEYUP,0)

实例:

# 关闭窗口
win32gui.PostMessage(win32lib.findWindow(classname, titlename), win32con.WM_CLOSE, 0, 0)
# 检查窗口是否最小化,如果是最大化
if(win32gui.IsIconic(hhwnd)):
    #   win32gui.ShowWindow(hhwnd, win32con.SW_SHOWNORMAL)
    win32gui.ShowWindow(hhwnd, 8)
    sleep(0.5)

说明:

参数

说明

SW_HIDE

隐藏窗口并激活其他窗口。nCmdShow=0。

SW_MAXIMIZE

最大化指定的窗口。nCmdShow=3。

SW_MINIMIZE

最小化指定的窗口并且激活在Z序中的下一个顶层窗口。nCmdShow=6。

SW_RESTORE

激活并显示窗口。如果窗口最小化或最大化,则系统将窗口恢复到原来的尺寸和位置。

 

在恢复最小化窗口时,应用程序应该指定这个标志。nCmdShow=9。

SW_SHOW

在窗口原来的位置以原来的尺寸激活和显示窗口。nCmdShow=5。

SW_SHOWDEFAULT

依据在STARTUPINFO结构中指定的SW_FLAG标志设定显示状态,

 

STARTUPINFO 结构是由启动应用程序的程序传递给CreateProcess。nCmdShow=10。

SW_SHOWMAXIMIZED

激活窗口并将其最大化。nCmdShow=3。

SW_SHOWMINIMIZED

激活窗口并将其最小化。nCmdShow=2。

SW_SHOWMINNOACTIVE

窗口最小化,激活窗口仍然维持激活状态。nCmdShow=7。

SW_SHOWNA

以窗口原来的状态显示窗口。激活窗口仍然维持激活状态。nCmdShow=8。

SW_SHOWNOACTIVATE

以窗口最近一次的大小和状态显示窗口。激活窗口仍然维持激活状态。nCmdShow=4。

SW_SHOWNORMAL

激活并显示一个窗口。如果窗口被最小化或最大化,系统将其恢复到原来的尺寸和大小。

 

应用程序在第一次显示窗口的时候应该指定此标志。nCmdShow=1。

 

实例:

# win32虽然也可控制键盘,但不如使用PyUserInput的方便
from pymouse import PyMouse
from pykeyboard import PyKeyboard
m = PyMouse()
k = PyKeyboard()

x_dim, y_dim = m.screen_size()
# 鼠标点击
m.click(x_dim/2, y_dim/2, 1)
# 键盘输入
k.type_string('Hello, World!')
# 按住一个键
k.press_key('H')
# 松开一个键
k.release_key('H')
# 按住并松开,tap一个键
k.tap_key('e')
# tap支持重复的间歇点击键
k.tap_key('l',n=2,interval=5)
# 发送判断文字
k.type_string('123456')
#创建组合键
k.press_key(k.alt_key)
k.tap_key(k.tab_key)
k.release_key(k.alt_key)
# 特殊功能键
k.tap_key(k.function_keys[5]) # Tap F5
k.tap_key(k.numpad_keys['Home']) # Tap 'Home' on the numpad
k.tap_key(k.numpad_keys[5], n=3) # Tap 5 on the numpad, thrice
# Mac系统
k.press_keys(['Command','shift','3'])
# Windows系统
k.press_keys([k.windows_l_key,'d'])
# 其中的PyMouseEvent和PyKeyboardEvent还可用于监听鼠标和键盘事件的输入