Solution
Are you expecting main.vi to loaded from inside the application or from its original files on disk?
From inside application:
If you've set main.vi as "Always Included" in your build, then you can load it from there but the path passed to the open VI ref should be the exe location not the source location. My guess is you are doing this and the 8.x layout works because there is a special case for open VI ref from inside this type of app that looks for the file name rather than the entire path. Thus even though you are providing the path to the source, LV loads it from the EXE. This is a safety net but is not the intended usage. Instead you should build a path inside the app like "<path>\exename.exe\main.vi". You can determine that dynamically with something like below. That path under the exe may be different for the non-8.x layout.

This will then not work when running from source. This can be solved by checking the type of application and using a different path for source. However, if the relative path between the 2 VIs is consistent, then you can compute the path to main.vi using the path of Launcher.vi. Just use the code below inside Launcher.vi. As long as neither is in a library, then this should work in both build layouts and from source.

From its original files on disk:
This just doesn't work. VI source can be source only and tends to reference files from vi.lib. The RTE can't load source only VIs and has no vi.lib. Anything you load in a built app needs to have gone through a build to prepare it and everything it depends on to be used in an RTE. Easiest answer is to include them in the EXE. A more complicated approach is to use a separate build to create a PPL with the dynamic VI. In this case, you'll need to provide the path inside that PPL to the open VI ref.