Using Python pywin32 to send keystrokes to interactive win32 console application - python

So I have been trying to use Python pywin32 package to send inputs to an interactive console based win32 exe which gives me a bunch of options when executed and based on the input keyed in by the user subsequent menus are displayed. After some reading around on the net I did try to execute the following code but it is still unable to send the input to the program, so if anyone has been able to achieve something similar, please let me know.
the code I have been trying is as follows:
import win32com.client
def main():
shell = win32com.client.Dispatch("WScript.Shell")
shell.run('cmd /K cd "E:\\Documents and Settings\\Owner\\Desktop\\pds\\" && CONVERT.EXE')
shell.AppActivate('E:\\Documents and Settings\\Owner\\Desktop\\pds\\CONVERT.EXE')
print("sending keys...")
shell.SendKeys("trial.bin")
shell.SendKeys("{ENTER}")
if __name__ == '__main__':
main()

I've made small improvement in pywinauto library. Now it can deal with console window like so:
import pywinauto
app = pywinauto.Application.start('cmd.exe', wait_for_idle=False)
app.Window_().TypeKeys('cmd.exe /?{ENTER}', with_spaces=True, pause=0.1)
app.Window_().TypeKeys('{ENTER 7}', pause=0.1)

Related

Unable to detect if Calc.exe is running - Python

I am trying to open a window application when it is not opened in the background. To do that, I need to check if the process is running in the background. I am using pymen to check if the calc.exe is running, and if it's not, I will use subprocess to open a new calc.exe window. However, the code that I am using is not detecting if my calc.exe is actually running or not. It will always be Calculator is Not Running...
from pymem import Pymem
try:
pm = Pymem('calc.exe')
print('Calculator Started And Is Running....')
except:
print ('Calculator Is Not Running....')
I believe that the code is going through the details tab as shown as below to check if calc.exe is running or not. However, I can't find it in here as well even though the calculator app is running.
The detail tab in Task Manager
App like Notepad and Chrome are working fine but calculator. I have no idea why it is not working for calculator.
From Microsoft Calculator Windows 10:
The Calculator in non-LTSC editions of Windows 10 is a Universal
Windows Platform app. In contrast, Windows 10 LTSC (which does not
include universal Windows apps) includes the traditional calculator,
but which is now named win32calc.exe. … Both the universal Windows
app and LTSC's win32calc.exe register themselves with the system as
handlers of a 'calculator:' pseudo-protocol. … All Windows 10
editions (both LTSC and non-LTSC) continue to have a calc.exe, which
however is just a stub that launches (via ShellExecute) the
handler that is associated with the 'calculator:' pseudo-protocol.
In other words, calc.exe is merely a wrapper which launches another executable:
import psutil
import subprocess
import time
def list_calc(phase):
print(phase)
for proc in psutil.process_iter():
if proc.name().startswith( PROCNAME):
print( proc.name())
print( proc.cmdline()[0])
if proc.name() == 'CalculatorApp.exe':
proc.kill()
PROCNAME = 'Calc'
list_calc('- before:')
calc = subprocess.Popen([PROCNAME+'.exe'])
time.sleep(3) # wait until calculator window appears
list_calc('- after:')
Result: ver && .\SO\75191242.py
Microsoft Windows [Version 10.0.19045.2486]
- before:
- after:
CalculatorApp.exe
C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_11.2210.0.0_x64__8wekyb3d8bbwe\CalculatorApp.exe

How to let user enter Python code as if they're running 'python' from terminal?

