无边框窗口阴影

在C++builder中为无边框窗口添加阴影

TShadow.h内容如下:

#ifndef __TSHADOW__
#define __TSHADOW__
#include <Forms.hpp>
#include <math.hpp>
#include <algorithm>
#include <map>
using std::min;
using std::max;

#include <gdiplus.h>
using namespace Gdiplus;
using namespace std;

class  TShadow : public TCustomForm
{
     private:
        int m_left,m_top,m_width,m_height;

        BLENDFUNCTION  m_Blend;
        ULONG_PTR m_GdiplusToken;
        Gdiplus::GdiplusStartupInput m_GdiplusStartupInput;
        HDC    m_hdcMemory;
        Gdiplus::Image *m_Image;

        //新的外部窗口过程
        void __fastcall  myWindowProc(Messages::TMessage &msg);
        //旧的窗口过程指针
        Classes::TWndMethod OldWindowProc;
        //外部窗口指针
        TForm * m_pForm;
        //外部TApplication查找主窗口
        TApplication * m_App;

     protected:
        Image * __stdcall GDIGetImageFromResource(HMODULE HInstance, char * RES_ID);
        void __stdcall    GdiDrawImageFromRes(HMODULE HInstance,char * RES_ID,int left,int top,int width,int height);
        void __fastcall   CreateParams(Controls::TCreateParams &Params);
     public:
        __fastcall TShadow(Classes::TComponent* AOwner, int Dummy);
        __fastcall ~TShadow();

        int __fastcall SetTransparent(int nTran);

        void __fastcall SetSize(int left,int top,int width,int height,TForm * AForm);

        void SetOutTForm(TForm * fm);
        void SetOutApplication(TApplication * outApp);

     __published:
        __property Width;
        __property Height;
        __property Left;
        __property Top;
        __property BorderStyle;
        __property AlphaBlend;
        __property AlphaBlendValue;
        __property Visible;

};

#endif

TShadow.cpp内容如下:

#define STRICT
#include <windows.h>
#include "TShadow.h"

using namespace std;
__fastcall TShadow::TShadow(Classes::TComponent* AOwner, int Dummy):TCustomForm(AOwner,Dummy)
{
    GdiplusStartup(&m_GdiplusToken, &m_GdiplusStartupInput, NULL);
    //
    m_Blend.BlendOp     = 0;           // the only BlendOp defined in Windows 2000
    m_Blend.BlendFlags  = 0;           // nothing else is special ...
    m_Blend.AlphaFormat = 1;           // ...
    m_Blend.SourceConstantAlpha = 255; // AC_SRC_ALPHA

    SetWindowLong(this->Handle,GWL_EXSTYLE, GetWindowLong(this->Handle,GWL_EXSTYLE) | WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_NOACTIVATE);

    long dwExStyle = GetWindowLong(this->Handle, GWL_EXSTYLE);
    dwExStyle &= ~WS_EX_TOPMOST;
    SetWindowLong(this->Handle, GWL_EXSTYLE, dwExStyle);

}
__fastcall TShadow::~TShadow()
{
    m_pForm->WindowProc = OldWindowProc;
    GdiplusShutdown(m_GdiplusToken);   //关闭GDI+
}
int __fastcall TShadow::SetTransparent(int nTran)
{
    // Use GDI+ load image
    //WideString f =lpSkinFile;
    m_Image = GDIGetImageFromResource(HInstance,"SHADOW");//Gdiplus::Image::FromFile(f.c_bstr());

    //Change Form size
    Width  = m_pForm->Width +11;//m_Image->GetWidth();
    Height = m_pForm->Height+11;//m_Image->GetHeight();

    // Create Compatible Bitmap
    HDC hdcTemp = GetDC(0);
    m_hdcMemory = CreateCompatibleDC(hdcTemp);
    HBITMAP hBitMap = CreateCompatibleBitmap(hdcTemp,Width,Height);


    SelectObject(m_hdcMemory, hBitMap);
    // Alpha Value
    if (nTran<0 || nTran >100)
        nTran = 100;
    m_Blend.SourceConstantAlpha = int(nTran * 2.55); // 1~255

    HDC hdcScreen = ::GetDC(0);
    RECT rct;
    GetWindowRect(Handle, &rct);

    POINT ptWinPos = {rct.left, rct.top};
    Gdiplus::Graphics graph(m_hdcMemory);

    graph.DrawImage(m_Image, 0, 0, Width, Height);

    SIZE sizeWindow = {this->Width, this->Height};
    POINT ptSrc = {0, 0};
	
    // Set Window style
    DWORD dwExStyle = GetWindowLong(Handle, GWL_EXSTYLE);
    if((dwExStyle & 0x80000) != 0x80000)
        SetWindowLong(Handle, GWL_EXSTYLE, dwExStyle ^ 0x80000);

    //perform the alpha blend
    BOOL bRet = UpdateLayeredWindow(Handle, hdcScreen, &ptWinPos,
                &sizeWindow, m_hdcMemory, &ptSrc, 0, &m_Blend, 2);

    graph.ReleaseHDC(m_hdcMemory);
    ReleaseDC(0, hdcScreen);
    hdcScreen = NULL;

    ReleaseDC(0, hdcTemp);
    hdcTemp = NULL;

    DeleteObject(hBitMap);

    DeleteDC(m_hdcMemory);
    m_hdcMemory = NULL;

    m_Image = NULL;
    return bRet;
}

