2011-06-08 11 views
6

मुझे ऐसी सुविधा लागू करना है जहां विंडो की अंतिम स्थिति सहेजी गई हो। जब एप्लिकेशन शुरू होता है तो इस स्थिति को प्राप्त करने और बहाल करने की आवश्यकता होती है।.NET सी # में Win32 GetMonitorInfo() का उपयोग कैसे करें?

अब यह हो सकता है कि दूसरा मॉनिटर नष्ट हो जाए। यदि अंतिम स्थिति अब गैर-दृश्यमान मॉनिटर पर है (दूसरे शब्दों में सहेजे गए निर्देशांक दृश्य निर्देशांक के बाहर हैं), तो इस मामले को पकड़ा जाना चाहिए और निर्देशांक अंतिम स्थिति की बजाय डिफ़ॉल्ट पर सेट किए जाएंगे।

मॉनीटर के बारे में जानकारी पुनर्प्राप्त करने के लिए मुझे Win32 का उपयोग करने की आवश्यकता है। यह काम करना मेरे लिए आसान नहीं है।

मैं एक सहायक वर्ग बनाया है:

public static class DisplayHelper 
    { 
     private const int MONITOR_DEFAULTTONEAREST = 2; 

     [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] 
     public static extern int GetSystemMetrics(int nIndex); 

     [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] 
     private static extern UInt32 MonitorFromPoint(Point pt, UInt32 dwFlags); 

     [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] 
     private static extern bool GetMonitorInfo(UInt32 monitorHandle, ref MonitorInfo mInfo); 


     public static void GetMonitorInfoNow(MonitorInfo mi, Point pt) 
     { 
      UInt32 mh = MonitorFromPoint(pt, 0); 
      mi.cbSize = (UInt32)System.Runtime.InteropServices.Marshal.SizeOf(typeof(MonitorInfo)); 
      mi.dwFlags = 0; 
      bool result = GetMonitorInfo(mh, ref mi); 

     } 
    } 

और इन MonitorInfo और रेक्ट कक्षाएं बनाने के लिए मेरे प्रयास कर रहे हैं:

