.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Rejected COM Call in WPF using a Background Worker Thread

5 REPLIES 5
Reply
Message 1 of 6
Anonymous
1788 Views, 5 Replies

Rejected COM Call in WPF using a Background Worker Thread

Hey all,

 

I've got a tricky problem and what no idea as to how to solve it.

First of all, my objective is to create a WPF application which starts AutoCAD using COM interop.  I've been able to do this successfully.

However, I want to process many drawings with this application, and want to give the user a progress bar telling him/her how many drawings have been processed.

 

This means I need to create a background thread performing AutoCAD operations.  This thread would prevent the WPF window from freezing up and allow the WPF window to update the progress bar.

 

Unforunately, when I attempt to work with AutoCAD in this background thread, I receive the exception:

The message filter indicated that the application is busy. (Exception from HRESULT: 0x8001010A (RPC_E_SERVERCALL_RETRYLATER))

Now, I've said that I've been able to successfully create the program without the progress bar feedback.  I was able to do that using this article:

Handling COM calls rejected by AutoCAD from an external .NET application

 

This article was useful for allowing COM operations to be called in the first place.  Without it, I could not even create the application without progress feedback.  Apparently, I needed to re-implement the message filter and change it so that is retries COM calls upon failure.

 

So after introducing this background thread, I come up with the same issue as before (as far as I can tell), regarding failing COM calls.

I am led to believe that the message filter is no longer set up properly because of this new thread.

 

To see the message filter code, please see the article.

Here is my threading code below:

//Called from WPF button.
private void BtnStart_Click(object sender, RoutedEventArgs e)
{
    if (!isRunning)
    {   //Update UI to show that the process started.
        isRunning = true;
        BtnStart.IsEnabled = false;
        BtnStop.IsEnabled = true;
        ProgTask.Value = 0;

        //Start the background thread.
        ThreadStart start = new ThreadStart(Run);
        Thread t = new Thread(start);
        t.Start();
    }
}

public void Run()
{
    //GetAcadInstance either connects to an existing instance, or 
    //creates a new one (works fine).
    AcadApplication app = GetAcadInstance();
    
    //COM call fails here
    app.ActiveDocument.Close(false);
    
    for (int i = 0; i < 1000000 && isRunning; i += 200)
    {
        //Make changes synchronously on the WPF thread.
        BtnStart.Dispatcher.Invoke(new RunDelegate(delegate
        {
            if (isRunning)
            {
                ProgTask.Value += 200;
                LblTask.Content = "Processed " + ProgTask.Value;
            }
        }), DispatcherPriority.Normal);
    }

    BtnStart.Dispatcher.Invoke(new RunDelegate(delegate
    {
        isRunning = false;
        BtnStart.IsEnabled = true;
        BtnStop.IsEnabled = false;
    }));

    app.Quit();
}

 

So, does anybody know what's going on here?  Any clues as to how this can be fixed?  I have several applications which need progress information.

 

Much appreciation,

Nicholas

5 REPLIES 5
Message 2 of 6
Anonymous
in reply to: Anonymous

I have no idea if this is at all useful, but I found that the CoRegisterMessageFilter function documentation says that

"Threads in multithreaded apartments cannot have message filters."

 

CoRegisterMessageFilter Documentation

 

I wonder if this is why the COM calls are being rejected after including a background thread.

Message 3 of 6
Tyler.J
in reply to: Anonymous

To add to this since I ran into this exact scenario today.  After creating the worker thread you must call SetApartmentState(ApartmentState.STA) before starting the thread or the messageFilter will not work.

 

I came here to ask why that was but after seeing Millerni's response I dug around MSDN articles for a bit and found that: "New threads are initialized as ApartmentState.MTA if their apartment state has not been set before they are started."

 

https://msdn.microsoft.com/en-us/library/system.threading.thread.setapartmentstate(v=vs.110).aspx

 

It is also worth noting (since OP's subject says "Background Worker") that you can not use a BackgroundWorker form control as that uses the threadpool which is always MTA.  You must create your own thread as OP did, just set to STA, and should be good to go!

Message 4 of 6
Anonymous
in reply to: Anonymous

Hi, did you get the solution to the problem? I'm experiencing the same issue on a windows forms application and a background worker to manipulate drawings. I'm partially solving it with 'try catch' blocks inside a 'while' that do many retries.
Message 5 of 6
Tyler.J
in reply to: Anonymous

Did you see my post above? Been awhile since I've messed around with this but I don't think you can use a BackgroundWorker. You must create your own thread, and explicitly set it the ApartmentState to STA.

 

        Dim threadStart As New ThreadStart(AddressOf AcadWork)
        Dim workerThread As Thread = New Thread(threadStart)
        workerThread.SetApartmentState(ApartmentState.STA)
        workerThread.Start()

 

If your issue is:

  • Application is busy (RPC_E_CALL_REJECTED 0x80010001)

  • Call was rejected by callee (RPC_E_SERVERCALL_RETRYLATER 0x8001010A)

You need to implement a message filter as described in this article:

 

https://msdn.microsoft.com/en-us/library/ms228772.aspx

 

Message 6 of 6
MMasood
in reply to: Tyler.J

you are a life saver @Tyler.J . i have been banging my head for a couple of weeks on this

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost