PC Review
Forums
Newsgroups
Microsoft DotNet
Microsoft Dot NET Framework Forms
Application.DoEvents() and COM
Forums
Newsgroups
Microsoft DotNet
Microsoft Dot NET Framework Forms
Application.DoEvents() and COM
![]() |
Application.DoEvents() and COM |
|
|
Thread Tools | Rate Thread |
|
|
#1 |
|
Guest
Posts: n/a
|
I understand the use of Application.DoEvents() to process all outstanding
messages on the message queue in a winforms application if you have long running process on the UI thread. But can anyone explain to me why I need to call DoEvents when I am using a COM component that calls back to into the ..Net application? - If I don't call DoEvents after receiving a callback then sometimes no more messages are pumped, it appears that the message pump is suspended until the call is made. I suspect that when a callback occurs from COM into the .Net process that it will not be guaranteed to be executed on the UI thread is this true? ( Note: I do know about updating the UI thread from a worker thread so people pleased don't try and tell me about the 'Invoke' method on the Control class) Cheers Ollie Riches |
|
|
|
#2 |
|
Guest
Posts: n/a
|
DoEvents() should never be called nor in a COM interop scenario and not on
the UI thread. All you have to do is make sure you don't block the message pumping/dispatching by calling functions or running code that take a long time before yielding (~300msec. might be too long for a decent user experience). The same thing goes for a COM callback that runs on the UI thread, messages aren't dispatched as long as the callback code runs. Now it's hard to tell what happens in your code without some more context (apartment requirements of COM object) and seeing any code; What's not clear is where you call DoEvents() on a UI thread that is not pumping, so it looks like your code blocks the message while running in a tight loop and you call DoEvents in the loop. Willy. "Ollie Riches" <ollie.riches@phoneanalyser.net> wrote in message news:enlwsWCmFHA.1044@tk2msftngp13.phx.gbl... >I understand the use of Application.DoEvents() to process all outstanding >messages on the message queue in a winforms application if you have long >running process on the UI thread. But can anyone explain to me why I need >to call DoEvents when I am using a COM component that calls back to into >the .Net application? - If I don't call DoEvents after receiving a callback >then sometimes no more messages are pumped, it appears that the message >pump is suspended until the call is made. > > I suspect that when a callback occurs from COM into the .Net process that > it will not be guaranteed to be executed on the UI thread is this true? > ( Note: I do know about updating the UI thread from a worker thread so > people pleased don't try and tell me about the 'Invoke' method on the > Control class) > > Cheers > > Ollie Riches > |
|
|
|
#3 |
|
Guest
Posts: n/a
|
Thanks for the reply Willy,
If you should never call DoEvents() then I have to ask why was it included? I believe it is similar to including GC.Collect in that it is exposed to the public for use in extreme circumstances. I can understand that while a message is being processed that no other message can be processed hence the name synchronous message processing. I can give an example taken straight from the support site of the product I am using, you can probably guess the product involved in the code. I am well aware that any code published on any site is not always the correct way to solve a problem. The code in question uses the primary interop assembly that was generated by the vendor. If you are using (primary) COM interop library are you required to initialise COM ? - as far as I am aware you do not have too. Here is the complete winforms example, check out the method 'Display_Instrument_Information' Cheers Ollie Riches using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data; namespace PriceUpdate { /// <summary> /// Summary description for Form1. /// </summary> public class Form1 : System.Windows.Forms.Form { private System.Windows.Forms.Label label1; private System.Windows.Forms.Label label2; private System.Windows.Forms.Label label3; private System.Windows.Forms.Label label4; private System.Windows.Forms.Label label5; private System.Windows.Forms.Label lblContract; private System.Windows.Forms.Label lblProdTape; private System.Windows.Forms.Label lblProduct; private System.Windows.Forms.Label lblExchange; private System.Windows.Forms.Label label6; private System.Windows.Forms.Label label7; private System.Windows.Forms.Label label8; private System.Windows.Forms.Label label9; private System.Windows.Forms.Label label14; private System.Windows.Forms.Label label15; private System.Windows.Forms.Label lblAskQty; private System.Windows.Forms.Label lblAskPrice; private System.Windows.Forms.Label lblBidQty; private System.Windows.Forms.Label lblBidPrice; private System.Windows.Forms.Label lblLastQty; private System.Windows.Forms.Label lblLastPrice; /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.Container components = null; // using XTAPI objects // this sample will need the drag and drop handler class, // the Instrument object to temporary hold the selected instrument, // and the instrument notification class for price updates private XTAPI.TTDropHandlerClass m_DropHandler = null; private XTAPI.TTInstrObj m_LiveInstr = null; private XTAPI.TTInstrNotifyClass m_InstrNotify = null; public Form1() { // // Required for Windows Form Designer support // InitializeComponent(); } /// <summary> /// Clean up any resources being used. /// </summary> protected override void Dispose( bool disposing ) { if( disposing ) { if (components != null) { components.Dispose(); } } base.Dispose( disposing ); } #region Windows Form Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { this.label1 = new System.Windows.Forms.Label(); this.label2 = new System.Windows.Forms.Label(); this.label3 = new System.Windows.Forms.Label(); this.label4 = new System.Windows.Forms.Label(); this.label5 = new System.Windows.Forms.Label(); this.lblContract = new System.Windows.Forms.Label(); this.lblProdTape = new System.Windows.Forms.Label(); this.lblProduct = new System.Windows.Forms.Label(); this.lblExchange = new System.Windows.Forms.Label(); this.label6 = new System.Windows.Forms.Label(); this.label7 = new System.Windows.Forms.Label(); this.label8 = new System.Windows.Forms.Label(); this.label9 = new System.Windows.Forms.Label(); this.lblAskQty = new System.Windows.Forms.Label(); this.lblAskPrice = new System.Windows.Forms.Label(); this.lblBidQty = new System.Windows.Forms.Label(); this.lblBidPrice = new System.Windows.Forms.Label(); this.label14 = new System.Windows.Forms.Label(); this.label15 = new System.Windows.Forms.Label(); this.lblLastQty = new System.Windows.Forms.Label(); this.lblLastPrice = new System.Windows.Forms.Label(); this.SuspendLayout(); // // label1 // this.label1.Location = new System.Drawing.Point(16, 123); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(96, 16); this.label1.TabIndex = 17; this.label1.Text = "CONTRACT:"; // // label2 // this.label2.Location = new System.Drawing.Point(16, 88); this.label2.Name = "label2"; this.label2.Size = new System.Drawing.Size(96, 16); this.label2.TabIndex = 16; this.label2.Text = "PRODUCT TYPE:"; // // label3 // this.label3.Location = new System.Drawing.Point(16, 56); this.label3.Name = "label3"; this.label3.Size = new System.Drawing.Size(96, 16); this.label3.TabIndex = 15; this.label3.Text = "PRODUCT:"; // // label4 // this.label4.Location = new System.Drawing.Point(16, 19); this.label4.Name = "label4"; this.label4.Size = new System.Drawing.Size(96, 16); this.label4.TabIndex = 14; this.label4.Text = "EXCHANGE:"; // // label5 // this.label5.Location = new System.Drawing.Point(144, 256); this.label5.Name = "label5"; this.label5.Size = new System.Drawing.Size(232, 56); this.label5.TabIndex = 13; this.label5.Text = "Drag an instrument from X_Trader Market Grid and drop it anywhere on this form."; // // lblContract // this.lblContract.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; this.lblContract.Location = new System.Drawing.Point(128, 120); this.lblContract.Name = "lblContract"; this.lblContract.TabIndex = 12; // // lblProdTape // this.lblProdTape.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; this.lblProdTape.Location = new System.Drawing.Point(128, 88); this.lblProdTape.Name = "lblProdTape"; this.lblProdTape.TabIndex = 18; // // lblProduct // this.lblProduct.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; this.lblProduct.Location = new System.Drawing.Point(128, 56); this.lblProduct.Name = "lblProduct"; this.lblProduct.TabIndex = 19; // // lblExchange // this.lblExchange.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; this.lblExchange.Location = new System.Drawing.Point(128, 16); this.lblExchange.Name = "lblExchange"; this.lblExchange.TabIndex = 20; // // label6 // this.label6.Location = new System.Drawing.Point(264, 120); this.label6.Name = "label6"; this.label6.Size = new System.Drawing.Size(96, 16); this.label6.TabIndex = 25; this.label6.Text = "ASK QTY:"; // // label7 // this.label7.Location = new System.Drawing.Point(264, 88); this.label7.Name = "label7"; this.label7.Size = new System.Drawing.Size(96, 16); this.label7.TabIndex = 24; this.label7.Text = "ASK PRICE:"; // // label8 // this.label8.Location = new System.Drawing.Point(264, 56); this.label8.Name = "label8"; this.label8.Size = new System.Drawing.Size(96, 16); this.label8.TabIndex = 23; this.label8.Text = "BID QTY:"; // // label9 // this.label9.Location = new System.Drawing.Point(264, 19); this.label9.Name = "label9"; this.label9.Size = new System.Drawing.Size(96, 16); this.label9.TabIndex = 22; this.label9.Text = "BID PRICE:"; // // lblAskQty // this.lblAskQty.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; this.lblAskQty.Location = new System.Drawing.Point(376, 120); this.lblAskQty.Name = "lblAskQty"; this.lblAskQty.TabIndex = 21; // // lblAskPrice // this.lblAskPrice.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; this.lblAskPrice.Location = new System.Drawing.Point(376, 88); this.lblAskPrice.Name = "lblAskPrice"; this.lblAskPrice.TabIndex = 26; // // lblBidQty // this.lblBidQty.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; this.lblBidQty.Location = new System.Drawing.Point(376, 56); this.lblBidQty.Name = "lblBidQty"; this.lblBidQty.TabIndex = 27; // // lblBidPrice // this.lblBidPrice.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; this.lblBidPrice.Location = new System.Drawing.Point(376, 16); this.lblBidPrice.Name = "lblBidPrice"; this.lblBidPrice.TabIndex = 28; // // label14 // this.label14.Location = new System.Drawing.Point(264, 184); this.label14.Name = "label14"; this.label14.Size = new System.Drawing.Size(96, 16); this.label14.TabIndex = 31; this.label14.Text = "LAST QTY:"; // // label15 // this.label15.Location = new System.Drawing.Point(264, 152); this.label15.Name = "label15"; this.label15.Size = new System.Drawing.Size(96, 16); this.label15.TabIndex = 30; this.label15.Text = "LAST PRICE:"; // // lblLastQty // this.lblLastQty.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; this.lblLastQty.Location = new System.Drawing.Point(376, 184); this.lblLastQty.Name = "lblLastQty"; this.lblLastQty.TabIndex = 29; // // lblLastPrice // this.lblLastPrice.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; this.lblLastPrice.Location = new System.Drawing.Point(376, 152); this.lblLastPrice.Name = "lblLastPrice"; this.lblLastPrice.TabIndex = 32; // // Form1 // this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.ClientSize = new System.Drawing.Size(496, 341); this.Controls.Add(this.label14); this.Controls.Add(this.label15); this.Controls.Add(this.lblLastQty); this.Controls.Add(this.lblLastPrice); this.Controls.Add(this.label6); this.Controls.Add(this.label7); this.Controls.Add(this.label8); this.Controls.Add(this.label9); this.Controls.Add(this.lblAskQty); this.Controls.Add(this.lblAskPrice); this.Controls.Add(this.lblBidQty); this.Controls.Add(this.lblBidPrice); this.Controls.Add(this.label1); this.Controls.Add(this.label2); this.Controls.Add(this.label3); this.Controls.Add(this.label4); this.Controls.Add(this.label5); this.Controls.Add(this.lblContract); this.Controls.Add(this.lblProdTape); this.Controls.Add(this.lblProduct); this.Controls.Add(this.lblExchange); this.Name = "Form1"; this.Text = " Price Update From"; this.Load += new System.EventHandler(this.Form1_Load); this.ResumeLayout(false); } #endregion /// <summary> /// The main entry point for the application. /// </summary> /// [STAThread] static void Main() { Application.Run(new Form1()); } private void Form1_Load(object sender, System.EventArgs e) { // initilize XTAPI needed classes and/or objects // Instantiate the drag and drop handler class m_DropHandler = new XTAPI.TTDropHandlerClass(); // register the active window to enable drag and drop m_DropHandler.RegisterDropWindow((int) this.Handle); // associate drop and drag events with the handler m_DropHandler.OnNotifyDrop += new XTAPI._ITTDropHandlerEvents_OnNotifyDropEventHandler(this.m_DropHandler_OnNotifyDrop); // instantiate the instrument notification class m_InstrNotify = new XTAPI.TTInstrNotifyClass(); // associate instrument notification events with the instrument notification class // setup the instrument notification call back function m_InstrNotify.OnNotifyFound += new XTAPI._ITTInstrNotifyEvents_OnNotifyFoundEventHandler(this.m_InstrNotify_OnNotifyFound); // setup the instrument update call back function m_InstrNotify.OnNotifyUpdate += new XTAPI._ITTInstrNotifyEvents_OnNotifyUpdateEventHandler(this.m_InstrNotify_OnNotifyUpdate); } // XTAPI specific used functions private void m_DropHandler_OnNotifyDrop() { // drag and drop call back function try { // get live instrument from the call back - Index starts at 1 // cast the call back instrument as an instrument object m_LiveInstr = (XTAPI.TTInstrObj) m_DropHandler[1]; // 1 for a single instrument // **** 88888888888888 ************* // must attach instrument to the notification object m_InstrNotify.AttachInstrument(m_LiveInstr); // **** 88888888888888 ************* // open / access selected instrument m_LiveInstr.Open(0); // turn off depth // clear drop handler list m_DropHandler.Reset(); } catch (Exception e) { MessageBox.Show(e.Message,"Exception"); } } private void m_InstrNotify_OnNotifyFound(XTAPI.TTInstrNotify pNotify, XTAPI.TTInstrObj pInstr) { // retrieve and display instrument information Display_Instrument_Information(pInstr); // retrieve and display pricing information Get_Live_Data(pInstr); // turn on price updates m_InstrNotify.EnablePriceUpdates = 1; // 1 for true } private void m_InstrNotify_OnNotifyUpdate(XTAPI.TTInstrNotify pNotify, XTAPI.TTInstrObj pInstr) { // retrieve live instrument prices Get_Live_Data(pInstr); } private void Display_Instrument_Information(XTAPI.TTInstrObj pInstr) { // display instrument fields onto labels this.lblExchange.Text = pInstr.Exchange; this.lblProduct.Text = pInstr.Product; this.lblProdTape.Text = pInstr.ProdType; this.lblContract.Text = pInstr.Contract; Application.DoEvents(); // force update in case it does not } private void Get_Live_Data(XTAPI.TTInstrObj pInstr) { // display instrument pricing information onto labels this.lblBidQty.Text = (string) pInstr.get_Get("BidQty$"); this.lblBidPrice.Text = (string) pInstr.get_Get("Bid$"); this.lblAskPrice.Text = (string) pInstr.get_Get("Ask$"); this.lblAskQty.Text= (string) pInstr.get_Get("AskQty$"); this.lblLastPrice.Text = (string) pInstr.get_Get("Last$"); this.lblLastQty.Text = (string) pInstr.get_Get("LastQty$"); Application.DoEvents(); // force update in case it does not } } } "Willy Denoyette [MVP]" <willy.denoyette@telenet.be> wrote in message news:egrATmCmFHA.4056@TK2MSFTNGP10.phx.gbl... > DoEvents() should never be called nor in a COM interop scenario and not on > the UI thread. All you have to do is make sure you don't block the message > pumping/dispatching by calling functions or running code that take a long > time before yielding (~300msec. might be too long for a decent user > experience). The same thing goes for a COM callback that runs on the UI > thread, messages aren't dispatched as long as the callback code runs. > Now it's hard to tell what happens in your code without some more context > (apartment requirements of COM object) and seeing any code; What's not clear > is where you call DoEvents() on a UI thread that is not pumping, so it looks > like your code blocks the message while running in a tight loop and you call > DoEvents in the loop. > > Willy. > > > > > "Ollie Riches" <ollie.riches@phoneanalyser.net> wrote in message > news:enlwsWCmFHA.1044@tk2msftngp13.phx.gbl... >>I understand the use of Application.DoEvents() to process all outstanding >>messages on the message queue in a winforms application if you have long >>running process on the UI thread. But can anyone explain to me why I need >>to call DoEvents when I am using a COM component that calls back to into >>the .Net application? - If I don't call DoEvents after receiving a callback >>then sometimes no more messages are pumped, it appears that the message >>pump is suspended until the call is made. >> >> I suspect that when a callback occurs from COM into the .Net process that >> it will not be guaranteed to be executed on the UI thread is this true? >> ( Note: I do know about updating the UI thread from a worker thread so >> people pleased don't try and tell me about the 'Invoke' method on the >> Control class) >> >> Cheers >> >> Ollie Riches >> > > |
|
|
|
#4 |
|
Guest
Posts: n/a
|
Well I really don't know why DoEvents included, but it's heritage is VB so I guess we have to look that way. Anyway there is no need ever to call DoEvents because there is a better solution and because it's not re-entrant safe.
Now as for this code, I can hardly be sure for 100% what's going on without any more info on the COM library itself (would like to know it's threadingmodel). What I see is that the UI is only meant to display data, there are no input controls (buttons etc...) only output controls (labels), and the callbacks are only used to update the labels at regular intervals. There are no calls made to the COM object from the UI, that means if the COM object doesn't return after the callback, that is when it blocks (in a sleep call fi) without pumping the message queue, you are screwed, and you have to resort to hacks like DoEvents() to update the UI (redraw) before you return from the eventhandler. Again without seeing the source code of the COM objects it's hard to be sure for 100% , but I wouldn't be surprised it's like that. All you have to do to get rid of the DoEvents hack, is create a separate thread initialized for STA, create an instance of the COM object and update the UI using Control.BeginInvoke. Willy. "Ollie Riches" <ollie.riches@phoneanalyser.net> wrote in message news:usLQtGDmFHA.3304@tk2msftngp13.phx.gbl... Thanks for the reply Willy, If you should never call DoEvents() then I have to ask why was it included? I believe it is similar to including GC.Collect in that it is exposed to the public for use in extreme circumstances. I can understand that while a message is being processed that no other message can be processed hence the name synchronous message processing. I can give an example taken straight from the support site of the product I am using, you can probably guess the product involved in the code. I am well aware that any code published on any site is not always the correct way to solve a problem. The code in question uses the primary interop assembly that was generated by the vendor. If you are using (primary) COM interop library are you required to initialise COM ? - as far as I am aware you do not have too. Here is the complete winforms example, check out the method 'Display_Instrument_Information' Cheers Ollie Riches "Willy Denoyette [MVP]" <willy.denoyette@telenet.be> wrote in message news:egrATmCmFHA.4056@TK2MSFTNGP10.phx.gbl... > DoEvents() should never be called nor in a COM interop scenario and not on > the UI thread. All you have to do is make sure you don't block the message > pumping/dispatching by calling functions or running code that take a long > time before yielding (~300msec. might be too long for a decent user > experience). The same thing goes for a COM callback that runs on the UI > thread, messages aren't dispatched as long as the callback code runs. > Now it's hard to tell what happens in your code without some more context > (apartment requirements of COM object) and seeing any code; What's not clear > is where you call DoEvents() on a UI thread that is not pumping, so it looks > like your code blocks the message while running in a tight loop and you call > DoEvents in the loop. > > Willy. > > > > > "Ollie Riches" <ollie.riches@phoneanalyser.net> wrote in message > news:enlwsWCmFHA.1044@tk2msftngp13.phx.gbl... >>I understand the use of Application.DoEvents() to process all outstanding >>messages on the message queue in a winforms application if you have long >>running process on the UI thread. But can anyone explain to me why I need >>to call DoEvents when I am using a COM component that calls back to into >>the .Net application? - If I don't call DoEvents after receiving a callback >>then sometimes no more messages are pumped, it appears that the message >>pump is suspended until the call is made. >> >> I suspect that when a callback occurs from COM into the .Net process that >> it will not be guaranteed to be executed on the UI thread is this true? >> ( Note: I do know about updating the UI thread from a worker thread so >> people pleased don't try and tell me about the 'Invoke' method on the >> Control class) >> >> Cheers >> >> Ollie Riches >> > > |
|
|
|
#5 |
|
Guest
Posts: n/a
|
Thanks for the info Willy, I realised the solution after posting the reply - its always good to talk out a problem...
Cheers Ollie Riches "Willy Denoyette [MVP]" <willy.denoyette@telenet.be> wrote in message news:O9kKkBFmFHA.3960@TK2MSFTNGP12.phx.gbl... Well I really don't know why DoEvents included, but it's heritage is VB so I guess we have to look that way. Anyway there is no need ever to call DoEvents because there is a better solution and because it's not re-entrant safe. Now as for this code, I can hardly be sure for 100% what's going on without any more info on the COM library itself (would like to know it's threadingmodel). What I see is that the UI is only meant to display data, there are no input controls (buttons etc...) only output controls (labels), and the callbacks are only used to update the labels at regular intervals. There are no calls made to the COM object from the UI, that means if the COM object doesn't return after the callback, that is when it blocks (in a sleep call fi) without pumping the message queue, you are screwed, and you have to resort to hacks like DoEvents() to update the UI (redraw) before you return from the eventhandler. Again without seeing the source code of the COM objects it's hard to be sure for 100% , but I wouldn't be surprised it's like that. All you have to do to get rid of the DoEvents hack, is create a separate thread initialized for STA, create an instance of the COM object and update the UI using Control.BeginInvoke. Willy. "Ollie Riches" <ollie.riches@phoneanalyser.net> wrote in message news:usLQtGDmFHA.3304@tk2msftngp13.phx.gbl... Thanks for the reply Willy, If you should never call DoEvents() then I have to ask why was it included? I believe it is similar to including GC.Collect in that it is exposed to the public for use in extreme circumstances. I can understand that while a message is being processed that no other message can be processed hence the name synchronous message processing. I can give an example taken straight from the support site of the product I am using, you can probably guess the product involved in the code. I am well aware that any code published on any site is not always the correct way to solve a problem. The code in question uses the primary interop assembly that was generated by the vendor. If you are using (primary) COM interop library are you required to initialise COM ? - as far as I am aware you do not have too. Here is the complete winforms example, check out the method 'Display_Instrument_Information' Cheers Ollie Riches "Willy Denoyette [MVP]" <willy.denoyette@telenet.be> wrote in message news:egrATmCmFHA.4056@TK2MSFTNGP10.phx.gbl... > DoEvents() should never be called nor in a COM interop scenario and not on > the UI thread. All you have to do is make sure you don't block the message > pumping/dispatching by calling functions or running code that take a long > time before yielding (~300msec. might be too long for a decent user > experience). The same thing goes for a COM callback that runs on the UI > thread, messages aren't dispatched as long as the callback code runs. > Now it's hard to tell what happens in your code without some more context > (apartment requirements of COM object) and seeing any code; What's not clear > is where you call DoEvents() on a UI thread that is not pumping, so it looks > like your code blocks the message while running in a tight loop and you call > DoEvents in the loop. > > Willy. > > > > > "Ollie Riches" <ollie.riches@phoneanalyser.net> wrote in message > news:enlwsWCmFHA.1044@tk2msftngp13.phx.gbl... >>I understand the use of Application.DoEvents() to process all outstanding >>messages on the message queue in a winforms application if you have long >>running process on the UI thread. But can anyone explain to me why I need >>to call DoEvents when I am using a COM component that calls back to into >>the .Net application? - If I don't call DoEvents after receiving a callback >>then sometimes no more messages are pumped, it appears that the message >>pump is suspended until the call is made. >> >> I suspect that when a callback occurs from COM into the .Net process that >> it will not be guaranteed to be executed on the UI thread is this true? >> ( Note: I do know about updating the UI thread from a worker thread so >> people pleased don't try and tell me about the 'Invoke' method on the >> Control class) >> >> Cheers >> >> Ollie Riches >> > > |
|
|
|
#6 |
|
Guest
Posts: n/a
|
Turns out the problem was related to the threading model, it should have been MTA not STA, with the wrong threading apartment the code required the use of Application.DoEvents().
So the next question is - why would having the wrong thread apartment for an unmanaged COM component cause the message pump to not work correctly and require the use of Application.DoEvents()? Cheers Ollie Riches "Ollie Riches" <ollie.riches@phoneanalyser.net> wrote in message news:unGmG6GmFHA.2080@TK2MSFTNGP10.phx.gbl... Thanks for the info Willy, I realised the solution after posting the reply - its always good to talk out a problem... Cheers Ollie Riches "Willy Denoyette [MVP]" <willy.denoyette@telenet.be> wrote in message news:O9kKkBFmFHA.3960@TK2MSFTNGP12.phx.gbl... Well I really don't know why DoEvents included, but it's heritage is VB so I guess we have to look that way. Anyway there is no need ever to call DoEvents because there is a better solution and because it's not re-entrant safe. Now as for this code, I can hardly be sure for 100% what's going on without any more info on the COM library itself (would like to know it's threadingmodel). What I see is that the UI is only meant to display data, there are no input controls (buttons etc...) only output controls (labels), and the callbacks are only used to update the labels at regular intervals. There are no calls made to the COM object from the UI, that means if the COM object doesn't return after the callback, that is when it blocks (in a sleep call fi) without pumping the message queue, you are screwed, and you have to resort to hacks like DoEvents() to update the UI (redraw) before you return from the eventhandler. Again without seeing the source code of the COM objects it's hard to be sure for 100% , but I wouldn't be surprised it's like that. All you have to do to get rid of the DoEvents hack, is create a separate thread initialized for STA, create an instance of the COM object and update the UI using Control.BeginInvoke. Willy. "Ollie Riches" <ollie.riches@phoneanalyser.net> wrote in message news:usLQtGDmFHA.3304@tk2msftngp13.phx.gbl... Thanks for the reply Willy, If you should never call DoEvents() then I have to ask why was it included? I believe it is similar to including GC.Collect in that it is exposed to the public for use in extreme circumstances. I can understand that while a message is being processed that no other message can be processed hence the name synchronous message processing. I can give an example taken straight from the support site of the product I am using, you can probably guess the product involved in the code. I am well aware that any code published on any site is not always the correct way to solve a problem. The code in question uses the primary interop assembly that was generated by the vendor. If you are using (primary) COM interop library are you required to initialise COM ? - as far as I am aware you do not have too. Here is the complete winforms example, check out the method 'Display_Instrument_Information' Cheers Ollie Riches "Willy Denoyette [MVP]" <willy.denoyette@telenet.be> wrote in message news:egrATmCmFHA.4056@TK2MSFTNGP10.phx.gbl... > DoEvents() should never be called nor in a COM interop scenario and not on > the UI thread. All you have to do is make sure you don't block the message > pumping/dispatching by calling functions or running code that take a long > time before yielding (~300msec. might be too long for a decent user > experience). The same thing goes for a COM callback that runs on the UI > thread, messages aren't dispatched as long as the callback code runs. > Now it's hard to tell what happens in your code without some more context > (apartment requirements of COM object) and seeing any code; What's not clear > is where you call DoEvents() on a UI thread that is not pumping, so it looks > like your code blocks the message while running in a tight loop and you call > DoEvents in the loop. > > Willy. > > > > > "Ollie Riches" <ollie.riches@phoneanalyser.net> wrote in message > news:enlwsWCmFHA.1044@tk2msftngp13.phx.gbl... >>I understand the use of Application.DoEvents() to process all outstanding >>messages on the message queue in a winforms application if you have long >>running process on the UI thread. But can anyone explain to me why I need >>to call DoEvents when I am using a COM component that calls back to into >>the .Net application? - If I don't call DoEvents after receiving a callback >>then sometimes no more messages are pumped, it appears that the message >>pump is suspended until the call is made. >> >> I suspect that when a callback occurs from COM into the .Net process that >> it will not be guaranteed to be executed on the UI thread is this true? >> ( Note: I do know about updating the UI thread from a worker thread so >> people pleased don't try and tell me about the 'Invoke' method on the >> Control class) >> >> Cheers >> >> Ollie Riches >> > > |
|
|
|
#7 |
|
Guest
Posts: n/a
|
Ollie,
Any STA COM object requires the thread on which it is created to run the message pump. It is due to the way the system serializes calls to STA COM objects - the calls are marshalled as private Windows messages to a dedicated hidden window, "OleMainThreadWnd" (not sure about exact spelling). If an STA thread makes a blocking call and stops processing Windows messages, no calls can be forwarded to any COM component in the STA apartment the thread belongs to. Application.DoEvents forces the Framework to process accumulated messages, thus allowing any serialized calls to complete. Does this answer your question? -- Sincerely, Dmytro Lapshyn [Visual Developer - Visual C# MVP] "Ollie Riches" <ollie.riches@phoneanalyser.net> wrote in message news:ua9y8lQnFHA.1968@TK2MSFTNGP14.phx.gbl... Turns out the problem was related to the threading model, it should have been MTA not STA, with the wrong threading apartment the code required the use of Application.DoEvents(). So the next question is - why would having the wrong thread apartment for an unmanaged COM component cause the message pump to not work correctly and require the use of Application.DoEvents()? Cheers Ollie Riches "Ollie Riches" <ollie.riches@phoneanalyser.net> wrote in message news:unGmG6GmFHA.2080@TK2MSFTNGP10.phx.gbl... Thanks for the info Willy, I realised the solution after posting the reply - its always good to talk out a problem... Cheers Ollie Riches "Willy Denoyette [MVP]" <willy.denoyette@telenet.be> wrote in message news:O9kKkBFmFHA.3960@TK2MSFTNGP12.phx.gbl... Well I really don't know why DoEvents included, but it's heritage is VB so I guess we have to look that way. Anyway there is no need ever to call DoEvents because there is a better solution and because it's not re-entrant safe. Now as for this code, I can hardly be sure for 100% what's going on without any more info on the COM library itself (would like to know it's threadingmodel). What I see is that the UI is only meant to display data, there are no input controls (buttons etc...) only output controls (labels), and the callbacks are only used to update the labels at regular intervals. There are no calls made to the COM object from the UI, that means if the COM object doesn't return after the callback, that is when it blocks (in a sleep call fi) without pumping the message queue, you are screwed, and you have to resort to hacks like DoEvents() to update the UI (redraw) before you return from the eventhandler. Again without seeing the source code of the COM objects it's hard to be sure for 100% , but I wouldn't be surprised it's like that. All you have to do to get rid of the DoEvents hack, is create a separate thread initialized for STA, create an instance of the COM object and update the UI using Control.BeginInvoke. Willy. "Ollie Riches" <ollie.riches@phoneanalyser.net> wrote in message news:usLQtGDmFHA.3304@tk2msftngp13.phx.gbl... Thanks for the reply Willy, If you should never call DoEvents() then I have to ask why was it included? I believe it is similar to including GC.Collect in that it is exposed to the public for use in extreme circumstances. I can understand that while a message is being processed that no other message can be processed hence the name synchronous message processing. I can give an example taken straight from the support site of the product I am using, you can probably guess the product involved in the code. I am well aware that any code published on any site is not always the correct way to solve a problem. The code in question uses the primary interop assembly that was generated by the vendor. If you are using (primary) COM interop library are you required to initialise COM ? - as far as I am aware you do not have too. Here is the complete winforms example, check out the method 'Display_Instrument_Information' Cheers Ollie Riches "Willy Denoyette [MVP]" <willy.denoyette@telenet.be> wrote in message news:egrATmCmFHA.4056@TK2MSFTNGP10.phx.gbl... > DoEvents() should never be called nor in a COM interop scenario and not on > the UI thread. All you have to do is make sure you don't block the message > pumping/dispatching by calling functions or running code that take a long > time before yielding (~300msec. might be too long for a decent user > experience). The same thing goes for a COM callback that runs on the UI > thread, messages aren't dispatched as long as the callback code runs. > Now it's hard to tell what happens in your code without some more context > (apartment requirements of COM object) and seeing any code; What's not > clear > is where you call DoEvents() on a UI thread that is not pumping, so it > looks > like your code blocks the message while running in a tight loop and you > call > DoEvents in the loop. > > Willy. > > > > > "Ollie Riches" <ollie.riches@phoneanalyser.net> wrote in message > news:enlwsWCmFHA.1044@tk2msftngp13.phx.gbl... >>I understand the use of Application.DoEvents() to process all outstanding >>messages on the message queue in a winforms application if you have long >>running process on the UI thread. But can anyone explain to me why I need >>to call DoEvents when I am using a COM component that calls back to into >>the .Net application? - If I don't call DoEvents after receiving a >>callback >>then sometimes no more messages are pumped, it appears that the message >>pump is suspended until the call is made. >> >> I suspect that when a callback occurs from COM into the .Net process that >> it will not be guaranteed to be executed on the UI thread is this true? >> ( Note: I do know about updating the UI thread from a worker thread so >> people pleased don't try and tell me about the 'Invoke' method on the >> Control class) >> >> Cheers >> >> Ollie Riches >> > > |
|
![]() |
|
| Thread Tools | |
| Rate This Thread | |
|
|

Main Page 

