I'm writing a Python script to toggle the "Hidden Items" status of the Windows Explorer. It changes the value of Computer\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\Hidden, but for the change to take effect all instances of the Explorer have to be refreshed.
I implemented the same idea a few months ago with AutoHotkey, there I could solve the refresh problem with the following commands I found on the AutoHotkey Forum:
WinGetClass, CabinetWClass
PostMessage, 0x111, 28931, , , A
PostMessage, 0x111, 41504, , , A
I tried different approaches to translate it, but wasn't able to get it working with Python. While searching for an answer I also found a solution with C# (Refresh Windows Explorer in Win7), which is far more complicated than the AutoHotkey version. I could let the Python script call the C# script, but I would much prefer a solution without auxiliary files.
How can I implement such behavior with Python?
Using pywin module:
import win32con
import win32gui
# List for handles:
handles = []
def collect_handles(h, _):
' Get window class name and add it to list '
if win32gui.GetClassName(h) == 'CabinetWClass':
handles.append(h)
def refresh_window(h):
' Send messages to window '
win32gui.PostMessage(h, win32con.WM_COMMAND, 28931, None)
win32gui.PostMessage(h, win32con.WM_COMMAND, 41504, None)
# Fill our list:
win32gui.EnumWindows(collect_handles, None)
# Perform action on our handles:
list(map(refresh_window, handles))
Related
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 a way to find the default browser in Python. I've seen https://docs.python.org/3.8/library/webbrowser.html
and there might be a way of converting a webbrowser instance which I do not know.
Does anybody know how I could go about doing that?
Also, I'm using Windows - it doesn't need to work for Mac or Ubuntu.
Edit:
I've already tried this website and it gives me an error saying that 'the file path does not exist'.
Additionally, I don't want to open a tab in the default browser, I just want the name.
Edit #2:
The following code works but returns Internet Explorer instead of my actual default which is Chrome.
from winreg import*
with OpenKey(HKEY_CLASSES_ROOT,r"http\\shell\\open\\command") as key:
cmd = QueryValue(key, None)
I have figured it out. I'm pretty sure this only works on Windows, but here's the code:
from winreg import *
with OpenKey(HKEY_CURRENT_USER, r"Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice") as key:
browser = QueryValueEx(key, 'Progid')[0]
It will return ChromeHTML for Chrome, FirefoxURL for Firefox, and IE.HTTP for Internet Explorer.
You can try this
import webbrowser
default_browser = webbrowser.get()
default_browser_name = default_browser.name
default_browser_basename = default_browser.basename
As the docs say
webbrowser.get([name])
Return a controller object for the browser type name. If name is empty, return a controller for a default browser appropriate to the caller’s environment.
I need to create a message box in python without using python Tkinter library so that I can use that before using exit() function this will display the message and answer as soon as user presses okay, user gets out of program.
Here's one way to do it with Windows' msg command. The code is based on #ErykSun's comment under the question Can't execute msg (and other) Windows commands via subprocess.
import os
import subprocess
sysroot = os.environ['SystemRoot']
sysnative = (os.path.join(sysroot, 'SysNative')
if os.path.exists(os.path.join(sysroot, 'SysNative'))
else
os.path.join(sysroot, 'System32'))
msgexe_path = os.path.join(sysnative, 'msg.exe')
subprocess.run([msgexe_path, '*', 'ALL YOUR BASE ARE WHERE BELONG TO US.'])
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'):])
Looking for help/tutorials/sample code of using python to listen to distributed notifications from applications on a mac. I know the py-objc lib is the bridge between python and mac/cocoa classes, and the Foundation library can be used to add observers, but looking for examples or tutorials on how to use this to monitor iTunes.
If anyone comes by to this question, i figured out how to listen, the code below works. However accessing attributes do not seem to work like standard python attribute access.
Update: you do not access attributes as you would in python i.e (.x), the code has been updated below, it now generates a dict called song_details.
Update3: Update to the code, now subclassing NSObject, removed adding the addObserver from the class. Will keep the code updated on github, no more updates here.
import Foundation
from AppKit import *
from PyObjCTools import AppHelper
class GetSongs(NSObject):
def getMySongs_(self, song):
song_details = {}
ui = song.userInfo()
for x in ui:
song_details[x] = ui.objectForKey_(x)
print song_details
nc = Foundation.NSDistributedNotificationCenter.defaultCenter()
GetSongs = GetSongs.new()
nc.addObserver_selector_name_object_(GetSongs, 'getMySongs:', 'com.apple.iTunes.playerInfo',None)
NSLog("Listening for new tunes....")
AppHelper.runConsoleEventLoop()
The source code for GrowlTunes might give you some clues here. You'd have to translate from Objective-C to PyObjC, but eh, whatever. :)
GrowlTurnesController.m
(Or grab the whole growl source tree and navigate to GrowlTunes so you can see it all in action.: here's a link to the directions on how to get the source