简体   繁体   中英

Passing Structure to Windows API in python ctypes

I'm trying to set the date in a SysDateTimeObject in an application on Windows 7. I'm using python 2.7 and the ctypes library with the following code which tries to send a DTM_SETSYSTEMTIME message to the 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 is a HWND to the correct SysDateTimeObject and 0x1002 is the code for the DTM_SETSYSTEMTIME message. The third parameter of SendMessageW is a constant to enable or disable the DateTimeControl. I can set it to 1 and it will disable the control, as expected. The fourth parameter is a pointer to a filled in SYSTEMTIME structure. However, it seems to do nothing as written above. I am able to send other messages but when a function requires a pointer to a structure, things start failing. Am I using ctypes wrong here?

I was using pywinauto and ran into this need and managed to solve it. The cause of the trouble is that you're trying to run it in a different process, while your SYSTEMTIME structure is in your own process's private memory space. Thus, whenever it tries to do anything with the passed structure, it fails—access denied. You need a remote memory block to resolve the problem.

pywinauto.controls.common_controls._RemoteMemoryBlock does exactly this.

The eventual effect is that you will have code like this:

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

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

If you need to use DTM_GETSYSTEMTIME, you would then put my_time = remote_mem.Read(my_time) after the SendMessage call.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM