如何使用unicode版本的Windows API:mciSendString(),Python

2024-06-26 01:34:32 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在Windows10:playsound上测试一个Python包

它似乎对路径名的某些字符有问题,例如“c:\sauté”和宽字符。所以找不到文件。在

Error 275 for command: open "C:\sauté.wav" alias playsound_0.4091468603477375 Cannot find the specified file. Make sure the path and filename are correct.

我试图使用unicode版本mciSendStringW()。结果发现mciSendStringW根本无法识别编码的命令。我不知道我现在还能做什么。在

def winCommand(*command):
    buf = c_buffer(255)
    command = ' '.join(command).encode(getfilesystemencoding())
    errorCode = int(windll.winmm.mciSendStringA(command, buf, 254, 0))
    if errorCode:
        errorBuffer = c_buffer(255)
        windll.winmm.mciGetErrorStringA(errorCode, errorBuffer, 254)
        exceptionMessage = ('\n    Error ' + str(errorCode) + ' for command:'
                            '\n        ' + command.decode() +
                            '\n    ' + errorBuffer.value.decode())
        raise PlaysoundException(exceptionMessage)
    return buf.value

prj站点:https://pypi.org/project/playsound/(包括安装和快速入门指南)

源代码:https://raw.githubusercontent.com/TaylorSMarks/playsound/master/playsound.py

Microsoft mciSendString函数: https://docs.microsoft.com/en-us/previous-versions/dd757161(v=vs.85)


Tags: thehttpsforbuffererror字符commandbuf
2条回答

虽然返回“0”(成功),但没有声音。我的是Python3.7和Win10。我也试过utf-8,utf-16-le,但都没用。

You need to add wait flag. Having this flag on, allows you indeed to wait until the called function completed. The reason you can actually play your file. In the case you removed it, it will initiate the play and immediately after close it.

整个代码(ASCII):

from ctypes import c_buffer, windll
from sys import getfilesystemencoding

if __name__ == '__main__':
    buf = c_buffer(255)
    filesystemencoding = getfilesystemencoding()
    filename = r'.\file_example.mp3'


    # ASCII
    command = 'open ' + filename + ' alias test2'
    waitcommand = 'play test2 wait'
    byte_string_command = command.encode(filesystemencoding)
    waiting = waitcommand.encode(filesystemencoding)
    errorCode = int(windll.winmm.mciSendStringA(byte_string_command, buf, 254, 0))
    # errorCode should be 275: Cannot find the file
    errorBuffer = c_buffer(255)
    windll.winmm.mciGetErrorStringA(errorCode, errorBuffer, 254)
    print("{}: {}".format(errorCode, errorBuffer.value.decode()))

    errorCode = int(windll.winmm.mciSendStringA(waiting, buf, 254, 0))
    # errorCode should be 275: Cannot find the file
    errorBuffer = c_buffer(255)
    windll.winmm.mciGetErrorStringA(errorCode, errorBuffer, 254)
    print("{}: {}".format(errorCode, errorBuffer.value.decode()))

UNICODE码:

^{pr2}$

如果代码有效,它将返回0: The specified command was carried out。在

注意:

  1. sys.getfilesystemencoding()

Return the name of the encoding used to convert between Unicode filenames and bytes filenames. For best compatibility, str should be used for filenames in all cases, although representing filenames as bytes is also supported. Functions accepting or returning filenames should support either str or bytes and internally convert to the system’s preferred representation.

This encoding is always ASCII-compatible.

[os.fsencode()][2] and [os.fsdecode()][3] should be used to ensure that the
correct encoding and errors mode are used.

In the UTF-8 mode, the encoding is utf-8 on any platform.

On macOS, the encoding is 'utf-8'.

On Unix, the encoding is the locale encoding.

On Windows, the encoding may be 'utf-8' or 'mbcs', depending on user
configuration.

Changed in version 3.6: Windows is no longer guaranteed to return
'mbcs'. See PEP 529 and [_enablelegacywindowsfsencoding()][4] for more
information.

Changed in version 3.7: Return ‘utf-8’ in the UTF-8 mode.
  1. Using an Alias

When you open a device, you can use the "alias" flag to specify a device identifier for the device. This flag lets you assign a short device identifier for compound devices with lengthy filenames, and it lets you open multiple instances of the same file or device.

  1. Avoid using wait

If you want play no wait, you need to handle the MCI_NOTIFY, set the callback window handle, and handle the MM_MCINOTIFY when the play has finish.

hwndCallback: Handle to a callback window if the "notify" flag was specified in the command string.

使用wide函数mciSendStringW时,不应对字符串进行编码。因此,您的行应该简单地读command = ' '.join(command)。至少在我安装了python3.6的Windows10机器上是这样。在

要重新检查,可以运行下面的代码。第二个错误代码是296,这只是抱怨它是错误的文件类型,因为我们为测试创建了一个空文件。在

from ctypes import c_buffer, windll
from sys import getfilesystemencoding

if __name__ == '__main__':
    buf = c_buffer(255)
    filesystemencoding = getfilesystemencoding()
    filename = r'.\sauté.wav'
    # create the file if it doesn't exist
    file = open(filename, 'w+')
    file.close()

    # ASCII
    command = 'open ' + filename
    byte_string_command = command.encode(filesystemencoding)

    errorCode = int(windll.winmm.mciSendStringA(byte_string_command, buf, 254, 0))
    # errorCode should be 275: Cannot find the file
    errorBuffer = c_buffer(255)
    windll.winmm.mciGetErrorStringA(errorCode, errorBuffer, 254)
    print("{}: {}".format(errorCode, errorBuffer.value.decode()))

    # Unicode
    errorCode = int(windll.winmm.mciSendStringW(command, buf, 254, 0))
    # errorCode should be 296: The specified file cannot be played
    errorBuffer = c_buffer(255)
    windll.winmm.mciGetErrorStringA(errorCode, errorBuffer, 254)
    print("{}: {}".format(errorCode, errorBuffer.value.decode()))

相关问题 更多 >