no creo que esto está documentado y disponible oficialmente, pero aquí hay algo de información:
Esto se almacena en el solution's .SUO file por el paquete integrado de Visual Studio. El archivo SUO tiene el formato de almacenamiento compuesto OLE. Puede explorarlo usando una herramienta como OpenMCDF (tiene una muestra de explorador). En este archivo, verá una secuencia llamada 'SolutionConfiguration
' que contiene un token dwStartupOpt seguido de la información que está buscando. La secuencia en sí tiene un formato binario personalizado.
La misma información está disponible desde VS a través del IVsPersistSolutionProps Interface. Es necesario para obtener un puntero a ella desde uno de los paquetes cargados (por ejemplo, la enumeración de la lista de paquetes utilizando el IVsShell.GetPackageEnum Method. Un paquete apoyará la interfaz IVsPersistSolutionProps con el 'SolutionConfiguration
' corriente.
Sin embargo, cualquiera que sea método que elija, terminará analizando manualmente la secuencia 'SolutionConfiguration'. Aquí presento un método que lo hace simplemente abriendo el archivo SUO y cortando los bits 'manualmente', por lo que funciona fuera de VS.
Aquí está la clase de utilidad que analiza la secuencia '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;
}
}
Seguido por un pequeño arroyo compuesto leer utilidad (sin necesidad de biblioteca externa):
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);
}
Y la muestra que guids proyectos pantalla asociados con las opciones de inicio:
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");
}
}
}
Cuál es su idioma ? ¿Estás desarrollando un paquete VS? un complemento VS? o alguna herramienta externa a VS? –
@SimonMourier Escribir un paquete de VS en C# –
Creé una [sugerencia de usuario para agregar esto a la API oficial] (http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/7555128-extend-visual -studio-api-with-a-method-to-set-star) –