The following code sort of works. It doesn't keep the monitor resolution.
void AppFrame::OnButtonModify(wxCommandEvent& event)
{
static bool bSwitch = false;
if (bSwitch)
{
ExtendExternalDisplay();
}
else
{
CloneExternalDisplay();
}
bSwitch = !bSwitch;
}
void AppFrame::ExtendExternalDisplay()
{
int nModeSwitch = NULL;
DEVMODE dmPrimary, dmSecondary, dmThird, savedmSecondary;
#define szPrimaryDisplay TEXT( "\\\\.\\DISPLAY1" )
#define szSecondaryDisplay TEXT( "\\\\.\\DISPLAY2" )
#define szThirdDisplay TEXT( "\\\\.\\DISPLAY3" )
ZeroMemory( &dmPrimary, sizeof(dmPrimary) );
dmPrimary.dmSize = sizeof(dmPrimary);
ZeroMemory( &dmSecondary, sizeof(dmSecondary) );
dmSecondary.dmSize = sizeof(dmSecondary);
ZeroMemory( &dmThird, sizeof(dmThird) );
dmThird.dmSize = sizeof(dmThird);
ZeroMemory( &dmThird, sizeof(dmThird) );
dmThird.dmSize = sizeof(dmThird);
BOOL result;
HDC handle;
DWORD iDevNum = 0;
DWORD dwFlags = 0;
DISPLAY_DEVICE lpDisplayDevice, lpDisplayDeviceOne, lpDisplayDeviceTwo;
ZeroMemory(&lpDisplayDevice, sizeof(lpDisplayDevice));
ZeroMemory(&lpDisplayDeviceOne, sizeof(lpDisplayDeviceOne));
ZeroMemory(&lpDisplayDeviceTwo, sizeof(lpDisplayDeviceTwo));
lpDisplayDevice.cb = sizeof(lpDisplayDevice);
lpDisplayDeviceOne.cb = sizeof(lpDisplayDeviceOne);
lpDisplayDeviceTwo.cb = sizeof(lpDisplayDeviceTwo);
// All this does is confirm the number of display devices the graphics board is capable of handling
while(EnumDisplayDevices(NULL, iDevNum, &lpDisplayDevice, dwFlags))
{
if (iDevNum == 0)
{
lpDisplayDeviceOne = lpDisplayDevice;
TRACE("DeviceName: '%s'\n", lpDisplayDeviceOne.DeviceName);
TRACE("DeviceString: '%s'\n", lpDisplayDeviceOne.DeviceString);
TRACE("Flags: %08X %s%s\n", lpDisplayDeviceOne.StateFlags,((lpDisplayDeviceOne.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) ? "Desktop " : ""), ((lpDisplayDeviceOne.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) ? "Primary" : ""));
}
if (iDevNum == 1)
{
lpDisplayDeviceTwo = lpDisplayDevice;
TRACE("DeviceName: '%s'\n", lpDisplayDeviceTwo.DeviceName);
TRACE("DeviceString: '%s'\n", lpDisplayDeviceTwo.DeviceString);
TRACE("Flags: %08X %s%s\n", lpDisplayDeviceTwo.StateFlags,((lpDisplayDeviceTwo.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) ? "Desktop " : ""), ((lpDisplayDeviceTwo.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) ? "Primary" : ""));
}
iDevNum ++;
}
// load DISPLAY1 monitor information // ENUM_CURRENT_SETTINGS
if (!EnumDisplaySettings(szPrimaryDisplay, ENUM_REGISTRY_SETTINGS, (DEVMODE*)&dmPrimary))
{
TRACE("EnumDisplaySettings unable to enumerate primary display\n");
return;
}
if (!EnumDisplaySettings(szSecondaryDisplay, ENUM_REGISTRY_SETTINGS, (DEVMODE*)&dmSecondary))
TRACE("EnumDisplaySettings unable to enumerate secondary display display\n");
// these don't enumerate in clone mode
if (!EnumDisplaySettings(szSecondaryDisplay, ENUM_CURRENT_SETTINGS, (DEVMODE*)&savedmSecondary))
TRACE("EnumDisplaySettings unable to enumerate secondary display using ENUM_CURRENT_SETTINGS settings\n");
// disable a display, doesn't work
// nModeSwitch = ChangeDisplaySettingsEx (szSecondaryDisplay, NULL, NULL, NULL, NULL);
// CDdx::ErrorDisplayDevice(nModeSwitch); // test and TRACE result
dmPrimary.dmFields = DM_POSITION;
dmPrimary.dmPosition.x = 0; // set DISPLAY1 as the primary display
dmPrimary.dmPosition.y = 0; // set DISPLAY1 as the primary display
// set DISPLAY1 as primary display (dmPosition.x = 0)
nModeSwitch = ChangeDisplaySettingsEx (szPrimaryDisplay, (DEVMODE*)&dmPrimary, NULL, (CDS_UPDATEREGISTRY | CDS_NORESET), NULL);
// CDdx::ErrorDisplayDevice(nModeSwitch); // test and TRACE result
// despite the other lines of code this next line is neccesary to wake the video projector
dmSecondary = dmPrimary;
dmSecondary.dmFields = DM_POSITION | DM_PELSWIDTH | DM_PELSHEIGHT;
dmSecondary.dmPosition.x = dmPrimary.dmPelsWidth + 1;
dmSecondary.dmPosition.y = 0;
dmSecondary.dmPelsWidth = dmPrimary.dmPelsWidth; // resize the primary display to match the secondary display
dmSecondary.dmPelsHeight = dmPrimary.dmPelsHeight; // resize the primary display to match the secondary display
nModeSwitch = ChangeDisplaySettingsEx (szSecondaryDisplay, (DEVMODE*)&dmSecondary, NULL, (CDS_UPDATEREGISTRY | CDS_NORESET), NULL);
// CDdx::ErrorDisplayDevice(nModeSwitch); // test and TRACE result
// load DISPLAY3 monitor information
if (!EnumDisplaySettings(szThirdDisplay, ENUM_CURRENT_SETTINGS, (DEVMODE*)&dmThird))
{
TRACE("EnumDisplaySettings unable to enumerate third display display\n");
}
else
{
dmThird.dmPelsWidth = dmSecondary.dmPelsWidth; // resize the primary display to match the secondary display
dmThird.dmPelsHeight = dmSecondary.dmPelsHeight; // resize the primary display to match the secondary display
dmThird.dmPosition.x = -dmThird.dmPelsWidth; // set DISPLAY3 as the third display
dmPrimary.dmPosition.y = 0; // set DISPLAY1 as the third display
// set DISPLAY3 as third display (-dmThird.dmPelsWidth)
nModeSwitch = ChangeDisplaySettingsEx (szThirdDisplay, (DEVMODE*)&dmThird, NULL, (CDS_UPDATEREGISTRY | CDS_NORESET), NULL);
// CDdx::ErrorDisplayDevice(nModeSwitch); // test and TRACE result
}
// really important line makes the whole thing happen
nModeSwitch = ChangeDisplaySettingsEx (NULL, NULL, NULL, 0, NULL);
// CDdx::ErrorDisplayDevice(nModeSwitch); // test and TRACE result
}
void AppFrame::CloneExternalDisplay()
{
int nModeSwitch = NULL;
DEVMODE dmPrimary, dmSecondary, dmThird;
#define szPrimaryDisplay TEXT( "\\\\.\\DISPLAY1" )
#define szSecondaryDisplay TEXT( "\\\\.\\DISPLAY2" )
#define szThirdDisplay TEXT( "\\\\.\\DISPLAY3" )
ZeroMemory( &dmPrimary, sizeof(dmPrimary) );
dmPrimary.dmSize = sizeof(dmPrimary);
ZeroMemory( &dmSecondary, sizeof(dmSecondary) );
dmSecondary.dmSize = sizeof(dmSecondary);
ZeroMemory( &dmThird, sizeof(dmThird) );
// load DISPLAY1 monitor information
if (!EnumDisplaySettings(szPrimaryDisplay, ENUM_CURRENT_SETTINGS, (DEVMODE*)&dmPrimary))
{
TRACE("EnumDisplaySettings unable to enumerate primary display\n");
return;
}
if (!EnumDisplaySettingsEx(szSecondaryDisplay, ENUM_REGISTRY_SETTINGS, (DEVMODE*)&dmSecondary, 0))
TRACE("EnumDisplaySettings unable to enumerate secondary display display\n");
dmPrimary.dmFields = DM_POSITION;
dmPrimary.dmPosition.x = 0; // set DISPLAY1 as the primary display
dmPrimary.dmPosition.y = 0; // set DISPLAY1 as the primary display
// set DISPLAY1 as primary display (dmPosition.x = 0)
nModeSwitch = ChangeDisplaySettingsEx (szPrimaryDisplay, (DEVMODE*)&dmPrimary, NULL, (CDS_UPDATEREGISTRY | CDS_NORESET), NULL);
// CDdx::ErrorDisplayDevice(nModeSwitch); // test and TRACE result
// this should disable display
dmSecondary.dmFields = DM_PELSWIDTH|DM_PELSHEIGHT;
dmSecondary.dmPelsWidth = 0; //dmPrimary.dmPelsWidth; // resize the primary display to match the secondary display
dmSecondary.dmPelsHeight = 0;//dmPrimary.dmPelsHeight; // resize the primary display to match the secondary display
// this should clone the display
dmSecondary.dmFields |= DM_POSITION;
dmSecondary.dmPosition.x = 0; // set DISPLAY1 as the primary display
dmSecondary.dmPosition.y = 0; // set DISPLAY1 as the primary display
nModeSwitch = ChangeDisplaySettingsEx (szSecondaryDisplay, (DEVMODE*)&dmSecondary, NULL, (CDS_UPDATEREGISTRY | CDS_NORESET), NULL);
// CDdx::ErrorDisplayDevice(nModeSwitch); // test and TRACE result
nModeSwitch = ChangeDisplaySettingsEx (NULL, NULL, NULL, 0, NULL); // set DISPLAY1 as the primary display
// CDdx::ErrorDisplayDevice(nModeSwitch); // test and TRACE result
}