方法一:通过检测屏幕四个角的HWND,看看他们是不是同一个窗口,但是对于一些播放器这种应用程序处于全屏的时候会出现问题,会带有一个进度条,导致四个角落所于不同的window。
BOOL IsFullModel()
{
HWND pWnd1 = NULL;
HWND pWnd2 = NULL;
HWND pWnd3 = NULL;
HWND pWnd4 = NULL;
int iCx=GetSystemMetrics(SM_CXSCREEN);
int iCy=GetSystemMetrics(SM_CYSCREEN);
POINT pt1;
pt1.x = 1;
pt1.y = 1;
POINT pt2;
pt2.x = 1;
pt2.y = iCy-1;
POINT pt3;
pt3.x = iCx-1;
pt3.y = 1;
POINT pt4;
pt4.x = iCx-1;
pt4.y = iCy-1;
pWnd1 = WindowFromPoint(pt1);
pWnd2 = WindowFromPoint(pt2);
pWnd3 = WindowFromPoint(pt3);
pWnd4 = WindowFromPoint(pt4);
if (pWnd1 == pWnd2 && pWnd2 == pWnd3 && pWnd3 == pWnd4)
{
return TRUE;
}
return FALSE;
}
同时这里也学习了一个函数:WindowFromPoint()通过屏幕上的点,来获取窗口的句柄。但是该方法好像很不好使用,好像只是在通过QQ的截屏功能、和IE的全屏模式才会触发,而使用QQ影音都不行。看来该方法只是一个思想,主要是的还是明白了原来还有WindowFromPoint这个函数。
方法二:获取屏幕的当前活动窗口GetActiveWindow(),但是要注意的是,当你点击的是桌面空白处的时候,我以为当前的窗口应该和GetDesktopWindow获得的句柄应该是一样的,因为当前的活动窗口就是Desktop,但是我发现他们居然是不一样的,然后使用方法GetWindowThreadProcessId来获取GetActiveWindow的进程ID,发现他居然是csrss的进程id,所以在后续的情况下,后来才知道,csrss.exe这个东西的窗口叫“Program Manager
CWnd *pWnd = GetActiveWindow();
CRect rect;
pWnd->GetWindowRect(&rect);
CString str;
str.Format("width = %d, height=%d", rect.Width(), rect.Height());
CRect fullRect;
CWnd *pFullWnd = ();
pFullWnd->GetWindowRect(fullRect);
DWORD foreProcessId;
DWORD deskProcessId;
::GetWindowThreadProcessId(pWnd->m_hWnd, &foreProcessId);
::GetWindowThreadProcessId(pFullWnd->m_hWnd, &deskProcessId);
char pName[100] ="";
pWnd->GetWindowText(pName , 100);
if (rect.Width() == fullRect.Width() && rect.Height() == fullRect.Height() && foreProcessId != deskProcessId && strcmp("Program Manager", pName) != 0)
{
MessageBox("有东西全屏了");
}”
从上面的代码可以看出,这个程序有个bug,也就是,如果由用户将自己的程序的窗口名字设置为:“Program Manager”,我们永远不知道这个窗口是不是全屏。
方法三:这个也是我最终采用的方法。
(1)在MFC的情况:
这里是一个简单的dlg窗口程序, 在
在头文件中定义
#define UM_APPBARID WM_USER + 100
在
BEGIN_MESSAGE_MAP(CGetWindowFullDlg, CDialog)
ON_MESSAGE(UM_APPBARID, OnMyMessage)//添加的其中UM_APPBARID是自己定义的事件
END_MESSAGE_MAP()
下面是非常重要的:
APPBARDATA m_abd;
memset(&m_abd, 0, sizeof(APPBARDATA));
m_abd.cbSize = sizeof(APPBARDATA);
m_abd.hWnd = this->m_hWnd;
m_abd.uCallbackMessage = UM_APPBARID;
SHAppBarMessage(ABM_NEW, &m_abd);
这个地方的作用就是安装全屏消息,这样,如果有窗口全屏的话,explorer.exe广播的消息就可以接受得到。
最后就是回调的相应函数:
ABN_FULLSCREENAPP这个东西是在这个头文件中#include "Shellapi.h"为2
LRESULT CGetWindowFullDlg::OnMyMessage(WPARAM wParam, LPARAM lParam)
{
switch (wParam)
{
case ABN_FULLSCREENAPP:
{
if (lParam == 1)
{
MessageBox("全屏");
}
if (lParam ==0)
{
// MessageBox("非全屏");
}
}
break;
}
return 0;
}
(2)Win32的情况:
使用的API: SHAppBarMessage (原型如下:)
WINSHELLAPI UINT APIENTRY SHAppBarMessage( DWORD dwMessage, PAPPBARDATA pData);
这个API可以向系统发送一个appbar message(也就是dwMessage,有很多消息,可以查阅MSDN),然后系统通过pData返回你想知道的信息,这里我们主要用这个API来注册一个新的appbar。这里还需要关注的是APPBARDATA这个结构体。
检测全屏的具体实现代码如下:
APPBARDATA abd;
memset(&abd, 0, sizeof(abd));
// Specify the structure size and handle to the appbar.
abd.cbSize = sizeof(APPBARDATA);
abd.hWnd = hwnd; // 这里的hwnd 是你要进行消息处理的窗体wnd
abd.uCallbackMessage = MSG_APPBAR_MSGID;
!::SHAppBarMessage(ABM_NEW, &abd);
注意MSG_APPBAR_MSGID这个,这是你自己定义的消息ID,当有全屏创建或者取消的时候,会给句柄为hwndAccessBar的窗口发送消息ID为MSG_APPBAR_MSGID的消息,具体到全屏消息,此时WPARAM为ABN_FULLSCREENAPP,而LPARAM则能够判断当前是有窗口全屏了还是有窗口取消全屏了,(BOOL) lParam为TRUE表示有窗口全屏了,而(BOOL) lParam为FALSE则表示有窗口取消全屏状态了。代码如下:
LRESULT WindowProc(UINT msg, WPARAM wp, LPARAM lp){
if (MSG_APPBAR_MSGID == msg)
{
switch((UINT)wp)
{
case ABN_FULLSCREENAPP:
{
if (TRUE == (BOOL)lp)
{
TRACE(TEXT("一个窗口全屏了\n"));
}
else
{
TRACE(TEXT("一个窗口取消全屏了\n"));
}
}
break;
default:
break;
}
}
return CSubclassWnd::WindowProc(msg, wp, lp);
}
上面给出的是怎么装载添加这样的shell监听,如何卸载呢?
下面是装载的:
APPBARDATA m_abd;
memset(&m_abd, 0, sizeof(APPBARDATA));
m_abd.cbSize = sizeof(APPBARDATA);
m_abd.hWnd = this->m_hWnd;
m_abd.uCallbackMessage = UM_APPBARID;
SHAppBarMessage(ABM_NEW, &m_abd);
卸载的是这样的:
APPBARDATA abd;
memset(&abd, 0, sizeof(abd));
// Specify the structure size and handle to the appbar.
abd.cbSize = sizeof(APPBARDATA);
abd.hWnd = GetHWND();
abd.uCallbackMessage = MSG_APPBAR_MSGID;
::SHAppBarMessage(ABM_REMOVE, &abd);//其实就是第一个参数从ABM_NEW改为ABM_REMOVE而已,实现卸载的功能