Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Help: how to draw on a monitor that is not part of Desktop?

451 views
Skip to first unread message

Marc Reinig

unread,
Aug 27, 2004, 5:33:44 PM8/27/04
to
I am trying to draw on a monitor that is not part of my desktop. It needs
to be an independent graphics display. For that, I think I need the HDC if
the monitor. If not, please let me know how to do it.

Here is what I have tried.

I can enumerate the display devices using
DISPLAY_DEVICE dd;
DISPLAY_DEVICE ddMon;
DWORD device = 0;
POINT pt;

while (EnumDisplayDevice(0, device, &dd, 0) )
{// Get each display device in turn
// Ignore Mirror drivers
if (!(dd.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
{ // Get each monitor attached to the display device in turn
while (EnumDisplayDevices(dd.DeviceName, devMon, &ddMon, 0))
{ // Only worry about the active monitor
if (ddMon.StateFlags & DISPLAY_DEVICE_ACTIVE)
break;
devMon++;
}
if (dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)
{ //These monitors are part of the desktop
pt = dm.dmPosition.x, dm.dmPosition.y };
hm = MonitorFromPoint (pt,MONITOR_DEVAULTTONULL);
} // I can use MonitorFromXXX as above to get an hdc to draw on
// any part of the desktop
else
{ // how do I get the hm or hdc of the Monitors that are not
// part of the desktop?
// I tried the following four combinations but hdc comes back
// NULL.
hdc = CreateDC(ddMon.DeviceName, NULL, NULL, NULL );
hdc = CreateDC(ddMon.DeviceName, NULL, NULL, &dm );
hdc = CreateDC(dd.DeviceName, NULL, NULL, NULL );
hdc = CreateDC(dd.DeviceName, NULL, NULL, &dm );

When I try GetLastError, the translation is usually "Invalid Printer Name".

What am I doing wrong?

Thanks in advance,

Marc Reinig
UCO Lick, LAO

Rhett Gong [MSFT]

unread,
Sep 3, 2004, 4:30:27 AM9/3/04
to
Hi Marc,
From your description, I feel unsure what type of monitor you are trying to
draw on. Could you try following code, post what it outputs in this thread
and point out which monitor you are going to draw please?
//--------------------------------------------------------------------------
----
int _tmain(int argc, _TCHAR* argv[])
{
BOOL bRet = FALSE;
DWORD dwNum =0;
vector< DISPLAY_DEVICE> dispVec;

do {
DISPLAY_DEVICE disp;
disp.cb = sizeof( DISPLAY_DEVICE );
bRet = EnumDisplayDevices(NULL,dwNum,&disp,0);
if( bRet)
dispVec.push_back(disp);
dwNum++;
} while(bRet);

vector<DISPLAY_DEVICE>::iterator it = dispVec.begin();
vector<DISPLAY_DEVICE>::iterator it_end = dispVec.end();

cout<<endl<<"* * * * * * Enumerate Monitor Devices * * * * * *"<<endl;
for ( ; it != it_end ; it++ )
{

cout<<"*********************************************************************
****"<<endl;
cout<<"DeviceName:\t" <<(*it).DeviceName << endl;
cout<< "DeviceString:\t"<<(*it).DeviceString << endl;
cout<<"StateFlag:\t"<<hex<<(*it).StateFlags<<endl;
cout<<"DeviceID:\t" <<(*it).DeviceID<<endl;
// code to obtain the monitor name
DISPLAY_DEVICE monInfo;
monInfo.cb = sizeof( DISPLAY_DEVICE );
if (EnumDisplayDevices(dispVec[0].DeviceName,0,&monInfo,0))
{
cout<< "Monitor name is :"<< monInfo.DeviceString <<endl;
}

cout<<"*********************************************************************
****"<<endl;
}

//.......Cleanup ...
}
//--------------------------------------------------------------------------
-------

Best regards,
Rhett Gong [MSFT]
Microsoft Online Partner Support

This posting is provided "AS IS" with no warranties, and confers no rights.
Please reply to newsgroups only. Thanks.

Marc Reinig

unread,
Sep 3, 2004, 2:48:18 PM9/3/04
to
Rhett,

Thanks for responding.

The output from your program is at the end.

I would like to draw or display images on \\.DISPLAY2 or \\.DISPLAY3.

Currently, \\.DISPLAY2 does not have a monitor attached, but that is easily
fixed.

Neither \\.DISPLAY2 nor \\.DISPLAY3 are part of my desktop. I just want to
use them as independent output devices. I don't want the mouse there, or
any desktop items.

Thanks in advance,

Marc Reinig
UCO/Lick
Laboratory for Adaptive Optics

* * * * * * Enumerate Monitor Devices * * * * * *

********************************************************************
DeviceName: \\.\DISPLAY1
DeviceString: NVIDIA Quadro NVS with AGP8X (Microsoft Corporation)
StateFlag: 8000005
DeviceID: PCI\VEN_10DE&DEV_018A&SUBSYS_019010DE&REV_C1
Monitor name is :Default Monitor
********************************************************************
********************************************************************
DeviceName: \\.\DISPLAY2
DeviceString: Matrox Millennium G400 - English
StateFlag: 0
DeviceID: PCI\VEN_102B&DEV_0525&SUBSYS_41E0102B&REV_05
Monitor name is :Default Monitor
********************************************************************
********************************************************************
DeviceName: \\.\DISPLAY3
DeviceString: NVIDIA Quadro NVS with AGP8X (Microsoft Corporation)
StateFlag: 8000001
DeviceID: PCI\VEN_10DE&DEV_018A&SUBSYS_019010DE&REV_C1
Monitor name is :Default Monitor
********************************************************************
********************************************************************
DeviceName: \\.\DISPLAYV1
DeviceString: NetMeeting driver
StateFlag: 8
DeviceID:
Monitor name is :Default Monitor
********************************************************************
********************************************************************
DeviceName: \\.\DISPLAYV2
DeviceString: RDPDD Chained DD
StateFlag: 8
DeviceID:
Monitor name is :Default Monitor
********************************************************************


Rhett Gong [MSFT]

unread,
Sep 6, 2004, 2:11:37 AM9/6/04
to
From the output, you have 3 display device connected to your computer.
Display1 &Display3 is attached to desktop, and Display2 does not. Then you
would like to draw on Display2 or Display3, but CreateDC always returns
NULL and says "Invalid Printer Name".

Since it will take some time for me to get a second display device for a
test, I suggest you try followings line to see if the dc could be properly
created.
hDC = CreateDC("DISPLAY", ddMon.DeviceName/*or dd.DeviceName*/, NULL, NULL);
Please let me know what you get when applying this line on Display2 and
Display3.

Thanks,

Marc Reinig

unread,
Sep 7, 2004, 6:41:19 PM9/7/04
to

"Rhett Gong [MSFT]" <v-ra...@online.microsoft.com> wrote in message
news:vshaeh9k...@cpmsftngxa10.phx.gbl...

> I suggest you try followings line to see if the dc could be properly
> created.
> hDC = CreateDC("DISPLAY", ddMon.DeviceName/*or dd.DeviceName*/, NULL,
> NULL);

using your original code, I add

if (EnumDisplayDevices(dispVec[0].DeviceName,0,&monInfo,0))
{
cout<< "Monitor name is :"<< monInfo.DeviceString <<endl;

// Now try and get an hDC
hDC_mon = CreateDC("DISPLAY", monInfo.DeviceString, NULL, NULL);
if ( hDC_mon != 0 )
{ // Got it
printf ( "hDC_mon = %X\n", hDC_mon );
// draws box in the upper left corner
bool result = Rectangle(hDC_mon,10,10,100,100);
if (result)
printf ( "Success!\n" );
else
printf ( "Failure!\n" );
}
else // Argh!
printf ( "hDC_dev = NULL\n" );
}

and I get an hDC for each monitor, Yea!.

What I see is that Rectangle() draws a small box in the upper left corner of
my desktop for that hDC so I know I am getting a correct hDC (at least for
that monitor). However, my monitors for the independent displays are still
not enabled so I can't see if I am drawing on them.

So, now that I can get an hDC for the independent monitors (I hope), how do
I enable them (i.e. have the video cards send them video), so I can see if I
can draw on them?

Note: If I go to the "Display Properties / Settings Tab", and make them
part of the desktop, they work fine, but when I remove them from the desktop
they go black.

So there must be some sequence to enable them I am missing.

Rhett Gong [MSFT]

unread,
Sep 8, 2004, 4:15:38 AM9/8/04
to
Hi Marc,
I will update you tomorrow after doing some tests. Thanks for your
patience.

Best regards,

Rhett Gong [MSFT]

unread,
Sep 8, 2004, 4:34:38 AM9/8/04
to
In addition, I made a mistake in my original code. Please modify the
original code as follows. Then try CreateDC inside this loop and let me
know if the dc could be correctly.
//-------------------------------------------------

for ( ; it != it_end ; it++ )
{

cout<<"*********************************************************************
****"<<endl;
cout<<"DeviceName:\t" <<(*it).DeviceName << endl;
cout<< "DeviceString:\t"<<(*it).DeviceString << endl;
cout<<"StateFlag:\t"<<hex<<(*it).StateFlags<<endl;
cout<<"DeviceID:\t" <<(*it).DeviceID<<endl;
// code to obtain the monitor name
DISPLAY_DEVICE monInfo;
monInfo.cb = sizeof( DISPLAY_DEVICE );
if (EnumDisplayDevices((*it).DeviceName,0,&monInfo,0))

{
cout<< "Monitor name is :"<< monInfo.DeviceString <<endl;
}

cout<<"*********************************************************************
****"<<endl;
}
//-------------------------------------------------

I need do some tests on my thought. I will update you later. Thanks.


Best regards,

Marc Reinig

unread,
Sep 8, 2004, 1:55:02 PM9/8/04
to
Rhett,

This produces the output below. It draws a white box in the upper left of
any of the monitors that are part of the desk top. in this case only
Display1 was on the desktop.

But, if a monitor is not on the desktop, it still doesn't draw on it and it
is still suspended, i.e. power is applied, but the indicator lights indicate
they are not receiving any video and the screen is black.

Thanks,

Marco


* * * * * * Enumerating Monitor Devices * * * * * *

****************************************************


DeviceName: \\.\DISPLAY1
DeviceString: NVIDIA Quadro NVS with AGP8X (Microsoft Corporation)
StateFlag: 8000005
DeviceID: PCI\VEN_10DE&DEV_018A&SUBSYS_019010DE&REV_C1

Using current Graphics modes
Resolution and refresh rate:
1280 x 1024 @ 0, 0 - 32-bit - 60 Hz


Monitor name is :Default Monitor

hDC_mon = 4E010E51
Rect Success!
****************************************************


****************************************************
DeviceName: \\.\DISPLAY2
DeviceString: Matrox Millennium G400 - English
StateFlag: 0
DeviceID: PCI\VEN_102B&DEV_0525&SUBSYS_41E0102B&REV_05

There are no current Graphics modes
Using Graphics modes in the registry
Resolution and refresh rate:
0 x 0 @ 0, 0 - 0-bit - 0 Hz


Monitor name is :Default Monitor

hDC_mon = 700108A3
Rect Success!
****************************************************


****************************************************
DeviceName: \\.\DISPLAY3
DeviceString: NVIDIA Quadro NVS with AGP8X (Microsoft Corporation)

StateFlag: 8000000
DeviceID: PCI\VEN_10DE&DEV_018A&SUBSYS_019010DE&REV_C1
There are no current Graphics modes
Using Graphics modes in the registry
Resolution and refresh rate:
1280 x 1024 @ 1280, 0 - 32-bit - 75 Hz


Monitor name is :Default Monitor

hDC_mon = 39010362
Rect Success!
****************************************************


****************************************************
DeviceName: \\.\DISPLAYV1
DeviceString: NetMeeting driver
StateFlag: 8
DeviceID:

There are no current Graphics modes
Using Graphics modes in the registry
Resolution and refresh rate:
800 x 600 @ 0, 0 - 16-bit - 75 Hz
****************************************************


****************************************************
DeviceName: \\.\DISPLAYV2
DeviceString: RDPDD Chained DD
StateFlag: 8
DeviceID:

There are no current Graphics modes
Using Graphics modes in the registry
Resolution and refresh rate:
800 x 600 @ 0, 0 - 16-bit - 75 Hz
****************************************************

Below is the current state of my code:

// MS_TEST.cpp

#include "stdafx.h"
#include <windows.h>
#include <vector>

using namespace std;

int
_tmain(int argc, _TCHAR* argv[])
{

DISPLAY_DEVICE disp;
DEVMODE dm;
BOOL result;


BOOL bRet = FALSE;
DWORD dwNum =0;
vector< DISPLAY_DEVICE> dispVec;

HDC hDC_dev = NULL;
HDC hDC_mon = NULL;

do
{ // find all the display devices and add them to a vector


disp.cb = sizeof( DISPLAY_DEVICE );

bRet = EnumDisplayDevices(NULL,dwNum,&disp,0);
if( bRet)

dispVec.push_back(disp); // add another element to the vector
dwNum++;
} while(bRet);

vector<DISPLAY_DEVICE>::iterator it = dispVec.begin();
vector<DISPLAY_DEVICE>::iterator it_end = dispVec.end();

cout<<endl<<"* * * * * * Enumerating Monitor Devices * * * * * *\n"<<endl;


for ( ; it != it_end ; it++ )
{

cout<<"****************************************************"<<endl;


cout<<"DeviceName:\t" <<(*it).DeviceName << endl;
cout<<" DeviceString:\t"<<(*it).DeviceString << endl;
cout<<" StateFlag:\t"<<hex<<(*it).StateFlags<<endl;
cout<<" DeviceID:\t" <<(*it).DeviceID<<endl;

// get information about the display's position and the current display
mode
ZeroMemory ( &dm, sizeof(dm) );
dm.dmSize = sizeof(dm);
if ( EnumDisplaySettingsEx ( (*it).DeviceName, ENUM_CURRENT_SETTINGS, &dm,
0 ) == FALSE )
{
printf ( " There are no current Graphics modes\n" );
if ( EnumDisplaySettingsEx ( (*it).DeviceName, ENUM_REGISTRY_SETTINGS,
&dm, 0 ) == FALSE )
printf ( " There are no Graphics modes in the registry\n" );
else
printf ( " Using Graphics modes in the registry\n" );
}
else
{
printf ( " Using current Graphics modes\n" );
}
printf ( " Resolution and refresh rate:\n %d x %d @ %d, %d - %d-bit -
%d Hz\r\n",
dm.dmPelsWidth, dm.dmPelsHeight,
dm.dmPosition.x, dm.dmPosition.y,
dm.dmBitsPerPel, dm.dmDisplayFrequency );

// Obtain the monitor name


DISPLAY_DEVICE monInfo;
monInfo.cb = sizeof( DISPLAY_DEVICE );
if (EnumDisplayDevices((*it).DeviceName,0,&monInfo,0))
{
cout<< " Monitor name is :"<< monInfo.DeviceString <<endl;

// Now try and get an hDC for the monitor


hDC_mon = CreateDC("DISPLAY", monInfo.DeviceString, NULL, NULL);
if ( hDC_mon != 0 )
{

printf ( " hDC_mon = %X\n", hDC_mon );

// Try to draw a box on the upper left corner of each monitor
result = Rectangle ( hDC_mon, dm.dmPosition.x + 10, dm.dmPosition.y +
10,
dm.dmPosition.x + 100, dm.dmPosition.y + 100 );
if (result)
printf ( " Rect Success!\n" );
else
printf ( " Rect Failure!\n" );
}
else


printf ( " hDC_dev = NULL\n" );
}

cout<<"****************************************************"<<endl;
}

printf ("\n");

//.......Cleanup ...
//------------------------------------------------------------------------
}


Rhett Gong [MSFT]

unread,
Sep 9, 2004, 3:28:01 AM9/9/04
to
Hi Marc,
I've confirmed this with our gdi guys. Unfortunately, the monitor *must* be
part of the desktop before we can use GDI or other Windows graphics
technologies to draw on it. As you found, if the monitor is not attached to
desktop, there will be no signals to it.

In addition, here is a function to attach a monitor to the desktop. Hope it
could help you in some way.
//----------------------------------------
BOOL AddUnattachedDisplayDeviceToDesktop()
{
DWORD DispNum = 0;
DISPLAY_DEVICE DisplayDevice;
DEVMODE defaultMode;
HDC hdc;
int nWidth;
BOOL bFoundSecondary = FALSE;
hdc = GetDC(0);
nWidth = GetDeviceCaps(hdc,HORZRES);
ReleaseDC(0,hdc);

// Initialize DisplayDevice.
ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
DisplayDevice.cb = sizeof(DisplayDevice);

// Get display devices.
while ((EnumDisplayDevices(NULL, DispNum, &DisplayDevice, 0)) &&
(bFoundSecondary == FALSE))
{
ZeroMemory(&defaultMode, sizeof(DEVMODE));
defaultMode.dmSize = sizeof(DEVMODE);
if (!EnumDisplaySettings((LPSTR)DisplayDevice.DeviceName,
ENUM_REGISTRY_SETTINGS, &defaultMode))
return FALSE; // Store default failed
if (!(DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE))
{
//Found the first secondary device.
bFoundSecondary = TRUE;
defaultMode.dmPosition.x += nWidth;
defaultMode.dmFields = DM_POSITION;
ChangeDisplaySettingsEx((LPSTR)DisplayDevice.DeviceName,
&defaultMode, NULL, CDS_NORESET|CDS_UPDATEREGISTRY,
NULL);
}
// Reinitialize DisplayDevice.
ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
DisplayDevice.cb = sizeof(DisplayDevice);
DispNum++;
} // End while the display devices.
return TRUE;
}
//--------------------------------------------------------------------------
-


Have a nice day,

Marc Reinig

unread,
Sep 9, 2004, 1:57:24 PM9/9/04
to
In the MSDN library, under:

Graphics and Multimedia
Windows GDI
Multiple Display Monitors
About Multiple Display Monitors
Using Multiple Monitors as Independent Displays

It says, "The window manager knows nothing about the independent displays.
They are completely controlled by the application, and no window manager
functions are available to the application (all window manager calls
automatically go to the primary display). Each independent display has its
own origin and horizontal and vertical coordinates, and is accessed through
the GDI functions such as CreateDC or the DirectX functions such as
DirectDrawCreate."

OK, so I can't use hWind's on them, but it says I can still access them
through GDI functions, but how?

Thanks in advance,

Marco

"Rhett Gong [MSFT]" <v-ra...@online.microsoft.com> wrote in message

news:c6goP6jl...@cpmsftngxa10.phx.gbl...

Rhett Gong [MSFT]

unread,
Sep 10, 2004, 2:20:12 AM9/10/04
to
Hi Marc,
That document is outdated, it is for the NT4/early-Win2K timeframe. But
current OSs do not allow this because it's a security risk. And we already
have a bug to get the CreateDC() docs updated.

Thanks,

Arnaud Debaene

unread,
Sep 10, 2004, 7:33:27 AM9/10/04
to
v-ra...@online.microsoft.com (Rhett Gong [MSFT]) wrote in message news:<de0l#4vlEH...@cpmsftngxa10.phx.gbl>...

> Hi Marc,
> That document is outdated, it is for the NT4/early-Win2K timeframe. But
> current OSs do not allow this because it's a security risk. And we already
> have a bug to get the CreateDC() docs updated.
>
Security risk? What security risk is there to draw on a display that
is not part of the Desktop?
I hope they are at least still accessible through DirectX ?

Arnaud
MVP - VC

Rhett Gong [MSFT]

unread,
Sep 12, 2004, 11:41:44 PM9/12/04
to
You can use DirectDraw on an unattached display with Win9x but this is not
available for 2000 or later.

Best regards,

Arnaud Debaene

unread,
Sep 13, 2004, 8:24:00 AM9/13/04
to
v-ra...@online.microsoft.com (Rhett Gong [MSFT]) wrote in message news:<IzKcbOUm...@cpmsftngxa10.phx.gbl>...

> You can use DirectDraw on an unattached display with Win9x but this is not
> available for 2000 or later.

Too bad :-(
I can't think of any good reason to such a limitation. Is that somehow
linked to the Window station/desktop management?

Arnaud
MVP - VC

vanho...@gmail.com

unread,
Sep 29, 2018, 3:26:23 AM9/29/18
to
Vào 15:30:27 UTC+7 Thứ Sáu, ngày 03 tháng 9 năm 2004, Rhett Gong [MSFT] đã viết:
Hi Rhett, I copy your code and built on visual studio 2017, but it had many errors ( identifier "vector" is undefined,identifier "dispVec" is undefined, expected a ;,...). what header I have to include?
0 new messages