这几天需要支持多个显示器的问题,上网上找了很多,也查看了msdn,基本上算是成功了,但是还有点问题。
下面先把代码贴出来,非常简单,就一个函数:
#if(WINVER < 0x0500)
typedef BOOL (CALLBACK *pEnumDisplayDevices)( PVOID Unused, DWORD iDevNum, PDISPLAY_DEVICEA lpDisplayDevice, DWORD dwFlags);
#endif /* WINVER < 0x0500 */
/*
获取显示器个数。
如果获取的个数出现异常是0时,就直接附值为1,表示至少有一个显示器
by Ligo, 2009.9.23
*/
long CDDrawDisplay::GetMonitors()
{
long lMonitorCount = 0;
#if(WINVER < 0x0500)
pEnumDisplayDevices EnumDisplayDevices = NULL;
HINSTANCE hInstUser32 = LoadLibrary( "User32.DLL" );
if ( hInstUser32 == NULL )
return 1;
EnumDisplayDevices = (pEnumDisplayDevices)GetProcAddress( hInstUser32, "EnumDisplayDevicesA" );
if ( EnumDisplayDevices == NULL )
return 1;
#endif
DISPLAY_DEVICE stuDevice[10];
DWORD dwCounts = 0;
m_lMonitorCount = 0;
memset( stuDevice, 0, sizeof(stuDevice) );
while ( 1 )
{
stuDevice[m_lMonitorCount].cb = sizeof(DISPLAY_DEVICE);
if ( EnumDisplayDevices( NULL, dwCounts, &stuDevice[m_lMonitorCount], 0 ) == FALSE )
break;
if ( stricmp( (const char*)stuDevice[m_lMonitorCount].DeviceName, ".//DISPLAYV1" ) != 0 &&
stricmp( (const char*)stuDevice[m_lMonitorCount].DeviceName, ".//DISPLAYV2" ) != 0 &&
stricmp( (const char*)stuDevice[m_lMonitorCount].DeviceName, ".//DISPLAYV3" ) != 0 )
{
lMonitorCount++;
}
dwCounts++;
}
#if (defined(DEBUG) || defined(_DEBUG))
static long lMsg = 0;
if ( lMsg == 0 )
{
char szMsg[32];
sprintf( szMsg, "display monitor count: %d", lMonitorCount );
MessageBox( GetDesktopWindow(), szMsg, "d3d error", MB_OK | MB_ICONSTOP );
lMsg = 1;
}
#endif
#if(WINVER < 0x0500)
FreeLibrary( hInstUser32 );
hInstUser32 = NULL;
#endif
if ( lMonitorCount == 0 )
lMonitorCount = 1;
return lMonitorCount;
}
因为在我自己的实现过程中,出了一些问题,所以特写此文,以便少走弯路
主要是需要关注 #if(WINVER < 0x0500) 这个编译选项,在文档中和网上搜索出来的结果中,基本上都没有说明这个问题,所以有些人在编译时说 EnumDisplayDevices 没有定义而无法通过
在查看windows对EnumDisplayDevices()的声明发现,它的外面增加了一个编译选项:
#if(WINVER >= 0x0500)
那么在vc6中无法编译通过,在stdafx.h中加上:
#define WINVER 0x0500
后,在编译时会出现很多编译问题,包括一大堆的警告,所以还是不加这个的好
为了解决EnumDisplayDevices 没有定义的错误,这里也加上编译选项,如果是WINVER < 0x0500的话,就自己定义EnumDisplayDevices 的函数原形,并且从user32.dll中获取其地址
以上的代码还有些问题,实际上获取的是显示支持的显示器数量而不是当前的显示器数量,比如有的显卡支持两个显示器,但是一个并没有打开(将屏幕扩展到那个显示器上没有勾选),这个时候此函数获取的还是2
后面找到解决方法之后,会继续修改本贴或者跟贴来提出解决方案
-------------------------------------------------------------------------------------------------
根据第一个回复,其代码如下:
DEVMODE devMode;
memset( &devMode, 0, sizeof(devMode) );
devMode.dmSize = sizeof(devMode);
if ( EnumDisplaySettings( (const char*)stuDevice[m_lMonitorCount].DeviceName, ENUM_CURRENT_SETTINGS, &devMode ) )
{
lMonitorCount++;
}
这几行代码放到以上的while下的第二个if中,即用来替换原来的行 lMonitorCount++;
这个代码有测试过的,比如电脑上接了两个显示器,如果你选中了第二个显示器的“扩展桌面到该显示器上”选项,则此处获取到的显示器个数即是2,如果没有选中,则这里获取到的个数为1.
但是没有测试有2个显示器时,把第二个直接从电脑上拔掉的情况