@@ -559,19 +559,21 @@ public static void AssertUninstalledPackageByProjectType(VisualStudioHost visual
559559
560560 /// <summary>
561561 /// Gets the path to MSBuild.exe from the Visual Studio installation.
562- /// Uses the VSAPPIDDIR environment variable to find the VS root folder,
563- /// same approach as Get-MSBuildExe in the PS E2E test infrastructure.
562+ /// Tries multiple strategies to locate the VS root:
563+ /// 1. The current process (devenv.exe when running under Apex)
564+ /// 2. The VisualStudio.InstallationUnderTest.Path environment variable (set by the Apex fixture)
565+ /// 3. VSAPPIDDIR / DevEnvDir environment variables
564566 /// </summary>
565567 public static string GetMSBuildExePath ( )
566568 {
567- string vsAppIdDir = Environment . GetEnvironmentVariable ( "VSAPPIDDIR" ) ?? Environment . GetEnvironmentVariable ( "DevEnvDir" ) ;
568- if ( string . IsNullOrEmpty ( vsAppIdDir ) )
569+ string vsRoot = GetVSRootDirectory ( ) ;
570+ if ( string . IsNullOrEmpty ( vsRoot ) )
569571 {
570- throw new InvalidOperationException ( "Could not determine Visual Studio installation path. Neither VSAPPIDDIR nor DevEnvDir environment variable is set." ) ;
572+ throw new InvalidOperationException (
573+ "Could not determine Visual Studio installation path. " +
574+ "The current process is not devenv.exe, and neither VisualStudio.InstallationUnderTest.Path, VSAPPIDDIR, nor DevEnvDir environment variable is set." ) ;
571575 }
572576
573- // VSAPPIDDIR is <VSRoot>\Common7\IDE\, go up 2 levels to get VS root
574- string vsRoot = Path . GetFullPath ( Path . Combine ( vsAppIdDir , ".." , ".." ) ) ;
575577 string msbuildPath = Path . Combine ( vsRoot , "MSBuild" , "Current" , "bin" , "MSBuild.exe" ) ;
576578
577579 if ( ! File . Exists ( msbuildPath ) )
@@ -581,5 +583,49 @@ public static string GetMSBuildExePath()
581583
582584 return msbuildPath ;
583585 }
586+
587+ /// <summary>
588+ /// Determines the VS root directory using multiple fallback strategies.
589+ /// </summary>
590+ private static string GetVSRootDirectory ( )
591+ {
592+ // Strategy 1: Apex tests run inside devenv.exe, so the current process path gives us the VS IDE directory.
593+ try
594+ {
595+ string processPath = Process . GetCurrentProcess ( ) . MainModule . FileName ;
596+ if ( ! string . IsNullOrEmpty ( processPath ) &&
597+ Path . GetFileName ( processPath ) . Equals ( "devenv.exe" , StringComparison . OrdinalIgnoreCase ) )
598+ {
599+ // devenv.exe is at <VSRoot>\Common7\IDE\devenv.exe, go up 2 levels
600+ return Path . GetFullPath ( Path . Combine ( Path . GetDirectoryName ( processPath ) , ".." , ".." ) ) ;
601+ }
602+ }
603+ catch
604+ {
605+ // MainModule access can throw; fall through to next strategy
606+ }
607+
608+ // Strategy 2: VisualStudio.InstallationUnderTest.Path is set by the Apex fixture to the devenv.exe path
609+ string vsUnderTestPath = Environment . GetEnvironmentVariable ( "VisualStudio.InstallationUnderTest.Path" ) ;
610+ if ( ! string . IsNullOrEmpty ( vsUnderTestPath ) )
611+ {
612+ // This can be either the devenv.exe path or the VS root directory
613+ if ( vsUnderTestPath . EndsWith ( "devenv.exe" , StringComparison . OrdinalIgnoreCase ) )
614+ {
615+ return Path . GetFullPath ( Path . Combine ( Path . GetDirectoryName ( vsUnderTestPath ) , ".." , ".." ) ) ;
616+ }
617+
618+ return vsUnderTestPath ;
619+ }
620+
621+ // Strategy 3: VSAPPIDDIR or DevEnvDir environment variables (Common7\IDE\)
622+ string vsAppIdDir = Environment . GetEnvironmentVariable ( "VSAPPIDDIR" ) ?? Environment . GetEnvironmentVariable ( "DevEnvDir" ) ;
623+ if ( ! string . IsNullOrEmpty ( vsAppIdDir ) )
624+ {
625+ return Path . GetFullPath ( Path . Combine ( vsAppIdDir , ".." , ".." ) ) ;
626+ }
627+
628+ return null ;
629+ }
584630 }
585631}
0 commit comments