Why Message Queue processing is nested (not consecutive)?

G

Guest

I've faced a really strange behaviour of my program. This happens both in
debug and release.
I have a function, (say RefreshMyCell() ) that is called in a control's
event handler (say OnScroll). The function calls my functions that DO NOT
call any event handlers. Than the strange happens: the function somehow calls
itself through very long list of other functions.
In stack we see:
RefreshMyCell()->MySubRefreshCell()->...->NativeWindow.DebuggableCallback()->WndProc()->...->OnScroll ->RefreshMyCell() -> ...
As you can see the next message in Message Queue was forced to be processed
BEFORE the previous one was served.

It seems to me that the main reason is DebuggableCallback() function's work
which is part of .NET framework.

This issue leads to application hang because infinite stack grows as
consecutive messages from MQ are served one inside other.

That's awful! I've thought that MQ processing is strictly consequtive. Am I
right?
 
G

Guest

ThePPK said:
I've faced a really strange behaviour of my program. This happens both in
debug and release.
I have a function, (say RefreshMyCell() ) that is called in a control's
event handler (say OnScroll). The function calls my functions that DO NOT
call any event handlers. Than the strange happens: the function somehow calls
itself through very long list of other functions.
In stack we see:
RefreshMyCell()->MySubRefreshCell()->...->NativeWindow.DebuggableCallback()->WndProc()->...->OnScroll ->RefreshMyCell() -> ...
As you can see the next message in Message Queue was forced to be processed
BEFORE the previous one was served.

Without seeing your code, it's tough to know for sure, but it's likely that
your RefreshMyCell() method does something which causes another event to
fire, which in turn results in your RefreshMyCell() method being called
again, eventually resulting in a stack overflow.

Windows messages are event-driven, meaning they are raised as soon as they
occur. This means that if your event handler takes too long or causes
another event to fire, your event handler can be interrupted and (as seen in
your case) actually re-entered in the same event, which of course can cause
all kinds of problems.

My recommendation is to follow the stack trace and see what you are doing in
your RefereshMyCell() method that is causing another event to fire. Perhaps
you are doing something which causes the OnScroll event to fire again?
 
G

Guest

Timm, thank you very much for your answer! I understand the principles of
windows messages processing and that is why I'm amazed. That is because I've
thoroughly checked that in the OnScroll processing code we do not fire any
event. On the other side it seems, that creation of a COM object (actually
MediaDet) causes this. Here you can see the stack (VS2003, Debug), where
VisualizeCells is the mentioned function (it creates new cells that have just
become visible after scroll):

