2

I have a winform (MyFrm) which contains a winforms user control (myWinformUserControl). I call a public method (MyMethod) from this user control:

using (var frm = new MyFrm())
{
      frm.myWinformUserControl.MyMethod();
}

public class myWinformUserControl: System.Windows.Forms.UserControl
{
     public void MyMethod()
     { 
          // Do some stuff
          TryToDisconnect();
     }

     private void TryToDisconnect()
     {
         myComObj.Disconnect(); // This throws COMException
     }
}

This user control communicates with a COM object. When I call to disconnect on the COM Object an exception is thrown:

COMException: Cannot call a 'Disconnect()' from within an event

so in order to solve this I use a thread instead of calling it directly:

 public void MyMethod()
 { 
     System.Threading.Thread th = new System.Threading.Thread(new 
     System.Threading.ThreadStart(TryToDisconnect));
     th.SetApartmentState(System.Threading.ApartmentState.STA);
     th.IsBackground = true;
     th.Priority = System.Threading.ThreadPriority.Highest;
     th.Start();
 }

The below block of code indicated at the beginning of this question:

using (var frm = new MyFrm())
{
      frm.myWinformUserControl.MyMethod();
}

... is called from a WPF MVVM view model class.

The problem I have here is that I need MyMethod to be done immediatelly so I set highest priority for the thread, and I want the call in view model class (frm.myWinformUserControl.MyMethod()) to stop and do not continue until this thread is completed. I have observed that the thread is not immediatelly executed, so how can I achieve this?

I have tried an asynchronous call and wait until it is completed instead of using a thread:

public void MyMethod()
{ 
   Action action = Foo;
   IAsyncResult result = action.BeginInvoke(ar => action.EndInvoke(ar), null);                    
   result.AsyncWaitHandle.WaitOne();
}

public delegate void Action();
private void Foo()
{
    TryToDisconnect();
}

but again the same COMException is thrown:

COMException: Cannot call a 'Disconnect()' from within an event

Also, in case of using the thread, If I immediatelly do th.Join() just after doing th.start() it does not work.

Willy
  • 9,848
  • 22
  • 141
  • 284
  • AFAIK you can't have guaranteed immediate response in a multithread application. and you are right about the other scenarios with that COM exception (the error means it wasn't intended for event handlers to call those methods) – Bizhan Jul 19 '18 at 16:09
  • @Bijan But in my case I am not calling those methods from within an event (event handlers)... In first implementation I am directly calling it so I do not understand why this exception is happening. – Willy Jul 19 '18 at 18:45
  • I imagine you're calling `TryToDisconnect` from an event handler of the event sourced by the COM object itself, is that the case? – noseratio Jul 20 '18 at 20:19
  • This exception almost surely comes from the COM component itself. Raising an event is a risky proposition, the client code can do too much to cause nasty re-entrancy problems. Like jerking the floor mat with a Disconnect() call. The debugger's Call Stack window is the most important tool to show you how that ball got rolling, it ought to show how the new MyFrm() code got activated. You solve it by calling Disconnect() later, after the event is handled by your code. DispatcherTimer can do it, more elegantly done by the Dispatcher.BeginInvoke() method. – Hans Passant Jul 20 '18 at 22:28
  • @HansPassant The caller is a button click event in WPF, that finally calls de MyFrm(). So I wonder if the COM component has this limitation, I mean, Disconnect() cannot be called from an event. Regarding DispatcherTimer, do you mean call Disconnect() from Dispather.BeginInvoke()? Or from Dispatcher.Invoke since I need call to be synchronous. – Willy Jul 24 '18 at 22:18

0 Answers0