判断程序集是否是一个gui应用程序
Determine whether assembly is a gui application
我正在尝试确定 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;
}
}
}
使用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 形式的 .NET 应用程序,甚至是 WPF
为了安全起见,@Killany 和@Nissim 建议的方法并非 100% 准确,因为控制台应用程序可以引用 System.Windows.* dll(错误或需要'System.Windows' 程序集提供的其他功能)。
我不确定是否存在 100% 的方法,因为可以为某些应用程序提供参数 运行 with/without ui(即静默)
您可以检查的一件事是文件 PE header 的 .subsystem
。如果您在 ILDASM 中打开文件并检查清单,如果它使用 Windows GUI 子系统,您将看到:
我认为 Assembly
class 中没有任何方法可以检查这个,所以您可能需要检查文件本身。
另一种检查方法是检查程序集中的类型,看看它们是否派生自 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
.
来让它更快
之前多次提到,您可以阅读子系统字段。
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;
}
}
}
我正在尝试确定 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;
}
}
}
使用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 形式的 .NET 应用程序,甚至是 WPF
为了安全起见,@Killany 和@Nissim 建议的方法并非 100% 准确,因为控制台应用程序可以引用 System.Windows.* dll(错误或需要'System.Windows' 程序集提供的其他功能)。
我不确定是否存在 100% 的方法,因为可以为某些应用程序提供参数 运行 with/without ui(即静默)
您可以检查的一件事是文件 PE header 的 .subsystem
。如果您在 ILDASM 中打开文件并检查清单,如果它使用 Windows GUI 子系统,您将看到:
我认为 Assembly
class 中没有任何方法可以检查这个,所以您可能需要检查文件本身。
另一种检查方法是检查程序集中的类型,看看它们是否派生自 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
.
之前多次提到,您可以阅读子系统字段。
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;
}
}
}