0

I have a project is use GetPixel to analysis the rgb color where i selected pixel, the code below is working fine on single monitor, but for multi monitors, not matter GetDC(GetDesktopWindow) or GetDC(0) the dc only contain the desktop on primary monitor (i use GetDeviceCaps HORZRES and VERTRES to check this).

i used EnumDisplayMonitors() it shows the width and height of virtual desktop is 3610x1875, it is right (i have two monitors), but i use GetDC(0) return dc is only 2560x1440 which is my primary monitor size only, so where is my secondary monitor...

what i want exactly is:

get a DC (device context) of entire desktop window (virtual desktop) for multi monitors on VB6.

i searched this 'This is by design with compatibility with older applications. It always returns the rectangle of the primary monitor.' from here, maybe this is why, but how to fix this.

any idea is welcome, thank you!


edited: thank for @RemyLebeau to help me to clear that only one desktop window on system even system has multi monitors.


Form1.frm, there is Text1, Text2, Text3, Timer1 (set Interval to 50) on form

Private Declare Function GetDC Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function EnumDisplayMonitors Lib "user32" (ByVal HDC As Long, ByVal lprcClip As Long, ByVal lpfnEnum As Long, dwData As Any) As Long
Private Declare Function ReleaseDC Lib "user32" (ByVal hWnd As Long, ByVal HDC As Long) As Long
Private Declare Function GetPixel Lib "gdi32" (ByVal HDC As Long, ByVal x As Long, ByVal y As Long) As Long
Private Declare Function GetDeviceCaps Lib "gdi32" (ByVal HDC As Long, ByVal nIndex As Long) As Long
Const HORZRES As Integer = 8
Const VERTRES As Integer = 10

'this is new dc, will be Assignment on callback function
Public new_dc1 As Long
Public new_dc2 As Long

Private Sub Form_Load()    
    Dim shDC As Long
    shDC = GetDC(0)    
    Call EnumDisplayMonitors(shDC, 0, AddressOf MyPaintEnumProc, 0)
    ReleaseDC 0&, shDC    
End Sub
    
Private Sub Timer1_Timer()
    Dim pixel As Long
    Dim r As Integer
    Dim b As Integer
    Dim g As Integer
    pixel = GetPixel(new_dc1, 100, 100)
    r = pixel& Mod 256
    g = ((pixel And &HFF00) / 256&) Mod 256&
    b = (pixel And &HFF0000) / 65536
    
    Text2.Text = Now() & " Color is: r: " & r & " g: " & g & " b: " & b & vbCrLf
    Text3.Text = GetDeviceCaps(new_dc1, HORZRES) & "*" & GetDeviceCaps(new_dc1, VERTRES)
End Sub

Module1.bas

Public Declare Sub CopyMemory Lib "kernel32" _
   Alias "RtlMoveMemory" _
  (Destination As Any, _
   Source As Any, _
   ByVal Length As Long)

Public Type RECT
   Left    As Long
   Top     As Long
   Right   As Long
   Bottom  As Long
End Type

Public Function MyPaintEnumProc(ByVal HMONITOR As Long, _
                                ByVal HDC As Long, _
                                ByVal LPRECT As Long, _
                                ByVal LPARAM As Long) As Long

   Dim rc As RECT
   CopyMemory rc, ByVal LPRECT, Len(rc)

    'this is only debug purpose, i know this function will execute twice
    If Form1.new_dc1 = 0 Then
        Form1.new_dc1 = HDC 
    Else
        Form1.new_dc2 = HDC 
    End If
  
   Form1.Text1.Text = Form1.Text1.Text & HMONITOR & vbCrLf
   Form1.Text1.Text = Form1.Text1.Text & HDC & vbCrLf
   Form1.Text1.Text = Form1.Text1.Text & LPRECT & vbCrLf
   Form1.Text1.Text = Form1.Text1.Text & LPARAM & vbCrLf
   
   Form1.Text1.Text = Form1.Text1.Text & "rc.Left: " & rc.Left & vbCrLf
   Form1.Text1.Text = Form1.Text1.Text & "rc.Top: " & rc.Top & vbCrLf
   Form1.Text1.Text = Form1.Text1.Text & "rc.Weight: " & rc.Right - rc.Left & vbCrLf
   Form1.Text1.Text = Form1.Text1.Text & "rc.Height: " & rc.Bottom - rc.Top & vbCrLf & vbCrLf
   

   MyPaintEnumProc = 1

