确定程序集是否为gui应用程序

时间:2015-06-17 11:21:56

标签: c# .net reflection .net-assembly

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

目前,我有一个例程,以递归方式处理Program Files(和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;
        }

    }
}




5 个答案:

答案 0 :(得分:4)

为了安全起见,@ Killany和@Nissim建议的方法不是100%准确,因为控制台应用程序可以引用System.Windows。* dll(错误或需要其他功能) ' System.Windows'程序集)。

我不确定是否存在100%的方法,因为某些应用程序可以使用/不使用ui(即无声地)运行参数

答案 1 :(得分:2)

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

    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;
            }
        }
    }

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

检测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应用程序

答案 4 :(得分:0)

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

enter image description here

我认为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来加快速度。