2016-06-24 6 views
0

ich die effektive DPI Bewusstsein Wert für einen bestimmten Prozess-ID in Windows 10 Pro 64-Bit abrufen möchten. Der Wert, den ich brauche, ist einer der PROCESS_DPI_AWARENESS Ich kann mit der WinAPI GetProcessDpiAwareness Funktion bekommen.Aufruf GetProcessDpiAwareness von C# immer wieder Fehler E_INVALIDARG

Um zu implementieren, was ich brauche, schrieb ich eine einfache Ein-Fenster-C# -WPF-App in VS 2015. Ich geben die Prozess-ID, die ich interessiert in die TextBox txtProcessID und das Ergebnis wird im TextBlock txtResult angezeigt, wenn ich drücke die txtProcessID Taste:

private const int S_OK = 0; 
private enum PROCESS_DPI_AWARENESS 
{ 
    PROCESS_DPI_UNAWARE = 0, 
    PROCESS_SYSTEM_DPI_AWARE = 1, 
    PROCESS_PER_MONITOR_DPI_AWARE = 2 
} 
[DllImport("Shcore.dll")] 
private static extern int GetProcessDpiAwareness(IntPtr hprocess, out PROCESS_DPI_AWARENESS value); 

private void btnGetDPIAwareness_Click(object sender, RoutedEventArgs e) 
{ 
    int procIDint = int.Parse(txtProcessID.Text); 
    IntPtr procID = new IntPtr(procIDint); 
    PROCESS_DPI_AWARENESS value; 
    int res = GetProcessDpiAwareness(procID, out value); 
    if (res == S_OK) 
     txtResult.Text = value.ToString(); 
    else 
     txtResult.Text = "Error: " + res.ToString("X"); 
} 

Aber GetProcessDpiAwareness Aufruf für jeden Prozess gibt mir immer einen Fehler E_INVALIDARG. Was mache ich falsch?

+4

[GetProcessDpiAwareness] (https://msdn.microsoft.com/en-us/library/windows/desktop/dn302113.aspx): * "hprocess: ** Handle ** des Prozesses, der abgefragt wird." * - Die API erwartet einen Handle, während Sie blind eine ID übergeben. Rufen Sie [OpenProcess] (https://msdn.microsoft.com/en-us/library/windows/desktop/ms684320.aspx) auf, um eine Prozesskennung von einer Prozess-ID abzurufen. – IInspectable

+2

https://msdn.microsoft.com/en-us/library/system.diagnostics.process.handle(v=vs.110).aspx –

Antwort

4

Aus der Dokumentation für GetProcessDpiAwareness der erste Parameter ist der Prozess handle, nicht die Prozess-ID. Sie müssen OpenProcess, erhalten Sie die gewünschten Informationen dann CloseHandle. (Bei der Definition ap/Invoke Unterschrift, einen beliebigen Variablennamen, die mit einem h oder lp beginnt wird in der Regel ein IntPtr in verwaltetem Code.)

Wie in:

private const int PROCESS_QUERY_INFORMATION = 0x0400; 
private const int PROCESS_VM_READ = 0x0010; 

[DllImport("Kernel32.dll", SetLastError = true)] 
private static extern IntPtr OpenProcess(uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwProcessId); 

[DllImport("Kernel32.dll")] 
[return: MarshalAs(UnmanagedType.Bool)] 
private static extern bool CloseHandle(IntPtr handle); 

private const int S_OK = 0; 
private enum PROCESS_DPI_AWARENESS 
{ 
    PROCESS_DPI_UNAWARE = 0, 
    PROCESS_SYSTEM_DPI_AWARE = 1, 
    PROCESS_PER_MONITOR_DPI_AWARE = 2 
} 
[DllImport("Shcore.dll")] 
private static extern int GetProcessDpiAwareness(IntPtr hprocess, out PROCESS_DPI_AWARENESS value); 

private PROCESS_DPI_AWARENESS GetDpiState(uint processId) 
{ 
    IntPtr handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, processId); 
    if (handle != IntPtr.Zero) 
    { 
     PROCESS_DPI_AWARENESS value; 
     int result = GetProcessDpiAwareness(handle, out value); 
     if (result == S_OK) 
     { 
      System.Diagnostics.Debug.Print(value.ToString()); 
     } 
     CloseHandle(handle); 
     if (result != S_OK) 
     { 
      throw new Win32Exception(result); 
     } 
     return value; 
    } 
    throw new Win32Exception(Marshal.GetLastWin32Error()); 
} 

Obwohl der einfachere Weg wäre die Verwendung System.Diagnostics.Process wie:

System.Diagnostics.Process proc = Process.GetProcessById(processId); 
PROCESS_DPI_AWARENESS value; 
int res = GetProcessDpiAwareness(proc.Handle, out value); 
+0

PROCESS_VM_READ ist nicht erforderlich. – Elmue

+0

WICHTIG: GetProcessDpiAwareness() funktioniert nicht, wenn es in einem Dienst (SYSTEM/NT AUTHORITY) ausgeführt wird, um diese Informationen von einem anderen Prozess zu erhalten. Es wird immer E_INVALIDARG – Elmue

0

Ja, es war meine Unterlassung. Ich musste den Prozesshandle an GetProcessDpiAwareness übergeben. Ich habe gerade meinen eigenen Arbeits Code geschrieben, basierend auf den ersten 2 Kommentare unter meiner Frage:

int procID = int.Parse(txtProcessID.Text); 
Process process = Process.GetProcessById(procID, "."); 
PROCESS_DPI_AWARENESS value; 
int res = GetProcessDpiAwareness(process.Handle, out value); 
if (res == S_OK) 
    txtResult.Text = value.ToString(); 
else 
    txtResult.Text = "Error: " + res.ToString("X"); 
process.Close(); 

Eine weiteren Kommentar: es ist besser, diesen Code mit Administratorrechten auszuführen Probleme mit dem Zugriff auf andere Prozessen zu vermeiden.

+4

zurückgeben. Es ist besser, diesen Code nicht mit Administratorrechten auszuführen. Übergeben Sie einfach das entsprechende [Zugriffsrecht] (https://msdn.microsoft.com/en-us/library/windows/desktop/ms684880.aspx) an [OpenProcess] (https://msdn.microsoft.com/de-de us/library/windows/desktop/ms684320.aspx). 'PROCESS_QUERY_LIMITED_INFORMATION' sollte ausreichend sein. – IInspectable

+0

@Intspectable, verwende ich die .NET-verwaltete Möglichkeit, um auf einen anderen Prozess zuzugreifen. Weißt du wie man das in dieser Umgebung macht? FYI: Das Starten meines Mini-Tools mit den Admin-Rechten ist für mich kein Problem, da alles innerhalb meines Dev-PCs erledigt wird :) – TecMan

+0

Es scheint keine Möglichkeit zu geben, die angeforderten Zugriffsrechte bei Verwendung des [System.Diagnostics .Process] (https://msdn.microsoft.com/en-us/library/system.diagnostics.process.aspx) Klasse. Sie könnten jedoch P/Invoke 'OpenProcess' aufrufen, wie in [theB's Antwort] (http://stackoverflow.com/a/38012663/1889329) erklärt. – IInspectable

Verwandte Themen