Revit 2019.1 add-in and CEFsharp library

Revit 2019.1 add-in and CEFsharp library

mikako_harada
Community Manager Community Manager
8,454 Views
8 Replies
Message 1 of 9

Revit 2019.1 add-in and CEFsharp library

mikako_harada
Community Manager
Community Manager

Revit 2019.1 Update has been released. There are quite a few interesting new feature. Please take a look here for more detail for new features in the product. For developers perspective, 2019.1 includes a few new API’s as well. We will come back to this later. But we’d like to point out up front one important item that might affect your apps if your app uses CEFsharp library. If you are using CEFsharp library, please read on.   

 

Revit 2019.1 and a few other Autodesk add-ins uses the CEFsharp library for several features. We have learned that some 3rd party add-ins also use this library.  Unfortunately, when different versions of the library are used, it leads to instability issues for Revit. In order to avoid version conflicts, we want to make it clear the version of CEFsharp that Revit uses: CEFsharp version  57.0.0

In addition, Revit 2019.1 now forcibly loads a version of CEFsharp prior to add-in initialization. This means that add-ins which load a different version of the CEFsharp library may not function as before.  Autodesk recommends realigning add-ins to use the version provided by and loaded by Revit. Example of features that uses CEFsharp library includes the new Revit Home and the Site Collaboration with Civil 3D feature in Revit 2019.1. Dynamo for Revit and P&ID add-in for Revit also uses CEFsharp prior to Revit 2019.1 release.  


Mikako Harada
Developer Technical Services
8,455 Views
8 Replies
Replies (8)
Message 2 of 9

Anonymous
Not applicable

Two thumbs up for moving to standardize CEF usage across addins -- it will be nice when we can distribute our addin without the bulky CEF dlls.

 

