BOOL IMsoComponentManager.FRegisterComponent(
                IMsoComponent component,
                MSOCRINFO *pcrinfo,
                UIntPtr *pdwComponentID)
            {
                if (pcrinfo == null || pdwComponentID == null ||
                    pcrinfo->cbSize < sizeof(MSOCRINFO))
                {
                    return(BOOL.FALSE);
                }

                // Construct Hashtable entry for this component
                ComponentHashtableEntry entry = new ComponentHashtableEntry
                {
                    component     = component,
                    componentInfo = *pcrinfo
                };

                _cookieCounter += 1;
                OleComponents.Add(_cookieCounter, entry);

                // Return the cookie
                *pdwComponentID = _cookieCounter;
                Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, $"ComponentManager: Component registered.  ID: {_cookieCounter}");
                return(BOOL.TRUE);
            }
            /// <include file='doc\Application.uex' path='docs/doc[@for="Application.ComponentManager.UnsafeNativeMethods.IMsoComponentManager.FRegisterComponent"]/*' />
            /// <devdoc>
            ///      Register component piComponent and its registration info pcrinfo with
            ///      this component manager.  Return in *pdwComponentID a cookie which will
            ///      identify the component when it calls other IMsoComponentManager
            ///      methods.
            ///      Return TRUE if successful, FALSE otherwise.
            /// </devdoc>
            bool UnsafeNativeMethods.IMsoComponentManager.FRegisterComponent(UnsafeNativeMethods.IMsoComponent component,
                                                         NativeMethods.MSOCRINFOSTRUCT pcrinfo,
                                                         out IntPtr dwComponentID) {

                // Construct Hashtable entry for this component
                //
                ComponentHashtableEntry entry = new ComponentHashtableEntry();
                entry.component = component;
                entry.componentInfo = pcrinfo;
                OleComponents.Add(++cookieCounter, entry);

                // Return the cookie
                //
                dwComponentID = (IntPtr)cookieCounter;
                Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager: Component registered.  ID: " + cookieCounter.ToString(CultureInfo.InvariantCulture));
                return true;
            }
            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);
            }
 bool System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FRegisterComponent(System.Windows.Forms.UnsafeNativeMethods.IMsoComponent component, System.Windows.Forms.NativeMethods.MSOCRINFOSTRUCT pcrinfo, out IntPtr dwComponentID)
 {
     ComponentHashtableEntry entry = new ComponentHashtableEntry {
         component = component,
         componentInfo = pcrinfo
     };
     this.OleComponents.Add(++this.cookieCounter, entry);
     dwComponentID = (IntPtr) this.cookieCounter;
     return true;
 }