从 C# 调用 GetProcessDpiAwareness 总是 returns 错误 E_INVALIDARG
Calling GetProcessDpiAwareness from C# always returns error E_INVALIDARG
我想检索 Windows 10 Pro 64 位中指定进程 ID 的有效 DPI 感知值。我需要的值是 PROCESS_DPI_AWARENESS I can get with the WinAPI GetProcessDpiAwareness 函数之一。
为了实现我所需要的,我在VS 2015中写了一个简单的-window C# WPF应用程序。我将我感兴趣的进程ID输入到TextBox txtProcessID中,结果显示在当我按下 txtProcessID 按钮时,TextBlock txtResult:
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");
}
但是为任何进程调用 GetProcessDpiAwareness 总是给我一个错误 E_INVALIDARG。我做错了什么?
根据 GetProcessDpiAwareness
的文档,第一个参数是进程句柄,而不是进程 ID。您需要 OpenProcess
,获取所需信息,然后 CloseHandle
。 (定义 p/Invoke 签名时,任何以 h
或 lp
开头的变量名称在托管代码中通常是 IntPtr
。)
如:
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
,例如:
System.Diagnostics.Process proc = Process.GetProcessById(processId);
PROCESS_DPI_AWARENESS value;
int res = GetProcessDpiAwareness(proc.Handle, out value);
是的,这是我的遗漏。我需要将进程句柄传递给 GetProcessDpiAwareness
。我刚刚根据问题下的前 2 条评论编写了自己的工作代码:
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();
补充说明:最好以管理员权限执行此代码,以避免访问其他进程时出现问题。
我想检索 Windows 10 Pro 64 位中指定进程 ID 的有效 DPI 感知值。我需要的值是 PROCESS_DPI_AWARENESS I can get with the WinAPI GetProcessDpiAwareness 函数之一。
为了实现我所需要的,我在VS 2015中写了一个简单的-window C# WPF应用程序。我将我感兴趣的进程ID输入到TextBox txtProcessID中,结果显示在当我按下 txtProcessID 按钮时,TextBlock txtResult:
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");
}
但是为任何进程调用 GetProcessDpiAwareness 总是给我一个错误 E_INVALIDARG。我做错了什么?
根据 GetProcessDpiAwareness
的文档,第一个参数是进程句柄,而不是进程 ID。您需要 OpenProcess
,获取所需信息,然后 CloseHandle
。 (定义 p/Invoke 签名时,任何以 h
或 lp
开头的变量名称在托管代码中通常是 IntPtr
。)
如:
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
,例如:
System.Diagnostics.Process proc = Process.GetProcessById(processId);
PROCESS_DPI_AWARENESS value;
int res = GetProcessDpiAwareness(proc.Handle, out value);
是的,这是我的遗漏。我需要将进程句柄传递给 GetProcessDpiAwareness
。我刚刚根据问题下的前 2 条评论编写了自己的工作代码:
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();
补充说明:最好以管理员权限执行此代码,以避免访问其他进程时出现问题。