We have one big problem with the new CEF behavior, and I was wondering if the API team considered our use case when you made the change. We initialize CEF and explicitly introduce a custom scheme (see: https://github.com/cefsharp/CefSharp/blob/master/CefSharp.Example/CefSharpSchemeHandler.cs) that we use to pass information back and forth between an html/js UI and a C# dll that calls into the revit API. As cef can only be initialized once, our addin is broken on 2019.1 until we can find a solution. We are considering adopting an approach involving moving our UI to a separate process entirely, similar to what is prototyped here (https://github.com/stever/AppHostCefSharp/tree/master/AppHostCefSharp), but are still in early phases of investigation.

 

Do you have any guidance on the best way forward for Addin developers that are currently initializing CEF themselves?

Message 3 of 9

Anonymous
Not applicable

@Anonymous, it seems we have very similar architectures.  We also rely on the custom scheme.  It looks like calling the following method of the `CefSettings` object (before it gets passed to `Cef.Initialize`):

 

settings.RegisterScheme(new CefCustomScheme {
                    SchemeName = "https",
                    DomainName = domain,
                    SchemeHandlerFactory = new FolderSchemeHandlerFactory(webPath, hostName: domain)
});

where `domain` is `https://localweb` and `webPath` links to our local installation folder.  If we can no longer use that, we will be forced to rewrite our app in WPF I suppose.  That would be a lot of unexpected work.

 

--------------------------


We also have this in the code:

#if DEBUG
                settings.RemoteDebuggingPort = 8088;
#endif

which would be nice to continue having access too.

Finally, we use some other settings.  For example in our code,  I'm seeing: 

 

// CefSharp defaults to Wcf for communicating cross process, but native chrome IPC is better
CefSharpSettings.WcfEnabled = false;

Not sure if that's important to us, but basically trying to say that it would be nice to know what Revit is doing under the covers when initializing. 


Garrett
Engineering @ UpCodes

Message 4 of 9

mikako_harada
Community Manager
Community Manager

Hi Andrew, Garret, 

 

I want to let you know that the Revit product team is investigating your inquiries above.  We'll update you when we have more info.  Thank you for your patience.  


Mikako Harada
Developer Technical Services
Message 5 of 9

Anonymous
Not applicable

Thank you @mikako_harada for driving the investigation with the Revit team. Looking forward to hearing results of your investigation.

 

In the meantime, I spent some time looking at the implications of sharing CEF 57 across Revit and addins, here are my findings, hopefully, they will be useful to others.


Short answer: it's possible, but there are several caveats.

 

  • You should still bundle CEF57 with your addin.
    You could potentially do something clever in your installer that detects the version of Revit installed and then decides whether to lay down the CEF binaries, but I would discourage that. Many customers have multiple versions of Revit installed and having different logic for each version is a pain.
  • If you already have a version of your addin with CEF >57 in the wild, you will have to change your installer to force it to overwrite CEF binaries with older versions.
    Windows installer, by default, will not allow you to do this. Your best option is to give all CEF binaries different component/file GUIDs instead of overriding Windows installer default behavior. (Make sure to test upgrade install to verify your changes)
  • CEF 57 doesn't have many of the nice V8 serialization improvements.
    This means that if you rely on C#/JavaScript bindings you are limited to passing primitives, value types, and arrays (which can only contain the same types). Meaning serializing a custom class from C# to JS is not allowed - you will get "Complex types cannot be serialized to Cef lists" exception (see: https://github.com/cefsharp/CefSharp/blob/cefsharp/57/CefSharp.Core/Internals/Serialization/V8Serial...)
  • If you are registering your own scheme handler, DON'T.
    Instead, use a RequestContext which will allow you to perform all scheme registrations local to your browser instance:

 

 

Browser = new ChromiumWebBrowser();
RequestContext addinRequestContext = new RequestContext();
string addinDomain = "addinlocal";
addinRequestContext.RegisterSchemeHandlerFactory("https", addinDomain, new FolderSchemeHandlerFactory(@"C:\My\Addin\Web\Content"));
Browser.RequestContext = addinRequestContext;

// Then you can navigate like this:
Browser.Load($"https://{addinDomain}/index.html");

 

 

  • Only initialize CEF if it hasn't been initialized yet:

 

var settings = new CefSettings {
    BrowserSubprocessPath = @"c:\path\to\my\installed\cefsharp.browsersubprocess.exe"
};

if (!Cef.IsInitialized) {
    Cef.Initialize(settings);
}
else {
    // CEF already initialized, skipping
}

 

 

  • Have a button/shortcut/whatever in your addin to show debug tools.
    Since your addin may or may not get to initialize CEF in setting debugging port parameters may not be possible. Instead, just use the Browser.ShowDevTools() method.
  • Don't modify CefSharpSettings, it's a singleton, so as long as noone touches it we will be OK.
  • Finally, the timing of initial navigation sequence is quite different in CEF 57 (vs CEF 63) so you might have to tweak your startup code.

I will update this thread if I find any other gotchas.

 

Mark

UpCodes Engineering

 

Message 6 of 9

Anonymous
Not applicable

Can't edit my post for some reason...

Some more information on debugging.

 

It looks like Revit initializes the debugging port to be the standard: http://localhost:8088@mikako_harada and all adding developers should have a pact that whoever initializes CEF first, sets up this port for debugging. This is nicer than .ShowDevTools() approach.

 

Mark

0 Likes
Message 7 of 9

kim_sivonen
Explorer
Explorer

Hi All,

We chose to study the possibility of running CEF in another process. After some headache, it actually turned out to be a decent alternative.

I attached a sample solution source code if someone is interested.
The solution consists of two projects; one Revit plugin and one Forms application. All CEF-specific is isolated in the Forms application, which is launched from the Revit plugin as an own process. The code was written very quickly just to prove that the functionality can be done, so please try to tolerate the sloppy code. There's probably many ways how the functionality can fail in different situations, but I believe everything can be handled.

Some comments:
- There's only a minimal amount of code and the technology can be used also for plugins on other platforms. 
- Forms form/window was used in the browser window, but the same technology can be used for WPF
- A few Windows API calls are used to handle Window behaviour and messaging
- The sample uses Window Messages as the IPC technology. The actual data between the Revit plugin and the browser window was done using WM_COPYDATA of the SendMessage in the Windwods API. The two apps exchange their window handles in the start, which enables sending the messages.
- One of the most important things to make the solution to work, was to make Revit behave as the owner of the window in the other process. This functionality was provided by the SetWindowLongPtr-method in the user32.dll. Setting the owner makes Windows handle some of the Window operations automatically: the window stays always on top of the owner window, it minimizes with it, etc.

Please note that this software is BEER-WARE. Description of the license below.
Kim Sivonen, ProdLib Oy

/*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
* ----------------------------------------------------------------------------
*/

 

Message 8 of 9

mikako_harada
Community Manager
Community Manager

Hi community, 

 

Revit engineering team would like to have an example of conflicting app for testing purpose.  

If you have an app with conflicting version, could you allow us to use it?  It does not has to be a actual app.  In fact, if you send them as minimum reproducible code, that will be better.  

 

If you have it, please send it to:  

Nachikethan S <nachikethan.s@autodesk.com>

or myself

mikako.harada@autodesk.com

 

Thank you for your corporation. 


Mikako Harada
Developer Technical Services
0 Likes
Message 9 of 9

jeremytammik
Autodesk
Autodesk

@kim_sivonen  wow, brilliant, thank you very much!

 

Edited and shared for posterity by The Building Coder:

 

https://thebuildingcoder.typepad.com/blog/2019/04/set-floor-level-and-use-ipc-for-disentanglement.ht...

 

Cheers,

 

Jeremy

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes