2016-06-24 45 views
0

Windows 10 Pro 64ビットで指定されたプロセスIDの有効なDPI認識値を取得したい。私が必要とする値は、WinAPI GetProcessDpiAwareness関数で取得できるPROCESS_DPI_AWARENESSの1つです。C#からGetProcessDpiAwarenessを呼び出すと常にエラーE_INVALIDARGが返される

私は必要なものを実装するために、VS 2015でシンプルな1ウィンドウC#WPFアプリケーションを作成しました。興味のあるプロセスIDをTextBox txtProcessIDに入力し、結果をTextBlock txtResultに表示しますtxtProcessIDボタン:

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

しかし、いつも私にエラーE_INVALIDARGを与える任意のプロセスのためにGetProcessDpiAwarenessを呼び出します。私は間違って何をしていますか?

+4

[GetProcessDpiAwareness](https://msdn.microsoft.com/en-us/library/windows/desktop/dn302113.aspx):* "hprocess:**問い合わせ中のプロセスのハンドル**" * - あなたは盲目的にIDを渡すのに対して、APIはハンドルを期待しています。プロセスIDからプロセスハンドルを取得するには、たとえば[OpenProcess](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684320.aspx)を呼び出します。 – IInspectable

+2

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

答えて

4

GetProcessDpiAwarenessのドキュメントの最初のパラメータは、プロセスIDではなくプロセスハンドルです。あなたはOpenProcessに、必要な情報を取得する必要がありますCloseHandle。 (AP /呼び出し署名、通常マネージコードでIntPtrなりh又はlpで始まる変数名を定義する場合。)

のように:簡単な方法を使用することであろうが

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

System.Diagnostics.Process like:

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

PROCESS_VM_READは必須ではありません。 – Elmue

+0

重要:GetProcessDpiAwareness()は、別のプロセスから情報を取得するためにサービス(SYSTEM/NT AUTHORITY)で実行されても機能しません。それは常にE_INVALIDARGを返します – Elmue

0

はい、私の省略です。私はプロセスハンドルをGetProcessDpiAwarenessに渡す必要がありました。

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(); 

1件の追加のコメント:それは他のプロセスへのアクセスの問題を回避するために、管理者権限でこのコードを実行する方が良いでしょう私はちょうど私の質問の下の最初の2つのコメントに基づいて自分自身の作業コードを書かれています。

+4

おそらく、このコードを管理者権限で実行する必要はない方がいいでしょう。適切な[アクセス権](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684880.aspx)を[OpenProcess](https://msdn.microsoft.com/en-us/)に渡すだけで、 us/library/windows/desktop/ms684320.aspx)。 'PROCESS_QUERY_LIMITED_INFORMATION'で十分でしょう。 – IInspectable

+0

@IInspectable、私は.NETの管理方法を使用して別のプロセスにアクセスします。あなたはこの環境でこれを行う方法を知っていますか?参考:管理者権限を持つ私のミニツールを起動することは、私のdev pc内で行われるため、私にとって問題ではありません:) – TecMan

+0

[System.Diagnosticsを使用するときに要求されたアクセス権を提供する方法がないようです.Process](https://msdn.microsoft.com/en-us/library/system.diagnostics.process.aspx)クラス。しかし、[theBの答え](http://stackoverflow.com/a/38012663/1889329)で説明されているように、OpenProcessをP/Invokeできます。 – IInspectable

関連する問題