[ said:
cellscontainercomponent.dll!CellsContainerComponent.VirtualCellsContainer.VisualizeCells() Line 580 C#

cellscontainercomponent.dll!CellsContainerComponent.VirtualCellsContainer._HorizontalScroller_Scroll(System.Object
sender = {CellsContainerComponent.MultiScrollBarScroller},
System.Windows.Forms.ScrollEventArgs e =
{System.Windows.Forms.ScrollEventArgs}) Line 219 C#

cellscontainercomponent.dll!CellsContainerComponent.MultiScrollBarScroller.OnScroll(System.Windows.Forms.ScrollEventArgs
args = {System.Windows.Forms.ScrollEventArgs}) Line 230 C#

cellscontainercomponent.dll!CellsContainerComponent.MultiScrollBarScroller.set_ScrollPosition(int value = 986) Line 94 C#

cellscontainercomponent.dll!CellsContainerComponent.MultiScrollBarScroller.ScrollBar_Scroll(System.Object
sender = {Value=986}, System.Windows.Forms.ScrollEventArgs e =
{System.Windows.Forms.ScrollEventArgs}) Line 49 C#
[<Non-user Code>]

cellscontainercomponent.dll!CellsContainerComponent.VirtualCellsContainer.VisualizeCells() Line 580 C#

cellscontainercomponent.dll!CellsContainerComponent.VirtualCellsContainer.ResumeCellsVisualization() Line 544 C#

cellscontainercomponent.dll!CellsContainerComponent.VirtualCellsContainer.RefreshContainer() Line 527 C#

cellscontainercomponent.dll!CellsContainerComponent.VirtualCellsContainer.OnSizeChanged(System.EventArgs e = {System.EventArgs}) Line 104 C#
[<Non-user Code>]
… [some other events called from Non-user Code]
[<Non-user Code>]
commontypes.dll!CommonTypes.Utilities.VideoFileInfo.CheckMediaFile(string
filePath = @"L_Geri.avi") Line 238 + 0xa bytes C#
commontypes.dll!CommonTypes.Utilities.VideoFileInfo.IsVideoFile(string
filePath = @"L_Geri.avi") Line 151 + 0x8 bytes C#

commontypes.dll!CommonTypes.Utilities.VideoFileInfo.ValidateVideoFile(string
filePath = @"L_Geri.avi") Line 103 + 0x8 bytes C#

controlserver.dll!ControlServer.ScoreRoutines.ScoreFilesValidator.CheckVideoClip(CommonTypes.VideoClip
clip = {CommonTypes.VideoClip}) Line 52 + 0x14 bytes C#

ControlPanel.exe!ControlPanel.CellsGUI.ScoreCells.ClipScoreCellGUI.AdjustClipPreviewAndDuration() Line 374 + 0x16 bytes C#

ControlPanel.exe!ControlPanel.CellsGUI.ScoreCells.ClipScoreCellGUI.RefreshGUI() Line 327 C#

cellscontainercomponent.dll!CellsContainerComponent.CellDescriptor.CellDescriptorBaseImplementation.Initialize() Line 65 C#

cellscontainercomponent.dll!CellsContainerComponent.VirtualCellsContainer.InitializeNewCells(System.Collections.Hashtable
cellsToDisplay = {Count=18}) Line 638 C#

cellscontainercomponent.dll!CellsContainerComponent.VirtualCellsContainer.VisualizeCells() Line 567 C#

cellscontainercomponent.dll!CellsContainerComponent.VirtualCellsContainer._HorizontalScroller_Scroll(System.Object
sender = {CellsContainerComponent.MultiScrollBarScroller},
System.Windows.Forms.ScrollEventArgs e =
{System.Windows.Forms.ScrollEventArgs}) Line 219 C#

cellscontainercomponent.dll!CellsContainerComponent.MultiScrollBarScroller.OnScroll(System.Windows.Forms.ScrollEventArgs
args = {System.Windows.Forms.ScrollEventArgs}) Line 230 C#

cellscontainercomponent.dll!CellsContainerComponent.MultiScrollBarScroller.set_ScrollPosition(int value = 986) Line 94 C#

cellscontainercomponent.dll!CellsContainerComponent.MultiScrollBarScroller.ScrollBar_Scroll(System.Object
sender = {Value=986}, System.Windows.Forms.ScrollEventArgs e =
{System.Windows.Forms.ScrollEventArgs}) Line 49 C#
[<Non-user Code>]
ControlPanel.exe!ControlPanel.ControlPanelApplication.Main() Line 26 C#




As you can see in a call to CheckMediaFile() function we get into another
message processing. Here you can see the body of the function:




/// <summary>
/// Checking media-file
/// </summary>
private static bool CheckMediaFile(string filePath)
{
if ( File.Exists(filePath) == false )
return false;

//Getting file information
try
{mediaDetector.Filename = filePath;
}
catch (Exception exc)
{
//There is no appropriate codec or bad media file
Debug.WriteLine(exc);
return false;
}
return true;
}



On the string marked by ">>>>>>>>>>" DebuggableCallback is surprisingly
called (here is the Non-user Code stack):




system.windows.forms.dll!ControlNativeWindow.OnMessage(System.Windows.Forms.Message m = {System.Windows.Forms.Message}) + 0x19 bytes

system.windows.forms.dll!ControlNativeWindow.WndProc(System.Windows.Forms.Message m = {System.Windows.Forms.Message}) + 0xd9 bytes

system.windows.forms.dll!System.Windows.Forms.NativeWindow.DebuggableCallback(int
hWnd = 66828, int msg = 71, int wparam = 0, int lparam = 1226992) + 0x39
bytes
system.windows.forms.dll!System.Windows.Forms.Control.SetBoundsCore(int x
= 0, int y = 108, int width = 0, int height = -130,
System.Windows.Forms.BoundsSpecified specified = None) + 0xfe bytes

system.windows.forms.dll!System.Windows.Forms.Control.LayoutManager.LayoutDockedControls(System.Windows.Forms.Control
container = {SciFusion.VideoDecorator.ControlPanel.MainForm.MainFormGUI},
System.Windows.Forms.LayoutEventArgs levent =
{System.Windows.Forms.LayoutEventArgs}) + 0x2d6 bytes

system.windows.forms.dll!System.Windows.Forms.Control.LayoutManager.OnLayout(System.Windows.Forms.Control
container = {SciFusion.VideoDecorator.ControlPanel.MainForm.MainFormGUI},
System.Windows.Forms.LayoutEventArgs levent =
{System.Windows.Forms.LayoutEventArgs}) + 0x13f bytes

system.windows.forms.dll!System.Windows.Forms.Control.OnLayout(System.Windows.Forms.LayoutEventArgs
levent = {System.Windows.Forms.LayoutEventArgs}) + 0x6d bytes

system.windows.forms.dll!System.Windows.Forms.ScrollableControl.OnLayout(System.Windows.Forms.LayoutEventArgs
levent = {System.Windows.Forms.LayoutEventArgs}) + 0x5f bytes

system.windows.forms.dll!System.Windows.Forms.Control.PerformLayout(System.Windows.Forms.Control
affectedControl =
{SciFusion.VideoDecorator.ControlPanel.MainForm.MainFormGUI}, string
affectedProperty = "Bounds") + 0x7b bytes

system.windows.forms.dll!System.Windows.Forms.Control.OnResize(System.EventArgs e = {System.EventArgs}) + 0x4d bytes

system.windows.forms.dll!System.Windows.Forms.Form.OnResize(System.EventArgs
e = {System.EventArgs}) + 0x17 bytes

system.windows.forms.dll!System.Windows.Forms.Control.OnSizeChanged(System.EventArgs e = {System.EventArgs}) + 0x1f bytes
system.windows.forms.dll!System.Windows.Forms.Control.UpdateBounds(int x =
-32000, int y = -32000, int width = 160, int height = 24, int clientWidth =
0, int clientHeight = 0) + 0xc7 bytes
system.windows.forms.dll!System.Windows.Forms.Control.UpdateBounds() +
0x133 bytes

system.windows.forms.dll!System.Windows.Forms.Control.WmMove(System.Windows.Forms.Message m = {System.Windows.Forms.Message}) + 0x20 bytes

system.windows.forms.dll!System.Windows.Forms.Control.WndProc(System.Windows.Forms.Message m = {System.Windows.Forms.Message}) + 0x64d bytes

system.windows.forms.dll!System.Windows.Forms.ScrollableControl.WndProc(System.Windows.Forms.Message m = {System.Windows.Forms.Message}) + 0x7d bytes

system.windows.forms.dll!System.Windows.Forms.ContainerControl.WndProc(System.Windows.Forms.Message m = {System.Windows.Forms.Message}) + 0x42 bytes

system.windows.forms.dll!System.Windows.Forms.Form.WndProc(System.Windows.Forms.Message m = {System.Windows.Forms.Message}) + 0x2c1 bytes

system.windows.forms.dll!ControlNativeWindow.OnMessage(System.Windows.Forms.Message m = {System.Windows.Forms.Message}) + 0x19 bytes

system.windows.forms.dll!ControlNativeWindow.WndProc(System.Windows.Forms.Message m = {System.Windows.Forms.Message}) + 0xd9 bytes

system.windows.forms.dll!System.Windows.Forms.NativeWindow.DebuggableCallback(int
hWnd = 66826, int msg = 3, int wparam = 0, int lparam = -2097118464) + 0x39
bytes

system.windows.forms.dll!System.Windows.Forms.NativeWindow.DefWndProc(System.Windows.Forms.Message m = {System.Windows.Forms.Message}) + 0xc2 bytes

system.windows.forms.dll!System.Windows.Forms.Control.DefWndProc(System.Windows.Forms.Message m = {System.Windows.Forms.Message}) + 0x19 bytes

system.windows.forms.dll!System.Windows.Forms.Form.DefWndProc(System.Windows.Forms.Message m = {System.Windows.Forms.Message}) + 0x109 bytes

system.windows.forms.dll!System.Windows.Forms.Control.WmWindowPosChanged(System.Windows.Forms.Message m = {System.Windows.Forms.Message}) + 0x27 bytes

system.windows.forms.dll!System.Windows.Forms.Control.WndProc(System.Windows.Forms.Message m = {System.Windows.Forms.Message}) + 0x771 bytes

system.windows.forms.dll!System.Windows.Forms.ScrollableControl.WndProc(System.Windows.Forms.Message m = {System.Windows.Forms.Message}) + 0x7d bytes

system.windows.forms.dll!System.Windows.Forms.ContainerControl.WndProc(System.Windows.Forms.Message m = {System.Windows.Forms.Message}) + 0x42 bytes

system.windows.forms.dll!System.Windows.Forms.Form.WmWindowPosChanged(System.Windows.Forms.Message m = {System.Windows.Forms.Message}) + 0x1e bytes

system.windows.forms.dll!System.Windows.Forms.Form.WndProc(System.Windows.Forms.Message m = {System.Windows.Forms.Message}) + 0x25e bytes

system.windows.forms.dll!ControlNativeWindow.OnMessage(System.Windows.Forms.Message m = {System.Windows.Forms.Message}) + 0x19 bytes

system.windows.forms.dll!ControlNativeWindow.WndProc(System.Windows.Forms.Message m = {System.Windows.Forms.Message}) + 0xd9 bytes

system.windows.forms.dll!System.Windows.Forms.NativeWindow.DebuggableCallback(int
hWnd = 66826, int msg = 71, int wparam = 0, int lparam = 1232776) + 0x39
bytes



Have you got any ideas why new message processing is called while a COM
object is being created.

P.S. This particular strange situation is only appears when tough scrolling
takes place and along with this user presses Win+D or selects another window
in taskbar. The situation never happens when user merely scrolls cells (even
very aggressively).
 
G

Guest

ThePPK said:
Timm, thank you very much for your answer! I understand the principles of
windows messages processing and that is why I'm amazed. That is because I've
thoroughly checked that in the OnScroll processing code we do not fire any
event. On the other side it seems, that creation of a COM object (actually
MediaDet) causes this. Here you can see the stack (VS2003, Debug), where
VisualizeCells is the mentioned function (it creates new cells that have just
become visible after scroll):

<snip>

This sure is a tough one! I noticed in the stack trace that OnSizeChanged
is also being called. Perhaps that is generating an extra event which is
causing trouble?

If you cannot solve the root cause of a problem, sometimes you can at least
treat the symptom. One way to avoid the stack overload is to check a member
variable when you enter the VisualizeCells method, and exit the method if the
variable has been set. For example:

class XYZ
{
private bool m_VisualizingNow;
public void VisualizeCells()
{
if (this.m_VisualizingNow)
return;
this.m_VisualizingNow = true;

try
{
// do stuff
}
finally
{
// in case something goes wrong
this.m_VisualizingNow = false;
}
}
}
 
G

Guest

Mini-Tools Timm said:
This sure is a tough one! I noticed in the stack trace that OnSizeChanged
is also being called. Perhaps that is generating an extra event which is
causing trouble?

Yes, that is absolutely correct. OnSizeChanged calls a long sequence of
functions that in turn call VisualizeCells and this is correct. The problem
is why OnSizeChanged called? It is called at the line "MediaDet mediaDetector
= new MediaDetClass();" as debugger says. And it is always called at this
certain line. This makes me think that creation of a MediaDet COM object
somehow causes new message processing. This MediaDet object is from DirectX
8.1 and mentioned only in MSDN2003 and not in MSDN 2005.

Moreover if I turn off creation of the MediaDet COM object the situation
never happens. That is why the problem's root is in the object. But there is
a question: if it is MediaDet's feature or all COM objects' one?

If you cannot solve the root cause of a problem, sometimes you can at least
treat the symptom. One way to avoid the stack overload is to check a member
variable when you enter the VisualizeCells method, and exit the method if the
variable has been set.

[skipped]

Yes, I see. It is the most easiest solution, but not the good one because as
you greatly said we cure just a symptom. But it might result in many other
symptoms of the same root.
 
G

Guest

ThePPK said:
Yes, that is absolutely correct. OnSizeChanged calls a long sequence of
functions that in turn call VisualizeCells and this is correct. The problem
is why OnSizeChanged called? It is called at the line "MediaDet mediaDetector
= new MediaDetClass();" as debugger says. And it is always called at this
certain line. This makes me think that creation of a MediaDet COM object
somehow causes new message processing. This MediaDet object is from DirectX
8.1 and mentioned only in MSDN2003 and not in MSDN 2005.

Moreover if I turn off creation of the MediaDet COM object the situation
never happens. That is why the problem's root is in the object. But there is
a question: if it is MediaDet's feature or all COM objects' one?

I am not familiar with MediaDet, but I've worked with other COM objects
before, and this is not a typical result. Somehow the creation of this
specific object is triggering the extra events.
Yes, I see. It is the most easiest solution, but not the good one because as
you greatly said we cure just a symptom. But it might result in many other
symptoms of the same root.

Perhaps. This is not always a bad solution, however. I've used this method
before when updating controls that may have side effects that could cause
other controls to update. This is a handy (and legitimate) way to prevent an
infinite update loop and stack overflow, which is essentially the problem
you're facing. Of course, the maddening thing is that you don't know why
this is happening.
 
G

Guest

Mini-Tools Timm said:
I am not familiar with MediaDet, but I've worked with other COM objects
before, and this is not a typical result. Somehow the creation of this
specific object is triggering the extra events.
Ok, thank you for sharing of your experience. I've never faced such
behaviour of COM objects too. I think the problem may be caused by DirectX to
managed wrapper.
Perhaps. This is not always a bad solution, however. I've used this method
before when updating controls that may have side effects that could cause
other controls to update. This is a handy (and legitimate) way to prevent an
infinite update loop and stack overflow, which is essentially the problem
you're facing. Of course, the maddening thing is that you don't know why
this is happening.
It works in our case and we've found no problems with this solution
(non-reenterable function). I think we'll try to use DirectX 10 Managed and
find other way to get videoclip's poster image and duration. Do you know any
way to do this rapidly from C#?

By the way, thank you very much, Timm!
 
G

Guest

ThePPK said:
I think we'll try to use DirectX 10 Managed and
find other way to get videoclip's poster image and duration. Do you know any
way to do this rapidly from C#?

No, sorry, I don't have any video experience.
By the way, thank you very much, Timm!

You're welcome... wish I could be more help!
 
Top