纯代码编写 skin 关于 WM_NCPAINT ,WM_NCCALCSIZE 的有关问题请问

纯代码编写 skin 关于 WM_NCPAINT ,WM_NCCALCSIZE 的问题请教!
我现在只是想做一个 skin 的 Form 出来。
我的做方法 得到窗体的 windowProc 指针,把它指向我的新 windowProc,再在我的 WindowProc 里拦 WM_NCxxx 消息,像对本窗口的边框 与栏题栏进行自画。
 
现在的问题有:
1. 诡异的 WM_NCCALCSIZE. 这个消息在 MSDN 上也说的不是很清楚。
  它在 wParam为真或假时 lParam 分别指向的内容不一样。而 MDSN 上也不是说的太说细,测试了很久也不是很明白,找到的一些代码只是说在 wParam 为真时,第一个矩形为窗口的位置,直接把它改小就可以了。但问题是第一次执行程序,居然不触发 WM_NCCALCSIZE 事件。但拉动窗口大小时,它又会触发。
 
2. 同样诡异的 WM_NCPAINT 与 GetDcEx
  这个消息在绘标题栏时触发。wParam 为 NC 区域的 HRGN (MSDN上说的). 但我的测试用 MSDN 上的代码基本就是不行,MSDN 上是用 GetDcEx 来得到 NC 区域的 DC.但我得到的 HDC 基本就不能绘画。最后用笨方法,用 GetWindowDc 得到窗口的 HDC,但手动算出 NC 区域的 HRGN 再 selectObject 把这个 HRGN 放到 HDC 里。
 
3. 更加诡异的 WM_NCHITTEST
 本来以我的想法,在 WM_NCHITTEST 里返回指定的值如 HTCLOSE,表示鼠标在 close 按钮上。我就这样测试,不窗鼠标在哪里,我都返回 HTCLOSE,这时我随便按那里,都是 close 按钮被按下了。但我松开鼠标,这时窗口居然没有被关闭。好呀,我在 WM_NCLBUTTONUP 里wparam = HTCLOSE 时,我 PostMessage( WM_SYSCOMMAND ,SC_CLOSE)。这样居然有时可能,有时又不行。
 
4. 效率如何提高?
  现在我没用双缓冲。每次都直接在窗口HDC 上画,但效果很低,特别时把一部分窗口移到桌面以外,慢慢向里拉时,CPU 占用很高。很时显停止状。想做成双缓冲,但一时也想不到如何做。在窗口大小变化时,内存 DC 如何处理?也跟着变?然后再画出来?这样我想效率也不会提高。
 
5. 边角不规则如何处理?
  现在要求窗口边角是圆边矩形,那还好做点,用 SetWindowRgn 来处理。但对不是很好描述的奇怪点的窗口呢?又要如何处理?我知道 vclskin 可以做到。
 
 
以上几点疑问,希望能在你有空的时间,给我一点指点,多谢了。
 


------解决方案--------------------
关注...
------解决方案--------------------
自己画不是那么容易的。何苦呢。。。。。。
------解决方案--------------------
不规则窗口,一般是要绘制一张窗口形状的图片,逐行扫描该图片,去除透明色,作为高度为1的矩形,CreateRectRgn,然后CombineRgn把每一行的这些RGN合并起来,就得到了整个不规则形状的RGN.
------解决方案--------------------
up
------解决方案--------------------
http://www.vckbase.com/document/viewdoc/?id=529
和你的思路差不多,用了hook,好像用了双缓冲,没仔细看。我觉得速度还可以,不知是否达到lz的要求。
------解决方案--------------------
没弄过。帮你顶一下了
------解决方案--------------------
感觉很像skin++的设计思路,可下一份skin++代码研究下,其实主要是两部分,1 消息分配 2 绘制
------解决方案--------------------
GDI+中也可以用Bitblt
我这下了Skin 5.0代码,你在网上找,如果还找不到就留个邮箱
------解决方案--------------------
up
------解决方案--------------------
我不发你邮箱了,这个作者真的很厚道,不支持说不过去,csdn应该不少人看过的,感谢作者分享
baidu -> skin+5.0.rar
http://topic.csdn.net/t/20060926/12/5048699.html
------解决方案--------------------
我现在对您的问题一一作个回答。

1. 诡异的 WM_NCCALCSIZE. 这个消息在 MSDN 上也说的不是很清楚。
它在 wParam为真或假时 lParam 分别指向的内容不一样。而 MDSN 上也不是说的太说细,测试了很久也不是很明白,找到的一些代码只是说在 wParam 为真时,第一个矩形为窗口的位置,直接把它改小就可以了。但问题是第一次执行程序,居然不触发 WM_NCCALCSIZE 事件。但拉动窗口大小时,它又会触发。

答:WM_NCCALCSIZE消息就是设置窗体的客户区与非客户区的大小。下面是Skin++的相关代码,你可以参考之。

C/C++ code

LRESULT CSkinObjectBase::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
        case WM_NCCALCSIZE:
        return OnNcCalcSize((BOOL)wParam, (NCCALCSIZE_PARAMS *)lParam );
        。。。。。。。。。
        }
}

LRESULT CSkinFrameBase::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS *lpncsp)
{
    if ( bCalcValidRects )
    {
        CRect oldrect = lpncsp->rgrc[0];
        NcCalcSize(lpncsp->rgrc[0]);
        lpncsp->rgrc[1] = lpncsp->rgrc[0];
        return 0;
    }

    return Default();
}

void CSkinFrameBase::NcCalcSize(RECT& rect)
{
    if (HasCaption())
    {
        rect.left +=  m_nBorderLeftWidth;//窗体左边框的宽度
        rect.right -= m_nBorderRightWidth;//窗体右边框的宽度
        rect.top += m_nTitleHeight; //窗体标题栏的高度
        rect.bottom -= m_nBorderBottomHeight;//窗体底边框的高度
    }
        
        。。。。。。。。
}