一个超实用的图片加载和显示的小工具PictureEx!

来源:互联网 发布:上海学声乐 知乎 编辑:程序博客网 时间:2024/05/21 13:58

众所周知VC工程中显示BMP格式图片很容易处理,但对GIF、JPEG、ICO、PNG等图片的显示处理却很繁琐。PictureEx是一款超实用的图片显示和简单处理的小插件,极易使用。


【HPP头文件:】

//////////////////////////////////////////////////////////////////////// PictureEx.cpp: implementation of the CPictureEx class.//// Picture displaying control with support for the following formats:// GIF (including animated GIF87a and GIF89a), JPEG, BMP, WMF, ICO, CUR// // Written by Oleg Bykov (oleg_bykoff@rsdn.ru)// Copyright (c) 2001//// To use CPictureEx, follow these steps://   - place a static control on your dialog (either a text or a bitmap)//   - change its identifier to something else (e.g. IDC_MYPIC)//   - associate a CStatic with it using ClassWizard//   - in your dialog's header file replace CStatic with CPictureEx//     (don't forget to #include "PictureEx.h" and add //     PictureEx.h and PictureEx.cpp to your project)//   - call one of the overloaded CPictureEx::Load() functions somewhere//     (OnInitDialog is a good place to start)//   - if the preceding Load() succeeded call Draw()//  // You can also add the control by defining a member variable of type // CPictureEx, calling CPictureEx::Create (derived from CStatic), then // CPictureEx::Load and CPictureEx::Draw.//// By default, the control initializes its background to COLOR_3DFACE// (see CPictureEx::PrepareDC()). You can change the background by// calling CPictureEx::SetBkColor(COLORREF) after CPictureEx::Load().//// I decided to leave in the class the functions to write separate frames from // animated GIF to disk. If you want to use them, uncomment #define GIF_TRACING // and an appropriate section in CPictureEx::Load(HGLOBAL, DWORD). These functions // won't be compiled and linked to your project unless you uncomment #define GIF_TRACING,// so you don't have to worry.// // Warning: this code hasn't been subject to a heavy testing, so// use it on your own risk. The author accepts no liability for the // possible damage caused by this code.//// Version 1.0  7 Aug 2001//              Initial release//// Version 1.1  6 Sept 2001//              ATL version of the class//// Version 1.2  14 Oct 2001//              - Fixed a problem with loading GIFs from resources//                in MFC-version of the class for multi-modules apps.//                Thanks to Ruben Avila-Carretero for finding this out.////              - Got rid of waitable timer in ThreadAnimation()//                Now CPictureEx[Wnd] works in Win95 too.//                Thanks to Alex Egiazarov and Wayne King for the idea.////              - Fixed a visual glitch of using SetBkColor.//                Thanks to Kwangjin Lee for finding this out.//// Version 1.3  10 Nov 2001//              - Fixed a DC leak. One DC leaked per each UnLoad()//                (forgot to put a ReleaseDC() in the end of //                CPictureExWnd::PrepareDC() function).////              - Now it is possible to set a clipping rectangle using//                CPictureEx[Wnd]::SetPaintRect(const LPRECT) function.//                The LPRECT parameter tells the class what portion of//                a picture should it display. If the clipping rect is //                not set, the whole picture is shown.//                Thanks to Fabrice Rodriguez for the idea.////              - Added support for Stop/Draw. Now you can Stop() an//                animated GIF, then Draw() it again, it will continue//                animation from the frame it was stopped on. You can //                also know if a GIF is currently playing with the //                IsPlaying() function.//             //              - Got rid of math.h and made m_bExitThread volatile. //                Thanks to Piotr Sawicki for the suggestion.////////////////////////////////////////////////////////////////////////#if !defined(AFX_PICTUREEX_H__0EFE5DE0_7B68_4DB7_8B34_5DC634948438__INCLUDED_)#define AFX_PICTUREEX_H__0EFE5DE0_7B68_4DB7_8B34_5DC634948438__INCLUDED_#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000#include <vector>//#define GIF_TRACING  // uncomment it if you want detailed TRACEsclass CPictureEx : public CStatic{public:struct TFrame    // structure that keeps a single frame info{IPicture *m_pPicture;  // pointer to the interface used for drawingSIZE     m_frameSize;SIZE     m_frameOffset;UINT     m_nDelay;     // delay (in 1/100s of a second)UINT     m_nDisposal;  // disposal method};#pragma pack(1)   // turn byte alignment onenum GIFBlockTypes{BLOCK_UNKNOWN,BLOCK_APPEXT,BLOCK_COMMEXT,BLOCK_CONTROLEXT,BLOCK_PLAINTEXT,BLOCK_IMAGE,BLOCK_TRAILER};enum ControlExtValues // graphic control extension packed field values{GCX_PACKED_DISPOSAL,  // disposal methodGCX_PACKED_USERINPUT,GCX_PACKED_TRANSPCOLOR};enum LSDPackedValues  // logical screen descriptor packed field values{LSD_PACKED_GLOBALCT,LSD_PACKED_CRESOLUTION,LSD_PACKED_SORT,LSD_PACKED_GLOBALCTSIZE};enum IDPackedValues   // image descriptor packed field values{ID_PACKED_LOCALCT,ID_PACKED_INTERLACE,ID_PACKED_SORT,ID_PACKED_LOCALCTSIZE};struct TGIFHeader       // GIF header  {char m_cSignature[3]; // Signature - Identifies the GIF Data Stream  // This field contains the fixed value 'GIF'char m_cVersion[3];// Version number. May be one of the following:// "87a" or "89a"};struct TGIFLSDescriptor // Logical Screen Descriptor{WORD m_wWidth;// 2 bytes. Logical screen widthWORD m_wHeight; // 2 bytes. Logical screen heightunsigned char m_cPacked;      // packed fieldunsigned char m_cBkIndex;     // 1 byte. Background color indexunsigned char m_cPixelAspect; // 1 byte. Pixel aspect ratioinline int GetPackedValue(enum LSDPackedValues Value);};struct TGIFAppExtension // application extension block{unsigned char m_cExtIntroducer; // extension introducer (0x21)unsigned char m_cExtLabel; // app. extension label (0xFF)unsigned char m_cBlockSize; // fixed value of 11char m_cAppIdentifier[8];   // application identifierchar m_cAppAuth[3];  // application authentication code};struct TGIFControlExt // graphic control extension block{unsigned char m_cExtIntroducer; // extension introducer (0x21)unsigned char m_cControlLabel;  // control extension label (0xF9)unsigned char m_cBlockSize; // fixed value of 4unsigned char m_cPacked;    // packed fieldWORD m_wDelayTime;// delay timeunsigned char m_cTColorIndex; // transparent color indexunsigned char m_cBlockTerm;   // block terminator (0x00)public:inline int GetPackedValue(enum ControlExtValues Value);};struct TGIFCommentExt  // comment extension block{unsigned char m_cExtIntroducer; // extension introducer (0x21)unsigned char m_cCommentLabel;  // comment extension label (0xFE)};struct TGIFPlainTextExt // plain text extension block{unsigned char m_cExtIntroducer;  // extension introducer (0x21)unsigned char m_cPlainTextLabel; // text extension label (0x01)unsigned char m_cBlockSize; // fixed value of 12WORD m_wLeftPos;    // text grid left positionWORD m_wTopPos;     // text grid top positionWORD m_wGridWidth;  // text grid widthWORD m_wGridHeight; // text grid heightunsigned char m_cCellWidth;  // character cell widthunsigned char m_cCellHeight; // character cell heightunsigned char m_cFgColor; // text foreground color indexunsigned char m_cBkColor; // text background color index};struct TGIFImageDescriptor // image descriptor block{unsigned char m_cImageSeparator; // image separator byte (0x2C)WORD m_wLeftPos; // image left positionWORD m_wTopPos;  // image top positionWORD m_wWidth;   // image widthWORD m_wHeight;  // image heightunsigned char m_cPacked; // packed fieldinline int GetPackedValue(enum IDPackedValues Value);};#pragma pack() // turn byte alignment offpublic:BOOL GetPaintRect(RECT *lpRect);BOOL SetPaintRect(const RECT *lpRect);CPictureEx();virtual ~CPictureEx();void Stop();   // stops animationvoid UnLoad(); // stops animation plus releases all resourcesBOOL IsGIF() const;BOOL IsPlaying() const;BOOL IsAnimatedGIF() const;SIZE GetSize() const;int GetFrameCount() const;COLORREF GetBkColor() const;void SetBkColor(COLORREF clr);// draws the picture (starts an animation thread if needed)// if an animation was previously stopped by Stop(),// continues it from the last displayed frameBOOL Draw();// loads a picture from a file// i.e. Load(_T("mypic.gif"));BOOL Load(LPCTSTR szFileName);// loads a picture from a global memory block (allocated by GlobalAlloc)// Warning: this function DOES NOT free the global memory, pointed to by hGlobalBOOL Load(HGLOBAL hGlobal, DWORD dwSize);// loads a picture from a program resource// i.e. Load(MAKEINTRESOURCE(IDR_MYPIC),_T("GIFTYPE"));BOOL Load(LPCTSTR szResourceName,LPCTSTR szResourceType);protected:#ifdef GIF_TRACINGvoid EnumGIFBlocks();void WriteDataOnDisk(CString szFileName, HGLOBAL hData, DWORD dwSize);#endif // GIF_TRACINGRECT m_PaintRect;SIZE m_PictureSize;COLORREF m_clrBackground;UINT m_nCurrFrame;UINT m_nDataSize;UINT m_nCurrOffset;UINT m_nGlobalCTSize;BOOL m_bIsGIF;BOOL m_bIsPlaying;volatile BOOL m_bExitThread;BOOL m_bIsInitialized;HDC m_hMemDC;HDC m_hDispMemDC;HBITMAP m_hDispMemBM;HBITMAP m_hDispOldBM;HBITMAP m_hBitmap;HBITMAP m_hOldBitmap;HANDLE m_hThread;HANDLE m_hExitEvent;IPicture * m_pPicture;TGIFHeader * m_pGIFHeader;unsigned char * m_pRawData;TGIFLSDescriptor * m_pGIFLSDescriptor;std::vector<TFrame> m_arrFrames;void ThreadAnimation();static UINT WINAPI _ThreadAnimation(LPVOID pParam);int GetNextBlockLen() const;BOOL SkipNextBlock();BOOL SkipNextGraphicBlock();BOOL PrepareDC(int nWidth, int nHeight);void ResetDataPointer();enum GIFBlockTypes GetNextBlock() const;UINT GetSubBlocksLen(UINT nStartingOffset) const;HGLOBAL GetNextGraphicBlock(UINT *pBlockLen, UINT *pDelay, SIZE *pBlockSize, SIZE *pBlockOffset, UINT *pDisposal);// Generated message map functions//{{AFX_MSG(CPictureEx)afx_msg void OnDestroy();afx_msg void OnPaint();//}}AFX_MSGDECLARE_MESSAGE_MAP()};#endif // !defined(AFX_PICTUREEX_H__0EFE5DE0_7B68_4DB7_8B34_5DC634948438__INCLUDED_)


