Python: кодировать текст в WPARAM для win32api.SendMessage () - PullRequest
3 голосов
/ 27 мая 2019

Я пытаюсь позвонить win32api.SendMessage() через мое приложение Python (т.е. отправляющее приложение).

API принимающего приложения утверждает, что формат сообщения: ::SendMessage(<app_name>, <msg_name>, (WPARAM) <value>)

Однако value - это строка из 3-4 символов (без пробелов).

Мой вопрос

Как правильно использовать win32api.SendMessage, особенно в отношении value?

Могу ли я просто поместить строку, как в: win32api.SendMessage(<app_name>, <msg_name>, "ABC")?

Или мне нужно преобразовать строку в тип WPARAM (и если да, то как мне это сделать)?

Я занимаюсь разработкой на Linux Python и у меня очень мало опыта работы с Windows и C ++. Буду признателен за любую помощь.

Заранее спасибо!

P.s. В ответ на комментарии получающим приложением на самом деле является AmiBroker, а фактический формат сообщения, указанный в документации API: ::SendMessage( g_hAmiBrokerWnd, WM_USER_STREAMING_UPDATE, (WPARAM) Ticker, (LPARAM) &recentInfoStructureForGivenTicker ); «Строка», о которой я упоминал ранее, - «Тикер», которую, по словам автора, составляет string (char*). Первоначально я не включил это, поскольку думал, что фактический формат сообщения не важен.

ИССЛЕДОВАНИЕ: Я прочитал из этого , что WPARAM по сути является целочисленным типом, и это привело меня к win32api. Среди многих статей, которые я прочитал; никто из них не помог ответить на мои вопросы выше (или, по крайней мере, так я думаю).

Ответы [ 2 ]

1 голос
/ 28 мая 2019

[Github]: mhammond / pywin32 - Расширения Python для Windows (pywin32) - это оболочка Python над WINAPI с, и поэтому предназначена для Python дружественный .

[ActiveState.Docs]: win32api.SendMessage (лучший документ, который я смог найти), является оберткой над [MS.Docs]: функция SendMessage .

Аргумент lParam (последний) является LONG_PTR , что означает, что он содержит адрес памяти, которыйможет указывать на что угодно.Обычно это тот, который используется для передачи данных, таких как строки.

Поскольку я не знаю, какое сообщение вы хотите отправить, я потратил некоторое время, пока не нашел [MS.Docs]: сообщение EM_REPLACESEL .

code0.py :

#!/usr/bin/env python3

import sys
import win32api
import win32gui
import win32con


is_py2 = sys.version_info.major < 3

if is_py2:
    _input = input
    input = raw_input


def main():
    np_wnd = win32gui.FindWindow(None, "Untitled - Notepad")
    if not np_wnd:
        print("Cound not get Notepad window")
        return
    np_edit_wnd = win32gui.GetWindow(np_wnd, win32con.GW_CHILD)
    if not np_edit_wnd:
        print("Cound not get Notepad child window")
        return
    heading = "After pressing ENTER, "
    #'''
    input("{:s}all text in Notepad will be selected ... ".format(heading))
    # HERE's when the 1st screenshot was taken
    win32api.SendMessage(np_edit_wnd, win32con.EM_SETSEL, 0, -1)
    replaced_text0 = "Replaced\nmultiline text."
    input("{:s}Notepad text will be set (via EM_REPLACESEL) to: \n\"\"\"\n{:s}\n\"\"\" ... ".format(heading, replaced_text0))
    win32api.SendMessage(np_edit_wnd, win32con.EM_REPLACESEL, 0, replaced_text0)  # Regular string
    # HERE's when the 2nd screenshot was taken. It was at the end of the program (at that time), but some stuff was added
    replaced_text1 = "Other\nreplaced\n\nnmultiline text."
    input("\n{:s}Notepad text will be set (via WM_SETTEXT) to: \n\"\"\"\n{:s}\n\"\"\" ... ".format(heading, replaced_text1))
    win32api.SendMessage(np_edit_wnd, win32con.WM_SETTEXT, 0, replaced_text1)
    if not is_py2:
        return
    #'''
    print("\nFor Python 2, also get the text back from Notepad")
    buf_size = 255
    buf = win32gui.PyMakeBuffer(buf_size)
    text_len = win32api.SendMessage(np_edit_wnd, win32con.WM_GETTEXT, buf_size, buf)
    print("    Original text length: {:d}\n    Retrieved text length: {:d}\n    Text: \"\"\"\n{:s}\n    \"\"\"".format(len(replaced_text1), text_len, buf[:text_len]))


