c# कई मॉनिटर के साथ SetWindowPos का उपयोग करना



windows user32 (1)

user32.dll और C # का उपयोग करके मैंने वह विधि लिखी जिसे आप नीचे देखते हैं। विंडो के लिए प्रोसेस हैंडल का उपयोग करते हुए, यह प्रदान की गई विंडो स्थिति को {x,y} स्थान पर सेट करेगा।

हालाँकि, बहु-मॉनिटर किए गए वातावरण में नीचे दी गई कोड विंडो की स्थिति को प्राथमिक मॉनीटर पर सेट करता है, केवल। मैं चाहूंगा कि कौन सा मॉनिटर भी सिलेक्ट किया जा सके।
किसी को समझा सकते हैं कि यह कैसे सेट किया जा सकता है SetWindowPos या शायद किसी अन्य user32.dll फ़ंक्शन के साथ संयोजन का उपयोग करके?

[DllImport("user32.dll", SetLastError = true)]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);

private const int SWP_NOSIZE = 0x0001;
private const int SWP_NOZORDER = 0x0004;
private const int SWP_SHOWWINDOW = 0x0040;

public static void SetWindowPosition(Process p, int x, int y)
{
    IntPtr handle = p.MainWindowHandle;
    if (handle != IntPtr.Zero)
    {
        SetWindowPos(handle, IntPtr.Zero, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
    }
}

जिमी की टिप्पणी पर आधारित समाधान।

यहाँ मेरा मॉनिटर कॉन्फ़िगरेशन है:

निरीक्षण करें कि मेरे पास मेरे प्राथमिक मॉनिटर के बाईं ओर एक माध्यमिक मॉनिटर है। जिमी द्वारा प्रदान किए गए वर्चुअल मॉनिटर लिंक को पढ़ने के बाद मैंने पाया कि विंडोज़ को सेकेंडरी मॉनिटर पर ले जाने के लिए कि मुझे एक नकारात्मक एक्स-मान का उपयोग करना होगा क्योंकि यह प्राथमिक मॉनिटर के मूल (ऊपरी बाएं कोने, या <0,0>) से बचा है।

इसलिए, अगर मैं अपनी विंडो स्थिति को द्वितीयक मॉनिटर के <0,0> समन्वय के लिए सेट करना चाहता हूं, तो मुझे प्राथमिक मॉनिटर की उत्पत्ति से माध्यमिक मॉनिटर की x-चौड़ाई को इस तरह से सबमिट करना होगा:

<0,0> - <1920,0> = <-1920,0>

अब, जब मैं अपने ग्राहक कोड में SetWindowPosition को कॉल करता हूं, तो मैं इसे इस तरह कहता हूं:

SetWindowPosition(Process p, -1920, 0);

नोट: मुझे नहीं पता कि मॉनिटर के अलग-अलग रिज़ॉल्यूशन होने पर आप क्या करेंगे। यह एक अधिक जटिल विषय है और ऐसा प्रश्न नहीं है जो मैं पूछ रहा हूं। इसके अलावा, मुझे इस विषय पर गहराई से अन्वेषण करने की आवश्यकता नहीं दिखी क्योंकि ऊपर दिए गए सरल उदाहरण ने मेरे सभी मुद्दों को हल कर दिया।


सिस्टम डिस्पेंस और वर्चुअलस्क्रीन प्रदर्शित करता है

एक विंडोज सिस्टम में, प्राइमरी स्क्रीन (प्रोग्रामिंग परिप्रेक्ष्य) डिस्प्ले डिवाइस है जिसका Point(0,0) पर ऊपरी बाएं कोने की स्थिति है।

इसका अर्थ है कि प्राथमिक स्क्रीन के बाईं ओर स्थित डिस्प्ले में नकारात्मक X निर्देशांक होंगे (यदि पोर्ट पोर्ट्रेट लेआउट में है तो Y निर्देशांक नकारात्मक हो सकता है)।
दाईं ओर के डिस्प्ले में सकारात्मक X निर्देशांक होंगे (यदि पोर्ट पोर्ट्रेट लेआउट में है तो Y निर्देशांक नकारात्मक हो सकता है)।

प्राथमिक स्क्रीन के बाईं ओर प्रदर्शित करता है :
दूसरे शब्दों में, प्रदर्शित करता है कि एक नकारात्मक Point.X मूल है
Point.X उत्पत्ति पूर्ववर्ती Screens[].Width के सभी का योग है Screens[].Width प्राथमिक स्क्रीन के Point.X मूल समन्वय से घटाया गया Screens[].Width

प्राथमिक स्क्रीन के दाईं ओर प्रदर्शित करता है :
दूसरे शब्दों में, प्रदर्शित करता है कि एक सकारात्मक Point.X मूल है
Point.X उत्पत्ति पूर्ववर्ती Screens[].Width के सभी का योग है Screens[].Width , प्राथमिक शामिल है , प्राथमिक स्क्रीन के मूल Point.X समन्वय में जोड़ा गया है।

महत्वपूर्ण नोट :
यदि एप्लिकेशन DPIAware नहीं है, तो इन सभी उपायों को सिस्टम द्वारा निष्पादित वर्चुअलाइजेशन और स्वचालित DPI स्केलिंग से समझौता किया जा सकता है। सभी उपायों को डिफ़ॉल्ट रूप से 96 डीपीआई के लिए समान किया जाएगा: आवेदक को स्केल किए गए मान प्राप्त होंगे। इसमें गैर- DpiAware Win32 Api फ़ंक्शंस से प्राप्त मान भी शामिल हैं। देख:

विंडोज पर उच्च डीपीआई डेस्कटॉप अनुप्रयोग विकास

app.manifest में सभी लक्षित सिस्टम के लिए समर्थन सक्षम करें। आवश्यक फाइल को app.manifest करके

app.manifest फ़ाइल में DpiAware और DpiA जागरूकता अनुभागों को जोड़ें / हटाएं।
PerMonitorV2 Dpi अवेयरनेस मोड को app.config फ़ाइल (विंडोज 10 क्रिएटर्स एडिशन से उपलब्ध) में सेट किया जा सकता है।

उदाहरण:
3 मॉनिटर्स वाले सिस्टम पर विचार करें:

PrimaryScreen             (\\.\DISPLAY1):  Width: (1920 x 1080)
Secondary Display (Right) (\\.\DISPLAY2):  Width: (1360 x 768)
Secondary Display (Left)  (\\.\DISPLAY3):  Width: (1680 x 1050)

PrimaryScreen: 
     Bounds: (0, 0, 1920, 1080)      Left: 0      Right: 1920  Top: 0  Bottom: 1080
Secondary Display (Right): 
     Bounds: (1360, 0, 1360, 768)    Left: 1360   Right: 2720  Top: 0  Bottom: 768
Secondary Display (Left): 
     Bounds: (-1680, 0, 1680, 1050)  Left: -1680  Right: 0     Top: 0  Bottom: 1050



यदि हम सिस्टम एप्लेट, प्राथमिक स्क्रीन संदर्भ का उपयोग करते हुए इसे \\.\DISPLAY3 , तो निर्देशांक तदनुसार संशोधित हो जाएंगे:


वर्चुअल स्क्रीन

वर्चुअल स्क्रीन एक वर्चुअल डिस्प्ले है, जिसके आयामों का प्रतिनिधित्व किया जाता है:
उत्पत्ति : सबसे बाईं ओर की Screen का मूल समन्वय
चौड़ाई : सभी Screens चौड़ाई का योग।
ऊँचाई : उच्चतम Screen की ऊँचाई

ये उपाय SystemInformation.VirtualScreen द्वारा सूचित किए गए हैं
प्राथमिक स्क्रीन का Size SystemInformation.PrimaryMonitorSize द्वारा रिपोर्ट किया गया है
सभी स्क्रीन वर्तमान उपायों और स्थिति को Screen.AllScreens का उपयोग Screen.AllScreens और प्रत्येक \\.\DISPLAY[N] गुणों का निरीक्षण करके भी पुनर्प्राप्त किया जा सकता है।

संदर्भ के रूप में पूर्ववर्ती उदाहरण का उपयोग करते हुए, पहले स्वभाव में, VirtualScreen सीमाएँ हैं:

Bounds: (-1680, 0, 3280, 1080)  Left: -1680  Right: 3280   Top: 0  Bottom: 1080

दूसरे स्वभाव में, VirtualScreen सीमाएं हैं:

Bounds: (0, 0, 4960, 1080)  Left: 0  Right: 4960   Top: 0  Bottom: 1080


एक प्रदर्शन क्षेत्र के अंदर खिड़की की स्थिति :

स्क्रीन क्लास कई विधियाँ प्रस्तुत करती है जिनका उपयोग यह निर्धारित करने के लिए किया जा सकता है कि वर्तमान में किस विंडो में एक विशिष्ट विंडो प्रदर्शित की गई है:

Screen.FromControl([Control reference])
Screen ऑब्जेक्ट लौटाता है जिसमें निर्दिष्ट Control संदर्भ का सबसे बड़ा खंड होता है।

Screen.FromHandle([Window Handle])
Screen ऑब्जेक्ट लौटाता है जिसमें एक Handle द्वारा संदर्भित विंडो \ कंट्रोल का सबसे बड़ा खंड होता है

Screen.FromPoint([Point])
Screen ऑब्जेक्ट देता है जिसमें एक विशिष्ट Point

Screen.FromRectangle([Rectangle])
उस Screen ऑब्जेक्ट को लौटाता है जिसमें निर्दिष्ट Rectangle का सबसे बड़ा भाग होता है

Screen.GetBounds() (ओवरलोडेड)
एक Rectangle संरचना लौटाता है जिसमें स्क्रीन सीमाएँ होती हैं जो संदर्भित होती हैं:
- एक विशिष्ट Point
- निर्दिष्ट Rectangle का सबसे बड़ा खंड
- एक Control संदर्भ

\\.\DISPLAY[N] निर्धारित करने के लिए जिसमें वर्तमान फॉर्म दिखाया गया है, कॉल करें (उदाहरण के लिए):

Screen.FromHandle(this);

यह निर्धारित करने के लिए कि किस स्क्रीन में एक द्वितीयक फॉर्म दिखाया गया है:
(उदाहरण में नमूना प्रदर्शनों का उपयोग करते हुए)

form2 = new Form2();
form2.Location = new Point(-1400, 100);
form2.Show();
Rectangle screenSize = Screen.GetBounds(form2);
Screen screen = Screen.FromHandle(form2.Handle);

screenSize = = to \\.\DISPLAY3 सीमा होगी।
screen Screen वस्तु होगी जो \\.\DISPLAY3 गुणों का प्रतिनिधित्व करती है।

screen ऑब्जेक्ट screen के \\.\DISPLAY[N] नाम की रिपोर्ट भी करेगा, जिसमें form2 दिखाया गया है।

एक स्क्रीन ऑब्जेक्ट के hMonitor हैंडल को प्राप्त करें :

.NET संदर्भ स्रोत बताता है कि hMonitor को [Screen].GetHashCode(); कॉल करके hMonitor है [Screen].GetHashCode();

IntPtr monitorHwnd = new IntPtr([Screen].GetHashCode());

या एक ही देशी Win32 कार्यों का उपयोग कर:

MonitorFromWindow , MonitorFromPoint और MonitorFromRect

[Flags]
internal enum MONITOR_DEFAULTTO
{
    NULL = 0x00000000,
    PRIMARY = 0x00000001,
    NEAREST = 0x00000002,
}

[DllImport("User32.dll", SetLastError = true)]
internal static extern IntPtr MonitorFromWindow(IntPtr hwnd, MONITOR_DEFAULTTO dwFlags);

[DllImport("User32.dll", SetLastError = true)]
internal static extern IntPtr MonitorFromPoint([In] POINT pt, MONITOR_DEFAULTTO dwFlags);

[DllImport("User32.dll", SetLastError = true)]
internal static extern IntPtr MonitorFromRect([In] ref RECT lprc, MONITOR_DEFAULTTO dwFlags);

किसी स्क्रीन के डिवाइस संदर्भ का एक हैंडल प्राप्त करें :
उपलब्ध किसी भी प्रदर्शन के hDC को पुनः प्राप्त करने के लिए एक सामान्य विधि।

स्क्रीन निर्देशांक या स्क्रीन डिवाइस केवल एक विशिष्ट स्क्रीन संदर्भ की आवश्यकता होने पर वर्णित विधियों में से एक का उपयोग करके निर्धारित किया जा सकता है।

Screen.DeviceName गुण का उपयोग GDI + CreateDC फ़ंक्शन के lpszDriver पैरामीटर के रूप में किया जा सकता है। यह प्रदर्शन के hDC को लौटाएगा जो Graphics.FromHdc एक वैध ग्राफिक्स ऑब्जेक्ट बनाने के लिए उपयोग कर सकता है जो एक विशिष्ट स्क्रीन पर पेंट करने की अनुमति देगा।

यहां, कम से कम दो डिस्प्ले उपलब्ध हैं:

[DllImport("gdi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
internal static extern IntPtr CreateDC(string lpszDriver, string lpszDevice, string lpszOutput, IntPtr lpInitData);

[DllImport("gdi32.dll", SetLastError = true, EntryPoint = "DeleteDC")]
internal static extern bool DeleteDC([In] IntPtr hdc);  

public static IntPtr CreateDCFromDeviceName(string deviceName)
{
    return CreateDC(deviceName, null, null, IntPtr.Zero);
}


Screen[] screens = Screen.AllScreens;
IntPtr screenDC1 = CreateDCFromDeviceName(screens[0].DeviceName);
IntPtr screenDC2 = CreateDCFromDeviceName(screens[1].DeviceName);
using (Graphics g1 = Graphics.FromHdc(screenDC1))
using (Graphics g2 = Graphics.FromHdc(screenDC2))
using (Pen pen = new Pen(Color.Red, 10))
{
    g1.DrawRectangle(pen, new Rectangle(new Point(100, 100), new Size(200, 200)));
    g2.DrawRectangle(pen, new Rectangle(new Point(100, 100), new Size(200, 200)));
}

DeleteDC(screenDC1);
DeleteDC(screenDC2);




user32