Search code examples
c#.netreflection.net-assembly

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.

Currently, I have a routine which recursively steps all directories in Program Files (and the x86 directory).

For each EXE it finds, the tool calls IsGuiApplication, passing the name of the EXE.

From there, I create an Assembly object using LoadFrom. I want to check whether this assembly is has a GUI output, but I'm unsure how to test this in 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.

My experience with reflection in C# is limited, so any help would be appreciated.

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

    }
}


Solution

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