if __name__ == "__main__":
    print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
    main()
    print("\nDone.")

Результат :

  • Исходное состояние:

    Img0

  • Конечное состояние:

    Img1

Вывод :

[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q056331657]> "e:\Work\Dev\VEnvs\py_064_02.07.15_test0\Scripts\python.exe" code0.py
Python 2.7.15 (v2.7.15:ca079a3ea3, Apr 30 2018, 16:30:26) [MSC v.1500 64 bit (AMD64)] on win32

After pressing ENTER, all text in Notepad will be selected ...
After pressing ENTER, Notepad text will be set (via EM_REPLACESEL) to:
"""
Replaced
multiline text.
""" ...

After pressing ENTER, Notepad text will be set (via WM_SETTEXT) to:
"""
Other
replaced

nmultiline text.
""" ...

For Python 2, also get the text from Notepad
    Original text length: 32
    Retrieved text length: 32
    Text: """
Other
replaced

nmultiline text.
    """

Done.

Как видно, он работает с обычной Python строкой.

Примечание : Мой Win пользователь имеет «супер» административные привилегии.Для обычного пользователя некоторые вещи могут работать не так, как ожидалось.

Вы также можете взглянуть на [SO]: событие клавиатуры не отправлено в окно с pywin32 (ответ @ CristiFati) дляобработка WM_CHAR подобных сообщений и более важно: как обрабатывать дочерние окна .

@ EDIT0 :

Добавлено:

  • WM_SETTEXT
  • WM_GETTEXT (* Python 2 только) - показать, какчтобы вернуть строки из SendMessage

Но так как WM_USER_STREAMING_UPDATE превышает WM_USER ( btw , я не сделалне вижу никакой документации для этого), вещи могут / не будут работать (согласно комментарию @ IInspectable, а также документации SendMessage ), поэтому потребуется дополнительная работа (маршалинг данных).

@ EDIT1 :

Я уже заметил, что вы пытаетесь работать с AmiBroker ( Google *)1124 * ing WM_USER_STREAMING_UPDATE ).
Однако я не смог найти никакой (официальной) документации для этого сообщения, в которой было бы раскрыто, что должны содержать аргументы WPARAM и LPARAM (например: [MS.Docs]: сообщение WM_SETTEXT ).
Вы пытаетесь написать плагин (имеется в виду, что вы находитесь в том же процессе с AmiBroker ), или вы просто пытаетесь отправить на него сообщения (как я делал в моем примере: Python -> Блокнот )?

1 голос
/ 27 мая 2019

Если вы отправляете пользовательское сообщение, тогда вполне нормально отправлять данные в WPARAM.Если вы отправляете стандартное оконное сообщение, тогда WPARAM действительно следует установить на значение, которое является правильным для отправленного сообщения.

Примечание. WPARAM - это 32-разрядное целое число, поэтому, если вы не можете уместить вашу строку в 32-разрядные (AKA4 байта), то нет, вы не можете сделать это.Обратите внимание, что если вы отправляете ASCII, это означает, что вы можете передать только 4 символа (по одному на байт).Я не знаю python, но я думаю, что вы можете сдвинуть 4 байта и ДОБАВИТЬ или ИЛИ их в одно 32-битное целое число для отправки в качестве WPARAM, может быть что-то вроде этого?

Псевдокод следует

Int32 wparam = 0
wparam = wparam | ((Int32)chr[0] << (32 - (8 * 1)))
wparam = wparam | ((Int32)chr[1] << (32 - (8 * 2)))
wparam = wparam | ((Int32)chr[2] << (32 - (8 * 3)))
wparam = wparam | ((Int32)chr[3] << (32 - (8 * 4)))

См. Функцию SendMessage на веб-сайте Micorsoft.

https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-sendmessage

См. Большое количество других вопросов об отправке пользовательского сообщения.

Отправка пользовательского сообщения Windows ... сортировка пользовательских данных

...