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!
Related
I have a python script I made a couple of months ago that is command line based. I want to make an optional GUI for it. It is a fairly basic program, it fetches cue files for game roms. I coded the GUI separately, and it came to mind that instead of trying to implement it into the code of the program, it'd be 10 times easier to just execute the program with the flags the user specified on the GUI, then print the output on a text field. This is the GUI:
The program parses flags with the argparse library. It has a positional argument which is the directory, and two optional flags being -r and -g (I guess you can identify which is which). How could I do it?
You can use subprocess.check_output() to get the output of a subprocess. Here's sample usage:
var = subprocess.check_output(
['python3', 'CueMaker.py'], shell=True, stderr=subprocess.STDOUT
)
# redirects the standrad error buffer to standrad output to store that in the variable.`
Then I can use var to change the text, assuming there's a StringVar() tied to the widget:
stringVar.set(var)
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 ✔
I want to open .wav file in default program. But it doesn´t work. This is my code:
audiofile=(myFile[index]+".wav") # I have all files in array (without ".wav")
try:
try:
os.system('xdg-open audiofile')
except:
os.system('start audiofile')
except:
print "error"
I don´t get any error, but it doesn´t work. How can I solve it? Thank you.
You aren't substituting the name of the audio file into your OS commands, so it can't possibly work.
You'd need something like:
os.system('xdg-open ' + audiofile)
This assumes that you have a default application associated with .wav files, which of course you can test by trying your command manually.
You might also want to check the return value of os.system for an error code, rather than relying on exceptions.
First of all, you should fill the variable audiofile into the command, not the string 'audiofile' itself
os.system('xdg-open %s' % audiofile)
Second,
os.system will NOT throw an exception when xdg-open or start doesn't exist in system.
Determine the type of system first by platform.system
>>> import platform
>>> platform.system()
'Linux'
I'm trying to use win32api to output a PDF document to a particular printer.
win32api.ShellExecute(0, "print", filename, '/d:"%s"' % printername, ".", 0)
filename is a full pathname to the file, and printname is the name of the target printer I get by going through the output of win32api.EnumPrinters(6).
The file is sent to the Windows default printer even if printername is the name of a different target (my expectation is that passing a specific printer would send the named file to that printer, rather than the default).
Any hints as to what I'm doing wrong? Is there a different way of generically printing a PDF file to a specific printer? Barring all else, is there a way of temporarily changing the default printer from my program?
MikeHunter's answer was a decent starting point.
The proposed solution is calling out to Acrobat or Acrobat Reader to do the actual printing, rather than going through the win32api. For my purposes, this is sufficient:
from subprocess import call
acrobat = "C:\Program Files\Adobe\Acrobat 7.0\Acrobat.exe" ## Acrobat reader would also work, apparently
file = "C:\path\to\my\file.pdf"
printer = "Printer Name Goes Here"
call([acrobat, "/T", file, printer])
That starts up Acrobat, and prints the given file to the named printer even if it's not the Windows default. The first print job processed this way takes a few seconds (I'm assuming this is the Acrobat service being started and cached in memory), subsequent jobs print instantly. I have not done any kind of load testing on this, but I assume the call is less than trivial, so don't trust it for massive throughput.
I'm trying to print any old file to a specific printer, so these answers did not help me. However, I did find the perfect solution. Windows has a canonical verb called printto that does not show up in the context menu. It is used as a way for users to drag and drop a document onto a printer to enable printing in that manner. We can use that feature; the second argument is the name of the printer. I could never get the /d: parameter to work correctly in conjunction with the print canonical verb, but this solution solved it for me. I put the printername in quotes in case there are spaces in it.
win32api.ShellExecute(0, "printto", filename, f'"{printername}"', ".", 0)
I use SumatraPDF to achieve a similar solution (Python 3) as user Inaimathi posted:
import time
from subprocess import call
start = time.perf_counter()
sumatra = "C:\\Program Files\\SumatraPDF\\SumatraPDF.exe"
file = "C:\\Users\\spiderman\\Desktop\\report.pdf"
call([sumatra, '-print-to-default', '-silent', file])
end = time.perf_counter()
print("PDF printing took %5.9f seconds" % (end - start))
The list of command-line arguments you can pass to SumatraPDF is here.
The best way I found is:
set the default printer to the printer you need
current_printer = win32print.GetDefaultPrinter()
os.system(f"RUNDLL32 PRINTUI.DLL,PrintUIEntry /y /n {name of needed printer}")
Print file
win32api.ShellExecute(0, "print", "{document}", '/d:"{name of printer}"', ".", 0)
Restore old printer as the default
time.sleep(3)
os.system(f"RUNDLL32 PRINTUI.DLL,PrintUIEntry /y /n {current_printer}")
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.