bool UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(
IntPtr dwComponentID,
int reason,
int pvLoopData // PVOID
) {
int dwLocalComponentID = unchecked((int)(long)dwComponentID);
// Hold onto old state to allow restore before we exit...
//
int currentLoopState = currentState;
bool continueLoop = true;
if (!OleComponents.ContainsKey(dwLocalComponentID)) {
return false;
}
UnsafeNativeMethods.IMsoComponent prevActive = this.activeComponent;
try {
// Execute the message loop until the active component tells us to stop.
//
NativeMethods.MSG msg = new NativeMethods.MSG();
NativeMethods.MSG[] rgmsg = new NativeMethods.MSG[] {msg};
bool unicodeWindow = false;
UnsafeNativeMethods.IMsoComponent requestingComponent;
ComponentHashtableEntry entry = (ComponentHashtableEntry)OleComponents[dwLocalComponentID];
if (entry == null) {
return false;
}
requestingComponent = entry.component;
this.activeComponent = requestingComponent;
Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager : Pushing message loop " + reason.ToString(CultureInfo.InvariantCulture));
Debug.Indent();
while (continueLoop) {
// Determine the component to route the message to
//
UnsafeNativeMethods.IMsoComponent component;
if (trackingComponent != null) {
component = trackingComponent;
}
else if (activeComponent != null) {
component = activeComponent;
}
else {
component = requestingComponent;
}
bool peeked = UnsafeNativeMethods.PeekMessage(ref msg, NativeMethods.NullHandleRef, 0, 0, NativeMethods.PM_NOREMOVE);
if (peeked) {
rgmsg[0] = msg;
continueLoop = component.FContinueMessageLoop(reason, pvLoopData, rgmsg);
// If the component wants us to process the message, do it.
// The component manager hosts windows from many places. We must be sensitive
// to ansi / Unicode windows here.
//
if (continueLoop) {
if (msg.hwnd != IntPtr.Zero && SafeNativeMethods.IsWindowUnicode(new HandleRef(null, msg.hwnd))) {
unicodeWindow = true;
UnsafeNativeMethods.GetMessageW(ref msg, NativeMethods.NullHandleRef, 0, 0);
}
else {
unicodeWindow = false;
UnsafeNativeMethods.GetMessageA(ref msg, NativeMethods.NullHandleRef, 0, 0);
}
if (msg.message == NativeMethods.WM_QUIT) {
Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager : Normal message loop termination");
Application.ThreadContext.FromCurrent().DisposeThreadWindows();
if (reason != NativeMethods.MSOCM.msoloopMain) {
UnsafeNativeMethods.PostQuitMessage((int)msg.wParam);
}
continueLoop = 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. But frankly, I'm afraid of what that might break.
// See ASURT 29415 for more background.
if (!component.FPreTranslateMessage(ref msg)) {
UnsafeNativeMethods.TranslateMessage(ref msg);
if (unicodeWindow) {
UnsafeNativeMethods.DispatchMessageW(ref msg);
}
else {
UnsafeNativeMethods.DispatchMessageA(ref msg);
}
}
}
}
else {
// If this is a DoEvents loop, then get out. There's nothing left
// for us to do.
//
if (reason == NativeMethods.MSOCM.msoloopDoEvents ||
reason == NativeMethods.MSOCM.msoloopDoEventsModal) {
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(-1);
}
}
// give the component one more chance to terminate the
// message loop.
//
continueLoop = component.FContinueMessageLoop(reason, pvLoopData, null);
if (continueLoop) {
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 ----
// the CPU. For Windows Forms this generally isn't an issue because
// our component always returns false from its idle request
UnsafeNativeMethods.MsgWaitForMultipleObjectsEx(0, IntPtr.Zero, 100, NativeMethods.QS_ALLINPUT, NativeMethods.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 (!UnsafeNativeMethods.PeekMessage(ref msg, NativeMethods.NullHandleRef, 0, 0, NativeMethods.PM_NOREMOVE)) {
UnsafeNativeMethods.WaitMessage();
}
}
}
}
}
Debug.Unindent();
Debug.WriteLineIf(CompModSwitches.MSOComponentManager.TraceInfo, "ComponentManager : message loop " + reason.ToString(CultureInfo.InvariantCulture) + " complete.");
}
finally {
currentState = currentLoopState;
this.activeComponent = prevActive;
}
return !continueLoop;
} |