[StructLayout(LayoutKind.Sequential)] 
    public class MonitorInfo 
    { 
     public UInt32 cbSize; 
     public Rectangle2 rcMonitor; 
     public Rectangle2 rcWork; 
     public UInt32 dwFlags; 

     public MonitorInfo() 
     { 
      rcMonitor = new Rectangle2(); 
      rcWork = new Rectangle2(); 

      cbSize = (UInt32)System.Runtime.InteropServices.Marshal.SizeOf(typeof(MonitorInfo)); 
      dwFlags = 0; 
     } 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    public class Rectangle2 
    { 
     public UInt64 left; 
     public UInt64 top; 
     public UInt64 right; 
     public UInt64 bottom; 

     public Rectangle2() 
     { 
      left = 0; 
      top = 0; 
      right = 0; 
      bottom = 0; 
     } 
    } 

मैं दिखाई पर नज़र रखता है प्राप्त करने के लिए इस तरह इस कोड का उपयोग कर रहा :

//80 means it counts only visible display monitors. 
int lcdNr = DisplayHelper.GetSystemMetrics(80); 
var point = new System.Drawing.Point((int) workSpaceWindow.Left, (int) workSpaceWindow.Top); 
MonitorInfo monitorInfo = new MonitorInfo(); 
DisplayHelper.GetMonitorInfoNow(monitorInfo, point); 

अंतिम विधि निष्पादित करने का प्रयास करते समय एक अपवाद फेंकता है

bool result = GetMonitorInfo(mh, ref mi); 

कोई सुझाव जो मुझे इसे ठीक करने के लिए करना है?

उत्तर

8

मूल एपीआई कॉल करने के बजाय, आपको System.Windows.Forms.Screen का उपयोग करना चाहिए। इसमें आपकी हर चीज होनी चाहिए, और उपयोग करने में बहुत आसान होना चाहिए।

Screen.FromPointMONITOR_DEFAULTTONEAREST विकल्प के साथ आपके GetMonitorInfoNow फ़ंक्शन के प्रबंधित समकक्ष है। मैंने अभी देखा है कि आप उस विकल्प का उपयोग नहीं कर रहे हैं, इसलिए आपको अपना खुद का लिखना होगा या सही पी/आमंत्रण हस्ताक्षर का उपयोग करना होगा।

यदि आप केवल System.Drawing और System.Windows.Forms संदर्भित करते हैं तो स्वयं को लिखना काफी सरल होना चाहिए। इन दोनों काम करना चाहिए:

static Screen ScreenFromPoint1(Point p) 
{ 
    System.Drawing.Point pt = new System.Drawing.Point((int)p.X, (int)p.Y); 
    return Screen.AllScreens 
        .Where(scr => scr.Bounds.Contains(pt)) 
        .FirstOrDefault(); 
} 

static Screen ScreenFromPoint2(Point p) 
{ 
    System.Drawing.Point pt = new System.Drawing.Point((int)p.X, (int)p.Y); 
    var scr = Screen.FromPoint(pt); 
    return scr.Bounds.Contains(pt) ? scr : null; 
} 

आप Win32 खुद कहता है, उचित पी बनाने के लिए पसंद करते हैं/हस्ताक्षर आह्वान (यानी आप decompiling नेट DLL से प्राप्त होता है क्या) कार्य आप कॉल करने की आवश्यकता के लिए हैं:

[DllImport("User32.dll", CharSet=CharSet.Auto)] 
    public static extern bool GetMonitorInfo(HandleRef hmonitor, [In, Out]MONITORINFOEX info); 
    [DllImport("User32.dll", ExactSpelling=true)] 
    public static extern IntPtr MonitorFromPoint(POINTSTRUCT pt, int flags); 

    [StructLayout(LayoutKind.Sequential,CharSet=CharSet.Auto, Pack=4)] 
    public class MONITORINFOEX { 
     public int  cbSize = Marshal.SizeOf(typeof(MONITORINFOEX)); 
     public RECT rcMonitor = new RECT(); 
     public RECT rcWork = new RECT(); 
     public int  dwFlags = 0; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst=32)] 
     public char[] szDevice = new char[32]; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    public struct POINTSTRUCT { 
     public int x; 
     public int y; 
     public POINTSTRUCT(int x, int y) { 
      this.x = x; 
      this.y = y; 
     } 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    public struct RECT { 
     public int left; 
     public int top; 
     public int right; 
     public int bottom; 
    } 
+0

धन्यवाद गेबे, मैं उल्लेख करना भूल गया हूं कि मेरा आवेदन डब्ल्यूपीएफ में लिखा गया है। सैद्धांतिक रूप से मुझे System.Windows.Forms.Screen तक कोई पहुंच नहीं होगी, जब तक कि यह WPF के साथ भी काम न करे? – Houman

+0

@ केव: बस System.Windows.Forms.dll का संदर्भ जोड़ें और आप इसे WPF से उपयोग कर सकते हैं। – Gabe

+0

@Gabe - यह आसान हो सकता है, लेकिन मुझे यकीन नहीं है कि मैं किसी भी अनुकूलन के साथ भी एक वर्ग/विधि के लिए 5 एमबी असेंबली लोड करूंगा।इसकी निर्भरताओं का जिक्र नहीं करना ;-) – CodeNaked

0

आपके आयत 2 को Int32 या केवल int का उपयोग करना चाहिए, Int64 नहीं। अधिक जानकारी here मिल सकती है।

इसके अलावा इसे एक वर्ग नहीं बल्कि एक वर्ग होना चाहिए। आपके मॉनिटरइन्फो क्लास के लिए भी जाता है (यह एक स्ट्रक्चर होना चाहिए)। मैं ऊपर दिए गए लिंक से संस्करण की कोशिश करने की सिफारिश करता हूं, या अपने संस्करणों के साथ उनकी तुलना करता हूं।

+0

कोई फर्क नहीं पड़ता। यह अभी भी दुर्घटनाग्रस्त है। – Houman

+1

@ केव - अपडेट किया गया उत्तर। – CodeNaked

संबंधित मुद्दे