void __fastcall TShadow::SetSize(int left ,int top,int width,int height,TForm * AForm)
{
    m_left   = left;
    m_top    = top;
    m_width  = width  + 11;
    m_height = height + 11;

    this->Left   = m_pForm->Left  -5;
    this->Top    = m_pForm->Top   -5;
    this->Width  = m_pForm->Width +11;
    this->Height = m_pForm->Height+11;

    SetTransparent(120);

    SetWindowPos(this->Handle,HWND_TOP,left-5,top-5,width+12,height+11,SWP_NOMOVE|SWP_NOSIZE);
}

void __fastcall  TShadow::myWindowProc(Messages::TMessage &msg)
{
    switch(msg.Msg)  
    {
      case WM_ERASEBKGND:  
      case WM_PAINT:
      case WM_MOVE:  
      case WM_ACTIVATE:  
      case WM_NCACTIVATE:  
          {  
              if (::IsWindowVisible(this->Handle))   
              {   
                  this->Left   = m_pForm->Left  - 5;
                  this->Top    = m_pForm->Top   - 5;
                  this->Width  = m_pForm->Width + 11;
                  this->Height = m_pForm->Height+ 11;
              }  
              break;  
          }  
      case WM_DESTROY:  
          {  
              // Destroy the shadow window.  
              //this->Hide();
              break;
          }  
      case WM_NCDESTROY:  
          {  
              // Remove shadow window from map.
              //this->Hide();
              break;
          }
      case WM_CLOSE:
          {
             if(this != m_App->MainForm)
               this->Hide();
             else
               this->Close();

             break;
          }
      case WM_SYSCOMMAND:
          {
             if(msg.WParam == 0xf020)
             {
                ShowWindow(this->Handle,SW_HIDE);
             }
             break;
          }
      case WM_SHOWWINDOW:  
          {  
              // the window is being hidden  
              if (!msg.WParam)
              {  
                  ShowWindow(this->Handle,SW_HIDE);
              }  
              else  
              {
                  SetSize(m_left,m_top,m_width,m_height,m_pForm);
                  ShowWindow(this->Handle,SW_SHOW);
                  m_pForm->BringToFront();
              }
              break;  
          }  
      default:  
          {  
              break;  
          }
    }

    OldWindowProc(msg);
}

void TShadow::SetOutTForm(TForm * fm)
{
    m_pForm        = fm;
    OldWindowProc  = fm->WindowProc;
    fm->WindowProc = myWindowProc;
}

//从资源中加载图片
Image * __stdcall TShadow::GDIGetImageFromResource(HMODULE HInstance, char * RES_ID)
{
    //LPCTSTR pResourceName = MAKEINTRESOURCE(nResourceID);
    //HMODULE hInstance = ahInstance;
    HRSRC hResource = FindResource(HInstance,_T(RES_ID),RT_RCDATA);
    if(!hResource)
    {
            Application->MessageBox("未找到资源","提示",0);
            return NULL;
    }

    //取得资源大小
    DWORD dwResourceSize = SizeofResource(HInstance, hResource);
    if(!dwResourceSize)
    {
            return NULL;
    }

    const void* pResourceData = LockResource(LoadResource(HInstance, hResource));

    if(!pResourceData)
    {
            return NULL;
    }

    HGLOBAL hResourceBuffer = GlobalAlloc(GMEM_MOVEABLE, dwResourceSize);
    if(!hResourceBuffer)
    {
            GlobalFree(hResourceBuffer);
            return NULL;
    }

    void* pResourceBuffer = GlobalLock(hResourceBuffer);
    if(!pResourceBuffer)
    {
            GlobalUnlock(hResourceBuffer);
            GlobalFree(hResourceBuffer);
            return NULL;
    }

    //把资源拷贝到分配的内存中
    CopyMemory(pResourceBuffer, pResourceData, dwResourceSize);

    IStream* pIStream = NULL;
    if(CreateStreamOnHGlobal(hResourceBuffer, FALSE, &pIStream)==S_OK)
    {
        Image *pImage = Gdiplus::Image::FromStream(pIStream);

        pIStream->Release();

        GlobalUnlock(hResourceBuffer);

        GlobalFree(hResourceBuffer);

        return pImage;
    }

    return NULL;
}

//从资源中显示图片
//资源类型:Icon,Cursor,Bitmap,String,Accelerators,Menu,Dialog,RCData,Version info
void __stdcall  TShadow::GdiDrawImageFromRes(HMODULE HInstance,char * RES_ID,int left,int top,int width,int height)
{
   Image *img = GDIGetImageFromResource(HInstance,RES_ID);
}
void TShadow::SetOutApplication(TApplication * outApp)
{
    m_App = outApp;
}

void __fastcall TShadow::CreateParams(Controls::TCreateParams &Params)
{
     TCustomForm::CreateParams(Params);
     Params.WndParent = GetDesktopWindow();
}

在无边框窗口的构造函数中,调用如下:

#include <vcl.h>
#include <windows.h>
#include "TShadow.h"
__fastcall TfrmShowMessage::TfrmShowMessage(TComponent* Owner)
        : TForm(Owner)
{
    m_pShadow = new TShadow(Application,3);
    
    m_pShadow->SetOutTForm(this);
    m_pShadow->SetOutApplication(Application);
    m_pShadow->SetSize(this->Left,this->Top,this->Width,this->Height,this);
}

在编译的时候,工程中须包含gdiplus.lib,同时还要包含一个资源文件,此资源文件中包含一幅有阴影的png图片.rc文件内容如下:

SHADOW  RCDATA test.png

.rc文件编译成.res如下:

brcc32 -32 shadow.rc  //在记事本中添加此行内容,并保为.bat为扩展名的文件,然后执行,产生相应的res文件,将此res添加到工程中