• GetDC,0 -> EnumDisplayMonitors -> No results ?

    From R.Wieser@21:1/5 to All on Sun Jan 24 12:47:35 2021
    Hello all,

    I've just connected a second monitor to my 'puter and am looking a the
    results returned by the "EnumDisplayMonitors" (user32.dll) call. The
    callback returns both monitors *as long as* I provide a NULL as the DC
    argument (and the clipping rectangle argument).

    When I set the DC argument to the output of "GetDC,0" (which should return
    the DC of the desktop) neither the primary nor the secondary monitor is
    shown.

    I must be misunderstanding something, but I have no idea what ... :-(

    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumdisplaymonitors

    Regards,
    Rudy Wieser

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From JJ@21:1/5 to R.Wieser on Sun Jan 24 20:57:22 2021
    On Sun, 24 Jan 2021 12:47:35 +0100, R.Wieser wrote:
    Hello all,

    I've just connected a second monitor to my 'puter and am looking a the results returned by the "EnumDisplayMonitors" (user32.dll) call. The callback returns both monitors *as long as* I provide a NULL as the DC argument (and the clipping rectangle argument).

    When I set the DC argument to the output of "GetDC,0" (which should return the DC of the desktop) neither the primary nor the secondary monitor is shown.

    I must be misunderstanding something, but I have no idea what ... :-(

    https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumdisplaymonitors

    Regards,
    Rudy Wieser

    The given HDC doesn't really matter as long as it's a valid handle or is
    NULL. `EnumDisplayMonitors()` should always enumerate a monitor as long as
    RECT is NULL or within a monitor's area.

    So, chances are that you're giving a RECT which is outside of all monitors' area.

    Here's my test application log in a VM with two monitors.
    #1 is 1204x716. #2 is 800x600.
    `GetDc(0)` is stored in a variable and is reused for the enumeration.

    Single monitor configuration:

    enum#1: dc=none, rect=none
    mon:00170281, dc:00000000, rect:(0,0)-(1204,716)=1204x716
    enum#2: dc=getdc(0)=0B010893, rect=none
    mon:00170281, dc:18010863, rect:(0,0)-(1204,716)=1204x716
    enum#3: dc=none, rect=(100,100)-(110,110)
    mon:00170281, dc:00000000, rect:(100,100)-(110,110)=10x10
    enum#4: dc=getdc(0)=0B010893, rect=(100,100)-(110,110)
    mon:00170281, dc:18010863, rect:(100,100)-(110,110)=10x10
    enum#5: dc=getdc(0)=0B010893, rect=(1400,100)-(1410,110)

    Two monitors configuration:
    #2 as separate desktop (i.e. not a desktop extension)

    enum#1: dc=none, rect=none
    mon:009502D5, dc:00000000, rect:(0,0)-(1204,716)=1204x716
    mon:00180281, dc:00000000, rect:(1204,1204)-(2004,600)=800x600
    enum#2: dc=getdc(0)=4201088F, rect=none
    mon:009502D5, dc:49010CCE, rect:(0,0)-(1204,716)=1204x716
    mon:00180281, dc:8F010C4E, rect:(1204,1204)-(2004,600)=800x600
    enum#3: dc=none, rect=(100,100)-(110,110)
    mon:009502D5, dc:00000000, rect:(100,100)-(110,110)=10x10
    enum#4: dc=getdc(0)=4201088F, rect=(100,100)-(110,110)
    mon:009502D5, dc:49010CCE, rect:(100,100)-(110,110)=10x10
    enum#5: dc=getdc(0)=4201088F, rect=(1400,100)-(1410,110)
    mon:00180281, dc:8F010C4E, rect:(1400,1400)-(1410,110)=10x10

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From JJ@21:1/5 to All on Sun Jan 24 21:03:34 2021
    On Sun, 24 Jan 2021 20:57:22 +0700, JJ wrote:
    The given HDC doesn't really matter as long as it's a valid handle or is NULL.

    Correction: HDC matters. It defines the RECT's origin. i.e. if it's NULL,
    the origin would be the virtual screen, which is the entire monitors
    combined as a large display are which is larger than any single monitor. Otherwise, the origin is the window of the HDC.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From R.Wieser@21:1/5 to All on Sun Jan 24 17:23:35 2021
    JJ,

    So, chances are that you're giving a RECT which is outside of
    all monitors' area.

    Thats the thing, I'm not giving it a rectangle at all. Its NULL.

    As the documentation says it, "This parameter can be NULL if you don't want
    to clip the region specified by hdc."

    Correction: HDC matters.
    ...
    Otherwise, the origin is the window of the HDC.

    The documentattion to "GetDC" says this : "A handle to the window whose DC
    is to be retrieved. *If this value is NULL, GetDC retrieves the DC for the entire screen*."

    I'm entirely sure what the "entire screen" stands for, but I guessed thats
    ment as the whole of the desktop (including all of its monitors). But even
    if it just (randomly?) picks a monitor it boundaries should thus encompass
    at least that monitor.

    ... but I'm getting nothing back ...

    Also :

    Single monitor configuration:

    I have no idea how you get five entries. On my machine
    "EnumDisplayMonitors" only calls its callback twice, once for each monitor
    on the desktop (if I detach the second monitor from the desktop the callback gets called only once - for the primary monitor).


    I've just given "EnumDisplayMonitors" both a DC and a (ludicrous large) clipping rectange. It still fails to return anything. Keeping the
    clipping retangle but setting the DC to NULL again returns both monitors.
    Than shrinking the clipping rectangle to just around 0,0 returns just the primary monitor. IOW, the clipping rectangle works as expected.

    In all cases "EnumDisplayMonitors" returns a non-zero (OK) value.

    hmmm... I just realized: The "clipping rectangle" isn't /clipping/ but
    rather a "in which monitor(s) does this area reside" indicator.

    Regards,
    Rudy Wieser

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From JJ@21:1/5 to R.Wieser on Mon Jan 25 19:41:50 2021
    On Sun, 24 Jan 2021 17:23:35 +0100, R.Wieser wrote:

    I have no idea how you get five entries.

    You misunderstood. Each "enum#" log represent each call to EnumDisplayMonitors(), but with different arguments. The indented lines are
    the reports of the callback.

    On my machine
    "EnumDisplayMonitors" only calls its callback twice, once for each monitor
    on the desktop (if I detach the second monitor from the desktop the callback gets called only once - for the primary monitor).

    As do mine. The enumerations report zero up to two monitors, depending on
    the given enumeration arguments.

    but rather a "in which monitor(s) does this area reside" indicator.

    I was trying to tell you that. Maybe my English isn't good enough.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From R.Wieser@21:1/5 to All on Mon Jan 25 16:43:43 2021
    JJ,

    You misunderstood. Each "enum#" log represent each call
    to EnumDisplayMonitors(), but with different arguments.

    Ah yes, now I see. Sorry 'bout that.

    But that creates a problem: I've done the same four with-and-without DC and rectangle tests, but you get results back using a DC while I get none. :-|

    The only difference I can currently imagine is the used OS. In my case
    thats XPsp3.

    but rather a "in which monitor(s) does this area reside" indicator.

    I was trying to tell you that. Maybe my English isn't good enough.

    More likely I was too stuck on the "clipping" [1] in its description to
    notice what you tried to tell me.

    [1] I did some bare-bones line-drawing recently (Bresenham) and implemented
    a clipping rectangle. It seems that the "remove everything outside of it" still lingered.

    And by the way, English/American is not my mothertongue either (and not a language regulary spoken around here). Its therefore quite possible I just didn't understand and therefore grasp what you tried to tell me.

    Regards,
    Rudy Wieser

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From JJ@21:1/5 to R.Wieser on Tue Jan 26 22:06:37 2021
    On Mon, 25 Jan 2021 16:43:43 +0100, R.Wieser wrote:

    But that creates a problem: I've done the same four with-and-without DC and rectangle tests, but you get results back using a DC while I get none. :-|

    The only difference I can currently imagine is the used OS. In my case
    thats XPsp3.

    My test was for Win7, but it's the same for XP SP3.

    Below log is for the same hardware setup (monitor #1, then #2; left to
    right) except that monitor #1 resolution is 1024x704, which is different
    than previous setup.

    Single monitor configuration:

    enum#1: dc=none, rect=none
    mon:002000BF, dc:00000000, rect:(0,0)-(1024,704)=1024x704
    enum#2: dc=getdc(0)=01010053, rect=none
    mon:002000BF, dc:D4010226, rect:(0,0)-(1024,704)=1024x704
    enum#3: dc=none, rect=(100,100)-(110,110)
    mon:002000BF, dc:00000000, rect:(100,100)-(110,110)=10x10
    enum#4: dc=getdc(0)=01010053, rect=(100,100)-(110,110)
    mon:002000BF, dc:D4010226, rect:(100,100)-(110,110)=10x10
    enum#5: dc=getdc(0)=01010053, rect=(1400,100)-(1410,110)

    Two monitors configuration:

    enum#1: dc=none, rect=none
    mon:002C014F, dc:00000000, rect:(0,0)-(1024,704)=1024x704
    mon:002100BF, dc:00000000, rect:(1024,1024)-(1824,600)=800x600
    enum#2: dc=getdc(0)=01010052, rect=none
    mon:002C014F, dc:3C01034F, rect:(0,0)-(1024,704)=1024x704
    mon:002100BF, dc:0D0102D3, rect:(1024,1024)-(1824,600)=800x600
    enum#3: dc=none, rect=(100,100)-(110,110)
    mon:002C014F, dc:00000000, rect:(100,100)-(110,110)=10x10
    enum#4: dc=getdc(0)=01010052, rect=(100,100)-(110,110)
    mon:002C014F, dc:3C01034F, rect:(100,100)-(110,110)=10x10
    enum#5: dc=getdc(0)=01010052, rect=(1400,100)-(1410,110)
    mon:002100BF, dc:0D0102D3, rect:(1400,1400)-(1410,110)=10x10

    Assuming that EnumDisplayMonitors() returns TRUE when non zero DC is
    given...

    You may need to debug your program to check the arguments right before EnumDisplayMonitors() is called. i.e. after the arguments are pushed into
    the stack.

    Manually check the arguments in the memory to make sure they're passed with
    the correct order, structure (plus alignments), value types (or bitness),
    and values.

    Then do a single step debugging to make sure that its the
    EnumDisplayMonitors() function which is called, instead of other function.

    This may seem overkill, but I'm trying to leave no stone unturned.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From R.Wieser@21:1/5 to All on Tue Jan 26 17:58:45 2021
    JJ,

    This may seem overkill, but I'm trying to leave no stone unturned.

    I found it, and you will never guess to what the problem was/is ....




    I ran that code from within a fullscreen (80x25 text mode) *console* . When
    I switched to windowed (GUI) mode I got four results for the four tests.

    Although the GetDC,0 result looked to be OK, it must have pointed to
    something different than the actual virtual screen.

    Regards,
    Rudy Wieser

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From R.Wieser@21:1/5 to All on Tue Jan 26 17:34:36 2021
    JJ,

    You may need to debug your program to check the arguments right before EnumDisplayMonitors() is called. i.e. after the arguments are pushed into
    the stack.

    Remember that I'm programming in Assembly ? There is *nothing* in between
    me pushing the arguments and calling the function. I can give you the .lst file if you want. :-)

    Manually check the arguments in the memory to make sure they're
    passed with the correct order, structure (plus alignments), value
    types (or bitness), and values.

    Done, done and triple-checked. Also provided a special value to the fourth, LPARM argument and got the exact same value back in the callback function.

    Then do a single step debugging

    I'm sorry, but I never liked single-step debuggers and would currently not
    even know if I have one. Except for DEBUG.COM that is.

    to make sure that its the EnumDisplayMonitors() function which
    is called, instead of other function.

    From four test calls to the function the callback function is called twice
    (for a single monitor), with the expected values. IOW, the function work, just not always.

    The function itself is called by name, and resolved by the OS
    (double-checked that just now)

    This may seem overkill, but I'm trying to leave no stone unturned.

    Following one of Murphies Laws : the problem will often be there where you least expect it. :-)

    Below is the output of my four tests (single monitor).

    -[1] No DC, no rectangle
    00010001 00000000 0012FF78 12345678
    Res:00000001
    -[2] DC only
    Res:00000001
    -[3] DC + rectangle
    Res:00000001
    -[4] rectangle only
    00010001 00000000 0012FF78 12345678
    Res:00000001

    "Res:" is ofcourse the result. OK in all four.

    If you know whats going on you may tell me.

    Regards,
    Rudy Wieser

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From JJ@21:1/5 to R.Wieser on Thu Jan 28 09:58:44 2021
    On Tue, 26 Jan 2021 17:58:45 +0100, R.Wieser wrote:
    JJ,

    This may seem overkill, but I'm trying to leave no stone unturned.

    I found it, and you will never guess to what the problem was/is ....

    I ran that code from within a fullscreen (80x25 text mode) *console* . When I switched to windowed (GUI) mode I got four results for the four tests.

    Although the GetDC,0 result looked to be OK, it must have pointed to something different than the actual virtual screen.

    Oh... If your program is built as a console application, it's probably due
    to the fact that a console application's thread by default is not a GUI
    thread. Calling any GUI related functions without converting the thread to a GUI thread first using `IsGUIThread()`, while according to the documentation the system will automatically do that, but it may do it a bit too late or unreliably.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From JJ@21:1/5 to R.Wieser on Thu Jan 28 09:46:34 2021
    On Tue, 26 Jan 2021 17:34:36 +0100, R.Wieser wrote:

    IOW, the function work, just not always.

    That raises a flag. The cause of the problem may be elsewhere in the system, and inconsistency is difficult to troubleshoot.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From R.Wieser@21:1/5 to All on Thu Jan 28 07:21:13 2021
    JJ,

    Oh... If your program is built as a console application, it's
    probably due to the fact that a console application's thread
    by default is not a GUI thread.

    I have a bit of a problem in understanding that. I'm asking for the destop
    DC (GetDC,0) but am not getting it. Why ? What has /my/ thread not being a GUI thread have anything to do with that ?

    Also, what am I getting instead (and why does the MS documentation not
    mention it ? :-( ).

    ... using `IsGUIThread()`, while according to the documentation ...

    The "docs.microsoft.com" description for that function is rather lacking in depth. Could you tell me which documentation you are referring to ?

    Regards,
    Rudy Wieser

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From JJ@21:1/5 to R.Wieser on Sat Jan 30 10:58:29 2021
    On Thu, 28 Jan 2021 07:21:13 +0100, R.Wieser wrote:
    JJ,

    Oh... If your program is built as a console application, it's
    probably due to the fact that a console application's thread
    by default is not a GUI thread.

    I have a bit of a problem in understanding that. I'm asking for the destop DC (GetDC,0) but am not getting it. Why ? What has /my/ thread not being a GUI thread have anything to do with that ?

    Also, what am I getting instead (and why does the MS documentation not mention it ? :-( ).

    ... using `IsGUIThread()`, while according to the documentation ...

    The "docs.microsoft.com" description for that function is rather lacking in depth. Could you tell me which documentation you are referring to ?

    Sorry, I was mistaken.

    GUI thread is for message queue. It's not needed if the function doesn't involve message queue.

    I've tested as a console application, and sure enough, it still works.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From R.Wieser@21:1/5 to All on Sat Jan 30 08:58:38 2021
    JJ,

    I've tested as a console application, and sure enough, it still works.

    It does, as long as you are in GUI mode (a windowed console). It doesn't
    (at least at my end) when you switch to full-screen text-mode. In my case I always start with "MODE CON COLS=80 LINES=25".

    And I realized just now that that is what makes it extra strange : The app
    is a console app one in both cases, but in the full-screen mode it suddenly looses track of its (GUI) desktop DC.

    I just test to ask for the DC twice (and destroy it) ihn the same thread,
    but in between switch from fullscreen console to GUI (windowed) mode (using ALT-tab). I get two different DC results. As a test I also just ran it fully in GUI and after in console mode. In the former I get the same DC
    back twice. In the latter I get two different ones.

    Regards,
    Rudy Wieser

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From R.Wieser@21:1/5 to All on Sat Jan 30 19:23:59 2021
    (using ALT-tab)

    Whoops, that should have been ALT-Enter ofcourse.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From JJ@21:1/5 to R.Wieser on Mon Feb 1 04:59:29 2021
    On Sat, 30 Jan 2021 08:58:38 +0100, R.Wieser wrote:
    JJ,

    I've tested as a console application, and sure enough, it still works.

    It does, as long as you are in GUI mode (a windowed console). It doesn't
    (at least at my end) when you switch to full-screen text-mode. In my case I always start with "MODE CON COLS=80 LINES=25".

    And I realized just now that that is what makes it extra strange : The app
    is a console app one in both cases, but in the full-screen mode it suddenly looses track of its (GUI) desktop DC.

    I just test to ask for the DC twice (and destroy it) ihn the same thread,
    but in between switch from fullscreen console to GUI (windowed) mode (using ALT-tab). I get two different DC results. As a test I also just ran it fully in GUI and after in console mode. In the former I get the same DC
    back twice. In the latter I get two different ones.

    Judging from what I can see from my (further) tests, either DC or its
    geometry, becomes wonky in fullscreen text mode. It's exactly as what you've experienced.

    The cause is probably because GDI is not applicable for text video mode,
    where the screen "window", is not graphical. However, `GetDC(0)` returns a valid handle regardless. That confuses me.

    Here's my result if I tested it as a console application, without and with fullscreen mode. The output was done in a single console window created by
    CMD. Test #1 is in windowsed mode, #2 is in fullscreen, and #3 is back to windowed mode.

    Microsoft Windows XP [Version 5.1.2600]
    (C) Copyright 1985-2001 Microsoft Corp.

    C:\Documents and Settings\user>cd Desktop

    C:\Documents and Settings\user\Desktop>Project2.exe
    enum#1: dc=none, rect=none
    mon:0010008F, dc:00000000, rect:(0,0)-(1032,702)=1032x702
    mon:00020001, dc:00000000, rect:(1032,1032)-(1832,600)=800x600
    enum#2: dc=getdc(0)=01010052, rect=none
    mon:0010008F, dc:AC0102B9, rect:(0,0)-(1032,702)=1032x702
    mon:00020001, dc:BE010299, rect:(1032,1032)-(1832,600)=800x600
    enum#3: dc=none, rect=(100,100)-(110,110)
    mon:0010008F, dc:00000000, rect:(100,100)-(110,110)=10x10
    enum#4: dc=getdc(0)=01010052, rect=(100,100)-(110,110)
    mon:0010008F, dc:AC0102B9, rect:(100,100)-(110,110)=10x10
    enum#5: dc=getdc(0)=01010052, rect=(1400,100)-(1410,110)
    mon:00020001, dc:BE010299, rect:(1400,1400)-(1410,110)=10x10

    C:\Documents and Settings\user\Desktop>Project2.exe
    enum#1: dc=none, rect=none
    mon:0010008F, dc:00000000, rect:(0,0)-(1032,702)=1032x702
    mon:00020001, dc:00000000, rect:(1032,1032)-(1832,600)=800x600
    enum#2: dc=getdc(0)=01010055, rect=none
    enum#3: dc=none, rect=(100,100)-(110,110)
    mon:0010008F, dc:00000000, rect:(100,100)-(110,110)=10x10
    enum#4: dc=getdc(0)=01010055, rect=(100,100)-(110,110)
    enum#5: dc=getdc(0)=01010055, rect=(1400,100)-(1410,110)

    C:\Documents and Settings\user\Desktop>Project2.exe
    enum#1: dc=none, rect=none
    mon:0010008F, dc:00000000, rect:(0,0)-(1032,702)=1032x702
    mon:00020001, dc:00000000, rect:(1032,1032)-(1832,600)=800x600
    enum#2: dc=getdc(0)=01010051, rect=none
    mon:0010008F, dc:AC0102B9, rect:(0,0)-(1032,702)=1032x702
    mon:00020001, dc:BE010299, rect:(1032,1032)-(1832,600)=800x600
    enum#3: dc=none, rect=(100,100)-(110,110)
    mon:0010008F, dc:00000000, rect:(100,100)-(110,110)=10x10
    enum#4: dc=getdc(0)=01010051, rect=(100,100)-(110,110)
    mon:0010008F, dc:AC0102B9, rect:(100,100)-(110,110)=10x10
    enum#5: dc=getdc(0)=01010051, rect=(1400,100)-(1410,110)
    mon:00020001, dc:BE010299, rect:(1400,1400)-(1410,110)=10x10

    C:\Documents and Settings\user\Desktop>

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From R.Wieser@21:1/5 to All on Mon Feb 1 10:02:39 2021
    JJ,

    However, `GetDC(0)` returns a valid handle regardless. That confuses me.

    Same here.

    As I was not even sure if it is in fact a /valid/ handle (and not just some random number) I tried to draw on it.

    In windowed mode I saw the FillRect and MoveToExe & LineTo expected results appear on the desktop.

    In fullscreen mode I see nothing happening - which seems to indicate that
    the GetDC(0) in fullscreen mode doesn't actually (somehow) point at the text screen.

    In both cases all involved functions returned 0x1 (OK), so it looks like the returned DC is valid in textmode too.

    .. no idea where it points to though - or why (and not return a NULL handle
    for the full-screen text mode). :-|

    Regards,
    Rudy Wieser

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)