private static IntPtr WindowProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) { IntPtr oldWndProc = GetProp(hWnd, "SystemMenu"); try { switch (msg) { case WM_DESTROY: //Automatically uninstall ourself upon Form close SetWindowLongPtr(hWnd, GWL_WNDPROC, oldWndProc); break; case WM_SYSCOMMAND: //if (wParam.ToInt32() >= SC_MENUSTART) break; IntPtr handler = GetProp(hWnd, "SystemMenuHandler"); if (handler != IntPtr.Zero) { //SystemMenuHandler syshandler = Marshal.GetDelegateForFunctionPointer(handler, typeof(SystemMenuHandler)) as SystemMenuHandler; //This only works for static methods! SystemMenuHandler syshandler = GCHandle.FromIntPtr(handler).Target as SystemMenuHandler; if (syshandler.Invoke(wParam.ToInt32())) { return(IntPtr.Zero); } } break; } } catch { //if we get an unhandled error, uninstall ourself. SetWindowLongPtr(hWnd, GWL_WNDPROC, oldWndProc); } return(CallWindowProc(oldWndProc, hWnd, msg, wParam, lParam)); }
/// <summary> /// Assign a handler for the system menu events. There can only be one. /// Any previously set handler will be replaced. This cannot be called /// in the constructor because the underlying Win32 window has not yet /// been created. Should be called during the Form.Load event. /// </summary> /// <param name="form">form to assign the handler to</param> /// <param name="handler">Delegate handler to handle the events</param> public static void SetHandler(Form form, SystemMenuHandler handler) { IntPtr hWnd = form.Handle; if (hWnd == null || hWnd == IntPtr.Zero) { return; } //IntPtr handle = Marshal.GetFunctionPointerForDelegate(handler); //This only works for static methods! IntPtr handle = GCHandle.ToIntPtr(GCHandle.Alloc(handler)); SetProp(hWnd, "SystemMenuHandler", handle); if (GetProp(hWnd, "SystemMenu") != IntPtr.Zero) { return; //Only subclass once! } IntPtr wndProcPtr = Marshal.GetFunctionPointerForDelegate(_wndProc); SetProp(hWnd, "SystemMenu", SetWindowLongPtr(hWnd, GWL_WNDPROC, wndProcPtr)); }