簡體   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