Next post: Avoiding race conditions when copying files

Sending WM_COPYDATA in Python with ctypes

Wherever I looked online, the example code I saw to send WM_COPYDATA messages had a dependency on win32gui (not part of Python's standard library). My project runs Python embedded in a C++ project, though, and so I want to have as few dependencies as possible.

The code below
  • Supports 32-bit and 64-bit Python
  • Uses only standard libraries (in Python 2.5+), not win32gui

import sys
import ctypes
from ctypes import wintypes

WM_COPYDATA = 0x4a

context64bit = sys.maxsize > 2**32
if context64bit:
  class COPYDATASTRUCT(ctypes.Structure):
    _fields_ = [('dwData', ctypes.c_ulonglong),
      ('cbData', ctypes.wintypes.DWORD),
      ('lpData', ctypes.c_void_p)]
else:
  class COPYDATASTRUCT(ctypes.Structure):
    _fields_ = [('dwData', ctypes.wintypes.DWORD),
      ('cbData', ctypes.wintypes.DWORD),
      ('lpData', ctypes.c_void_p)]

def findWindow(windowClass):
  receiver = None
  hwnd = ctypes.windll.user32.FindWindowA(
    windowClass, receiver)
  return hwnd or None

def sendMessage(message, hwnd, dwData=0):
  assert isinstance(message, str)
  
  sender_hwnd = 0
  buf = ctypes.create_string_buffer(message)
  copydata = COPYDATASTRUCT()
  copydata.dwData = dwData
  copydata.cbData = buf._length_
  copydata.lpData = ctypes.cast(buf, ctypes.c_void_p)
  return ctypes.windll.user32.SendMessageA(
    hwnd, WM_COPYDATA, sender_hwnd,
    ctypes.byref(copydata))


This code is in Python 2; the same approach can be used in Python 3 with minor changes like making the parameter a bytes object instead of a str object.