2015-08-21 19 views
6

Tôi đã cố gắng vô hiệu hóa nhận thức DPI trên một ứng dụng ClickOnce.
Tôi nhanh chóng phát hiện ra, không thể chỉ định nó trong tệp kê khai, bởi vì ClickOnce không hỗ trợ asm.v3 trong tệp kê khai.SetProcessDpiAwareness không có hiệu lực

Tùy chọn tiếp theo tôi tìm thấy đang gọi chức năng Windows mới SetProcessDpiAwareness.

Theo this hướng dẫn,

Call SetProcessDpiAwareness before you create the application window.

this hướng dẫn,

you must call SetProcessDpiAwareness prior to any Win32API call

Bạn cần phải gọi hàm khá sớm. Vì vậy, để kiểm tra, tôi đã tạo ra một ứng dụng WPF hoàn toàn trống, và thực hiện điều này toàn bộ lớp App của tôi:

[DllImport("SHCore.dll", SetLastError = true)] 
private static extern bool SetProcessDpiAwareness(PROCESS_DPI_AWARENESS awareness); 

[DllImport("SHCore.dll", SetLastError = true)] 
private static extern void GetProcessDpiAwareness(IntPtr hprocess, out PROCESS_DPI_AWARENESS awareness); 

private enum PROCESS_DPI_AWARENESS 
{ 
    Process_DPI_Unaware = 0, 
    Process_System_DPI_Aware = 1, 
    Process_Per_Monitor_DPI_Aware = 2 
} 

static App() 
{ 
    var result = SetProcessDpiAwareness(PROCESS_DPI_AWARENESS.Process_DPI_Unaware); 
    var setDpiError = Marshal.GetLastWin32Error(); 
    MessageBox.Show("Dpi set: " + result.ToString()); 

    PROCESS_DPI_AWARENESS awareness; 
    GetProcessDpiAwareness(Process.GetCurrentProcess().Handle, out awareness); 
    var getDpiError = Marshal.GetLastWin32Error(); 
    MessageBox.Show(awareness.ToString()); 

    MessageBox.Show("Set DPI error: " + new Win32Exception(setDpiError).ToString()); 
    MessageBox.Show("Get DPI error: " + new Win32Exception(getDpiError).ToString()); 
} 

3 hộp thư hiển thị nội dung này:

Dpi set: True
Process_System_DPI_Aware
Set DPI error: System.ComponentModel.Win32Exception (0x80004005): Access is denied
System.ComponentModel.Win32Exception (0x80004005): The operation completed successfully

Tại sao là ứng dụng vẫn thiết lập tới DPI_Aware? Cuộc gọi này có đủ sớm không?
Ứng dụng thực sự trải nghiệm quy mô DPI.

Khi tôi sử dụng định nghĩa manifest:

<application xmlns="urn:schemas-microsoft-com:asm.v3"> 
    <windowsSettings> 
    <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">false</dpiAware> 
    </windowsSettings> 
</application> 

Nó trở Process_DPI_Unaware.

EDIT 1:
Bây giờ grabbing Marshal.GetLastWin32Error() trực tiếp sau khi các phương pháp PInvoke, điều này bây giờ thực sự trả về một lỗi.

Trả lời

5

Cẩn thận với SetLastErrorGetLastWin32Error, mọi cuộc gọi ở giữa như MessageBox.Show sẽ ảnh hưởng đến kết quả của nó. Đảm bảo luôn nhận được lỗi cuối cùng ngay sau khi gọi phương thức gốc của bạn.

Vì vậy, có thể rất tốt khi bạn đang nhận được hành vi mong đợi nhưng bị lừa bởi mã lỗi.

Xem bài viết trên blog này để giải thích đầy đủ: http://blogs.msdn.com/b/oldnewthing/archive/2015/08/19/10636096.aspx

EDIT

Không hoàn toàn chắc chắn về những gì đang gây access denied ... nhưng có một mẹo đơn giản và hiệu quả mà vô hiệu hóa nhận thức DPI:

Chỉnh sửa AssemblyInfo.cs và thêm thông tin sau:

[assembly: DisableDpiAwareness] 

Nguồn: https://code.msdn.microsoft.com/windowsdesktop/Per-Monitor-Aware-WPF-e43cde33 (nhận xét trong PerMonitorAwareWPFWindow.xaml.cs)

+0

Ah! Tất nhiên! Vui lòng xem mã đã chỉnh sửa của tôi, trả về "Đặt lỗi DPI: System.ComponentModel.Win32Exception (0x80004005): Truy cập bị từ chối" –

+2

Xem bản chỉnh sửa của tôi để biết cách tiếp cận khác. – Aybe

+1

Điều đó hoạt động hoàn hảo! Cảm ơn! –

Các vấn đề liên quan