[英]Determine whether assembly is a gui application
I am trying to determine whether a C# assembly is a GUI or a Console application in order to build a tool which will automatically recreate lost short cuts. 我试图确定C#程序集是GUI还是控制台应用程序,以便构建可以自动重新创建丢失的快捷方式的工具。
Currently, I have a routine which recursively steps all directories in Program Files (and the x86 directory). 当前,我有一个例程可以递归地执行程序文件中的所有目录(和x86目录)。
For each EXE it finds, the tool calls IsGuiApplication, passing the name of the EXE. 对于找到的每个EXE,该工具都会调用IsGuiApplication,并传递EXE的名称。
From there, I create an Assembly object using LoadFrom. 从那里,我使用LoadFrom创建一个Assembly对象。 I want to check whether this assembly is has a GUI output, but I'm unsure how to test this in C#.
我想检查该程序集是否具有GUI输出,但是不确定如何在C#中对此进行测试。
My current idea is to use GetStdHandle, but I'm not sure how to apply this to an assembly outside of the running application. 我当前的想法是使用GetStdHandle,但是我不确定如何将其应用于正在运行的应用程序之外的程序集。
My experience with reflection in C# is limited, so any help would be appreciated. 我在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; } } }
Just to be safe here, the method suggested by @Killany and @Nissim suggest is not 100% accurate, as console applications can reference the System.Windows.* dlls (either by mistake or by a need of other functionality given by the 'System.Windows' assembly). 为了安全起见,@ Killany和@Nissim建议的方法并非100%准确,因为控制台应用程序可以引用System.Windows。* dll(由于错误或由于“系统”提供的其他功能的需要.Windows的程序集)。
I'm not sure a 100% method exist, as some applications can be given a parameter to run with/without ui (ie silently) 我不确定是否存在100%的方法,因为可以为某些应用程序提供一个可以使用ui或不使用ui的参数(即静默运行)
As several times mentioned before, you can read the Subsystem Field. 如前所述,您可以阅读子系统字段。
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;
}
}
}
Use GetReferencedAssemblies()
to get all referenced assemblies and look for the system.windows.forms assembly 使用
GetReferencedAssemblies()
获取所有引用的程序集并查找system.windows.forms程序集
AssemblyName[] referencedAssemblies = assm.GetReferencedAssemblies();
foreach (var assmName in referencedAssemblies)
{
if (assmName.Name.StartsWith("System.Windows"))
//bingo
}
A basic idea to detect GUI apps is that GUI apps always use assembly System.Windows.*
. 检测GUI应用程序的基本思想是GUI应用程序始终使用程序集
System.Windows.*
。
bool isGui(Assembly exeAsm) {
foreach (var asm in exeAsm.GetReferencedAssemblies()) {
if (asm.FullName.Contains("System.Windows"))
return true;
}
return false;
}
This will detect all .NET applications that are windows forms, or even WPF 这将检测所有是Windows窗体甚至WPF的.NET应用程序
One thing you could check is the .subsystem
of the file's PE header. 您可以检查的一件事是文件PE标头的
.subsystem
。 If you open up the file in ILDASM and check the manifest, you'll see this if it uses the Windows GUI subsystem: 如果在ILDASM中打开文件并检查清单,则如果使用Windows GUI子系统,则会看到以下内容:
I don't think there's any method in the Assembly
class to check this, so you'll probably need to check the file itself. 我认为
Assembly
类中没有任何方法可以检查此内容,因此您可能需要检查文件本身。
Another way to check would be to go through the types in the assembly and see if any of them derive from System.Windows.Forms.Form
(Windows Forms) or System.Windows.Window
(WPF): 检查的另一种方法是检查程序集中的类型,并查看它们中的任何一个是否派生自
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));
}
Note that you'll need to add references to System.Windows.Forms.dll
and PresentationFramework.dll
to gain access to these types. 请注意,您需要添加对
System.Windows.Forms.dll
和PresentationFramework.dll
引用才能访问这些类型。
You can use Assembly.LoadFrom(string)
to load the assembly. 您可以使用
Assembly.LoadFrom(string)
来加载程序集。 I tested this method myself and it seemed a bit slow so perhaps you can make it faster by involving Parallel.ForEach
. 我自己测试了此方法,它似乎有点慢,因此也许可以通过使用
Parallel.ForEach
使其更快。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.