VC6.0 怎么释放资源

一、概述

GDI+的应用使得平面图形图象编程变的更加容易,本文以一个基于对话框的时钟程序为例,在VC6.0中调用*.png图片实现半透明渐变窗口,该程序实现了指针式和数字式两种时钟显示方式。窗口实现了半透明渐变窗口、窗口拖动无移动矩形框、隐藏了任务栏窗体按钮等。

效果图如下:

图一?程序执行后与WindowXP桌面背景效果图

二、准备工作

1、图片资源准备工作。首先在Photoshop中编辑好时钟的背景、时针、分针以及数字时钟显示方式的所有图片,如下图:将这些图片保存成为带透明通道的.png格式(GDI+调用显示时能够透明调背景)。这样程序中图片资源就准备好了。

2、下面开始做好在VC6.0下展开此项工作的基本准备工作。

(1)、下载gdiplus?forVC6.0的SDK,(总***两兆多)

(2)、在C盘建立文件夹“GDI+”将开发包拷贝在里面,亦即建立如下路径,以便例子代码顺利编译(当然你可以放到任意你喜欢的地方,只要在你的Project中正确包含路径即可!)。

C:\GDI+\Includes

C:\GDI+\Lib

C:\GDI+\gdiplus.dll

(3)在stdAfx.h中添加对GDI+环境的设置

#define?UNICODE

#ifndef?ULONG_PTR

#define?ULONG_PTR?unsigned?long*

#endif

#include?"c:\gdi+\includes\gdiplus.h"?////请修改为你的头文件路径

using?namespace?Gdiplus;?

#pragma?comment(lib,?"c:\\gdi+\\lib\\gdiplus.lib")?////请修改为你的.lib文件路径

(4)在GDIPClock.cpp中编辑app的InitInstance()中添加如下代码进行GDI+的初始化工作

GdiplusStartupInput?gdiplusStartupInput;

ULONG_PTR?gdiplusToken;

GdiplusStartup(&gdiplusToken,?&gdiplusStartupInput,?NULL);

......

//在对话框程序结束后

//关闭gdiplus的环境

GdiplusShutdown(gdiplusToken);

三、程序的实现全过程

1、建立一个基于对话框的Project,这里的名称为GDIPClock

2、在GDIPClockDlg.h中定义所有类成员变量,包括所有图片的指针和图片的长宽尺寸信息。

Image?*m_pImageClock;

Image?*m_pImageClock1;

Image?*m_pImageHHour;

Image?*m_pImageHMinu;

Image?*m_pImageHSec;

Image?*m_pImageNum;

int?m_BakWidth?,?m_BakHeight?;

int?m_HourWidth,?m_HourHeight;

int?m_MinuWidth?,?m_MinuHeight;

int?m_SecWidth?,?m_SecHeight?;

HINSTANCE?hFuncInst?;

Typedef?BOOL?(WINAPI*MYFUNC)(HWND,HDC,POINT*,SIZE*,HDC,POINT*,

COLORREF,BLENDFUNCTION*,DWORD);?

MYFUNC?UpdateLayeredWindow;

在这一步中需要特别说明的是,在创建透明窗口式需要调用一个Windows?API函数UpdateLayeredWindow(),该函数在.net以上的版本的SDK中有申明,但是在VC6.0下要调用要么下载200多兆的高版本SDK,要么从动态链接库“User32.dll”中调用,这里选择从“User32.dll”中调用。以上定义中后三项就是为此作准备的。?

3、在对话框的OnCreate()中添加如下代码:对2的函数和成员变量进行初始化!(其中ImageFromIDResource()函数为从资源中载入Png图像的一个方法!)

int?CGDIPClockDlg::OnCreate(LPCREATESTRUCT?lpCreateStruct)?

{

if?(CDialog::OnCreate(lpCreateStruct)?==?-1)

return?-1;

hFuncInst?=?LoadLibrary("User32.DLL");?

BOOL?bRet=FALSE;

if(hFuncInst)?

UpdateLayeredWindow=(MYFUNC)GetProcAddress(hFuncInst,?"UpdateLayeredWindow");

else

{

AfxMessageBox("User32.dll?ERROR!");

exit(0);

}

//初始化gdiplus的环境

//?Initialize?GDI+.

m_Blend.BlendOp=0;?//theonlyBlendOpdefinedinWindows2000

m_Blend.BlendFlags=0;?//nothingelseisspecial...

m_Blend.AlphaFormat=1;?//...

m_Blend.SourceConstantAlpha=255;//AC_SRC_ALPHA

//?png图片添加到资源中了在"PNG"下:所以这里可以从资源中调用,

//?这里Image没有提供字节调用资源中图像的函数,

//?ImageFromIDResource()是通过资源名称"PNG"和资源ID号将图像

//?的Image指针传递给指针应用。来完成的。

ImageFromIDResource(IDR_PNGBAK1,"PNG",m_pImageClock1);

ImageFromIDResource(IDR_PNGNUM,"PNG",m_pImageNum);

ImageFromIDResource(IDR_PNGBAK,"PNG",m_pImageClock);

ImageFromIDResource(IDR_PNGHOUR,"PNG",m_pImageHHour);

ImageFromIDResource(IDR_PNGMIN,"PNG",m_pImageHMinu);

ImageFromIDResource(IDR_PNGSEC,"PNG",m_pImageHSec);

m_BakWidth?=m_pImageClock->GetWidth();

m_BakHeight?=m_pImageClock->GetHeight();

m_HourWidth?=m_pImageHHour->GetWidth();

m_HourHeight=m_pImageHHour->GetHeight();

m_MinuWidth?=m_pImageHMinu->GetWidth();

m_MinuHeight=m_pImageHMinu->GetHeight();

m_SecWidth?=m_pImageHSec->GetWidth();

m_SecHeight?=m_pImageHSec->GetHeight();

::SetWindowPos(m_hWnd,?HWND_TOPMOST,0,0,m_BakWidth,m_BakHeight,SWP_NOSIZE|SWP_NOMOVE);

return?0;

}