When you run "python" in your terminal, you get a running instance of python where you can run python code.
I want to do this, but after my script has run a few functions first.
But what I want is this type of interface at the end of my script.
I.e. I want to run my_script.py, in "main" call a few functions, but then after those functions, keep the "workspace" open with the >>> interface so that the user can run more python code.
if __name__ == "__main__":
excel_file = sys.argv[1]
my_list = load_file(excel_file)
#... do a bunch of other things
# open python interface now >>>
while True:
# accept user python commands like in the terminal example above
Is there any way to do this?
You could run your script in interactive mode so that when it would normally exit, you instead drop into an interactive Python interpreter:
python -i my_script.py
You could also enter interactive mode from the script file without the command line flag using the Python code module like in this example:
import code
if __name__ == "__main__":
# Do something.
code.interact(local = locals())
Alternatively, you could use something like the exec keyword in a loop to execute arbitrary commands and kind of "fake it" with something like this:
if __name__ == "__main__":
# Do something.
try:
while True:
exec(input(">>> "))
except KeyboardInterrupt:
sys.exit()
Though this approach is a lot less clean than using interactive mode, especially for executing multi-line code.
If I understand you correctly, you want to load files into variables and play around with those variables.
I think the better option, instead of your proposed makeshift workspace, is to use a Jupyter notebook.
This video gives a good introduction on how the workflow looks like to read an Excel file and play around with it.

Trouble running a Python script through VB

The objective is to receive an image path and pass that to a Python program as an argument, then receive the results.
This is done through a web app using VB (on the IIS server) and it works perfectly except when I import the python module OpenCV (imported in Python as cv2, more specifically).
What's even more confusing is that the script runs perfectly with the imported cv2 module when executed directly from cmd. It only fails to work when the VB code runs the script including the line import cv2.
I'll show some code below, for clarity.
VB code running Python script with image path as an argument:
Dim Processtask As New System.Diagnostics.Process()
Processtask.StartInfo.FileName = "cmd.exe"
Processtask.StartInfo.Arguments = "/c python " + path.ToString + " " + ImageURL.ToString
Processtask.StartInfo.UseShellExecute = False
Processtask.StartInfo.RedirectStandardOutput = True
Processtask.StartInfo.RedirectStandardError = True
Processtask.StartInfo.CreateNoWindow = True
Processtask.Start()
Processtask.WaitForExit()
output = Processtask.StandardOutput.ReadToEnd()
Python code snippet receiving image path:
import sys
import cv2
if __name__ == "__main__":
im = str(sys.argv[1])
print(im)
I have run out of possible ideas as to what could cause this problem. Any advice would be greatly appreciated.
EDIT
I managed to find the full error message which reads as follows:
System.Exception: System.IO.StreamReader
System.InvalidOperationException: Process has exited, so the requested
information is not available.
at System.Diagnostics.Process.EnsureState(State state) at
System.Diagnostics.Process.get_ProcessName()
at System.Diagnostics.Process.ToString()
Got the solution eventually, I'll post it here in case anyone else ever runs into this problem:
The dll files of opencv installed onto the server which hosted the web app had different access rights. The files were denied access when being called from the web application, whereas the rest of the modules called had no issue.
I used sysinternals process monitor to trace which files were being denied access and was able to change the rights by hand. Not very elegant but it worked out.

How do I keep my code open in the shell with a pass command in the main() function?

I'm trying to learn how to build a web browser bot as half learning half project for someone else and I've hit a snag.
The site I'm using as guide has:
def main():
pass
Which he claims keeps the shell window open do he can run various functions like get x,y cords of the mouse position and take screen shots.
However when I run my code exactly as he has it in the guide it immediately opens and closes.
What I don't want is something like, "make it so pressing enter closes shell instead", what needs to happen is the window stays open so I can enter various functions.
What am I doing wrong? Am I suppose to just import the code in a different shell and run the functions outside it?
The code:
import os
import time
import ImageGrab
x_pad = 0
y_pad = 61
def screenGrab():
box = (x_pad,y_pad,x_pad+1919,y_pad+970)
im = ImageGrab.grab(box)
im.save(os.getcwd() + '\\full_snap__' + str(int(time.time())) + '.png','PNG')
def main():
pass
if __name__ == '__main__':
main()
The guide is: http://code.tutsplus.com/tutorials/how-to-build-a-python-bot-that-can-play-web-games--active-11117
You have three ways:
Start the intepreter with the -i option, as suggested by Ulrich in the comments:
python -i my-script.py
This way, the interpreter will be left open as soon as your script finishes execution and a prompt will be shown.
Use pdb. This is often used for debugging, and has a different interface than the usual Python prompt. If you're not familiar with it, it might not be the best option in your case. Replace pass with these two lines:
import pdb
pdb.set_trace()
Use code. This will give you an interface much more similar to the usual Python shell and can be an alternative to pdb if you're not familiar with it:
import code
code.interact()
By the way, you were not doing anything wrong per se. The pass statement is not meant to "halt Python and start a prompt", it's just needed as a filler for functions or loops with an empty body.

how to include NSUserNotificationCenter in py2app

I am making an app in python 2.7 on mac osx 10.8.5 I want to show notification number of times, therefore using NSUserNotificationCenter. Notifications are coming while running code on eclipse. But, the issue is when I made app using py2app, Notifications are not coming. Moreover, the default page of error of open console and Terminate is coming. Please suggest some way, how to include Notification in dist generated by py2app, so that It will work on any other machine.
My setup.py is
from setuptools import setup
APP=['CC4Box.py']
DATA_FILES= [('',['config.cfg'])]
OPTIONS={'iconfile':'cc.icns','argv_emulation': True,'plist':{'CFBundleShortVersionString':'1.0'}}
setup(
app=APP,
data_files=DATA_FILES,
options={'py2app': OPTIONS},
setup_requires=['py2app']
)
My notification code is:
def notify(title, subtitle, info_text, delay=0, sound=False, userInfo={}):
NSUserNotification = objc.lookUpClass('NSUserNotification')
NSUserNotificationCenter = objc.lookUpClass('NSUserNotificationCenter')
notification = NSUserNotification.alloc().init()
notification.setTitle_(title)
notification.setSubtitle_(subtitle)
notification.setInformativeText_(info_text)
notification.setUserInfo_(userInfo)
if sound:
notification.setSoundName_("NSUserNotificationDefaultSoundName")
notification.setDeliveryDate_(Foundation.NSDate.dateWithTimeInterval_sinceDate_(delay, Foundation.NSDate.date()))
NSUserNotificationCenter.defaultUserNotificationCenter().scheduleNotification_(notification)
def notificationBalloon(title,msg):
notify(title1, msg1,"", sound=False)
On eclipse, notifications are coming as expected, however, import error produced in lines:
NSUserNotification = objc.lookUpClass('NSUserNotification')
NSUserNotificationCenter = objc.lookUpClass('NSUserNotificationCenter')
but in terminal these lines are nicely run.
My guess is, .lookUpClass() should be resolved at runtime. Thus you don't actually want to include that class in your py2app. Unless you wrote this class yourself that it.
What you do want to include is objc and related libraries. Make sure it's in your virtualenv when you call py2app. If python -m pydoc objc works, so should python setup.py py2app.
If you are trying to create a pop-up window to notify the user of certain information, there are plenty of python modules for this purpose. Wx python is a good choice. Here is the documentation for pop-up windows:
http://wxpython.org/docs/api/wx.PopupWindow-class.html
EDIT: That won't get an apple notification in the way you want. Try this code. It uses a downloadable command line tool called terminal-notifier to make notifications, accessed through python via sub process:
import subprocess
def notification(title, subtitle, message):
subprocess.Popen(['terminal-notifier','-message',message,'-title',title,'-subtitle',subtitle])
notification(title = 'notification title', subtitle = 'subtitle', message = 'Hello World')
This should get the results you want, although to install it automatically you need to run a build in ruby. You could also get it to play sounds, change some ID parameters, and even tell it to run a shell command when you click on it. For more information go here, this is where you can get the source and the docs:
https://github.com/julienXX/terminal-notifier

Categories