需要实时在桌面DC上绘制,但是在绘制前如何刷新前面绘制的残留

Nirvana__ 2013-08-26 10:08:37
最近在项目中要用到桌面共享功能,在共享了一个桌面上的任意一个程序后,需要在该程序的窗口四周绘制一个红色矩形边框,让用户知道他当前正在共享红色矩形内的程序,类似于Skype的桌面共享程序。
我选择在桌面DC上绘制,通过定时器控制。代码如下,但是遇到一个问题,在重新绘制新的边框之前,老的边框还残留在上面。试了几种方法都没有能让桌面重绘,
::SHChangeNotify( SHCNE_ASSOCCHANGED , SHCNF_IDLIST | SHCNF_FLUSH, 0, 0); 

可能刷掉,但是桌面闪动太厉害。请问大家有没有什么好的方法刷新一下桌面?


void CShareWindowSolidDlg::OnTest()
{
GetDesktopWindow()->Invalidate(false);
GetDesktopWindow()->UpdateWindow();

//::PostMessage( GetDesktopWindow()->GetSafeHwnd(),WM_ERASEBKGND,NULL,NULL);
//::PostMessage(GetDesktopWindow()->GetSafeHwnd(),WM_PAINT,NULL,NULL);
//::SHChangeNotify( SHCNE_ASSOCCHANGED , SHCNF_IDLIST | SHCNF_FLUSH, 0, 0);
CRect rcWnd;
this->GetWindowRect( &rcWnd );
//CDC* pWndDC = m_pWnd->GetWindowDC();
HDC hDesk = ::GetDC( NULL );
CDC* pWndDC = CDC::FromHandle(hDesk );

CPen pen( PS_SOLID,5, RGB(255, 0, 0));
pWndDC->SelectObject( &pen );

//pWndDC->DrawEdge( rcWnd, BDR_RAISEDINNER|BDR_RAISEDOUTER, BF_RECT );
pWndDC->MoveTo( CPoint(rcWnd.left - 6, rcWnd.top - 6 ) );
pWndDC->LineTo( CPoint(rcWnd.right + 6, rcWnd.top - 6 ) );
// 此处只绘制一条直线实验
::ReleaseDC( GetDesktopWindow()->m_hWnd ,hDesk );
}


void CShareWindowSolidDlg::OnBnClickedOk()
{
SetWindowText( _T("ShareWindow") );
HWND hWnd = ::FindWindow( _T(""), _T("ShareWindow") );

m_pWnd = CWnd::FromHandle( this->GetSafeHwnd() );
SetTimer( 1, 100, NULL );
}

void CShareWindowSolidDlg::OnTimer( UINT_PTR nIDEvent )
{
OnTest();
}

...全文
259 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
向立天 2013-09-27
  • 打赏
  • 举报
回复
您好 我是本版版主 此帖已多日无人关注 请您及时结帖 如您认为问题没有解决可按无满意结帖处理 另外本版设置了疑难问题汇总帖 并已在版面置顶 相关规定其帖子中有说明 您可以根据规定提交您帖子的链接 如您目前不想结帖只需回帖说明 我们会删除此结帖通知 见此回复三日内无回应 我们将强制结帖 相关规定详见界面界面版关于版主结帖工作的具体办法
schlafenhamster 2013-08-27
  • 打赏
  • 举报
回复
不要 这么 复杂。 1. 找打一个程序后。 取得 该 窗口 的 hWnd, 2. SetROP(dc,R2_XORPEN); 3. 画 边框。 4. 在 找到 另一个 窗口 时, 对 上次 窗口 再 画 一次。
Nirvana__ 2013-08-27
  • 打赏
  • 举报
回复
引用 4 楼 schlafenhamster 的回复:
“刷新一下桌面” 肯定会闪。
是的。现在我采用新的方法,我自己弄一半部分透明的窗口盖上去。但是这涉及到不到进程窗口的Z序问题,我理想的方式是将我的半透的窗口通过定时器始终置为某个特定窗口(不同的进程)的正前面或者正后面,但是我用SetWindowPos设置时显示拒绝访问,SetParent操作也没有效果,可能就是因为不同进程的原因,请问一下有没有什么好的方式能够让我的窗口放在特定窗口的正前面或者正后面呢?
schlafenhamster 2013-08-27
  • 打赏
  • 举报
回复
“刷新一下桌面” 肯定会闪。
Nirvana__ 2013-08-27
  • 打赏
  • 举报
回复
现在遇到了一个新的问题。因为是两个进程的窗口,一个是未知程序,一个是我自己的隐形窗口,但是我现在需要将隐形窗口恒放在某个特定的窗口下面(此窗口的句柄知道),用

CRect rcSomeWnd;
SomeWnd.GetWindowRect( &rcSomeWnd );
rcSomeWnd.inflatRect( 6, 6, 6, 6 );
::SetWindowPos( &myHideWnd, &SomeWnd,rcSomeWnd.left, rcSomeWnd.right, rcSomeWnd.width, rcSomeWnd.height, SWP_NOACTIVE|SWP_SHOWWINDOW ); 
但是显示SetWindowPos操作失败,GetLastError=5,权限不够。请教一下不同进程的窗口不能够用SetWindowPos操作么?有没有什么好的办法实现呢?
Nirvana__ 2013-08-27
  • 打赏
  • 举报
回复
在桌面上直接绘制的代价比较高,并且效果不太好,现在已经改为在后面创建一个隐形的窗口,边框不透明,其它的透明的方式来实现。
Nirvana__ 2013-08-27
  • 打赏
  • 举报
回复
引用 8 楼 tiger9991 的回复:
截取当前桌面DC,放在内存里面,定时器绘制在内存DC中的内容,一次显示。 这个双缓存效果应该会好很多
嗯,双缓冲在工程里应用非常广泛,但是这里可能不太符合当前的需求。也有可以是共享某个程序的窗口
Nirvana__ 2013-08-27
  • 打赏
  • 举报
回复
决定采用6L的方法。但是因为移动桌面区域外的问题,所以采用R2_XORPEN的配合定时器的方式。而后切换窗口时,向原来的窗口发送WM_SIZE消息,能够让他自己重绘一下(发送WM_PAINT和WM_ERASEBKGND均没有效果)。感觉自己真是化神奇为腐朽,不过暂时没有方法,如果其他人有更好的方式,麻烦交流一下。
傻X 2013-08-27
  • 打赏
  • 举报
回复
截取当前桌面DC,放在内存里面,定时器绘制在内存DC中的内容,一次显示。 这个双缓存效果应该会好很多
Nirvana__ 2013-08-27
  • 打赏
  • 举报
回复
引用 6 楼 schlafenhamster 的回复:
不要 这么 复杂。 1. 找打一个程序后。 取得 该 窗口 的 hWnd, 2. SetROP(dc,R2_XORPEN); 3. 画 边框。 4. 在 找到 另一个 窗口 时, 对 上次 窗口 再 画 一次。
试了下你的方法,确实是个很好的思路,效果也很好,惟一的缺陷是把程序的窗口移动桌面区域外,会引起它自己的部分重绘,再次绘制时有部分是绘制的,有一部分没有绘制。
zc1821 2013-08-26
  • 打赏
  • 举报
回复
INvalidate或者REDRAW

15,979

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 界面
社区管理员
  • 界面
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