【CPP源文件:】

//////////////////////////////////////////////////////////////////////// PictureEx.cpp: implementation of the CPictureEx class.//// Picture displaying control with support for the following formats:// GIF (including animated GIF87a and GIF89a), JPEG, BMP, WMF, ICO, CUR// // Written by Oleg Bykov (oleg_bykoff@rsdn.ru)// Copyright (c) 2001//// To use CPictureEx, follow these steps://   - place a static control on your dialog (either a text or a bitmap)//   - change its identifier to something else (e.g. IDC_MYPIC)//   - associate a CStatic with it using ClassWizard//   - in your dialog's header file replace CStatic with CPictureEx//     (don't forget to #include "PictureEx.h" and add //     PictureEx.h and PictureEx.cpp to your project)//   - call one of the overloaded CPictureEx::Load() functions somewhere//     (OnInitDialog is a good place to start)//   - if the preceding Load() succeeded call Draw()//  // You can also add the control by defining a member variable of type // CPictureEx, calling CPictureEx::Create (derived from CStatic), then // CPictureEx::Load and CPictureEx::Draw.//// By default, the control initializes its background to COLOR_3DFACE// (see CPictureEx::PrepareDC()). You can change the background by// calling CPictureEx::SetBkColor(COLORREF) after CPictureEx::Load().//// I decided to leave in the class the functions to write separate frames from // animated GIF to disk. If you want to use them, uncomment #define GIF_TRACING // and an appropriate section in CPictureEx::Load(HGLOBAL, DWORD). These functions // won't be compiled and linked to your project unless you uncomment #define GIF_TRACING,// so you don't have to worry.// // Warning: this code hasn't been subject to a heavy testing, so// use it on your own risk. The author accepts no liability for the // possible damage caused by this code.//// Version 1.0  7 Aug 2001//              Initial release//// Version 1.1  6 Sept 2001//              ATL version of the class//// Version 1.2  14 Oct 2001//              - Fixed a problem with loading GIFs from resources//                in MFC-version of the class for multi-modules apps.//                Thanks to Ruben Avila-Carretero for finding this out.////              - Got rid of waitable timer in ThreadAnimation()//                Now CPictureEx[Wnd] works in Win95 too.//                Thanks to Alex Egiazarov and Wayne King for the idea.////              - Fixed a visual glitch of using SetBkColor.//                Thanks to Kwangjin Lee for finding this out.//// Version 1.3  10 Nov 2001//              - Fixed a DC leak. One DC leaked per each UnLoad()//                (forgot to put a ReleaseDC() in the end of //                CPictureExWnd::PrepareDC() function).////              - Now it is possible to set a clipping rectangle using//                CPictureEx[Wnd]::SetPaintRect(const LPRECT) function.//                The LPRECT parameter tells the class what portion of//                a picture should it display. If the clipping rect is //                not set, the whole picture is shown.//                Thanks to Fabrice Rodriguez for the idea.////              - Added support for Stop/Draw. Now you can Stop() an//                animated GIF, then Draw() it again, it will continue//                animation from the frame it was stopped on. You can //                also know if a GIF is currently playing with the //                IsPlaying() function.//             //              - Got rid of math.h and made m_bExitThread volatile. //                Thanks to Piotr Sawicki for the suggestion.////////////////////////////////////////////////////////////////////////#include "stdafx.h"#include "PictureEx.h"#include <process.h>#ifdef _DEBUG#undef THIS_FILEstatic char THIS_FILE[]=__FILE__;#define new DEBUG_NEW#endif//////////////////////////////////////////////////////////////////////// Nested structures member functions//////////////////////////////////////////////////////////////////////inline int CPictureEx::TGIFControlExt::GetPackedValue(enum ControlExtValues Value){int nRet = (int)m_cPacked;switch (Value){case GCX_PACKED_DISPOSAL:nRet = (nRet & 28) >> 2;break;case GCX_PACKED_USERINPUT:nRet = (nRet & 2) >> 1;break;case GCX_PACKED_TRANSPCOLOR:nRet &= 1;break;};return nRet;}inline int CPictureEx::TGIFLSDescriptor::GetPackedValue(enum LSDPackedValues Value){int nRet = (int)m_cPacked;switch (Value){case LSD_PACKED_GLOBALCT:nRet = nRet >> 7;break;case LSD_PACKED_CRESOLUTION:nRet = ((nRet & 0x70) >> 4) + 1;break;case LSD_PACKED_SORT:nRet = (nRet & 8) >> 3;break;case LSD_PACKED_GLOBALCTSIZE:nRet &= 7;break;};return nRet;}inline int CPictureEx::TGIFImageDescriptor::GetPackedValue(enum IDPackedValues Value){int nRet = (int)m_cPacked;switch (Value){case ID_PACKED_LOCALCT:nRet >>= 7;break;case ID_PACKED_INTERLACE:nRet = ((nRet & 0x40) >> 6);break;case ID_PACKED_SORT:nRet = (nRet & 0x20) >> 5;break;case ID_PACKED_LOCALCTSIZE:nRet &= 7;break;};return nRet;}//////////////////////////////////////////////////////////////////////// Construction/Destruction//////////////////////////////////////////////////////////////////////CPictureEx::CPictureEx(){// check structures sizeASSERT(sizeof(TGIFImageDescriptor) == 10);ASSERT(sizeof(TGIFAppExtension)    == 14);ASSERT(sizeof(TGIFPlainTextExt)    == 15);ASSERT(sizeof(TGIFLSDescriptor)    ==  7);ASSERT(sizeof(TGIFControlExt)   ==  8);ASSERT(sizeof(TGIFCommentExt)   ==  2);ASSERT(sizeof(TGIFHeader)   ==  6);m_pGIFLSDescriptor = NULL;m_pGIFHeader   = NULL;m_pPicture   = NULL;m_pRawData   = NULL;m_hThread   = NULL;m_hBitmap          = NULL;m_hMemDC   = NULL;m_hDispMemDC       = NULL;m_hDispMemBM       = NULL;m_hDispOldBM       = NULL;m_bIsInitialized   = FALSE;m_bExitThread   = FALSE;m_bIsPlaying       = FALSE;m_bIsGIF   = FALSE;m_clrBackground    = RGB(255,255,255); // white by defaultm_nGlobalCTSize    = 0;m_nCurrOffset   = 0;m_nCurrFrame   = 0;m_nDataSize   = 0;m_PictureSize.cx = m_PictureSize.cy = 0;SetRect(&m_PaintRect,0,0,0,0);m_hExitEvent = CreateEvent(NULL,TRUE,FALSE,NULL);}CPictureEx::~CPictureEx(){UnLoad();CloseHandle(m_hExitEvent);}BEGIN_MESSAGE_MAP(CPictureEx, CStatic)//{{AFX_MSG_MAP(CPictureEx)ON_WM_DESTROY()ON_WM_PAINT()//}}AFX_MSG_MAPEND_MESSAGE_MAP()BOOL CPictureEx::Load(HGLOBAL hGlobal, DWORD dwSize){IStream *pStream = NULL;UnLoad();if (!(m_pRawData = reinterpret_cast<unsigned char*> (GlobalLock(hGlobal))) ){TRACE(_T("Load: Error locking memory\n"));return FALSE;};m_nDataSize = dwSize;m_pGIFHeader = reinterpret_cast<TGIFHeader *> (m_pRawData);if ((memcmp(&m_pGIFHeader->m_cSignature,"GIF",3) != 0) &&((memcmp(&m_pGIFHeader->m_cVersion,"87a",3) != 0) || (memcmp(&m_pGIFHeader->m_cVersion,"89a",3) != 0)) ){// it's neither GIF87a nor GIF89a// do the default processing// clear GIF variablesm_pRawData = NULL;GlobalUnlock(hGlobal);// don't delete memory on object's releaseif (CreateStreamOnHGlobal(hGlobal,FALSE,&pStream) != S_OK)return FALSE;if (OleLoadPicture(pStream,dwSize,FALSE,IID_IPicture,reinterpret_cast<LPVOID *>(&m_pPicture)) != S_OK){pStream->Release();return FALSE;};pStream->Release();// store picture's sizelong hmWidth;long hmHeight;m_pPicture->get_Width(&hmWidth);m_pPicture->get_Height(&hmHeight);HDC hDC = ::GetDC(m_hWnd);m_PictureSize.cx = MulDiv(hmWidth, GetDeviceCaps(hDC,LOGPIXELSX), 2540);m_PictureSize.cy = MulDiv(hmHeight, GetDeviceCaps(hDC,LOGPIXELSY), 2540);::ReleaseDC(m_hWnd,hDC);}else{// it's a GIFm_bIsGIF = TRUE;m_pGIFLSDescriptor = reinterpret_cast<TGIFLSDescriptor *>(m_pRawData + sizeof(TGIFHeader));if (m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCT) == 1){// calculate the globat color table sizem_nGlobalCTSize = static_cast<int>(3* (1 << (m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCTSIZE)+1)));// get the background color if GCT is presentunsigned char *pBkClr = m_pRawData + sizeof(TGIFHeader) + sizeof(TGIFLSDescriptor) + 3*m_pGIFLSDescriptor->m_cBkIndex;m_clrBackground = RGB(pBkClr[0],pBkClr[1],pBkClr[2]);};// store the picture's sizem_PictureSize.cx = m_pGIFLSDescriptor->m_wWidth;m_PictureSize.cy = m_pGIFLSDescriptor->m_wHeight;// determine frame count for this pictureUINT nFrameCount=0;ResetDataPointer();while (SkipNextGraphicBlock())nFrameCount++;#ifdef GIF_TRACINGTRACE(_T(" -= GIF encountered\n"   "Logical Screen dimensions = %dx%d\n"   "Global color table = %d\n"   "Color depth = %d\n"   "Sort flag = %d\n"   "Size of Global Color Table = %d\n"   "Background color index = %d\n"   "Pixel aspect ratio = %d\n"   "Frame count = %d\n"   "Background color = %06Xh\n\n"  ),m_pGIFLSDescriptor->m_wWidth,m_pGIFLSDescriptor->m_wHeight,m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCT),m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_CRESOLUTION),m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_SORT),m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCTSIZE),m_pGIFLSDescriptor->m_cBkIndex,m_pGIFLSDescriptor->m_cPixelAspect,nFrameCount,m_clrBackground);EnumGIFBlocks();#endifif (nFrameCount == 0) // it's an empty GIF!{m_pRawData = NULL;GlobalUnlock(hGlobal);return FALSE;};// now check the frame count// if there's only one frame, no need to animate this GIF// therefore, treat it like any other picif (nFrameCount == 1){// clear GIF variablesm_pRawData = NULL;GlobalUnlock(hGlobal);// don't delete memory on object's releaseif (CreateStreamOnHGlobal(hGlobal,FALSE,&pStream) != S_OK)return FALSE;if (OleLoadPicture(pStream,dwSize,FALSE,IID_IPicture,(LPVOID *)&m_pPicture) != S_OK){pStream->Release();return FALSE;};pStream->Release();}else{// if, on the contrary, there are several frames// then store separate frames in an arrayTFrame frame;UINT nBlockLen;HGLOBAL hFrameData;UINT nCurFrame = 0;ResetDataPointer();while (hFrameData = GetNextGraphicBlock(&nBlockLen,&frame.m_nDelay, &frame.m_frameSize,&frame.m_frameOffset, &frame.m_nDisposal) ){#ifdef GIF_TRACING//////////////////////////////////////////////// uncomment the following strings if you want // to write separate frames on disk////CString szName;//szName.Format(_T("%.4d.gif"),nCurFrame);//WriteDataOnDisk(szName,hFrameData,nBlockLen);//nCurFrame++;#endif // GIF_TRACINGIStream *pStream = NULL;// delete memory on object's releaseif (CreateStreamOnHGlobal(hFrameData,TRUE,&pStream) != S_OK){GlobalFree(hFrameData);continue;};if (OleLoadPicture(pStream,nBlockLen,FALSE,IID_IPicture,reinterpret_cast<LPVOID *>(&frame.m_pPicture)) != S_OK){pStream->Release();continue;};pStream->Release();// everything went well, add this framem_arrFrames.push_back(frame);};// clean after ourselvesm_pRawData = NULL;GlobalUnlock(hGlobal);if (m_arrFrames.empty()) // couldn't load any framesreturn FALSE;};}; // if (!IsGIF...return PrepareDC(m_PictureSize.cx,m_PictureSize.cy);}void CPictureEx::UnLoad(){Stop();if (m_pPicture){m_pPicture->Release();m_pPicture = NULL;};std::vector<TFrame>::iterator it;for (it=m_arrFrames.begin();it<m_arrFrames.end();it++)(*it).m_pPicture->Release();m_arrFrames.clear();if (m_hMemDC){SelectObject(m_hMemDC,m_hOldBitmap);::DeleteDC(m_hMemDC);::DeleteObject(m_hBitmap);m_hMemDC  = NULL;m_hBitmap = NULL;};if (m_hDispMemDC){SelectObject(m_hDispMemDC,m_hDispOldBM);::DeleteDC(m_hDispMemDC);::DeleteObject(m_hDispMemBM);m_hDispMemDC  = NULL;m_hDispMemBM = NULL;};SetRect(&m_PaintRect,0,0,0,0);m_pGIFLSDescriptor = NULL;m_pGIFHeader   = NULL;m_pRawData   = NULL;m_hThread   = NULL;m_bIsInitialized   = FALSE;m_bExitThread   = FALSE;m_bIsGIF   = FALSE;m_clrBackground    = RGB(255,255,255); // white by defaultm_nGlobalCTSize   = 0;m_nCurrOffset   = 0;m_nCurrFrame   = 0;m_nDataSize   = 0;}BOOL CPictureEx::Draw(){if (!m_bIsInitialized){TRACE(_T("Call one of the CPictureEx::Load() member functions before calling Draw()\n"));return FALSE;};if (IsAnimatedGIF()){// the picture needs animation// we'll start the thread that will handle it for usunsigned int nDummy;m_hThread = (HANDLE) _beginthreadex(NULL,0,_ThreadAnimation,this,CREATE_SUSPENDED,&nDummy);if (!m_hThread){TRACE(_T("Draw: Couldn't start a GIF animation thread\n"));return FALSE;} else ResumeThread(m_hThread);} else{if (m_pPicture){long hmWidth;long hmHeight;m_pPicture->get_Width(&hmWidth);m_pPicture->get_Height(&hmHeight);if (m_pPicture->Render(m_hMemDC, 0, 0, m_PictureSize.cx, m_PictureSize.cy, 0, hmHeight, hmWidth, -hmHeight, NULL) == S_OK){Invalidate(FALSE);return TRUE;};};};return FALSE;}SIZE CPictureEx::GetSize() const{return m_PictureSize;}BOOL CPictureEx::Load(LPCTSTR szFileName){ASSERT(szFileName);CFile file;HGLOBAL hGlobal;DWORD dwSize;if (!file.Open(szFileName,CFile::modeRead | CFile::shareDenyWrite) ){TRACE(_T("Load (file): Error opening file %s\n"),szFileName);return FALSE;};dwSize = file.GetLength();hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD,dwSize);if (!hGlobal){TRACE(_T("Load (file): Error allocating memory\n"));return FALSE;};char *pData = reinterpret_cast<char*>(GlobalLock(hGlobal));if (!pData){TRACE(_T("Load (file): Error locking memory\n"));GlobalFree(hGlobal);return FALSE;};TRY{file.Read(pData,dwSize);}CATCH(CFileException, e);                                          {TRACE(_T("Load (file): An exception occured while reading the file %s\n"),szFileName);GlobalFree(hGlobal);e->Delete();file.Close();return FALSE;}END_CATCHGlobalUnlock(hGlobal);file.Close();BOOL bRetValue = Load(hGlobal,dwSize);GlobalFree(hGlobal);return bRetValue;}BOOL CPictureEx::Load(LPCTSTR szResourceName, LPCTSTR szResourceType){ASSERT(szResourceName);ASSERT(szResourceType);HRSRC hPicture = FindResource(AfxGetResourceHandle(),szResourceName,szResourceType);HGLOBAL hResData;if (!hPicture || !(hResData = LoadResource(AfxGetResourceHandle(),hPicture))){TRACE(_T("Load (resource): Error loading resource %s\n"),szResourceName);return FALSE;};DWORD dwSize = SizeofResource(AfxGetResourceHandle(),hPicture);// hResData is not the real HGLOBAL (we can't lock it)// let's make it realHGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD,dwSize);if (!hGlobal){TRACE(_T("Load (resource): Error allocating memory\n"));FreeResource(hResData);return FALSE;};char *pDest = reinterpret_cast<char *> (GlobalLock(hGlobal));char *pSrc = reinterpret_cast<char *> (LockResource(hResData));if (!pSrc || !pDest){TRACE(_T("Load (resource): Error locking memory\n"));GlobalFree(hGlobal);FreeResource(hResData);return FALSE;};CopyMemory(pDest,pSrc,dwSize);FreeResource(hResData);GlobalUnlock(hGlobal);BOOL bRetValue = Load(hGlobal,dwSize);GlobalFree(hGlobal);return bRetValue;}void CPictureEx::ResetDataPointer(){// skip header and logical screen descriptorm_nCurrOffset = sizeof(TGIFHeader)+sizeof(TGIFLSDescriptor)+m_nGlobalCTSize;}BOOL CPictureEx::SkipNextGraphicBlock(){if (!m_pRawData) return FALSE;// GIF header + LSDescriptor [+ GCT] [+ Control block] + Dataenum GIFBlockTypes nBlock;nBlock = GetNextBlock();while ((nBlock != BLOCK_CONTROLEXT) &&   (nBlock != BLOCK_IMAGE) &&   (nBlock != BLOCK_PLAINTEXT) &&   (nBlock != BLOCK_UNKNOWN) &&   (nBlock != BLOCK_TRAILER) ){if (!SkipNextBlock()) return NULL;nBlock = GetNextBlock();};if ((nBlock == BLOCK_UNKNOWN) ||(nBlock == BLOCK_TRAILER))return FALSE;// it's either a control ext.block, an image or a plain textif (GetNextBlockLen() <= 0) return FALSE;if (nBlock == BLOCK_CONTROLEXT){if (!SkipNextBlock()) return FALSE;nBlock = GetNextBlock();// skip everything until we meet an image block or a plain-text blockwhile ((nBlock != BLOCK_IMAGE) &&   (nBlock != BLOCK_PLAINTEXT) &&   (nBlock != BLOCK_UNKNOWN) &&   (nBlock != BLOCK_TRAILER) ){if (!SkipNextBlock()) return NULL;nBlock = GetNextBlock();};if ((nBlock == BLOCK_UNKNOWN) ||(nBlock == BLOCK_TRAILER))return FALSE;};// skip the found data block (image or plain-text)if (!SkipNextBlock()) return FALSE;return TRUE;}UINT CPictureEx::GetSubBlocksLen(UINT nStartingOffset) const{UINT nRet = 0;UINT nCurOffset = nStartingOffset;while (m_pRawData[nCurOffset] != 0){nRet += m_pRawData[nCurOffset]+1;nCurOffset += m_pRawData[nCurOffset]+1;};return nRet+1;}enum CPictureEx::GIFBlockTypes CPictureEx::GetNextBlock() const{switch(m_pRawData[m_nCurrOffset]){case 0x21:// extension blockswitch(m_pRawData[m_nCurrOffset+1]){case 0x01:// plain text extensionreturn BLOCK_PLAINTEXT;break;case 0xF9:// graphic control extensionreturn BLOCK_CONTROLEXT;break;case 0xFE:// comment extensionreturn BLOCK_COMMEXT;break;case 0xFF:// application extensionreturn BLOCK_APPEXT;break;};break;case 0x3B:// trailerreturn BLOCK_TRAILER;break;case 0x2C:// image datareturn BLOCK_IMAGE;break;};return BLOCK_UNKNOWN;}BOOL CPictureEx::SkipNextBlock(){if (!m_pRawData) return FALSE;int nLen = GetNextBlockLen();if ((nLen <= 0) || ((m_nCurrOffset+nLen) > m_nDataSize))return FALSE;m_nCurrOffset += nLen;return TRUE;}int CPictureEx::GetNextBlockLen() const{GIFBlockTypes nBlock = GetNextBlock();int nTmp;switch(nBlock){case BLOCK_UNKNOWN:return -1;break;case BLOCK_TRAILER:return 1;break;case BLOCK_APPEXT:nTmp = GetSubBlocksLen(m_nCurrOffset+sizeof(TGIFAppExtension));if (nTmp > 0)return sizeof(TGIFAppExtension)+nTmp;break;case BLOCK_COMMEXT:nTmp = GetSubBlocksLen(m_nCurrOffset+sizeof(TGIFCommentExt));if (nTmp > 0)return sizeof(TGIFCommentExt)+nTmp;break;case BLOCK_CONTROLEXT:return sizeof(TGIFControlExt);break;case BLOCK_PLAINTEXT:nTmp = GetSubBlocksLen(m_nCurrOffset+sizeof(TGIFPlainTextExt));if (nTmp > 0)return sizeof(TGIFPlainTextExt)+nTmp;break;case BLOCK_IMAGE:TGIFImageDescriptor *pIDescr = reinterpret_cast<TGIFImageDescriptor *> (&m_pRawData[m_nCurrOffset]);int nLCTSize = (int)(pIDescr->GetPackedValue(ID_PACKED_LOCALCT)*3*(1 << (pIDescr->GetPackedValue(ID_PACKED_LOCALCTSIZE)+1)));int nTmp = GetSubBlocksLen(m_nCurrOffset+sizeof(TGIFImageDescriptor) + nLCTSize + 1);if (nTmp > 0)return sizeof(TGIFImageDescriptor) + nLCTSize + 1 + nTmp;break;};return 0;}UINT WINAPI CPictureEx::_ThreadAnimation(LPVOID pParam){ASSERT(pParam);CPictureEx *pPic = reinterpret_cast<CPictureEx *> (pParam);pPic->m_bIsPlaying = TRUE;pPic->ThreadAnimation();pPic->m_bIsPlaying = FALSE;// this thread has finished its work so we close the handleCloseHandle(pPic->m_hThread); // and init the handle to zero (so that Stop() doesn't Wait on it)pPic->m_hThread = 0;return 0;}void CPictureEx::ThreadAnimation(){// first, restore background (for stop/draw support)// disposal method #2if (m_arrFrames[m_nCurrFrame].m_nDisposal == 2){HBRUSH hBrush = CreateSolidBrush(m_clrBackground);if (hBrush){RECT rect = {m_arrFrames[m_nCurrFrame].m_frameOffset.cx,m_arrFrames[m_nCurrFrame].m_frameOffset.cy,m_arrFrames[m_nCurrFrame].m_frameOffset.cx + m_arrFrames[m_nCurrFrame].m_frameSize.cx,m_arrFrames[m_nCurrFrame].m_frameOffset.cy + m_arrFrames[m_nCurrFrame].m_frameSize.cy };FillRect(m_hMemDC,&rect,hBrush);DeleteObject(hBrush);};} else// disposal method #3if (m_hDispMemDC && (m_arrFrames[m_nCurrFrame].m_nDisposal == 3) ){// put it backBitBlt(m_hMemDC,m_arrFrames[m_nCurrFrame].m_frameOffset.cx,m_arrFrames[m_nCurrFrame].m_frameOffset.cy,m_arrFrames[m_nCurrFrame].m_frameSize.cx,m_arrFrames[m_nCurrFrame].m_frameSize.cy,m_hDispMemDC,0,0, SRCCOPY);// init variablesSelectObject(m_hDispMemDC,m_hDispOldBM);DeleteDC(m_hDispMemDC); m_hDispMemDC = NULL;DeleteObject(m_hDispMemBM); m_hDispMemBM = NULL;};while (!m_bExitThread){if (m_arrFrames[m_nCurrFrame].m_pPicture){///////////////////////////////////////////////////////// Before rendering a frame we should take care of what's // behind that frame. TFrame::m_nDisposal will be our guide://   0 - no disposal specified (do nothing)//   1 - do not dispose (again, do nothing)//   2 - restore to background color (m_clrBackground)//   3 - restore to previous//////// disposal method #3if (m_arrFrames[m_nCurrFrame].m_nDisposal == 3){// prepare a memory DC and store the background in itm_hDispMemDC = CreateCompatibleDC(m_hMemDC);m_hDispMemBM = CreateCompatibleBitmap(m_hMemDC,m_arrFrames[m_nCurrFrame].m_frameSize.cx,m_arrFrames[m_nCurrFrame].m_frameSize.cy);if (m_hDispMemDC && m_hDispMemBM){m_hDispOldBM = reinterpret_cast<HBITMAP> (SelectObject(m_hDispMemDC,m_hDispMemBM));BitBlt(m_hDispMemDC,0,0,m_arrFrames[m_nCurrFrame].m_frameSize.cx,m_arrFrames[m_nCurrFrame].m_frameSize.cy,m_hMemDC,m_arrFrames[m_nCurrFrame].m_frameOffset.cx,m_arrFrames[m_nCurrFrame].m_frameOffset.cy,SRCCOPY);};};///////////////////////long hmWidth;long hmHeight;m_arrFrames[m_nCurrFrame].m_pPicture->get_Width(&hmWidth);m_arrFrames[m_nCurrFrame].m_pPicture->get_Height(&hmHeight);if (m_arrFrames[m_nCurrFrame].m_pPicture->Render(m_hMemDC, m_arrFrames[m_nCurrFrame].m_frameOffset.cx, m_arrFrames[m_nCurrFrame].m_frameOffset.cy, m_arrFrames[m_nCurrFrame].m_frameSize.cx, m_arrFrames[m_nCurrFrame].m_frameSize.cy, 0, hmHeight, hmWidth, -hmHeight, NULL) == S_OK){Invalidate(FALSE);};if (m_bExitThread) break;// if the delay time is too short (like in old GIFs), wait for 100msif (m_arrFrames[m_nCurrFrame].m_nDelay < 5) WaitForSingleObject(m_hExitEvent, 100);elseWaitForSingleObject(m_hExitEvent, 10*m_arrFrames[m_nCurrFrame].m_nDelay);if (m_bExitThread) break;// disposal method #2if (m_arrFrames[m_nCurrFrame].m_nDisposal == 2){HBRUSH hBrush = CreateSolidBrush(m_clrBackground);if (hBrush){RECT rect = {m_arrFrames[m_nCurrFrame].m_frameOffset.cx,m_arrFrames[m_nCurrFrame].m_frameOffset.cy,m_arrFrames[m_nCurrFrame].m_frameOffset.cx + m_arrFrames[m_nCurrFrame].m_frameSize.cx,m_arrFrames[m_nCurrFrame].m_frameOffset.cy + m_arrFrames[m_nCurrFrame].m_frameSize.cy };FillRect(m_hMemDC,&rect,hBrush);DeleteObject(hBrush);};} elseif (m_hDispMemDC && (m_arrFrames[m_nCurrFrame].m_nDisposal == 3) ){// put it backBitBlt(m_hMemDC,m_arrFrames[m_nCurrFrame].m_frameOffset.cx,m_arrFrames[m_nCurrFrame].m_frameOffset.cy,m_arrFrames[m_nCurrFrame].m_frameSize.cx,m_arrFrames[m_nCurrFrame].m_frameSize.cy,m_hDispMemDC,0,0, SRCCOPY);// init variablesSelectObject(m_hDispMemDC,m_hDispOldBM);DeleteDC(m_hDispMemDC); m_hDispMemDC = NULL;DeleteObject(m_hDispMemBM); m_hDispMemBM = NULL;};};m_nCurrFrame++;if (m_nCurrFrame == m_arrFrames.size()){m_nCurrFrame= 0; // init the screen for the first frame,HBRUSH hBrush = CreateSolidBrush(m_clrBackground);if (hBrush){RECT rect = {0,0,m_PictureSize.cx,m_PictureSize.cy};FillRect(m_hMemDC,&rect,hBrush);DeleteObject(hBrush);};};};}void CPictureEx::Stop(){m_bIsPlaying = FALSE;m_bExitThread = TRUE;SetEvent(m_hExitEvent);if (m_hThread){// we'll wait for 5 seconds then continue executionWaitForSingleObject(m_hThread,5000);CloseHandle(m_hThread);m_hThread = NULL;}// make it possible to Draw() againResetEvent(m_hExitEvent);m_bExitThread = FALSE;}HGLOBAL CPictureEx::GetNextGraphicBlock(UINT *pBlockLen, UINT *pDelay, SIZE *pBlockSize, SIZE *pBlockOffset, UINT *pDisposal){if (!m_pRawData) return NULL;// GIF header + LSDescriptor [+ GCT] [+ Control block] + Data*pDisposal = 0;enum GIFBlockTypes nBlock;nBlock = GetNextBlock();while ((nBlock != BLOCK_CONTROLEXT) &&(nBlock != BLOCK_IMAGE) &&(nBlock != BLOCK_PLAINTEXT) &&(nBlock != BLOCK_UNKNOWN) &&(nBlock != BLOCK_TRAILER)){if (!SkipNextBlock()) return NULL;nBlock = GetNextBlock();};if ((nBlock == BLOCK_UNKNOWN) ||(nBlock == BLOCK_TRAILER))return NULL;// it's either a control ext.block, an image or a plain textint nStart = m_nCurrOffset;int nBlockLen = GetNextBlockLen();if (nBlockLen <= 0) return NULL;if (nBlock == BLOCK_CONTROLEXT){// get the following dataTGIFControlExt *pControl = reinterpret_cast<TGIFControlExt *> (&m_pRawData[m_nCurrOffset]);// store delay time*pDelay = pControl->m_wDelayTime;// store disposal method*pDisposal = pControl->GetPackedValue(GCX_PACKED_DISPOSAL);if (!SkipNextBlock()) return NULL;nBlock = GetNextBlock();// skip everything until we find data to display // (image block or plain-text block)while ((nBlock != BLOCK_IMAGE) &&(nBlock != BLOCK_PLAINTEXT) &&(nBlock != BLOCK_UNKNOWN) &&(nBlock != BLOCK_TRAILER)){if (!SkipNextBlock()) return NULL;nBlock = GetNextBlock();nBlockLen += GetNextBlockLen();};if ((nBlock == BLOCK_UNKNOWN) || (nBlock == BLOCK_TRAILER))return NULL;nBlockLen += GetNextBlockLen();}else*pDelay = -1; // to indicate that there was no delay valueif (nBlock == BLOCK_IMAGE){// store size and offsetsTGIFImageDescriptor *pImage = reinterpret_cast<TGIFImageDescriptor *> (&m_pRawData[m_nCurrOffset]);pBlockSize->cx = pImage->m_wWidth;pBlockSize->cy = pImage->m_wHeight;pBlockOffset->cx = pImage->m_wLeftPos;pBlockOffset->cy = pImage->m_wTopPos;};if (!SkipNextBlock()) return NULL;HGLOBAL hGlobal = GlobalAlloc(GMEM_FIXED,sizeof(TGIFHeader) +sizeof(TGIFLSDescriptor) +m_nGlobalCTSize +nBlockLen + 1);  // for the trailerif (!hGlobal) return NULL;int nOffset = 0; // GMEM_FIXED means we get a pointerunsigned char *pGlobal = reinterpret_cast<unsigned char *> (hGlobal);CopyMemory(pGlobal,m_pRawData, sizeof(TGIFHeader)+sizeof(TGIFLSDescriptor)+m_nGlobalCTSize);nOffset += sizeof(TGIFHeader)+sizeof(TGIFLSDescriptor)+m_nGlobalCTSize;CopyMemory(pGlobal + nOffset,&m_pRawData[nStart], nBlockLen);nOffset += nBlockLen;pGlobal[nOffset] = 0x3B; // trailernOffset++;*pBlockLen = nOffset;return hGlobal;}BOOL CPictureEx::IsGIF() const{return m_bIsGIF;}BOOL CPictureEx::IsAnimatedGIF() const{return (m_bIsGIF && (m_arrFrames.size() > 1));}BOOL CPictureEx::IsPlaying() const{return m_bIsPlaying;}int CPictureEx::GetFrameCount() const{if (!IsAnimatedGIF())return 0;return m_arrFrames.size();}COLORREF CPictureEx::GetBkColor() const{return m_clrBackground;}void CPictureEx::OnPaint() {CPaintDC dc(this); // device context for paintingLONG nPaintWidth = m_PaintRect.right-m_PaintRect.left;if (nPaintWidth > 0){LONG nPaintHeight = m_PaintRect.bottom - m_PaintRect.top;::BitBlt(dc.m_hDC, 0, 0, nPaintWidth, nPaintHeight,m_hMemDC, m_PaintRect.left, m_PaintRect.top, SRCCOPY);}else{::BitBlt(dc.m_hDC, 0, 0, m_PictureSize.cx, m_PictureSize.cy,m_hMemDC, 0, 0, SRCCOPY);};}BOOL CPictureEx::PrepareDC(int nWidth, int nHeight){SetWindowPos(NULL,0,0,nWidth,nHeight,SWP_NOMOVE | SWP_NOZORDER);HDC hWinDC = ::GetDC(m_hWnd);if (!hWinDC) return FALSE;m_hMemDC = CreateCompatibleDC(hWinDC);if (!m_hMemDC) {::ReleaseDC(m_hWnd,hWinDC);return FALSE;};m_hBitmap  = CreateCompatibleBitmap(hWinDC,nWidth,nHeight);if (!m_hBitmap) {::ReleaseDC(m_hWnd,hWinDC);::DeleteDC(m_hMemDC);return FALSE;};m_hOldBitmap = reinterpret_cast<HBITMAP> (SelectObject(m_hMemDC,m_hBitmap));// fill the backgroundm_clrBackground = GetSysColor(COLOR_3DFACE);RECT rect = {0,0,nWidth,nHeight};FillRect(m_hMemDC,&rect,(HBRUSH)(COLOR_WINDOW));::ReleaseDC(m_hWnd,hWinDC);m_bIsInitialized = TRUE;return TRUE;}void CPictureEx::OnDestroy() {Stop();CStatic::OnDestroy();}void CPictureEx::SetBkColor(COLORREF clr){if (!m_bIsInitialized) return;m_clrBackground = clr;HBRUSH hBrush = CreateSolidBrush(clr);if (hBrush){RECT rect = {0,0,m_PictureSize.cx,m_PictureSize.cy};FillRect(m_hMemDC,&rect,hBrush);DeleteObject(hBrush);};}#ifdef GIF_TRACINGvoid CPictureEx::WriteDataOnDisk(CString szFileName, HGLOBAL hData, DWORD dwSize){CFile file;if (!file.Open(szFileName,CFile::modeCreate |CFile::modeWrite |CFile::shareDenyNone)){TRACE(_T("WriteData: Error creating file %s\n"),szFileName);return;};char *pData = reinterpret_cast<char *> (GlobalLock(hData));if (!pData){TRACE(_T("WriteData: Error locking memory\n"));return;};TRY{file.Write(pData,dwSize);}CATCH(CFileException, e);                                          {TRACE(_T("WriteData: An exception occured while writing to the file %s\n"),szFileName);e->Delete();GlobalUnlock(hData);file.Close();return;}END_CATCHGlobalUnlock(hData);file.Close();}void CPictureEx::EnumGIFBlocks(){enum GIFBlockTypes nBlock;ResetDataPointer();while(m_nCurrOffset < m_nDataSize){nBlock = GetNextBlock();switch(nBlock){case BLOCK_UNKNOWN:TRACE(_T("- Unknown block\n"));return;break;case BLOCK_TRAILER:TRACE(_T("- Trailer block\n"));break;case BLOCK_APPEXT:TRACE(_T("- Application extension block\n"));break;case BLOCK_COMMEXT:TRACE(_T("- Comment extension block\n"));break;case BLOCK_CONTROLEXT:{TGIFControlExt *pControl = reinterpret_cast<TGIFControlExt *> (&m_pRawData[m_nCurrOffset]);TRACE(_T("- Graphic control extension block (delay %d, disposal %d)\n"),pControl->m_wDelayTime, pControl->GetPackedValue(GCX_PACKED_DISPOSAL));};break;case BLOCK_PLAINTEXT:TRACE(_T("- Plain text extension block\n"));break;case BLOCK_IMAGE:TGIFImageDescriptor *pIDescr = reinterpret_cast<TGIFImageDescriptor *> (&m_pRawData[m_nCurrOffset]);TRACE(_T("- Image data block (%dx%d  %d,%d)\n"),pIDescr->m_wWidth,pIDescr->m_wHeight,pIDescr->m_wLeftPos,pIDescr->m_wTopPos);break;};SkipNextBlock();};TRACE(_T("\n"));}#endif // GIF_TRACINGBOOL CPictureEx::SetPaintRect(const RECT *lpRect){return CopyRect(&m_PaintRect, lpRect);}BOOL CPictureEx::GetPaintRect(RECT *lpRect){return CopyRect(lpRect, &m_PaintRect);}

