Pregunta

En Solution-> Propiedades, puedo establecer múltiples proyectos de inicio:Solution Properties

Sé que puedo obtener la lista de proyectos marcados con "Inicio" (usando Envdte: solution.SolutionBuild.StartupProjects), pero ¿cómo obtengo la lista de proyectos cuya acción es "comenzar sin depurar"? No aparecen en la lista.

¿Fue útil?

Solución

No creo que esto esté documentado y disponible oficialmente, pero aquí hay información:

  • Esto se almacena en el archivo de solución .suo 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 transmisión llamada 'SolutionConfiguration'Eso contiene un token DWStartupt seguido de la información que está buscando. La transmisión en sí tiene un formato binario personalizado.

  • La misma información está disponible desde dentro de VS a través del IVSPERSISSOLUTIONPRESPRESPRESES. Debe obtener un puntero de uno de los paquetes cargados (por ejemplo, enumerando la lista de paquetes utilizando el Ivsshell.getPackageEnum Método. Un paquete admitirá la interfaz IVSpersistolutionProps con el 'SolutionConfiguration' corriente.

Sin embargo, sea cual sea el método que elija, terminará analizando la corriente de 'Configuración de soluciones' manualmente, creo. Presento aquí un método que lo hace simplemente abriendo el archivo suo y pirateando los bits 'manualmente', por lo que funciona fuera de Vs.

Aquí está la clase de utilidad que analiza la secuencia de 'Configuración de soluciones':

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 de una pequeña utilidad de lectura de flujo compuesto (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 muestra GUIDS del proyecto asociadas 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");
        }
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top