Access BIM360 Cloud Links, Thumbnail and Dynamo

This post is somewhat overdue and hence rather full of various topics, mainly due to my struggles with my MacBook slowing to an unbearable crawl in the heat last week:

Accessing BIM360 Cloud Links

My colleague Eason Kang researched how to access BIM360 file links in a Revit project and summarised the results for us:

Question: In Revit 2017, I used a method based on ExternalFileReferences to report linked files hosted in BIM360.

In Revit 2019, this method no longer works.

Has there been a change in this area?

Is there a different method we should be using?

Answer: Neither of these two methods support cloud links in Revit 2018 or Revit 2019.

In Revit 2017, they appeared to work, because back then, the cloud links were downloaded as local copies by the Autodesk Desktop Connector before linking.

Nowadays, BIM360 cloud links are treated as external sources. This behaviour started from with Revit 2018.

Therefore, please use ExternalResourceUtils GetAllExternalResourceReferences instead.

Here is a working code snippet:

  // Obtain all external resource references 
  // (saying BIM360 Cloud references and local 
  // file references this time)

  ISet<ElementId> xrefs = ExternalResourceUtils
    .GetAllExternalResourceReferences( doc );

  string caption = "BIM360 Links";

    int n = 0;
    var msg = string.Empty;

    foreachElementId eid in xrefs )
      var elem = doc.GetElement( eid );
      if( elem == null ) continue;

      // Get RVT document links only this time

      var link = elem as RevitLinkType;
      if( link == null ) continue;

      var map = link.GetExternalResourceReferences();
      var keys = map.Keys;

      foreachvar key in keys )
        var reference = map[key];

        // Contains Forge BIM360 ProjectId 
        // (i.e., LinkedModelModelId) and 
        // ModelId (i.e., LinkedModelModelId) 
        // if it's from BIM360 Docs. 
        // They can be used in calls to
        // ModelPathUtils.ConvertCloudGUIDsToCloudPath.

        var dictinfo = reference.GetReferenceInformation();

        // Link Name shown on the Manage Links dialog

        var displayName = reference.GetResourceShortDisplayName();
        var path = reference.InSessionPath;

        // Load model temporarily to get the model 
        // path of the cloud link

        var result = link.Load();

        // Link ModelPath for Revit internal use

        var mdPath = result.GetModelName();

        link.Unload( null );

        // Convert model path to user visible path, 
        // i.e., saved Path shown on the Manage Links 
        // dialog

        var path = ModelPathUtils
          .ConvertModelPathToUserVisiblePath( mdPath );

        // Reference Type shown on the Manage Links dialog

        var refType = link.AttachmentType;

        msg += string.Format( "{0} {1}\r\n", 
          link.AttachmentType, path );

      catchException ex ) // never catch all exceptions!
        TaskDialog.Show( caption, ex.Message );

    caption = string.Format( "{0} BIM360 Link{1}", 
      n, Util.PluralSuffix( n ) );

    TaskDialog.Show( caption, msg );
  catchException ex )
    TaskDialog.Show( caption, ex.Message );

Here are snapshots of the result:

BIM360 links

BIM360 links

Many thanks to Eason for this research and clear explanation!

I added this sample code to The Building Coder samples as a new external command CmdBim360Links in release 2020.0.146.0

Retrieve RVT Preview Thumbnail Image with Python

Franco Tonutti researched and solved how to retrieve the RVT preview thumbnail image with Python in his comments on determining the RVT file version using Python

Question: Hi Jeremy, how can I get the preview image of a .rfa file?

I'm trying the following without success:

  import os.path as op
  import olefile

  def get_rvt_preview(rvt_file):
    if op.exists(rvt_file):
      if olefile.isOleFile(rvt_file):
        rvt_ole = olefile.OleFileIO(rvt_file)
        bfi = rvt_ole.openstream("RevitPreview4.0")
        readed =
        f = open('my_file.bmp', 'w+b')
        print("file does not apper to be an ole file: {}".format(rvt_file))
      print("file not found: {}".format(rvt_file))

Answer: I have not looked into this for a while.

Please take a look at the other explorations reading RVT files without using the Revit API:

Response: Thank you very much.

I solved the problem by looking for the PNG file signature 89504e470d0a1a0a:

def get_rvt_preview(rvt_file, png_path):
  if op.exists(rvt_file):
    if olefile.isOleFile(rvt_file):
      # Open ole file
      rvt_ole = olefile.OleFileIO(rvt_file)
      bfi = rvt_ole.openstream("RevitPreview4.0")
      readed =

      # Find png signature
      readed_hex = readed.hex()
      pos = readed_hex.find('89504e470d0a1a0a')
      png_hex = readed_hex[pos:]
      data = bytes.fromhex(png_hex)

      # Save png file
      f = open(png_path, 'w+b')
      print("file does not apper to be an ole file: {}".format(rvt_file))
    print("file not found: {}".format(rvt_file))

Python code get_rvt_preview

Paolo's Dynamo Primer and Slide Deck Compendium

I already mentioned Paolo Serra's Dynamo Primer discussing Revit API versus Dynamo for Revit.

Here is another very valuable and extensive related resource of his, covering numerous aspects of Dynamo, its features, Python, the Revit API and the relationships between them.

In terms of Dynamo for Revit you can refer to my Dynamo Primer, specifically chapter 8 for the integration with Revit.

You can also check out the slide deck compendium I put together over the years that covers the basics of the Revit API and how to access it through Dynamo and Python at

It includes the following sections:

Slow MacBook with kernel_task Using Several 100% CPU

As I mentioned in the introduction above, after three years or so, my MacBook Pro slowed down to an unusable crawl, especially when it got warm.

I looked at the results in the activity monitor, worrying about a virus, and only saw that the kernel_task was often using several hundred percent of the CPU.

After weeks of this, I decided to upgrade OSX to the newest version to see whether that would help.

The upgrade went fine, and at least the situation was no worse.

Soon, however, the slowdown worsened still further.

Finally, I found the solution:

This description of what kernel_task is, and why it is running on my Mac, explains how kernel_task pretends to use CPU cycles to keep things cool.

That is confirmed by the Apple support thread on kernel_task using a large percentage of your Mac CPU.

In the next step, I looked at a helpful five-minute video on how to clean MacBook Pro fans.

Opening the MacBook is simple, but it does require the smallest screwdriver I have ever seen, a 1.2 mm Pentalobe:

Miniscule screwdriver

I never opened the PC before myself.

Using that, however, it was easy to open and blow out the dust clogging the fans with a pressurised air spray can.

One fan was so clogged with dust it was probably not running at all.

It seems better now. Please keep your fingers crossed for me that it stays that way and continues working   :-)

Failings of the Political Establishment

Turning from technical stuff to politics for a moment, Rezo's German 55-minute video about the failings of the established politicians who have been driving the planet to the brink of catastrophe, ignoring all scientifical evidence and economic indicators for several decades, caused quite a stir in the past few weeks, including affecting the recent election results:

I tested the auto-translated English subtitles for this video. Sorry to say, they do not make much sense in this case.