Dialog box unresponsive with Windows Script Host (Python) - python

I am trying to modify the Print Setup option found under File > Print Setup.
I am using Windows Script Host with Python. I use the Alt + F followed by S to open the appropriate dialogue box:
When I do those commands by hand, the Print Setup box is in focus, so I can press F to select "Print to File" then {ENTER} or O to accept the changes.
However, I neither ALT+F nor F is selecting the File option.
shell = win32com.client.Dispatch("WScript.Shell")
shell.AppActivate('Point of Sale')
shell.SendKeys("%fs") # I also tried "%fsf and "%fs%f" removing the other call to SendKeys"
time.sleep(0.1) # Removing this (or using a longer wait) makes no difference
shell.SendKeys("F")

You have to wait for the dialog to appear before sending "F".
Try this:
shell.SendKeys("%fs")
time.sleep(.25)
shell.SendKeys("f")

This problem had to do with incorrect implementing on part of the developer of this software. To solve the problem, I used SendKeys to send multiple TABS until File was selected.

Related

Python - Printing file on Windows w/ Printer Name

I am making a program which has a functionality to print things. I have managed to put together this snippet which fetches the name of the default printer (if there is one):
import ctypes
buffer = ctypes.create_unicode_buffer(1024)
ctypes.WinDLL("winspool.drv").GetDefaultPrinterW(buffer, ctypes.byref(ctypes.c_ulong(1024)))
printerName = buffer.value
However I cannot figure out how to actually print the file with this. Using notepad.exe with the -P argument (or running a text file with the print verb) it can print but it opens a notepad window and such, which I want to be silent.
The print command does not allow direct printer names, it requires you to set an LPT port and use that.
If you have any clue how to print the file, now that I have the printer name (It's a txt file if that matters) I would greatly appreciate it!

Can't open Microsoft Teams with python (3.8) script using any method

I am trying to make a script to automate the login into Microsoft Teams and all of my code works except the part where the application has to be opened. The weird thing is that this is capable of opening any other application except MS Teams (Chrome, Notepad, Firefox, Edge etc.)
Here's the relevant code:
def openfile():
if os.stat("stor.txt").st_size == 0:
name = filedialog.askopenfilename()
newfile = open("stor.txt", "w")
newfile.write(name)
else:
name = (open("stor.txt", "r").read())
os.startfile(name)
sleep(5)
keyboard.write(open("user.txt", "r").read())
keyboard.press("enter")
sleep(3)
keyboard.write(open("pass.txt", "r").read())
keyboard.press("enter")
I tried this with os.startfile, os.system(start..) and every other method on the web. Doesn't work.
The value I'm passing in to os.startfile() when I try to run Teams is C:/Users/Raghav/AppData/Local/Microsoft/Teams/Update.exe.
First of all, I don't recommend storing your password in plain text like that. It's not very secure, and if another program takes focus at the right time your code will even type your password somewhere else!
Teams should remember your credentials after the first time you log in. I suggest letting it handle that part.
In any case, running os.startfile("foo.exe") is like double-clicking on foo.exe. The file name that you're passing in is C:/Users/Raghav/AppData/Local/Microsoft/Teams/Update.exe, and Update.exe doesn't look like something that should launch Teams to me.
Inspecting the Teams shortcut in my own Start menu, I see that things are a bit more complicated. This shortcut runs Update.exe and passes it some arguments:
C:\...\Update.exe --processStart "Teams.exe"
There is no way to pass arguments to a program with os.startfile(). Try os.system() instead:
os.system('C:/Users/Raghav/AppData/Local/Microsoft/Teams/Update.exe --processStart "Teams.exe"')
There are lots of other ways to run external commands in Python, but this is likely simplest since you don't need Teams' output streams. This command should return 0 if it succeeds and some other value if it fails.
import os
os.system("C:\\Users\\Lenovo\\AppData\\Local\\Discord\\Update.exe --processStart Discord.exe")
For applications that have an address like above, there are also some tips:
Sometimes Discord.exe name of the file in the address have "Discord.exe" (with double-quotes). Remove it.
Instead of single \ use double \\ in the address.
It will definitely work GO AHEAD ✔

Is there a way to directly tell my python program to use the mouse with os.system("import filename.png")?

I've been trying to write a little screenshot script for arch. It works, but the problem is when I try to assign it a keybinding in my i3-config it does nothing.
First I tried writing it fully in bash which worked fine but I stumbled onto the same problem with it not executing.
So I have redirected the output to a log-file to check it out and it welcomes me with this:
import: unable to grab mouse '': Datei oder Verzeichnis nicht gefunden # error/xwindow.c/XSelectWindow/9306.
import: unable to read X window image '': Erfolg # error/xwindow.c/XImportImage/4942.
import: unable to read X window image '': Erfolg # error/xwindow.c/XImportImage/5049.
import: `/home/lukas/Screenshot/20190419/scoot7.png' # error/import.c/ImportImageCommand/1288.
Translation first line: Couldn't find file or directory # error[...]
Translation Erfolg: success
I've tried googling it, which didn't lead me to anything really and I didn't really find any path resembling error/xwindow.c and so on.
Here is my code:
#!/usr/bin/env python
import os, os.path
import datetime
import sys
d = datetime.datetime.today()
directory="/home/lukas/Screenshot/%s"%d.strftime('%Y%m%d')
if not os.path.exists(directory):
os.mkdir(directory)
fileCount = 1
for file in os.listdir(directory):
if file.endswith('.png'):
fileCount+=1
filename = "%s/scr%d.png"%(directory,fileCount)
os.system("import %s"%filename)
and here is my entry to my i3 config:
bindsym $mod+Shift+F12 exec --no-startup-id scoot > /tmp/log.out 2>&1
The expected outcome of this is that when I press mod+shift+f12 it should transform my mouse-pointer to a "crosshair" so I can select something and takes a screenshot of that.
The actual result is that if I run it normaly it works, but if I try to use the Keyboard-Shortcut it just does nothing but output to my logfile.
I am pretty much a newbie to programming and linux, and I have no idea why it cannot find my mouse and I wanted to know if I can explicitly tell the program to use it or if there is another way to do this.
Thanks alot.
Hugenotte
I wrote a bash script a little while ago to do exactly what you are trying to do, using the very common utility ImageMagick that you can find here on Arch.
Here it is in case you are open to this alternative:
#!/bin/bash
# take screenshot using import from imagemagick
# allows to select the area by dragging across a rectangle
# or to select entire window by clicking inside it
set -e
# the date and time will be used as the file name
time=$(date +"%F_%H:%M:%S")
# naming the urxvt window "screenshot" so that the i3 "no_focus" option gets applied to it
urxvt -title "screenshot" -e bash -c "import $HOME/Screenshot/$time.png"
I then use it in i3 with:
no_focus [title="screenshot"]
bindsym $mod+Shift+F12 layout tabbed; exec --no-startup-id bash my_script.sh
Of course, you may want to change the date format to what you had in python. I like having the time in case I take several screenshots in a row. And you have to replace urxvt with the name of your terminal emulator and you might have to adapt the -title flag if your terminal emulator doesn't give windows a name in this way.
Note that naming the window is important: it took me a little while to figure out how to go around what happens without naming the window and using the no_focus on that window in i3:
The focus would jump to the screen capture window and thus out of the window of which I wanted to take a screenshot. It might be possible that the issue you are facing with your bash and python scripts may be related to this. You have to force i3 to keep your mouse on the old window and not jump to the screen capture window triggered by the script (by default, i3 will focus on a newly created window).

Have Win32 MessageBox appear over other programs

I've recently started learning Python and wrote a little script that informs me when a certain website changes content. I then added it as a scheduled task to Windows so it can run every 10 minutes. I'd like to be informed of the website changing right away so I added a win32ui MessageBox that pops up if the script detects that the website has changed. Here's the little code snippet I'm using for the MessageBox (imaginative text, I know):
win32ui.MessageBox("The website has changed.", "Website Change", 0)
My issue is this, I spend most of my time using remote desktop so when the MessageBox does pop up it sits behind the remote desktop session, is there any way to force the MessageBox to appear on top of it?
On a similar note when the script runs the command line opens up very briefly over the remote desktop session which I don't want, is there any way of stopping this behaviour?
I'm happy with Windows specific solutions as I'm aware it might mean dealing with the windowing manager or possibly an alternative way to inform me rather than using a MessageBox.
When you start anything from Task Scheduler, Windows blocks any "easy" ways to bring your windows or dialogs to top.
First way - use MB_SYSTEMMODAL (4096 value) flag. In my experience, it makes Msg dialog "Always on top".
win32ui.MessageBox("The website has changed.", "Website Change", MB_SYSTEMMODAL)
Second way - try to bring your console/window/dialog to the front with Following calls. Of course, if you use MessageBox you must do that (for your own created window) before calling MessageBox.
SetForegroundWindow(Wnd);
BringWindowToTop(Wnd);
SetForegroundWindow(Wnd);
As for flickering of the console window, you may try to start Python in a hidden state. For example, use ConEmu, ‘HidCon’ or cmdow. Refer to their parameters, something like:
ConEmu -basic -MinTSA -cmd C:\Python27\python.exe C:\pythonScript.py
or
CMDOW /RUN /MIN C:\Python27\python.exe C:\pythonScript.py
Avoiding the command window flash is done by naming the script with a pyw extension instead of simply py. You might also use pythonw.exe instead of python.exe, it really depends on your requirements.
See http://onlamp.com/pub/a/python/excerpts/chpt20/index.html?page=2
Use ctypes it displays an windows error message box very easy to use,
import ctypes
if condition:
ctypes.windll.user32.MessageBoxW(0, u"Error", u"Error", 0)
This works for me:
from ctypes import *
def MessageBox(title, text, style):
sty = int(style) + 4096
return windll.user32.MessageBoxW(0, text, title, sty) #MB_SYSTEMMODAL==4096
## Button Styles:
### 0:OK -- 1:OK|Cancel -- 2:Abort|Retry|Ignore -- 3:Yes|No|Cancel -- 4:Yes|No -- 5:Retry|No -- 6:Cancel|Try Again|Continue
## To also change icon, add these values to previous number
### 16 Stop-sign ### 32 Question-mark ### 48 Exclamation-point ### 64 Information-sign ('i' in a circle)
Usage:
MessageBox('Here is my Title', 'Message to be displayed', 64)
Making the message box system modal will cause it to pop up over every application, but none can be interacted with until it is dismissed. Consider either creating a custom dialog box window that you can bring to the front or using a notification bubble instead.
Windows tries to make it hard to pop a window over the active application. Users find it annoying, especially since the interrupting window generally steals keyboard focus.
The Windows way to give a notification like this is with a balloon in the notification area rather than a message box. Notification balloons don't steal focus and are (supposedly) less distracting.
I'm not sure if the python Windows UI library offers wrappers for notification balloons.
Very easy modal async message box with help of Python and MSG command (working on Win10):
# In CMD (you may use Username logged on target machine instead of * to send message to particular user):
msg /server:IP_or_ComputerName * /v /time:appearance_in_secs Message_up_to_255_chars
# I.e. send "Hello everybody!" to all users on 192.168.0.110 disappearing after 5 mins
msg /server:192.168.0.110 * /v /time:300 "Hello everybody!"
In Python I've been using subprocess to send CMD commands, allows me to read and process output, find error etc.
import subprocess as sp
name = 'Lucas'
message = f'Express yourself {name} in 255 characters ;)'
command = f'msg /server:192.168.0.110 * /v /time:360 "{message}"'
output = str(sp.run(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
if 'returncode=0' in output:
pint('Message sent')
else:
print('Error occurred. Details:\n')
print(output[output.index('stdout=b'):])

Open specific file type with Python script?

How can I make a Python script to be a specific file type's (e.g., *.foo) default application? As in, when I double click the file in the Finder / Explorer I want the file to open in the Python script.
Is this possible to do in Win and/or OS X? The application is a PySide app if that matters.
Mac OS X
On Mac OS X you can use Automator to create an application that calls your python app and passes the input file path as a string argument. In the application workflow wizard, add action "Run Shell Script", select Pass input: as as arguments, and in the text box add:
python /path/to/my/app/myapp.py "$#"
The "$#" passes along whatever arguments were in the input (aka the selected file) as strings. As long as your script is set up to deal with the input (sys.argv) as a list of strings (the first one being the python app path), then it will work.
When you save that Automator workflow, it is treated by OS X like any other app, and you can set that app as the default for files of type "*.foo". To associate "*.foo" with that app, right click a .foo file, Get Info, Open with: Other..., choose the app you created in Automator, then click the Change All... button.
Windows
A similar but hopefully less-involved approach might work in Windows. You could probably create a batch file (.bat) with the following:
python C:\path\to\my\app\myapp.py %*
The %* expands to all arguments.
As long as you can associate a file extension with that batch file, then you could do that, and that's your solution. However, I haven't tried this Windows solution, so take it with a grain of salt. The Mac solution, on the other hand, I have tested.
By example, here's a universal solution I wrote for:
1) opening a Windows desktop link (*.URL) that's been copied to a Linux box.
Or
2) opening a Linux .Desktop link that's been copied to a Windows box.
Here's the Python script that handles both cases:
# UseDesktopLink.py
import sys
import webbrowser
script, filename = sys.argv
file_object = open(filename,'r')
for line in file_object:
if line[0:4]=="URL=":
url=line[4:]
webbrowser.open_new(url)
file_object.close()
On Windows, use Scott H's method (via a bat file) to handle the association.
On Linux, right-click a Windows URL file. Choose Properties, and Open With. Click Add to add a new application. Then at the bottom of the "Add Application" window, click "Use a custom command". Then browse to the UseDesktopLink.py file and click Open. But before you click Add, in the textbox below "Use a custom command", put "python " before the filename (without the quotes). Then click Add and Close.
Hope that helps.
Find any file of type foo
right-click -> Get Info or Click on the file icon,then click Get info or click on the file and hit Command+I
In the Open With pane that shows up, select the path to the python binary
Once selected, You can click the change All button
It'll ask for confirmation, just say continue
I found this old question while looking for an answer myself, and I thought I would share my solution. I used a simple c program to direct the arguments to a python script, allowing the python script to stay a script instead of needing to compile it to make things work. Here is my c program:
int main(int argc, char *argv[]){
char cmd[0xFF];
// For me, argv[1] is the location of the file that is being opened. I'm not sure if this is different on other OSes
snprintf(cmd,sizeof cmd,"python YOUR_PYTHON_SCRIPT_HERE.py -a %s", argv[1]);
system(cmd);
return 0;
}
I then compiled the c program and set that as the default application for the file extension.
Then, in the python script YOUR_PYTHON_SCRIPT_HERE.py, I receive the argument like this:
import sys
assert len(sys.argv) > 2 # Breaks if you call the script without the arguments
theFile = " ".join(sys.argv[2:]) # What the c program gives us
print(theFile) # Print it out to prove that it works
theFile will contain the location of the file that is being opened
Get the contents of the file by using:
with open(theFile,"r") as f:
fileContents = f.read()
On Windows:
Right click the file (I used a .docx file for this example)
Select Open with...
From the applications list, select python
Optional: Select the Always use the selected program to open this kind of file.
Note: this will run the contents of the .docx file in context of the python shell. It will immediately close once it is finished evaluating the contents of the file. If you'd like to edit the file in a word processor, perhaps you should download notepad++, and select that application as the default.

Categories

Resources