internal override void RemoveReflectChild()
            {
                if (--_childCount < 0)
                {
                    Debug.Fail("How did parkingwindow childcount go negative???");
                    _childCount = 0;
                }

                if (_childCount != 0 || !IsHandleCreated)
                {
                    return;
                }

                // Check to see if we are running on the thread that owns the parkingwindow.
                // If so, we can destroy immediately.
                //
                // This is important for scenarios where apps leak controls until after the
                // messagepump is gone and then decide to clean them up.  We should clean
                // up the parkingwindow in this case and a postmessage won't do it.

                uint          id      = User32.GetWindowThreadProcessId(HandleInternal, out _);
                ThreadContext context = ThreadContext.FromId(id);

                // We only do this if the ThreadContext tells us that we are currently
                // handling a window message.
                if (context is null || !ReferenceEquals(context, ThreadContext.FromCurrent()))
                {
                    User32.PostMessageW(HandleInternal, (User32.WM)WM_CHECKDESTROY);
                }
Пример #2
0
            internal void Enable(bool state)
            {
                if (!_onlyWinForms && !state)
                {
                    _activeHwnd = User32.GetActiveWindow();
                    Control activatingControl = ThreadContext.FromCurrent().ActivatingControl;
                    if (activatingControl != null)
                    {
                        _focusedHwnd = activatingControl.Handle;
                    }
                    else
                    {
                        _focusedHwnd = User32.GetFocus();
                    }
                }

                for (int i = 0; i < _windowCount; i++)
                {
                    IntPtr hWnd = _windows[i];
                    Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager : Changing enabled on window: " + hWnd.ToString() + " : " + state.ToString());
                    if (User32.IsWindow(hWnd).IsTrue())
                    {
                        User32.EnableWindow(hWnd, state.ToBOOL());
                    }
                }

                // OpenFileDialog is not returning the focus the way other dialogs do.
                // Important that we re-activate the old window when we are closing
                // our modal dialog.
                //
                // edit mode forever with Excel application
                // But, DON'T change other people's state when we're simply
                // responding to external MSOCM events about modality.  When we are,
                // we are created with a TRUE for onlyWinForms.
                if (!_onlyWinForms && state)
                {
                    if (_activeHwnd != IntPtr.Zero && User32.IsWindow(_activeHwnd).IsTrue())
                    {
                        User32.SetActiveWindow(_activeHwnd);
                    }

                    if (_focusedHwnd != IntPtr.Zero && User32.IsWindow(_focusedHwnd).IsTrue())
                    {
                        User32.SetFocus(_focusedHwnd);
                    }
                }
            }
            BOOL IMsoComponentManager.FPushMessageLoop(
                UIntPtr dwComponentID,
                msoloop uReason,
                void *pvLoopData)
            {
                // Hold onto old state to allow restore before we exit...
                msocstate currentLoopState = _currentState;
                BOOL      continueLoop     = BOOL.TRUE;

                if (!OleComponents.TryGetValue(dwComponentID, out ComponentHashtableEntry entry))
                {
                    return(BOOL.FALSE);
                }

                IMsoComponent prevActive = _activeComponent;

                try
                {
                    User32.MSG    msg = new User32.MSG();
                    IMsoComponent requestingComponent = entry.component;
                    _activeComponent = requestingComponent;

                    Debug.WriteLineIf(
                        CompModSwitches.MSOComponentManager.TraceInfo,
                        $"ComponentManager : Pushing message loop {uReason}");
                    Debug.Indent();

                    while (continueLoop.IsTrue())
                    {
                        // Determine the component to route the message to
                        IMsoComponent component = _trackingComponent ?? _activeComponent ?? requestingComponent;

                        bool useAnsi = false;
                        BOOL peeked  = User32.PeekMessageW(ref msg);

                        if (peeked.IsTrue())
                        {
                            useAnsi = msg.hwnd != IntPtr.Zero && User32.IsWindowUnicode(msg.hwnd).IsFalse();
                            if (useAnsi)
                            {
                                peeked = User32.PeekMessageA(ref msg);
                            }
                        }

                        if (peeked.IsTrue())
                        {
                            continueLoop = component.FContinueMessageLoop(uReason, pvLoopData, &msg);

                            // If the component wants us to process the message, do it.
                            if (continueLoop.IsTrue())
                            {
                                if (useAnsi)
                                {
                                    User32.GetMessageA(ref msg);
                                    Debug.Assert(User32.IsWindowUnicode(msg.hwnd).IsFalse());
                                }
                                else
                                {
                                    User32.GetMessageW(ref msg);
                                    Debug.Assert(msg.hwnd == IntPtr.Zero || User32.IsWindowUnicode(msg.hwnd).IsTrue());
                                }

                                if (msg.message == User32.WM.QUIT)
                                {
                                    Debug.WriteLineIf(
                                        CompModSwitches.MSOComponentManager.TraceInfo,
                                        "ComponentManager : Normal message loop termination");

                                    ThreadContext.FromCurrent().DisposeThreadWindows();

                                    if (uReason != msoloop.Main)
                                    {
                                        User32.PostQuitMessage((int)msg.wParam);
                                    }

                                    continueLoop = BOOL.FALSE;
                                    break;
                                }

                                // Now translate and dispatch the message.
                                //
                                // Reading through the rather sparse documentation,
                                // it seems we should only call FPreTranslateMessage
                                // on the active component.
                                if (component.FPreTranslateMessage(&msg).IsFalse())
                                {
                                    User32.TranslateMessage(ref msg);
                                    if (useAnsi)
                                    {
                                        User32.DispatchMessageA(ref msg);
                                    }
                                    else
                                    {
                                        User32.DispatchMessageW(ref msg);
                                    }
                                }
                            }
                        }
                        else
                        {
                            // If this is a DoEvents loop, then get out. There's nothing left for us to do.
                            if (uReason == msoloop.DoEvents || uReason == msoloop.DoEventsModal)
                            {
                                break;
                            }

                            // Nothing is on the message queue. Perform idle processing and then do a WaitMessage.
                            bool continueIdle = false;

                            if (OleComponents != null)
                            {
                                IEnumerator enumerator = OleComponents.Values.GetEnumerator();

                                while (enumerator.MoveNext())
                                {
                                    ComponentHashtableEntry idleEntry = (ComponentHashtableEntry)enumerator.Current;
                                    continueIdle |= idleEntry.component.FDoIdle(msoidlef.All).IsTrue();
                                }
                            }

                            // Give the component one more chance to terminate the message loop.
                            continueLoop = component.FContinueMessageLoop(uReason, pvLoopData, null);

                            if (continueLoop.IsTrue())
                            {
                                if (continueIdle)
                                {
                                    // If someone has asked for idle time, give it to them.  However,
                                    // don't cycle immediately; wait up to 100ms.  Why?  Because we don't
                                    // want someone to attach to idle, forget to detach, and then cause
                                    // CPU to end up in race condition.  For Windows Forms this generally isn't an issue because
                                    // our component always returns false from its idle request
                                    User32.MsgWaitForMultipleObjectsEx(0, IntPtr.Zero, 100, User32.QS.ALLINPUT, User32.MWMO.INPUTAVAILABLE);
                                }
                                else
                                {
                                    // We should call GetMessage here, but we cannot because
                                    // the component manager requires that we notify the
                                    // active component before we pull the message off the
                                    // queue.  This is a bit of a problem, because WaitMessage
                                    // waits for a NEW message to appear on the queue.  If a
                                    // message appeared between processing and now WaitMessage
                                    // would wait for the next message.  We minimize this here
                                    // by calling PeekMessage.
                                    if (User32.PeekMessageW(ref msg, IntPtr.Zero, 0, 0, User32.PM.NOREMOVE).IsFalse())
                                    {
                                        User32.WaitMessage();
                                    }
                                }
                            }
                        }
                    }

                    Debug.Unindent();
                    Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, $"ComponentManager : message loop {uReason} complete.");
                }
                finally
                {
                    _currentState    = currentLoopState;
                    _activeComponent = prevActive;
                }

                return(continueLoop.IsFalse() ? BOOL.TRUE : BOOL.FALSE);
            }