VC6.0 怎么释放资源

VC6.0 怎么释放资源,第1张

一、概述

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。希望通过此文能增进与大家交流。

仅供参考,请自借鉴

希望对您有帮助

因为 preSt = st // 更新完毕后记录前一次的状态 return 0

这一行 把return 0 注释掉了 导致 顺寻进入case WM_CHAR DestroyWindow 销毁窗口。。。。

请在“状态”后面敲个回车

根据我的使用经验,挂钟后有三个按扭,SET.WAVE,RESET.一,双手同时按住前两个纽,使秒针转到十点钟方向,再单第一个纽到你需要的正常的北京时间即可,这时的挂钟就是一个普通挂钟因为关闭了受信电波,反之双手同时按住前两个纽,使秒针转到二点钟方向即可恢复原来的功能.


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/yw/11748614.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-18
下一篇2023-05-18

发表评论

登录后才能评论

评论列表(0条)

    保存