2010-06-24 13 views
5

W aplikacji C# chciałbym ustalić, czy inna aplikacja .NET jest aplikacją konsoli, czy nie.Jak określić podsystem używany przez dany zestaw .NET?

Czy można to zrobić za pomocą interfejsu API do odczytywania?

EDYCJA: OK, nie wygląda na to, że dostanę dobrą odpowiedź na to pytanie, ponieważ nie wygląda na to, że szkielet udostępnia funkcjonalność, jakiej chcę. I wykopali wokół w PE/COFF specyfikacji i podszedł z tym:

/// <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*/ 
    } 
} 

Odpowiedz

4

to jest poza zakresem kodu zarządzanego. Z konsoli widoku .net i wygranych aplikacji są takie same, musisz zajrzeć do nagłówka pliku PE. poszukiwanie pracy „Subsystem” na tej stronie http://msdn.microsoft.com/en-us/magazine/bb985997.aspx

+0

Tak - w kodzie natywnym zwykle używam do tego API dbghelp, ale nie mam kodu natywnego :( –

+0

@Billy ONeal struktura nagłówków jest bardzo prosta i dobrze znana, zajmuje kilka wierszy kodu w C++ (+ nagłówków), aby dowiedzieć się podsystemu, myślę, że w języku C# nie powinno zabrać dużo więcej. – Andrey

0

Nie sądzę, istnieje sposób naukowy do określenia go, najbliższa obejście, które przychodzi mi na myśl jest użycie refleksji aby sprawdzić, czy odwołania do aplikacji i ładuje zestaw WinForms, ale nie jestem do końca pewien. Może spróbować.

+1

Nie można tego definitywnie znaleźć za pomocą refleksji. powinieneś sprawdzić nagłówek pliku exe. – Andrey

+0

Mój "anwser" był najwyraźniej uważany, kiedy masz dostęp do programu, który przeglądasz, a nie skompilowanego exe. Przepraszam za nieporozumienie. –

+0

To nie zadziała, ponieważ można użyć WinForms (lub WPF) z aplikacji konsoli, a aplikacja inna niż konsola nie musi używać WinForm (na przykład usługa Windows nie używa). Sprawdzanie nagłówka .exe jest jedynym sposobem. – Ruben

1

Funkcja SHGetFileInfo można to zrobić:

[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), 
} 

Następnie, zgodnie ze specyfikacją, jeśli to tylko MZ lub PE, jest otwarty w konsoli inaczej (jeśli podano wersję), jest otwarta w oknie.

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

-1: PE może nadal korzystać z podsystemu konsoli - trzeba by sprawdzić część podsystemu w nagłówkach PE –

+0

(mam na myśli , NE i LE mogą być tylko aplikacjami konsolowymi, PE może być jednym ze wszystkich 3 podsystemów: –

+0

@BillyONeal I kto mówi, że nie? Specyfikacja mówi (w zasadzie) jeśli nie ma numeru wersji w kodzie powrotu ("ExeType" tutaj), jest to aplikacja konsolowa: – IllidanS4

Powiązane problemy