2012-01-11 9 views
6

Pod Roztwór podstawowy> Właściwości, mogę ustawić wiele projektów rozruchu: Solution PropertiesJak programowo znaleźć działanie każdego projektu StartUp w rozwiązaniu?

wiem, że mogę uzyskać listę projektów oznaczonych „start” (przy użyciu EnvDTE: solution.SolutionBuild.StartupProjects), ale jak to zrobić uzyskać listę projektów, których działanie to "Uruchom bez debugowania"? Nie pojawiają się na liście.

+0

jaki jest Twój język ? czy rozwijasz pakiet VS? dodatek VS? lub niektóre narzędzia zewnętrzne do VS? –

+0

@SimonMourier Pisanie pakietu VS w C# –

+0

Stworzyłem [sugestię użytkownika, aby dodać to do oficjalnego API] (http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/7555128-extend-visual -studio-api-z-metoda-do-ustaw-gwiazda) –

Odpowiedz

4

nie sądzę, to jest udokumentowane i dostępne oficjalnie, ale oto kilka informacji:

  • ta jest przechowywana w solution's .SUO file przez Visual Studio wbudowanym opakowaniu. Plik SUO ma format przechowywania złożonego OLE. Możesz go przeglądać za pomocą narzędzia, takiego jak OpenMCDF (ma próbkę eksploratora). W tym pliku zobaczysz strumień o nazwie "SolutionConfiguration", który zawiera znacznik dwStartupOpt, a następnie informacje, których szukasz. Sam strumień ma niestandardowy format binarny.

  • Ta sama informacja jest dostępna od wewnątrz VS przez IVsPersistSolutionProps Interface. Trzeba uzyskać wskaźnik do niego z jednej z ładowanych pakietów (na przykład wymieniając listę pakietów wykorzystujących IVsShell.GetPackageEnum Method. Jedno opakowanie będzie obsługiwać interfejs IVsPersistSolutionProps z „SolutionConfiguration” strumienia.

Jednak cokolwiek Metoda, którą wybierzesz, skończę analizować strumień "SolutionConfiguration" ręcznie, jak sądzę, Przedstawiam tu metodę, która po prostu otwiera plik SUO i hakuje bity "ręcznie", więc działa poza VS.

Oto klasa narzędziowa, która analizuje strumień "SolutionConfiguration":

public sealed class StartupOptions 
{ 
    private StartupOptions() 
    { 
    } 

    public static IDictionary<Guid, int> ReadStartupOptions(string filePath) 
    { 
     if (filePath == null) 
      throw new ArgumentNullException("filePath"); 

     // look for this token in the file 
     const string token = "dwStartupOpt\0="; 
     byte[] tokenBytes = Encoding.Unicode.GetBytes(token); 
     Dictionary<Guid, int> dic = new Dictionary<Guid, int>(); 
     byte[] bytes; 
     using (MemoryStream stream = new MemoryStream()) 
     { 
      CompoundFileUtilities.ExtractStream(filePath, "SolutionConfiguration", stream); 
      bytes = stream.ToArray(); 
     } 

     int i = 0; 
     do 
     { 
      bool found = true; 
      for (int j = 0; j < tokenBytes.Length; j++) 
      { 
       if (bytes[i + j] != tokenBytes[j]) 
       { 
        found = false; 
        break; 
       } 
      } 
      if (found) 
      { 
       // back read the corresponding project guid 
       // guid is formatted as {guid} 
       // len to read is Guid length* 2 and there are two offset bytes between guid and startup options token 
       byte[] guidBytes = new byte[38 * 2]; 
       Array.Copy(bytes, i - guidBytes.Length - 2, guidBytes, 0, guidBytes.Length); 
       Guid guid = new Guid(Encoding.Unicode.GetString(guidBytes)); 

       // skip VT_I4 
       int options = BitConverter.ToInt32(bytes, i + tokenBytes.Length + 2); 
       dic[guid] = options; 
      } 
      i++; 
     } 
     while (i < bytes.Length); 
     return dic; 
    } 
} 

Obserwowani przez mały strumień związku czytać narzędzie (nie ma potrzeby zewnętrznej biblioteki):

public static class CompoundFileUtilities 
{ 
    public static void ExtractStream(string filePath, string streamName, string streamPath) 
    { 
     if (filePath == null) 
      throw new ArgumentNullException("filePath"); 

     if (streamName == null) 
      throw new ArgumentNullException("streamName"); 

     if (streamPath == null) 
      throw new ArgumentNullException("streamPath"); 

     using (FileStream output = new FileStream(streamPath, FileMode.Create)) 
     { 
      ExtractStream(filePath, streamName, output); 
     } 
    } 

    public static void ExtractStream(string filePath, string streamName, Stream output) 
    { 
     if (filePath == null) 
      throw new ArgumentNullException("filePath"); 

     if (streamName == null) 
      throw new ArgumentNullException("streamName"); 

     if (output == null) 
      throw new ArgumentNullException("output"); 

     IStorage storage; 
     int hr = StgOpenStorage(filePath, null, STGM.READ | STGM.SHARE_DENY_WRITE, IntPtr.Zero, 0, out storage); 
     if (hr != 0) 
      throw new Win32Exception(hr); 

     try 
     { 
      IStream stream; 
      hr = storage.OpenStream(streamName, IntPtr.Zero, STGM.READ | STGM.SHARE_EXCLUSIVE, 0, out stream); 
      if (hr != 0) 
       throw new Win32Exception(hr); 

      int read = 0; 
      IntPtr readPtr = Marshal.AllocHGlobal(Marshal.SizeOf(read)); 
      try 
      { 
       byte[] bytes = new byte[0x1000]; 
       do 
       { 
        stream.Read(bytes, bytes.Length, readPtr); 
        read = Marshal.ReadInt32(readPtr); 
        if (read == 0) 
         break; 

        output.Write(bytes, 0, read); 
       } 
       while(true); 
      } 
      finally 
      { 
       Marshal.FreeHGlobal(readPtr); 
       Marshal.ReleaseComObject(stream); 
      } 
     } 
     finally 
     { 
      Marshal.ReleaseComObject(storage); 
     } 
    } 

    [ComImport, Guid("0000000b-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
    private interface IStorage 
    { 
     void Unimplemented0(); 

     [PreserveSig] 
     int OpenStream([MarshalAs(UnmanagedType.LPWStr)] string pwcsName, IntPtr reserved1, STGM grfMode, uint reserved2, out IStream ppstm); 

     // other methods not declared for simplicity 
    } 

    [Flags] 
    private enum STGM 
    { 
     READ = 0x00000000, 
     SHARE_DENY_WRITE = 0x00000020, 
     SHARE_EXCLUSIVE = 0x00000010, 
     // other values not declared for simplicity 
    } 

    [DllImport("ole32.dll")] 
    private static extern int StgOpenStorage([MarshalAs(UnmanagedType.LPWStr)] string pwcsName, IStorage pstgPriority, STGM grfMode, IntPtr snbExclude, uint reserved, out IStorage ppstgOpen); 
} 

i próbka że GUID projektu wyświetlacz związane z opcjami uruchamiania:

static void SafeMain(string[] args) 
{ 
    foreach (var kvp in StartupOptions.ReadStartupOptions("mySample.suo")) 
    { 
     if ((kvp.Value & 1) != 0) 
     { 
      Console.WriteLine("Project " + kvp.Key + " has option Start"); 
     } 
     if ((kvp.Value & 2) != 0) 
     { 
      Console.WriteLine("Project " + kvp.Key + " has option Start with debugging"); 
     } 
    } 
} 
+0

Dziękuję! Próbowałem uruchomić to jako aplikację zewnętrzną i działało, ale jeśli zmienię ustawienia i uruchomię je ponownie, nadal otrzymuję stare wartości - dopóki nie zamknę rozwiązania, w którym to momencie VS pisze do SUO, i następnie ponowne uruchomienie daje mi nowe wartości. Czy za pomocą IVsPersistSolutionProps naprawisz to, a jeśli nie, to czy znasz jakiś sposób zmuszenia Visual Studio do napisania .suo? –

+0

Należy zapisać rozwiązanie, aby zapewnić zatwierdzenie zmian suo. –

+0

To rozwiązanie działa doskonale w przypadku pełnej struktury, ale nie działa na zwartej strukturze. 'BitConverter.ToInt32 (bytes, i + tokenBytes.Length + 2)' ma wartość 0 dla wszystkich przewodników. jakiekolwiek obejście tego problemu działa na zwartą strukturę? – user678229

Powiązane problemy