4.在OnInitDialog()种添加如下代码对调用透明窗体初始化和设置时钟进行刷新,代码意义有注解:

//启动后立刻更新窗口样式为透明窗体

UpdateClockDisplay();

SetTimer(1,500,NULL);

//去除任务栏窗口对应按钮

ModifyStyleEx?(WS_EX_APPWINDOW,WS_EX_TOOLWINDOW?);

void?CGDIPClockDlg::OnTimer(UINT?nIDEvent)?

{

//?TODO:?Add?your?message?handler?code?here?and/or?call?default

UpdateClockDisplay();

CDialog::OnTimer(nIDEvent);

}

5、透明窗体创建于刷新,均调用以下函数完成,函数的参数表示整个窗体的透明度

在该函数中包括了GDI+中对Image.DrawImage()函数的集中重载方式的使用,还有在GDI+中图像变换矩阵的使用初步研究。

BOOL?CGDIPClockDlg::UpdateClockDisplay(int?Transparent)

{

HDC?hdcTemp=GetDC()->m_hDC;

m_hdcMemory=CreateCompatibleDC(hdcTemp);

HBITMAP?hBitMap=CreateCompatibleBitmap(hdcTemp,m_BakWidth,m_BakHeight);

SelectObject(m_hdcMemory,hBitMap);

if(Transparent<0||Transparent>100)?Transparent=100;

m_Blend.SourceConstantAlpha=int(Transparent*2.55);

HDC?hdcScreen=::GetDC?(m_hWnd);

RECT?rct;

GetWindowRect(&rct);

POINT?ptWinPos={rct.left,rct.top};

Graphics?graph(m_hdcMemory);

Point?points[]?=?{?Point(0,?0),?

Point(m_BakWidth,?0),?

Point(0,?m_BakHeight)

};

static?bool?bFly=false;

bFly?graph.DrawImage(m_pImageClock,?points,?3):?graph.DrawImage(m_pImageClock1,?points,?3);?

bFly=!bFly;

int?OxyX=140;//m_BakWidth/2+8;

int?OxyY=90;//m_BakHeight/2+10;

SYSTEMTIME?SystemTime;//?address?of?system?time?structure

GetLocalTime(&SystemTime);

//?定义一个单位矩阵,坐标原点在表盘中央

Matrix?matrixH(1,0,0,1,OxyX,OxyY);?

//?时针旋转的角度度

matrixH.Rotate(SystemTime.wHour*30+SystemTime.wMinute/2.0-180);?

Point?pointsH[]?=?{?Point(0,?0),Point(m_HourWidth,?0),Point(0,?m_HourHeight)};

matrixH.Translate(-m_HourWidth/2,-m_HourHeight/6);

//?用该矩阵转换points

matrixH.TransformPoints(?pointsH,?3);?

graph.DrawImage?(m_pImageHHour,pointsH,?3);

//?定义一个单位矩阵,坐标原点在表盘中央

Matrix?matrixM(1,0,0,1,OxyX,OxyY);?

//?分针旋转的角度度

matrixM.Rotate(SystemTime.wMinute*6-180);?

Point?pointsM[]?=?{?Point(0,?0),Point(m_MinuWidth,?0),Point(0,?m_MinuHeight)};

matrixM.Translate(-m_MinuWidth/2,-m_MinuHeight/6);

//?用该矩阵转换pointsM

matrixM.TransformPoints(?pointsM,?3);?

graph.DrawImage?(m_pImageHMinu,pointsM,?3);

//?定义一个单位矩阵,坐标原点在表盘中央

Matrix?matrix(1,0,0,1,OxyX,OxyY);?

//?秒针旋转的角度度

matrix.Rotate(SystemTime.wSecond*6-180);?

Point?pointsS[]?=?{?Point(0,?0),Point(?m_SecWidth,0),Point(0,m_SecHeight?)};

matrix.Translate(-m_SecWidth/2,-m_SecHeight/7);

//?用该矩阵转换pointsS

matrix.TransformPoints(?pointsS,?3);?

graph.DrawImage?(m_pImageHSec,pointsS,?3);

//HH:MM:SS

//该函数从m_pImageClock中剪切指定rect中的像素draw到指定位置

graph.DrawImage(m_pImageNum,0,?0,?14*(SystemTime.wHour/10),?0,14,23,UnitPixel);?

//该函数从m_pImageClock中剪切指定rect中的像素draw到指定位置

graph.DrawImage(m_pImageNum,20,0,?14*(SystemTime.wHour%10),?0,14,23,UnitPixel);?

//该函数从m_pImageClock中剪切指定rect中的像素draw到指定位置

graph.DrawImage(m_pImageNum,20*2,0,?140,?0,14,23,UnitPixel);?

//该函数从m_pImageClock中剪切指定rect中的像素draw到指定位置

graph.DrawImage(m_pImageNum,20*3,?0,?14*(SystemTime.wMinute/10),?0,14,23,UnitPixel);?

//该函数从m_pImageClock中剪切指定rect中的像素draw到指定位置

graph.DrawImage(m_pImageNum,20*4,0,?14*(SystemTime.wMinute%10),?0,14,23,UnitPixel);?

//该函数从m_pImageClock中剪切指定rect中的像素draw到指定位置

graph.DrawImage(m_pImageNum,20*5,0,?140,?0,14,23,UnitPixel);?

//该函数从m_pImageClock中剪切指定rect中的像素draw到指定位置

graph.DrawImage(m_pImageNum,20*6,?0,?14*(SystemTime.wSecond/10),?0,14,23,UnitPixel);?

//该函数从m_pImageClock中剪切指定rect中的像素draw到指定位置

graph.DrawImage(m_pImageNum,20*7,0,?14*(SystemTime.wSecond%10),?0,14,23,UnitPixel);?

SIZE?sizeWindow={m_BakWidth,m_BakHeight};

POINT?ptSrc={0,0};

DWORD?dwExStyle=GetWindowLong(m_hWnd,GWL_EXSTYLE);

if((dwExStyle&0x80000)!=0x80000)

SetWindowLong(m_hWnd,GWL_EXSTYLE,dwExStyle^0x80000);

BOOL?bRet=FALSE;

bRet=?UpdateLayeredWindow(?m_hWnd,hdcScreen,&ptWinPos,

&sizeWindow,m_hdcMemory,&ptSrc,0,&m_Blend,2);

graph.ReleaseHDC(m_hdcMemory);

::ReleaseDC(m_hWnd,hdcScreen);

hdcScreen=NULL;

::ReleaseDC(m_hWnd,hdcTemp);

hdcTemp=NULL;

DeleteObject(hBitMap);

DeleteDC(m_hdcMemory);

m_hdcMemory=NULL;

return?bRet;

}

