简体   繁体   English

如何确定给定 .NET 程序集使用的子系统?

[英]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.在 C# 应用程序中,我想确定另一个 .NET 应用程序是否是控制台应用程序。

Can this be done using the reflection APIs?这可以使用反射 API 来完成吗?

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:我仔细研究了 PE/COFF 规范并提出了这个:

/// <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.从 .NET 的角度来看,控制台和 Windows UI 应用程序是相同的。 You have to peek into the PE file header.您必须查看 PE 文件头。 Search for the word, "Subsystem" on this page http://msdn.microsoft.com/en-us/magazine/bb985997.aspx在此页面上搜索“子系统”一词http://msdn.microsoft.com/en-us/magazine/bb985997.aspx

The SHGetFileInfo function can do this: SHGetFileInfo函数可以这样做:

[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.然后,根据规范,如果只是MZ或PE,则在控制台中打开,否则(如果指定了版本),则在窗口中打开。

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.我不认为有一种科学的方法来确定它,我想到的最接近的解决方法是使用反射来检查应用程序是否引用并加载了 WinForms 程序集,但我不完全确定。 Might give it a try.可以试试看

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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