Передача структуры в Windows API в Python ctypes

Я пытаюсь установить дату в SysDateTimeObject в приложении на Windows 7. Я использую Python 2.7 и библиотеку ctypes со следующим кодом, который пытается отправить сообщение DTM_SETSYSTEMTIME в SysDateTimeObject:

from ctypes import *
from ctypes.wintypes import BOOL,HWND,RECT,LPCSTR,UINT,INT,DWORD,WORD
import sys
import time

class SYSTEMTIME(Structure):
    _fields_=[('wYear',WORD),
              ('wMonth',WORD),
              ('wDayOfWeek',WORD),
              ('wDay',WORD),
              ('wHour',WORD),
              ('wMinute',WORD),
              ('wSecond',WORD),
              ('wMilliseconds',WORD)]

self.user32 = windll.user32
my_time=SYSTEMTIME(2035,0,0,0,0,0,0,0)
self.user32.SendMessageW(window,c_uint(0x1002),0,byref(my_time))

window - это HWND для правильного SysDateTimeObject, а 0x1002 - это код сообщения DTM_SETSYSTEMTIME. Третий параметр SendMessageW - это константа для включения или отключения DateTimeControl. Я могу установить его на 1, и он отключит контроль, как и ожидалось. Четвертый параметр - указатель на заполненную структуру SYSTEMTIME. Тем не менее, кажется, ничего не делает, как написано выше. Я могу отправлять другие сообщения, но когда функция требует указатель на структуру, вещи начинают терпеть неудачу. Я неправильно использую ctypes?

1 ответ

Я использовал pywinauto, столкнулся с этой необходимостью и сумел ее решить. Причина проблемы в том, что вы пытаетесь запустить его в другом процессе, в то время как ваш SYSTEMTIME структура находится в личной памяти вашего собственного процесса. Таким образом, всякий раз, когда он пытается что-то сделать с переданной структурой, он терпит неудачу - доступ запрещен. Вам нужен удаленный блок памяти для решения проблемы.

pywinauto.controls.common_controls._RemoteMemoryBlock делает именно это

В конечном итоге вы получите такой код:

remote_mem = common_controls._RemoteMemoryBlock(window)
remote_mem.Write(my_time)

user32.SendMessageW(window, win32defines.DTM_SETSYSTEMTIME,
        win32defines.GDT_VALID, remote_mem)

Если вам нужно использовать DTM_GETSYSTEMTIME, вы должны поставить my_time = remote_mem.Read(my_time) после вызова SendMessage.

Другие вопросы по тегам