pythonpython-3.3wm-copydata

Sending WM_COPYDATA with Python 3


I'm trying to write a python script that will interface with my copy of stickies. I'm having trouble with how Python interacts with the WM_COPYDATA struct, and unfortunately I haven't been able to find many examples online.

Using the code:

import struct
import win32con
import win32gui

import struct, array
int_buffer = array.array("L", [0])
char_buffer = array.array('b', 'do new sticky')
int_buffer_address = int_buffer.buffer_info()[0]
char_buffer_address, char_buffer_size = char_buffer.buffer_info

copy_struct = struct.pack("pLp",
int_buffer_address,
char_buffer_size, char_buffer_address)

hwnd = win32gui.FindWindow("ZhornSoftwareStickiesMain", None)

win32gui.SendMessage(w, WM_COPYDATA, hwnd, copy_struct)

I get the following error:

C:\Users\%userprofile%\Desktop>python sender.py
Traceback (most recent call last):
  File "sender.py", line 7, in <module>
    char_buffer = array.array('b', 'do new sticky')
TypeError: an integer is required

I can't seem to figure out why I'm getting such an error. Any ideas?

Edit: Some partially working code

import struct
import win32con
import win32gui
import struct, array


int_buffer = array.array("L", [0])
char_buffer = array.array('b', b"do manage open")
int_buffer_address = int_buffer.buffer_info()[0]

# Add () to buffer_info to call it.
char_buffer_address, char_buffer_size = char_buffer.buffer_info()

# Need P  type for the addresses.
copy_struct = struct.pack("PLP",int_buffer_address,char_buffer_size, char_buffer_address)

hwnd = win32gui.FindWindow(None, "ZhornSoftwareStickiesMain")
win32gui.SendMessage(hwnd, win32con.WM_COPYDATA, None, copy_struct)

Solution

  • In Python 3, strings are Unicode. Try using a byte string:

    >>> import array
    >>> array.array('b',b'do new sticky')
    array('b', [100, 111, 32, 110, 101, 119, 32, 115, 116, 105, 99, 107, 121])
    

    There are a few other changes as well:

    import struct, array
    int_buffer = array.array("L", [0])
    char_buffer = array.array('b', b'do new sticky')
    int_buffer_address = int_buffer.buffer_info()[0]
    
    # Add () to buffer_info to call it.
    char_buffer_address, char_buffer_size = char_buffer.buffer_info()
    
    # Need P  type for the addresses.
    copy_struct = struct.pack("PLP",int_buffer_address,char_buffer_size, char_buffer_address)
    

    I didn't install the software, but I think the next lines should be:

    hwnd = win32gui.FindWindow(None, "ZhornSoftwareStickiesMain")
    win32gui.SendMessage(hwnd, win32con.WM_COPYDATA, None, copy_struct)
    

    Edit

    I installed the software. Initially I couldn't get any commands to work, but the trick that wasn't clear from the API documentation is that each string must start with api:

    import struct
    import win32con
    import win32gui
    import array
    
    char_buffer = array.array('B', b'api do new sticky hello, world')
    char_buffer_address, char_buffer_size = char_buffer.buffer_info()
    copy_struct = struct.pack("PLP", 12345, char_buffer_size, char_buffer_address)
    hwnd = win32gui.FindWindow(None, "ZhornSoftwareStickiesMain")
    win32gui.SendMessage(hwnd, win32con.WM_COPYDATA, None, copy_struct)
    

    Stickies sample