Basically I want to use the PlaySound()
function in ctypes.
Yes I know winsound module is built on it and I could use that, but I have a reason to not do so :)
In C I would call the function like this:
PlaySound("sound.wav", NULL, SND_FILENAME);
I have my Python script equivalent:
import ctypes
winmm = ctypes.WinDLL('winmm.dll')
winmm.PlaySound("sound.wav", None, 0x20000)
I run it, no error is returned but the sound does not play either.
I suspect that the problem lies with the hex value (0x20000
) since everything else seems fine. I got this value like this:
import winsound
print(hex(winsound.SND_FILENAME))
Or in a different way:
import ctypes, winsound
winmm = ctypes.WinDLL('winmm.dll')
winmm.PlaySound("sound.wav", None, winsound.SND_FILENAME)
So how can I get this working so that my file plays?
In Windows, there are Unicode and ANSI versions of functions. The documentation indicates the filename is an LPCTSTR
. For the ANSI version that is defined as LPCSTR
and for Unicode it is LPCWSTR
.
Here's the proper way to call a Windows function. Generally you want the W
version of the function. Defining .argtypes
and .restype
will also help with error checking. As you found, you can pass the wrong type and it will not work. With .argtypes
defined, incompatible types will be caught.
from ctypes import *
from ctypes import wintypes as w
dll = WinDLL('winmm')
dll.PlaySoundW.argtypes = w.LPCWSTR,w.HMODULE,w.DWORD
dll.PlaySoundW.restype = w.BOOL
SND_FILENAME = 0x20000
# Call it with a Unicode string and it works.
dll.PlaySoundW('sound.wav',None,SND_FILENAME)
# Call it with a byte string and get an error since `.argtypes` is defined.
dll.PlaySoundW(b'sound.wav',None,SND_FILENAME)
Output (after sound plays):
Traceback (most recent call last):
File "C:\test.py", line 15, in <module>
dll.PlaySoundW(b'sound.wav',None,SND_FILENAME)
ctypes.ArgumentError: argument 1: <class 'TypeError'>: wrong type
Or skip all that work and just use the winsound module:
import winsound
winsound.PlaySound('sound.wav',winsound.SND_FILENAME)