End Function
user1928432
  • 133
  • 1
  • 9
  • Perhaps [this link](https://stackoverflow.com/a/10123008/5162073) might be helpful? – Brian M Stafford Apr 22 '21 at 12:58
  • Use `GetDC(0)` instead. See [Painting on a DC That Spans Multiple Displays](https://learn.microsoft.com/en-us/windows/win32/gdi/painting-on-a-dc-that-spans-multiple-displays) and [GetDC(NULL) gets primary monitor or virtual screen?](https://stackoverflow.com/questions/14715527/) – Remy Lebeau Apr 22 '21 at 14:21
  • @RemyLebeau thank you for your reply, but `GetDC(0)` actually return the handle of desktop window of primary screen, 'This is by design with compatibility with older applications.' from [here](https://forums.codeguru.com/showthread.php?528101-GetDesktopWindow()) – user1928432 Apr 22 '21 at 14:52
  • @BrianMStafford thank you for your reply, but `hDC = GetWindowDC(GetDesktopWindow)` only return the handle of desktop window of primary screen, `hDC = GetWindowDC(hWnd)` the problem is how to get the `hWnd` of secondary monitor.. – user1928432 Apr 22 '21 at 14:54
  • @user1928432 "*but GetDC(0) actually return the handle of desktop window of primary screen*" - that is incorrect. The article you linked to talks about `GetDesktopWindow()`, not `GetDC()`. `GetDC(0)` returns a device context, not a window handle, for the entire [Virtual Screen](https://learn.microsoft.com/en-us/windows/win32/gdi/the-virtual-screen) – Remy Lebeau Apr 22 '21 at 14:59
  • @RemyLebeau thank you for correct me, what i want is get the `Hwnd` of secondary monitor and use `GetDC()` to get device context, i did many google search and still has no idea.. your link looks explain what is virtual desktop but not told how to get it. – user1928432 Apr 22 '21 at 15:32
  • @user1928432 Monitors don't have `HWND` handles, they have `HMONITOR` handles. See [HMONITOR and the Device Context](https://learn.microsoft.com/en-us/windows/win32/gdi/hmonitor-and-the-device-context). Have you read the [Multiple Display Monitors](https://learn.microsoft.com/en-us/windows/win32/gdi/multiple-display-monitors) documentation yet? – Remy Lebeau Apr 22 '21 at 15:54
  • @RemyLebeau thank you for your reply, sorry my express, but as my question, I want: a. each handle of desktop window for each monitors; or.. b. one handle of entire desktop window (virtual desktop) for multi monitors; – user1928432 Apr 22 '21 at 16:04
  • @RemyLebeau for simple, why `GetDesktopWindow` can get the `hwnd` of desktop window on primary monitor, but i can't get the `hwnd` of desktop window on secondary monitor. – user1928432 Apr 22 '21 at 16:09
  • 2
    @user1928432 There is only 1 desktop window, spanning the entire [Virtual Screen](https://learn.microsoft.com/en-us/windows/win32/gdi/the-virtual-screen). "*The bounding rectangle of all the monitors is the virtual screen. **The desktop covers the virtual screen instead of a single monitor**.*" So, there is no `HWND` for a "*desktop window on secondary monitor*". Rread the documentation more carefully. Why do you need a per-monitor `HWND`? What are you going to do with it? This is starting to sound like an [XY Problem](https://meta.stackexchange.com/questions/66377/). – Remy Lebeau Apr 22 '21 at 16:16
  • If you want to study pixels across the entire virtual screen, then use `GetDC(0)` to get an `HDC` for the entire screen, and pass it to `EnumDisplayMonitors()` so the callback will then give you an `HDC` suitable for each monitor. – Remy Lebeau Apr 22 '21 at 16:22
  • @RemyLebeau thank you for help me clear this, i used `EnumDisplayMonitors()` it shows the width and height of virtual desktop is 3610*1875, it is right (i have two monitors), but i use `GetDC(0)` return dc is only 2560*1440 (i use `GetDeviceCaps` `HORZRES` and `VERTRES` to check this), 2560*1440 is my primary monitor size only, so where is my secondary monitor... i don't know why this will happen. thank you very much, i just wake up, it is morning in China now. – user1928432 Apr 23 '21 at 03:09
  • 'This is by design with compatibility with older applications. It always returns the rectangle of the primary monitor.' from [here](https://forums.codeguru.com/showthread.php?528101-GetDesktopWindow()) maybe this is why, and then how to fix this? all i want is using `GetPixel` to analysis the pixel i want, but on the entire screen, not the primary screen only. – user1928432 Apr 23 '21 at 03:16
  • @user1928432 I already told you what to do. I will not repeat myself, go re-read my previous comments more carefully. This is documented behavior – Remy Lebeau Apr 23 '21 at 03:59
  • @RemyLebeau i read your comment before carefully, i through `GetDC(0)` `EnumDisplayMonitors` got the `width` `height` `left` `top` information of two desktop each self, but how to convert these information to DC (device context) to let me to continue next operate (`GetPixel`, should pass the DC to it) ? thank you again. – user1928432 Apr 23 '21 at 05:52
  • @user1928432 "*use `GetDC(0)` to get an `HDC` for the entire screen, and pass it to `EnumDisplayMonitors()` so **the callback will then give you an `HDC` suitable for each monitor**.*" This is literally explained in the [`EnumDisplayMonitors()` documenation](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumdisplaymonitors) – Remy Lebeau Apr 23 '21 at 06:02
  • @user1928432 please edit your question to show the actual code you are using. You are obviously doing something wrong in it, but we can't see it, and we're just going around in circles. Also, you don't need to query the `HDC`s for sizes when the callback literally gives you a `RECT` relative to each `HDC` – Remy Lebeau Apr 23 '21 at 14:20
  • @RemyLebeau Good morning, i think i will solve this problem soon with your help. i use `Call EnumDisplayMonitors(GetDC(0), 0, AddressOf MyPaintEnumProc, 0)` and truly, the callback function execute twice, and second parameter of callback is `HDC` from this [Microsoft doc](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nc-winuser-monitorenumproc) but when i using `GetDeviceCaps(new_dc1, HORZRES)` `GetDeviceCaps(new_dc1, VERTRES)` these result are both `0` i will edit my question and post my code, thank you again. – user1928432 Apr 23 '21 at 16:04
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/231521/discussion-between-remy-lebeau-and-user1928432). – Remy Lebeau Apr 23 '21 at 16:12

0 Answers0