Skip to content

Overriden WndProc() method on Form control in WinForms is never getting called #2536

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
proneon267 opened this issue Dec 30, 2024 · 2 comments

Comments

@proneon267
Copy link

proneon267 commented Dec 30, 2024

Environment

  • Pythonnet version: 3.0.5
  • Python version: 3.13.0
  • Operating System: Windows 11
  • .NET Runtime: .NET Framework 4.8.9282.0

Details

I am trying to override the WndProc() method on the Form control in WinForms. As described here in the docs: https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.control.wndproc, WndProc() is meant to be overridden to custom handle window messages.

Here is a sample test script:

import clr
clr.AddReference("System.Windows.Forms")
clr.AddReference("System.Drawing")

from System.Windows.Forms import Form, Application
from System.Drawing import Size


class MyForm(Form):
    def __init__(self):
        super().__init__()
        self.Text = "WndProc Example"
        self.Size = Size(300, 200)

    def WndProc(self, m):
        print(f"WndProc called with message: {m}")
        super().WndProc(m)


Application.Run(MyForm())

However, on running the app, the WndProc() method is never getting called. I had also tried to override the WndProc() method of NativeWindow(https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.nativewindow.wndproc?view=windowsdesktop-9.0#system-windows-forms-nativewindow-wndproc(system-windows-forms-message@)), but the overriden WndProc() method is also never getting triggered.

@proneon267
Copy link
Author

For anyone else who might need it, we can achieve the same using win32 APIs directly:

import clr

clr.AddReference("System.Windows.Forms")
clr.AddReference("System.Drawing")

from System.Windows.Forms import Form, Application
from System.Drawing import Size
import ctypes
from ctypes import wintypes

# Define necessary constants and functions
GWL_WNDPROC = -4
WM_CLOSE = 0x0010  # Example: close message

# Define SetWindowLongPtrW
windll = ctypes.WinDLL('user32', use_last_error=True)
SetWindowLongPtr = windll.SetWindowLongPtrW
SetWindowLongPtr.argtypes = [wintypes.HWND, wintypes.INT, ctypes.c_void_p]
SetWindowLongPtr.restype = ctypes.c_void_p

# Define GetWindowLongPtrW
GetWindowLongPtr = windll.GetWindowLongPtrW
GetWindowLongPtr.argtypes = [wintypes.HWND, wintypes.INT]
GetWindowLongPtr.restype = ctypes.c_void_p

# Define CallWindowProcW
CallWindowProc = windll.CallWindowProcW
CallWindowProc.argtypes = [
    ctypes.c_void_p,
    wintypes.HWND,
    wintypes.UINT,
    wintypes.WPARAM,
    wintypes.LPARAM,
]
CallWindowProc.restype = ctypes.c_long


class MyForm(Form):
    def __init__(self):
        super().__init__()
        self.Text = "WndProc Example"
        self.Size = Size(300, 200)

        # Get the window procedure (WndProc) for the window
        self.original_wndproc = GetWindowLongPtr(self.Handle.ToInt64(), GWL_WNDPROC)
        print(f"Original WndProc: {self.original_wndproc}")

        # Create a callback for the window procedure
        WNDPROC = ctypes.WINFUNCTYPE(
            ctypes.c_long,
            wintypes.HWND,
            wintypes.UINT,
            wintypes.WPARAM,
            wintypes.LPARAM,
        )

        # Register our WndProc to handle window messages
        self.wndproc_callback = WNDPROC(self.WndProc)
        SetWindowLongPtr(
            self.Handle.ToInt64(),
            GWL_WNDPROC,
            ctypes.cast(self.wndproc_callback, ctypes.c_void_p),
        )

        current_wndproc = GetWindowLongPtr(self.Handle.ToInt64(), GWL_WNDPROC)
        print(f"Current WndProc: {current_wndproc}")

    def WndProc(self, hwnd, msg, w_param, l_param):
        print(
            f"WndProc called: hwnd={hwnd}, msg={msg}, w_param={w_param}, l_param={l_param}"
        )

        # Handle specific message (for example, WM_CLOSE)
        if msg == WM_CLOSE:
            print("Window is closing.")
            return 0  # Prevent default close handling

        # Call the original window procedure for default handling
        return CallWindowProc(self.original_wndproc, hwnd, msg, w_param, l_param)


# Run the application and create an instance of the form
Application.Run(MyForm())

@proneon267
Copy link
Author

Perhaps this is a duplicate of #2192, so close this issue as per your discretion.

@lostmsu lostmsu closed this as completed Apr 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants