[英]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.dll
和PresentationFramework.dll
引用才能访问这些类型。
您可以使用Assembly.LoadFrom(string)
来加载程序集。 我自己测试了此方法,它似乎有点慢,因此也许可以通过使用Parallel.ForEach
使其更快。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.