BOOL?CGDIPClockDlg::ImageFromIDResource(UINT?nID,?LPCTSTR?sTR,Image?*?&pImg)

{

HINSTANCE?hInst?=?AfxGetResourceHandle();

HRSRC?hRsrc?=?::FindResource?(hInst,MAKEINTRESOURCE(nID),sTR);?//?type

if?(!hRsrc)

return?FALSE;

//?load?resource?into?memory

DWORD?len?=?SizeofResource(hInst,?hRsrc);

BYTE*?lpRsrc?=?(BYTE*)LoadResource(hInst,?hRsrc);

if?(!lpRsrc)

return?FALSE;

//?Allocate?global?memory?on?which?to?create?stream

HGLOBAL?m_hMem?=?GlobalAlloc(GMEM_FIXED,?len);

BYTE*?pmem?=?(BYTE*)GlobalLock(m_hMem);

memcpy(pmem,lpRsrc,len);

IStream*?pstm;

CreateStreamOnHGlobal(m_hMem,FALSE,&pstm);

//?load?from?stream

pImg=Gdiplus::Image::FromStream(pstm);

//?free/release?stuff

GlobalUnlock(m_hMem);

pstm->Release();

FreeResource(lpRsrc);

}

void?CGDIPClockDlg::OnLButtonDown(UINT?nFlags,?CPoint?point)?

{

//禁止显示移动矩形窗体框

::SystemParametersInfo(SPI_SETDRAGFULLWINDOWS,TRUE,NULL,0);

//非标题栏移动整个窗口

SendMessage(WM_SYSCOMMAND,0xF012,0);?

//?PostMessage(WM_NCLBUTTONDOWN,HTCAPTION,MAKELPARAM(point.x,point.y));?

CDialog::OnLButtonDown(nFlags,?point);

}

详细实现过程请参考源代码!

四、结束语

编写该程序的主要动力来自于对GDI+图像、图形功能的好奇,网上好多例子和文章都是关于C#或delphi等语言的。本人一直以来习惯于使用VC6.0。希望通过此文能增进与大家交流。

仅供参考,请自借鉴

希望对您有帮助