Revit 2018 Addin - After initializing a singleton at startup, assigning the instance to a variable in a command keeps the variable as null

Revit 2018 Addin - After initializing a singleton at startup, assigning the instance to a variable in a command keeps the variable as null

sam.najjarJVR3P
Participant Participant
626 Views
5 Replies
Message 1 of 6

Revit 2018 Addin - After initializing a singleton at startup, assigning the instance to a variable in a command keeps the variable as null

sam.najjarJVR3P
Participant
Participant

7Developing a multi-version Revit addin. My code is running fine on Revit 2019 and above, but is having an issue in Revit 2018.

I am initializing a singleton class (HostApplication) at startup to gather common properties that can be used in all commands.

Stepping into the code, the singleton is being initialized successfully at startup, but when I try to assign it's instance to a variable in command level, the variable remains null.

Stepping into the command, I can see that the instance is still populated, it is just not being accessed by the = operator? 

 

samnajjarJVR3P_2-1666985991388.png

As you can see in the screenshot above, the debugger is showing that HostApplication.Instance has a value, but the ha variable is still null after the assignment (I made the snapshot while I was trying to assign the variable again as a desperate measure).

As far as I can see, this is not a Revit Api issue, could it be related to the underlaying .net framework being used in Revit 2018?

Here is the HostApplication class:

public class HostApplication
    {
        public static void Init(UIControlledApplication uiApp, Assembly bimotoAssembly)
        {
            if (Instance == null)
                Instance =  new HostApplication(uiApp, bimotoAssembly);
        }

        private readonly UIControlledApplication _uiApp;
        private readonly Assembly _bimotoAssembly;

        public static HostApplication Instance { get; private set; } = null;

        private HostApplication(UIControlledApplication uiApp, Assembly bimotoAssembly)
        {
            _uiApp = uiApp;
            _bimotoAssembly = bimotoAssembly;
            BimotoInstallationDirectory = (new DirectoryInfo(_bimotoAssembly.Location)).Parent;
            BimotoSharedFolderPath =
#if DEBUG
            "C:\\Dev\\Repos\\PAE.BIMOTO\\src\\PAE.BIMOTO.Revit.Ribbon\\Shared";
#else
            BimotoInstallationDirectory.Parent.FullName + "\\Shared";
#endif

            BimotoRevitUsersSettings =
                BimotoRevitUserSettings.ReadFromFile(
                    $"{BimotoSharedFolderPath}\\{BimotoRevitKeys.UserSettingsFileName}.json");

        }



        public static int DefaultDpi = 96;

        public ControlledApplication App => _uiApp.ControlledApplication;

        public int Version => int.Parse(App.VersionNumber);

        public string BimotoVersion => _bimotoAssembly.GetName().Version.ToString();

        public DirectoryInfo BimotoInstallationDirectory { get; private set; }


        public string BimotoSharedFolderPath { get; private set; }

        public BimotoRevitUserSettings BimotoRevitUsersSettings { get; private set; }

        public IntPtr AppWindowHandle
        {
            get
            {

#if REVIT2018
                return Autodesk.Windows.ComponentManager.ApplicationWindow;
#else
                    return _uiApp.MainWindowHandle;
#endif
            }
        }

        public System.Windows.Forms.Screen AppScreen => System.Windows.Forms.Screen.FromHandle(AppWindowHandle);

        public double ScreenScaleFactor
        {
            get
            {
                if (AppScreen == null) return 1;
                var actualWidth = SystemParameters.PrimaryScreenWidth;
                var scaledWidth = Screen.PrimaryScreen.WorkingArea.Width;
                return Math.Abs(scaledWidth / actualWidth);
            }
        }

    }

Initializing it at startup:

  public Result OnStartup(UIControlledApplication application)
        {
            //Get the path of the Ribbon dll
            MainAssembly = Assembly.GetExecutingAssembly();
            AssemblyPath = MainAssembly.Location;

            //Initialize the application wrapper
            HostApplication.Init(application, MainAssembly);
            ...
            ...
            }

Accessing it's instance in the command:

//get defaults file
WarehouseBrowserUserSettings warehouseSettings = null;
try
{
    var ha = HostApplication.Instance; //in Revit 2018 ha remains null after the assignment
    var us = ha.BimotoRevitUsersSettings;
    warehouseSettings = us.GetSetting<WarehouseBrowserUserSettings>();
}
catch (Exception e)
{
    TaskDialog.Show("Error", e.Message);

 

0 Likes
627 Views
5 Replies
Replies (5)
Message 2 of 6

ricaun
Advisor
Advisor

That's really strange, I usually create from 2017 to 2023 and never had a problem like this...

 

"As far as I can see, this is not a Revit Api issue, could it be related to the underlaying .net framework being used in Revit 2018?"

 

Are you compiling with the Framework net 4.6? That's the version used in Revit 2018 and 2017.

 

Luiz Henrique Cassettari

ricaun.com - Revit API Developer

AppLoader EasyConduit WireInConduit ConduitMaterial CircuitName ElectricalUtils

0 Likes
Message 3 of 6

sam.najjarJVR3P
Participant
Participant

I'm compiling 2021 and above with 4.8 and 2018 to 2020 with 4.7.2

0 Likes
Message 4 of 6

RPTHOMAS108
Mentor
Mentor

Odd, you should as a starting point replace 'var' with an actual type since var forces compiler to decide what it is based on what is assigned. It is an extra layer of the compiler doing something that could be avoided with an explicit type declaration. What C# language version are you using?

 

Would also suggest you look further afield and follow the entire process from OnStartUp (observing what 'instance' is at key stages and trial using parts of it elsewhere) rather than fixating on where the error is finally evident. If there are any compiler conditional statements similar to the ones above, then I would focus on the differences that those cause.

 

The property 'Instance' is assigned an initial value of null but that is what it is right (before it is given a value).

0 Likes
Message 5 of 6

sam.najjarJVR3P
Participant
Participant

Thank you for taking the time to look into this.
Going a couple of levels deeper I found a swallowed error happening when deserializing a json file using  Newtonsoft.Json library. The library is not being able to determine the concrete type of one interface property although I'm using the proper type flags and -again- the same code is working in higher Revit versions.
The Newtonsoft library I'm referencing is in a recompiled / renamed assembly to avoid dll hell, nonetheless, the error is happening.
I guess I can try changing the property to be of a concrete class rather than of an interface but that would be a step back that I'm not comfortable taking.
Any similar experience with Newtonsoft and Revit 2018 in particular?

0 Likes
Message 6 of 6

ricaun
Advisor
Advisor

The only problem I found with Newtonsoft.Json is related to using a version higher than the current one in Revit, and I don't think that is the problem. For more info the link: https://forums.autodesk.com/t5/revit-api-forum/bim-360-links-not-found-fix/td-p/11463147

 

You should try to compile your 2018 version in the net 4.6 Framework, and make some try. You can compile in a lower version and gonna work fine, the framework as I know is backward compatible, forward I don't think so.

Luiz Henrique Cassettari

ricaun.com - Revit API Developer

AppLoader EasyConduit WireInConduit ConduitMaterial CircuitName ElectricalUtils

0 Likes