【用法:】

1. 新建项目:在VC6中用MFC新建一个基于对话框的GifDemo应用程序,接受所有缺省选项即可;
  2.在项目中插入文件:把PictureEx.h,PictureEx.cpp文件copy 到项目文件夹下,Project->Add to Project->Files中选上PictureEx.h,PictureEx.cpp, Insert;
  3.加入图片控件:从对话框控件中把Picture Control(图片控件)拖入主对话框中,修改其属性:ID:IDC_GIF,TYPE:Rectangle,其余接受缺省选项。再在ClassWiard中为IDF_GIF加入CSatic控制变量m_GifPic, 注意看一下,GifDemoDlg.h中是否加上了#include "PictureEx.h"(由ClassWiard加入)。然后将CSatic m_GifPic;更改成CPictureEx m_GifPic;
  4.加载动画文件:先将要加载的动画文件放到 res 资源文件夹下,再将其Import进项目中,由于MFC只支持256BMP文件的图片,因此,我们要新建一个图片类型:"GIF",我在这里将我网站的宣传图片roaring.gif放进去 (希望大家多支持),并将其ID修改成:IDR_GIFROARING。
  ____________________________________
  import(导入)gif动画的详细过程:
  在resourceview窗口中,单击鼠标右键,在出现的环境菜单中选择“import...”命令,会出现“import resource”选择文件对话框,文件类型选择“所有文件(*.*)”,open as 选项为"auto",再选择动画文件所在目录,选上要载入的动画文件 roaring.gif,再单击 import,由于gif动画类型不是vc默认的文件类型,这时会出现"custom resource type"对话框,键入“"gif"”,再单击ok,然后再修改其id。
  ________________________________________________________________
  5.在程序的适当位置添入加载代码: 这里,我们在CGifDemoDlg::OnInitDialog()函数中加入如下代码:
  // TODO: Add extra initialization here
  if (m_GifPic.Load(MAKEINTRESOURCE(IDR_GIFROARING),_T("Gif")))
  m_GifPic.Draw();
  如果仅仅把动画载入,到这就可以了,运行一下,应该看看您的的成果了。

0 0
原创粉丝点击