2010-06-24 5 views
5

In einer C# -Anwendung möchte ich feststellen, ob eine andere .NET-Anwendung eine Konsolenanwendung ist oder nicht.Wie kann ich das Subsystem ermitteln, das von einer bestimmten .NET-Assembly verwendet wird?

Kann dies mit den Reflektions-APIs geschehen?

EDIT: OK, es sieht nicht so aus, als würde ich eine gute Antwort auf diese Frage bekommen, weil es nicht so aussieht, als würde das Framework die Funktionalität offen legen, die ich möchte. Ich kramte in der PE/COFF spec und kam mit dieser:

/// <summary> 
/// Parses the PE header and determines whether the given assembly is a console application. 
/// </summary> 
/// <param name="assemblyPath">The path of the assembly to check.</param> 
/// <returns>True if the given assembly is a console application; false otherwise.</returns> 
/// <remarks>The magic numbers in this method are extracted from the PE/COFF file 
/// format specification available from http://www.microsoft.com/whdc/system/platform/firmware/pecoff.mspx 
/// </remarks> 
bool AssemblyUsesConsoleSubsystem(string assemblyPath) 
{ 
    using (var s = new FileStream(assemblyPath, FileMode.Open, FileAccess.Read)) 
    { 
     var rawPeSignatureOffset = new byte[4]; 
     s.Seek(0x3c, SeekOrigin.Begin); 
     s.Read(rawPeSignatureOffset, 0, 4); 
     int peSignatureOffset = rawPeSignatureOffset[0]; 
     peSignatureOffset |= rawPeSignatureOffset[1] << 8; 
     peSignatureOffset |= rawPeSignatureOffset[2] << 16; 
     peSignatureOffset |= rawPeSignatureOffset[3] << 24; 
     var coffHeader = new byte[24]; 
     s.Seek(peSignatureOffset, SeekOrigin.Begin); 
     s.Read(coffHeader, 0, 24); 
     byte[] signature = {(byte)'P', (byte)'E', (byte)'\0', (byte)'\0'}; 
     for (int index = 0; index < 4; index++) 
     { 
      Assert.That(coffHeader[index], Is.EqualTo(signature[index]), 
       "Attempted to check a non PE file for the console subsystem!"); 
     } 
     var subsystemBytes = new byte[2]; 
     s.Seek(68, SeekOrigin.Current); 
     s.Read(subsystemBytes, 0, 2); 
     int subSystem = subsystemBytes[0] | subsystemBytes[1] << 8; 
     return subSystem == 3; /*IMAGE_SUBSYSTEM_WINDOWS_CUI*/ 
    } 
} 

Antwort

4

dies von verwalteten Code außerhalb des Gültigkeitsbereichs. Von .net Ansicht Konsole und Win-Anwendungen sind die gleichen, müssen Sie in PE-Datei-Header schauen. Suche nach Arbeit „Subsystem“ auf dieser Seite http://msdn.microsoft.com/en-us/magazine/bb985997.aspx

+0

Ja - im nativen Code verwende ich normalerweise die dbghelp Apis dafür, aber ich bin nicht im systemeigenen Code :( –

+0

@Billy ONeal die Struktur der Header ist sehr einfach und gut bekannt. Es dauert einige Zeilen Code in C++ (+ Header) – Andrey

0

Ich glaube nicht, dass es eine wissenschaftliche Art und Weise ist es zu bestimmen, die am nächsten Abhilfe, die mir in den Sinn kommt Reflexion verwendet zu überprüfen, ob die Anwendungsreferenzen und lädt die WinForms-Assembly, aber ich bin mir nicht ganz sicher. Könnte es versuchen.

+1

können Sie nicht definitiv herausfinden, mit Reflektion. Sie sollten den Header der EXE-Datei überprüfen. – Andrey

+0

Mein "Anwsser" wurde offensichtlich gedacht, wenn Sie Zugriff auf das Programm haben, das Sie gerade untersuchen, nicht auf die kompilierte Exe. Entschuldigen Sie das Missverständnis. –

+0

Das wird nicht funktionieren, weil Sie WinForms (oder WPF) von einer Konsolenanwendung verwenden können, und eine Nichtkonsolenanwendung muss WinForms nicht verwenden (beispielsweise verwendet ein Windows-Dienst keines). Das Überprüfen der .exe-Kopfzeile ist die einzige Möglichkeit. – Ruben

1

Die SHGetFileInfo Funktion kann dies tun:

[DllImport("shell32.dll", CharSet=CharSet.Auto, EntryPoint="SHGetFileInfo")] 
public static extern ExeType GetExeType(string pszPath, uint dwFileAttributes = 0, IntPtr psfi = default(IntPtr), uint cbFileInfo = 0, uint uFlags = 0x2000); 

[Flags] 
public enum ExeType 
{ 
    None = 0, 
    WinNT = 0x04000000, 
    PE = ((int)'P') | ((int)'E' << 8), 
    NE = ((int)'N') | ((int)'E' << 8), 
    MZ = ((int)'M') | ((int)'Z' << 8), 
} 

Dann wird gemäß der Spezifikation, wenn es nur MZ oder PE ist, ist es in der Konsole geöffnet ist, andernfalls (Wenn eine Version angegeben wird, ist sie in einem Fenster geöffnet.

ExeType type = GetExeType("program.exe"); 
if(type == ExeType.PE || type == ExeType.MZ) return "console"; 
else return "window"; 
+0

-1: PEs können immer noch das Konsolen - Subsystem verwenden - Sie müssten den Subsystem - Teil in den PE - Headern überprüfen ( –

+0

) NE und LE können nur Konsolen-Apps sein, PE kann eines von allen 3 Subsystemen sein. –

+0

@BillyONeal Und wer sagt, dass sie das nicht tun? Die Spezifikation sagt (im Prinzip), ob es keine Versionsnummer im Rückgabecode gibt ('ExeType' hier)), es ist eine Konsolenanwendung – IllidanS4

Verwandte Themen