简体   繁体   中英

How can I determine the subsystem used by a given .NET assembly?

In a C# application, I'd like to determine whether another .NET application is a Console application or not.

Can this be done using the reflection APIs?

EDIT: OK, it doesn't look like I'm going to get a good answer to this question because it doesn't look like the framework exposes the functionality I want. I dug around in the PE/COFF spec and came up with this:

/// <summary>
/// Parses the PE header and determines whether the given assembly is a console application.
/// </summary>
/// <param name="assemblyPath">The path of the assembly to check.</param>
/// <returns>True if the given assembly is a console application; false otherwise.</returns>
/// <remarks>The magic numbers in this method are extracted from the PE/COFF file
/// format specification available from http://www.microsoft.com/whdc/system/platform/firmware/pecoff.mspx
/// </remarks>
bool AssemblyUsesConsoleSubsystem(string assemblyPath)
{
    using (var s = new FileStream(assemblyPath, FileMode.Open, FileAccess.Read))
    {
        var rawPeSignatureOffset = new byte[4];
        s.Seek(0x3c, SeekOrigin.Begin);
        s.Read(rawPeSignatureOffset, 0, 4);
        int peSignatureOffset = rawPeSignatureOffset[0];
        peSignatureOffset |= rawPeSignatureOffset[1] << 8;
        peSignatureOffset |= rawPeSignatureOffset[2] << 16;
        peSignatureOffset |= rawPeSignatureOffset[3] << 24;
        var coffHeader = new byte[24];
        s.Seek(peSignatureOffset, SeekOrigin.Begin);
        s.Read(coffHeader, 0, 24);
        byte[] signature = {(byte)'P', (byte)'E', (byte)'\0', (byte)'\0'};
        for (int index = 0; index < 4; index++)
        {
            Assert.That(coffHeader[index], Is.EqualTo(signature[index]),
                "Attempted to check a non PE file for the console subsystem!");
        }
        var subsystemBytes = new byte[2];
        s.Seek(68, SeekOrigin.Current);
        s.Read(subsystemBytes, 0, 2);
        int subSystem = subsystemBytes[0] | subsystemBytes[1] << 8;
        return subSystem == 3; /*IMAGE_SUBSYSTEM_WINDOWS_CUI*/
    }
}

This is out of the scope of managed code. From the .NET perspective, Console and Windows UI applications are the same. You have to peek into the PE file header. Search for the word, "Subsystem" on this page http://msdn.microsoft.com/en-us/magazine/bb985997.aspx

The SHGetFileInfo function can do this:

[DllImport("shell32.dll", CharSet=CharSet.Auto, EntryPoint="SHGetFileInfo")]
public static extern ExeType GetExeType(string pszPath, uint dwFileAttributes = 0, IntPtr psfi = default(IntPtr), uint cbFileInfo = 0, uint uFlags = 0x2000);

[Flags]
public enum ExeType
{
    None = 0,
    WinNT = 0x04000000,
    PE = ((int)'P') | ((int)'E' << 8),
    NE = ((int)'N') | ((int)'E' << 8),
    MZ = ((int)'M') | ((int)'Z' << 8),
}

Then, according to the specification, if it's only MZ or PE, it is opened in console, otherwise (if a version is specified), it is open in a window.

ExeType type = GetExeType("program.exe");
if(type == ExeType.PE || type == ExeType.MZ) return "console";
else return "window";

我想它应该与本机应用程序相同,因此您可以将本文从 C++ 改编为 C# 以读取 PE 标头:如何确定应用程序是控制台还是 GUI

I don't think there's a scientific way to determine it, the closest workaround that comes to my mind is using reflection to check if the application references and loads the WinForms assembly, but I'm not entirely sure. Might give it a try.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM