private object DispatcherCallbackOperation(object o) { DispatcherOperationCallbackParameter param = (DispatcherOperationCallbackParameter)o; param.handled = false; param.retVal = IntPtr.Zero; if (_bond == Bond.Attached) { HwndWrapperHook hook = _hook.Target as HwndWrapperHook; if (hook != null) { // make the call param.retVal = hook(param.hwnd, param.msg, param.wParam, param.lParam, ref param.handled); } } return(param); }
/// <summary> /// This is the WNDPROC that gets inserted into the window's /// WNDPROC chain. It responds to various conditions that /// would cause this HwndSubclass object to unsubclass the window, /// and then calls the delegate specified to the HwndSubclass /// constructor to process the message. If the delegate does not /// handle the message, the message is then passed on down the /// WNDPROC chain for further processing. /// </summary> /// <param name="hwnd"> /// The window that this message was sent or posted to. /// </param> /// <param name="msg"> /// The message that was sent or posted. /// </param> /// <param name="wParam"> /// A parameter for the message that was sent or posted. /// </param> /// <param name="lParam"> /// A parameter for the message that was sent or posted. /// </param> /// <returns> /// The value that is the result of processing the message. /// </returns> internal IntPtr SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam) { IntPtr retval = IntPtr.Zero; bool handled = false; WindowMessage message = (WindowMessage)msg; // If we are unattached and we receive a message, then we must have // been used as the original window proc. In this case, we insert // ourselves as if the original window proc had been DefWindowProc. // We pass in DefWndProcStub as a workaround for a bug in UxTheme on // Windows XP. For details see the comment on the DefWndProcWrapper method. if (_bond == Bond.Unattached) { HookWindowProc(hwnd, new NativeMethods.WndProc(SubclassWndProc), Marshal.GetFunctionPointerForDelegate(DefWndProcStub)); } else if (_bond == Bond.Detached) { throw new InvalidOperationException(); } IntPtr oldWndProc = _oldWndProc; // in case we get detached during this method if (message == DetachMessage) { // We received our special message to detach. Make sure it is intended // for us by matching the bridge. if (wParam == IntPtr.Zero || wParam == (IntPtr)_gcHandle) { int param = (int)lParam; // 0 - normal, 1 - force, 2 - force and forward bool force = (param > 0); retval = CriticalDetach(force) ? new IntPtr(1) : IntPtr.Zero; handled = (param < 2); } } else { // Pass this message to our delegate function. Do this under // the exception filter/handlers of the dispatcher for this thread. Dispatcher dispatcher = Dispatcher.FromThread(Thread.CurrentThread); if (dispatcher != null && !dispatcher.HasShutdownFinished) { if (_dispatcherOperationCallback == null) { _dispatcherOperationCallback = new DispatcherOperationCallback(this.DispatcherCallbackOperation); } // _paramDispatcherCallbackOperation is a thread static member which should be reused to avoid // creating a new data structure every time we call DispatcherCallbackOperation // Cache the param locally in case of reentrance and set _paramDispatcherCallbackOperation to null so reentrancy calls will create a new param if (_paramDispatcherCallbackOperation == null) { _paramDispatcherCallbackOperation = new DispatcherOperationCallbackParameter(); } DispatcherOperationCallbackParameter param = _paramDispatcherCallbackOperation; _paramDispatcherCallbackOperation = null; param.hwnd = hwnd; param.msg = msg; param.wParam = wParam; param.lParam = lParam; //synchronous call object result = dispatcher.Invoke( DispatcherPriority.Send, _dispatcherOperationCallback, param); if (result != null) { handled = param.handled; retval = param.retVal; } // Restore _paramDispatcherCallbackOperation to the previous value so we will reuse it on the next call _paramDispatcherCallbackOperation = param; } // Handle WM_NCDESTROY explicitly to forcibly clean up. if (message == WindowMessage.WM_NCDESTROY) { // The fact that we received this message means that we are // still in the call chain. This is our last chance to clean // up, and no other message should be received by this window // proc again. It is OK to force a cleanup now. CriticalDetach(true); // Always pass the WM_NCDESTROY message down the chain! handled = false; } } // If our window proc didn't handle this message, pass it on down the // chain. if (!handled) { retval = CallOldWindowProc(oldWndProc, hwnd, message, wParam, lParam); } return(retval); }
internal IntPtr SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam) { IntPtr retval = IntPtr.Zero; bool handled = false; WindowMessage message = (WindowMessage)msg; // If we are unattached and we receive a message, then we must have // been used as the original window proc. In this case, we insert // ourselves as if the original window proc had been DefWindowProc. // We pass in DefWndProcStub as a workaround for a bug in UxTheme on // Windows XP. For details see the comment on the DefWndProcWrapper method. if(_bond == Bond.Unattached) { HookWindowProc(hwnd, new NativeMethods.WndProc(SubclassWndProc), Marshal.GetFunctionPointerForDelegate(DefWndProcStub)); } else if(_bond == Bond.Detached) { throw new InvalidOperationException(); } IntPtr oldWndProc = _oldWndProc; // in case we get detached during this method if(message == DetachMessage) { // We received our special message to detach. Make sure it is intended // for us by matching the bridge. if(wParam == IntPtr.Zero || wParam == (IntPtr)_gcHandle) { int param = (int)lParam; // 0 - normal, 1 - force, 2 - force and forward bool force = (param > 0); retval = CriticalDetach(force) ? new IntPtr(1) : IntPtr.Zero ; handled = (param < 2); } } else { // Pass this message to our delegate function. Do this under // the exception filter/handlers of the dispatcher for this thread. Dispatcher dispatcher = Dispatcher.FromThread(Thread.CurrentThread); if(dispatcher != null && !dispatcher.HasShutdownFinished) { if (_dispatcherOperationCallback == null) _dispatcherOperationCallback = new DispatcherOperationCallback(this.DispatcherCallbackOperation); // _paramDispatcherCallbackOperation is a thread static member which should be reused to avoid // creating a new data structure every time we call DispatcherCallbackOperation // Cache the param locally in case of reentrance and set _paramDispatcherCallbackOperation to null so reentrancy calls will create a new param if (_paramDispatcherCallbackOperation == null) _paramDispatcherCallbackOperation = new DispatcherOperationCallbackParameter(); DispatcherOperationCallbackParameter param = _paramDispatcherCallbackOperation; _paramDispatcherCallbackOperation = null; param.hwnd = hwnd; param.msg = msg; param.wParam = wParam; param.lParam = lParam; //synchronous call object result = dispatcher.Invoke( DispatcherPriority.Send, _dispatcherOperationCallback, param); if (result != null) { handled = param.handled; retval = param.retVal; } // Restore _paramDispatcherCallbackOperation to the previous value so we will reuse it on the next call _paramDispatcherCallbackOperation = param; } // Handle WM_NCDESTROY explicitly to forcibly clean up. if(message == WindowMessage.WM_NCDESTROY) { // The fact that we received this message means that we are // still in the call chain. This is our last chance to clean // up, and no other message should be received by this window // proc again. It is OK to force a cleanup now. CriticalDetach(true); // Always pass the WM_NCDESTROY message down the chain! handled = false; } } // If our window proc didn't handle this message, pass it on down the // chain. if(!handled) { retval = CallOldWindowProc(oldWndProc, hwnd, message, wParam, lParam); } return retval; }