I’ve been using Python a lot more lately and have discovered some pretty interesting things – one of which I want to share here. A recent project had a requirement for a Python script that would be deployed to users’ machines as a scheduled task, triggered on boot to run at a set interval every n minutes. Normally, the script executes silently, without the need for any user interaction. However, there may be an occasional error or warning condition I want to surface to the user so that they may take the appropriate action. Because the script runs as a background task, without opening a command line window, there is no standard output to which
print() statements will be displayed to the user; there is no UI to alert the user.
If a UI is needed in Python, libraries like Qt, Tk, and many others get the job done nicely, but I didn’t want any additional dependencies. This script needs to maximize portability across a wide array of target machines, so sticking to the default libraries as much as possible was my goal. I only needed a basic message box to display the error or warning details with an “OK” button to acknowledge the user saw the alert – importing one of the GUI libraries would be too complex of a solution in my opinion. Because all of the target machines will be running Windows, I can directly use OS-specific features to render a message box using the ctypes library and the Windows API. Ctypes allows Python code to directly call various libraries, written in C, included with Windows.
Here is the sample code – you can also view as a GitHub Gist.
import ctypes def main(): WS_EX_TOPMOST = 0x40000 windowTitle = "Python Windows Message Box Test" message = "Hello, world! This Message box was created by calling the Windows API using the ctypes library." # display a message box; execution will stop here until user acknowledges ctypes.windll.user32.MessageBoxExW(None, message, windowTitle, WS_EX_TOPMOST) print("User clicked OK.") if __name__ == "__main__": main()
Here’s what’s happening in the script: the
ctypes library is imported first, and inside the
main() method, a variable named
WX_EX_TOPMOST is assigned a hexadecimal value of
0x4000. The variable name is taken from the different window styles in the Windows API, and “0x4000” is a constant value that will apply a “top most” window style to the dialog box. This will set its z-order so that the message box is on top of all other open windows. The
ctypes library exposes methods which essentially wrap up calls to the Windows API functions like
MessageBoxExW, making interacting with the API easy.
MessageBoxExW() is called, passing in
None for the owner window handle (so the message box has no parent window), the message to display, the window title, and the window style.
When the script is run, a Windows MessageBox is displayed. Clicking OK will resume execution of the script.