Revit API Forum
Welcome to Autodesk’s Revit API Forums. Share your knowledge, ask questions, and explore popular Revit API topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

How to trigger OnIdle event or execution of an ExternalEvent without user input

2 REPLIES 2
SOLVED
Reply
Message 1 of 3
bogdan.zavu
1381 Views, 2 Replies

How to trigger OnIdle event or execution of an ExternalEvent without user input

Hi,

First , If you don't want to read everything just go directly to the blue code section Smiley Wink

If you bumped into this by now you probably already know that it doesn't matter what method you use to execute your API code.

Subscription to the OnIdle or ExternalEvent will generate the same problem.

So what exactly happens ? Why sometimes works perfectly fine and sometimes not quite as well

Both OnIddle and ExtternalEvent framework rely on the WM_IDLE message which is pumped by the system in the app queue.

Here is a quote from MSDN : "OnIdle is called in the default message loop when the application's message queue is empty".

And that's the moment when you'll get OnIdle notification and External event execution in your Addin.

 

This is perfectly fine except in the case in which there is no message in the queue. 

If there is no message in queue there is not going to be any OnIdle notification or EV execution.

Most of the time there is going to be some kind of message there but there are some cases when the queue is empty.

 

Let's analyze both scenarios when it works and why it works and when it doesn't work.

Why it works when it works :

Your Addin has some kind of UI and everything is part of the Revit process.

This means automatically that you UI windows have some kind relantionship with Revit directly.

In other other words there is always going to some kind of messaging going back and forward between you UI and Revit.

And that's why your API is executed when you press Play in our Addin - because in this case there is always going to be some message in the queue which means for sure there is also going to be WM_IDLE at some point - which will lead to OnIdle notifications and ExternalEvents execution.

 

Why it doesn't work ...when it doesn't work

You Addin doesn't have any UI - strange isn't it ? but it might happen.

For variuous reasons ( especially in the cloud era ) you might have a completely separated process from Revit for your third party application which contains your UI and the rest of the code in the actual addin.dll 

Since now there is no addin window as part of the Revit process the message queue of Revit won't be filled so easily.

So yes, that's the moment when you need to move the mouse a little bit , give focus to Revit and so on.

So by user input you are actually filling the message queue of Revit which means there is going to be an WM_IDLE at some point which means you API is going to be executed.

 

Solution :

In order to make sure our API is going to be executed promptly we need to find a smart simple way to fill some message in the Revit queue.

Built in C# functionality helps us to solve this issue :

There a C# class which manages an external process and also gives you a little more information about that process , like the mainwindowhandle.

Here is a code sample you can adjust/use as you like :

 

//when you receive some notification on your worker thread ( yes , you can do this from a worker thread !) like some message from a service :

void PokeRevit()

{

........

    Process revitProcess = Process.GetCurrentProcess();

    if (revitProcess != null && !revitProcess.HasExited)
    {
        try
        {
            IntPtr mainrevitwindowhandle = revitProcess.MainWindowHandle;
            if (mainrevitwindowhandle != null && mainrevitwindowhandle.ToInt64() != 0)
            {
                PostMessage(mainrevitwindowhandle, 0, 0, 0);

            }

       }

      catch

      {

      //report error      

      }

.......

}

 

 

As you can see I'm not touching Revit API at all , I'm just using just built-in C# functionality.

So mainrevitwindowhandle = main Revit window , the father of all that says Revit 20XX - Project X.

Process class manages well the case when the main window is destroyed in which case the value is 0 (not null).

PostMessage is great because is thread safe !

And even more , the windows development team had so much trouble with this function when developers posted messages to already destroyed windows that they decided to manage the case internally - meaning PostMessage( garbage-bad-pointer , ....) will not crash you application ( even taught it clearly indicates a bug ).

 

So what message are we posting there ? Well , it is the harmful message of all = WM_NULL which is ignored by receiver but , but ..is enough for us to make the windows os post a WM_IDLE in our queue.

 

And that's it !

 

 

2 REPLIES 2
Message 2 of 3
Anonymous
in reply to: bogdan.zavu

I frequently use MessageBox for debugging purposes. Sometimes there is different, unwanted behavior when they are removed. This happens without any intentional event handling going on.  This might help in those instances. Thank you.

 

By the way, I assume this was missing:

 

 [DllImport("USER32.DLL")]
        public static extern bool PostMessage(
          IntPtr hWnd, uint msg, uint wParam, uint lParam);
Message 3 of 3
bogdan.zavu
in reply to: Anonymous

Yes, you'll have to use [DllImport("USER32.dll")]

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

Post to forums  

Autodesk Customer Advisory Groups


Rail Community