Как использовать Unicode версию Windows API: mciSendString (), Python - PullRequest
1 голос
/ 01 ноября 2019

Я тестирую пакет Python для Windows 10: playsound

Кажется, есть проблемы с некоторыми символами путей, такими как "c: \ sauté" и широкими символами. Поэтому он не может найти файлы.

Ошибка 275 для команды: открыть «C: \ sauté.wav» псевдоним playsound_0.4091468603477375 Не удается найти указанный файл. Убедитесь, что путь и имя файла указаны правильно.

Я пытался использовать версию 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 site: https://pypi.org/project/playsound/ (включая руководство по установке и быстрому запуску)

код src: https://raw.githubusercontent.com/TaylorSMarks/playsound/master/playsound.py

Функция Microsoft mciSendString: https://docs.microsoft.com/en-us/previous-versions/dd757161(v=vs.85)

Ответы [ 2 ]

0 голосов
/ 05 ноября 2019

Нет звука, хотя возвращается «0» (успешно). Мой Python3.7 и Win10. Я также пробовал utf-8, utf-16-le, ничего не получалось.

Вы должны добавить флаг wait. Если этот флажок установлен, вы действительно сможете ждать завершения вызываемой функции. Причина, по которой вы можете воспроизвести ваш файл. В случае, если вы удалили его, он начнет воспроизведение и сразу после его закрытия.

Весь код (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:

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 = r'open ' + filename + r' alias test2'
    waitcommand = r'play test2 wait'
    byte_string_command = command.encode(filesystemencoding)
    waiting = waitcommand.encode(filesystemencoding)

    # 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()))

    errorCode = int(windll.winmm.mciSendStringW(waitcommand, 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()))

Если код работает, он вернет 0: The specified command was carried out.

Примечание:

  1. sys.getfilesystemencoding ()

Возвращает имя кодировки, используемой для преобразования между именами файлов Unicode и именами байтов. Для лучшей совместимости str следует использовать для имен файлов во всех случаях, хотя также поддерживается представление имен файлов в байтах. Функции, принимающие или возвращающие имена файлов, должны поддерживать либо str, либо байты и внутренне преобразовываться в предпочтительное представление системы.

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.
Использование псевдонима

Когда вы открываете устройство, вы можете использовать флаг «псевдоним», чтобы указать идентификатор устройства для устройства. Этот флаг позволяет назначать короткий идентификатор устройства для составных устройств с длинными именами файлов и позволяет открывать несколько экземпляров одного и того же файла или устройства.

Избегайте использования wait

Если вы хотите играть без ожидания, вам нужно обработать MCI_NOTIFY, установить дескриптор окна обратного вызова и обработать MM_MCINOTIFY после завершения воспроизведения.

hwndCallback : Обрабатывать окно обратного вызова, если в командной строке был указан флаг "notify".

0 голосов
/ 03 ноября 2019

При использовании широкой функции, mciSendStringW, вам не следует кодировать строку. Следовательно, ваша строка должна читаться просто command = ' '.join(command). По крайней мере, так обстоит дело на моей машине с Windows10 с Python 3.6.

Для двойной проверки вы можете запустить приведенный ниже код. Второй код ошибки будет 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()))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...