繁体   English   中英

确定程序集是否是GUI应用程序

[英]Determine whether assembly is a gui application

我试图确定C#程序集是GUI还是控制台应用程序,以便构建可以自动重新创建丢失的快捷方式的工具。

当前,我有一个例程可以递归地执行程序文件中的所有目录(和x86目录)。

对于找到的每个EXE,该工具都会调用IsGuiApplication,并传递EXE的名称。

从那里,我使用LoadFrom创建一个Assembly对象。 我想检查该程序集是否具有GUI输出,但是不确定如何在C#中对此进行测试。

我当前的想法是使用GetStdHandle,但是我不确定如何将其应用于正在运行的应用程序之外的程序集。

我在C#中进行反射的经验有限,因此不胜感激。

 using Microsoft.Win32; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; namespace BatchShortcutBuild { class Program { //I'm uncertain that I need to use this method [DllImport("kernel32.dll", SetLastError = true)] static extern IntPtr GetStdHandle(int nStdHandle); static void Main(string[] args) { BuildShortcuts(); Console.ReadLine(); } public static void BuildShortcuts() { String dirRoot = "C:\\\\Program Files\\\\"; processRoot(dirRoot); dirRoot = "C:\\\\Program Files (x86)\\\\"; processRoot(dirRoot); Console.WriteLine("Finished enumerating files"); Console.ReadLine(); } public static void processRoot(String path) { try { foreach (String theDir in Directory.EnumerateDirectories(path)) { processRoot(theDir); } foreach (String theFile in Directory.EnumerateFiles(path, "*.exe")) { if (IsGuiApplication(theFile)) { //I would generate a shortcut here } } } catch { } } public static bool IsGuiApplication(String filePath) { Console.WriteLine(filePath); Assembly a = Assembly.LoadFrom(filePath); //How to get the program type from the assembly? return false; } } } 

为了安全起见,@ Killany和@Nissim建议的方法并非100%准确,因为控制台应用程序可以引用System.Windows。* dll(由于错误或由于“系统”提供的其他功能的需要.Windows的程序集)。

我不确定是否存在100%的方法,因为可以为某些应用程序提供一个可以使用ui或不使用ui的参数(即静默运行)

如前所述,您可以阅读子系统字段。

    private PEFileKinds GetFileType(string inFilename)
    {
        using (var fs = new FileStream(inFilename, FileMode.Open, FileAccess.Read))
        {
            var buffer = new byte[4];
            fs.Seek(0x3C, SeekOrigin.Begin);
            fs.Read(buffer, 0, 4);
            var peoffset = BitConverter.ToUInt32(buffer, 0);
            fs.Seek(peoffset + 0x5C, SeekOrigin.Begin);
            fs.Read(buffer, 0, 1);
            if (buffer[0] == 3)
            {
                return PEFileKinds.ConsoleApplication;
            }
            else if (buffer[0] == 2)
            {
                return PEFileKinds.WindowApplication;
            }
            else
            {
                return PEFileKinds.Dll;
            }
        }
    }

使用GetReferencedAssemblies()获取所有引用的程序集并查找system.windows.forms程序集

    AssemblyName[] referencedAssemblies = assm.GetReferencedAssemblies();
    foreach (var assmName in referencedAssemblies)
    {
      if (assmName.Name.StartsWith("System.Windows"))
       //bingo
    }

检测GUI应用程序的基本思想是GUI应用程序始终使用程序集System.Windows.*

bool isGui(Assembly exeAsm) {
   foreach (var asm in exeAsm.GetReferencedAssemblies()) {
       if (asm.FullName.Contains("System.Windows"))
          return true;
   }
   return false;
}

这将检测所有是Windows窗体甚至WPF的.NET应用程序

您可以检查的一件事是文件PE标头的.subsystem 如果在ILDASM中打开文件并检查清单,则如果使用Windows GUI子系统,则会看到以下内容:

在此处输入图片说明

我认为Assembly类中没有任何方法可以检查此内容,因此您可能需要检查文件本身。

检查的另一种方法是检查程序集中的类型,并查看它们中的任何一个是否派生自System.Windows.Forms.Form (Windows窗体)或System.Windows.Window (WPF):

private static bool HasGui(Assembly a)
{
    return a.DefinedTypes
        .Any(t => typeof(System.Windows.Forms.Form).IsAssignableFrom(t) ||
                  typeof(System.Windows.Window).IsAssignableFrom(t));
}

请注意,您需要添加对System.Windows.Forms.dllPresentationFramework.dll引用才能访问这些类型。

您可以使用Assembly.LoadFrom(string)来加载程序集。 我自己测试了此方法,它似乎有点慢,因此也许可以通过使用Parallel.ForEach使其更快。

暂无
暂无

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

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