Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get error message from ctypes windll

I'm trying to use a Python script to change the wallpaper on a windows 7 computer. If it matters, I'm invoking the script from a node-webkit application.

The shortened script looks as follows:

# ...
result = ctypes.windll.user32.SystemParametersInfoA(20, 0, path, 0)

Often, it works, but sometimes, seemingly randomly, it does not. Is there any way for me to retrieve more info about the error than the status code (0 or 1)?

I've been trying to use GetLastError which is sometimes mentioned in relation to the ctypes library, but have been unable to extract any error information.

like image 796
Robin Avatar asked Dec 01 '25 06:12

Robin


2 Answers

The ctypes documentation recommends using use_last_error=True to capture GetLastError() in a safe way. Note you need to retrieve the error code when raising WinError:

from ctypes import *

SPI_SETDESKWALLPAPER = 0x0014
SPIF_SENDCHANGE = 2
SPIF_UPDATEINIFILE = 1

def errcheck(result, func, args):
    if not result:
        raise WinError(get_last_error())

user32 = WinDLL('user32',use_last_error=True)
SystemParametersInfo = user32.SystemParametersInfoW
SystemParametersInfo.argtypes = c_uint, c_uint, c_void_p, c_uint
SystemParametersInfo.restype = c_int
SystemParametersInfo.errcheck = errcheck

SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, r'xxx', SPIF_UPDATEINIFILE | SPIF_SENDCHANGE)

Output:

Traceback (most recent call last):
  File "C:\test.py", line 17, in <module>
    SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, r'c:\xxx', SPIF_UPDATEINIFILE | SPIF_SENDCHANGE)
  File "C:\test.py", line 9, in errcheck
    raise WinError(get_last_error())
FileNotFoundError: [WinError 2] The system cannot find the file specified.

An alternative to all this work is to use pywin32 and call win32gui.SystemsParametersInfo.

like image 126
Mark Tolonen Avatar answered Dec 04 '25 00:12

Mark Tolonen


If you set the wallpaper to an existing file with an unsupported format you receive "The operation completed successfully" even though the wallpaper was not set.

Here is the code I used, which throws an error if you enter a path which does not exist. The function does not throw an error if the file exists, but the format is unsupported.

import ctypes, os, sys
from ctypes import WinError, c_int, WINFUNCTYPE, windll
from ctypes.wintypes import BOOL, HWND, LPCSTR, UINT

path = os.path.abspath(os.path.join(os.getcwd(), sys.argv[1]))

SPIF_SENDCHANGE = 2
SPIF_UPDATEINIFILE = 1

prototype = WINFUNCTYPE(BOOL, UINT, UINT, LPCSTR, UINT)
paramflags = (1, "SPI", 20), (1, "zero", 0), (1, "path", "test"), (1, "flags", 0)
SetWallpaperHandle = prototype(("SystemParametersInfoA", windll.user32), paramflags)
def errcheck (result, func, args):
    if result == 0:
        raise WinError()
    return result

SetWallpaperHandle.errcheck = errcheck 
try:
    i = SetWallpaperHandle(path=str(path), flags=(SPIF_UPDATEINIFILE | SPIF_SENDCHANGE))
    print(i)
except Exception as e:
    print(e)

I solved the problem by converting images to .jpg before setting them as a wallpaper.

like image 35
Robin Avatar answered Dec 03 '25 23:12

Robin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!