In case this is a XY problem, here is what i want to do:
I have a wxPython app, that has to communicate with another process using the WM_COPYDATA windows message. While sending the message with the ctypes module was surprisingly easy, receiving the answer requires me to overwrite the wx loop, since wx does not provide a specific event for this case.
On python2, I used the ctypes.windll.user32.SetWindowLongPtrW and the ctypes.windll.user32.CallWindowProcW Functions to get the desired behaviour. However, in python3, the same code leads to OSError: exception: access violation writing.
As far as I found out, the only difference between the python2 ctypes module and the python3 ctypes module is how they handle strings.
I also read, that there is a difference in how the two version layout the memory, but since I'm no C Expert, I can't find the problem in my code.
I have tested the code with python3.7 (64Bit) and python2.7(64Bit) and wx 4.0.7 (though it also works with wx2.8 and python2)
Here is minimal reproducible example:
import ctypes, ctypes.wintypes, win32con, wx, sys
_LPARAM = ctypes.wintypes.LPARAM
_WPARAM = ctypes.wintypes.WPARAM
_HWND = ctypes.wintypes.HWND
_UINT = ctypes.wintypes.UINT
_LPCWSTR = ctypes.wintypes.LPCWSTR
_LONG_PTR = ctypes.c_long
_LRESULT = _LONG_PTR
_LPCWSTR = ctypes.wintypes.LPCWSTR
_WNDPROC = ctypes.WINFUNCTYPE(_LPARAM, # return Value
_HWND, # First Param, the handle
_UINT, # second Param, message id
_WPARAM, # third param, additional message info (depends on message id)
_LPARAM, # fourth param, additional message info (depends on message id)
)
_SetWindowLongPtrW = ctypes.windll.user32.SetWindowLongPtrW
_SetWindowLongPtrW.argtypes = (_HWND, ctypes.c_int, _WNDPROC)
_SetWindowLongPtrW.restypes = _WNDPROC
_CallWindowProc = ctypes.windll.user32.CallWindowProcW
_CallWindowProc.argtypes = (_WNDPROC, _HWND, _UINT, _WPARAM, _LPARAM)
_CallWindowProc.restypes = _LRESULT
def _WndCallback(hwnd, msg, wparam, lparam):
print(hwnd, msg, wparam, lparam)
return _CallWindowProc(_old_wndproc, hwnd, msg, _WPARAM(wparam), _LPARAM(lparam))
_mywndproc = _WNDPROC(_WndCallback)
app = wx.App(redirect=False)
frame = wx.Frame(None, title='Simple application')
frame.Show()
_old_wndproc = _WNDPROC( _SetWindowLongPtrW(frame.GetHandle(), win32con.GWL_WNDPROC, _mywndproc ) )
if _old_wndproc == 0:
print( "Error" )
sys.exit(1)
app.MainLoop()
Edit: I know that there is a pywin32 module, that could potentially help me. However, since the code works on python2 I'm rather curious what is going on here.