• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-10  評論-9  文章-0  trackbacks-0

                今天開始想寫點東西了,很多時候寫過的代碼想翻出來看看就是找不到,發在blog上也許可以提供一個很好的查詢手段。
                 前些天幫同學寫了一個數據庫blob存取的一個小程序,從網上找了些別人的代碼改了改,作為一個圖片存儲和查看的小工具也還不錯,發到這里備份起來MyMfcPhoto。
                 這個程序用了一個別人寫的類CPictureEx,感覺不錯,代碼如下:
            ///////PictureEx.h///////////////////////////////////////////////////////////////
            // 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 TRACEs

            class CPictureEx : public CStatic
            {
            public:

            struct TFrame    // structure that keeps a single frame info
            {
             IPicture *m_pPicture;  // pointer to the interface used for drawing
             SIZE     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 on

            enum 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 method
             GCX_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 width
             WORD m_wHeight; // 2 bytes. Logical screen height

             unsigned char m_cPacked;      // packed field 

             unsigned char m_cBkIndex;     // 1 byte. Background color index
             unsigned char m_cPixelAspect; // 1 byte. Pixel aspect ratio
             inline 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 11
             char m_cAppIdentifier[8];   // application identifier
             char 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 4
             unsigned char m_cPacked;    // packed field
             WORD m_wDelayTime; // delay time
             unsigned char m_cTColorIndex; // transparent color index
             unsigned 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 12
             WORD m_wLeftPos;    // text grid left position
             WORD m_wTopPos;     // text grid top position
             WORD m_wGridWidth;  // text grid width
             WORD m_wGridHeight; // text grid height
             unsigned char m_cCellWidth;  // character cell width
             unsigned char m_cCellHeight; // character cell height
             unsigned char m_cFgColor; // text foreground color index
             unsigned 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 position
             WORD m_wTopPos;  // image top position
             WORD m_wWidth;   // image width
             WORD m_wHeight;  // image height
             unsigned char m_cPacked; // packed field
             inline int GetPackedValue(enum IDPackedValues Value);
            };

            #pragma pack() // turn byte alignment off

            public:
             BOOL GetPaintRect(RECT *lpRect);
             BOOL SetPaintRect(const RECT *lpRect);
             CPictureEx();
             virtual ~CPictureEx();
             void Stop();   // stops animation
             void UnLoad(); // stops animation plus releases all resources

             BOOL 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 frame
             BOOL 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 hGlobal
             BOOL 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);

             void setPictureSize( int _width,int _height );

            protected:

            #ifdef GIF_TRACING
             void EnumGIFBlocks();
             void WriteDataOnDisk(CString szFileName, HGLOBAL hData, DWORD dwSize);
            #endif // GIF_TRACING

             RECT 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_MSG
             
             DECLARE_MESSAGE_MAP()
            };

            #endif // !defined(AFX_PICTUREEX_H__0EFE5DE0_7B68_4DB7_8B34_5DC634948438__INCLUDED_)

            //////////////////////////////////////////////////////////////////////
            // 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_FILE
            static 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;
            }

            PictureEx.cpp:
            //////////////////////////////////////////////////////////////////////
            // Construction/Destruction
            //////////////////////////////////////////////////////////////////////

            CPictureEx::CPictureEx()
            {
             // check structures size
             ASSERT(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 default
             m_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_MAP
            END_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 variables
              m_pRawData = NULL;
              GlobalUnlock(hGlobal);

              // don't delete memory on object's release
              if (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 size

              long 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 GIF
              m_bIsGIF = TRUE;
              m_pGIFLSDescriptor = reinterpret_cast<TGIFLSDescriptor *>
               (m_pRawData + sizeof(TGIFHeader));
              if (m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCT) == 1)
              {
               // calculate the globat color table size
               m_nGlobalCTSize = static_cast<int>
                (3* (1 << (m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCTSIZE)+1)));
               // get the background color if GCT is present
               unsigned 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 size
              m_PictureSize.cx = m_pGIFLSDescriptor->m_wWidth;
              m_PictureSize.cy = m_pGIFLSDescriptor->m_wHeight;

              // determine frame count for this picture
              UINT nFrameCount=0;
              ResetDataPointer();
              while (SkipNextGraphicBlock())
               nFrameCount++;

            #ifdef GIF_TRACING
              TRACE(
               _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();
            #endif

              if (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 pic

              if (nFrameCount == 1)
              {
               // clear GIF variables
               m_pRawData = NULL;
               GlobalUnlock(hGlobal);

               // don't delete memory on object's release
               if (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 array

               TFrame 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_TRACING

                IStream *pStream = NULL;

                // delete memory on object's release
                if (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 frame
                m_arrFrames.push_back(frame);
               };

               // clean after ourselves
               m_pRawData = NULL;
               GlobalUnlock(hGlobal);

               if (m_arrFrames.empty()) // couldn't load any frames
                return 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 default
             m_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 us
             
              unsigned 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);

               float t_w,t_h;
               t_w = (float)hmWidth/10583;
               t_h = (float)hmHeight/10583;
               if(t_w>t_h)
               {
                m_PictureSize.cy /= t_w/t_h;
               }
               else
               {
                m_PictureSize.cx /= t_h/t_w;
               }

               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_CATCH
             GlobalUnlock(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 real

             HGLOBAL 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 descriptor
             m_nCurrOffset =
              sizeof(TGIFHeader)+sizeof(TGIFLSDescriptor)+m_nGlobalCTSize;
            }

            BOOL CPictureEx::SkipNextGraphicBlock()
            {
             if (!m_pRawData) return FALSE;

             // GIF header + LSDescriptor [+ GCT] [+ Control block] + Data

             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 FALSE;

             // it's either a control ext.block, an image or a plain text

             if (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 block
              while ((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 block
              switch(m_pRawData[m_nCurrOffset+1])
              {
              case 0x01:
              // plain text extension
               return BLOCK_PLAINTEXT;
               break;

              case 0xF9:
              // graphic control extension
               return BLOCK_CONTROLEXT;
               break;

              case 0xFE:
              // comment extension
               return BLOCK_COMMEXT;
               break;

              case 0xFF:
              // application extension
               return BLOCK_APPEXT;
               break;
              };
              break;
             
             case 0x3B:
             // trailer
              return BLOCK_TRAILER;
              break;

             case 0x2C:
             // image data
              return 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 handle
             CloseHandle(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 #2
             if (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 #3
              if (m_hDispMemDC && (m_arrFrames[m_nCurrFrame].m_nDisposal == 3) )
              {
               // put it back
               BitBlt(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 variables
               SelectObject(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 #3
               if (m_arrFrames[m_nCurrFrame].m_nDisposal == 3)
               {
                // prepare a memory DC and store the background in it
                m_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 100ms
               if (m_arrFrames[m_nCurrFrame].m_nDelay < 5)
                WaitForSingleObject(m_hExitEvent, 100);
               else
                WaitForSingleObject(m_hExitEvent, 10*m_arrFrames[m_nCurrFrame].m_nDelay);

               if (m_bExitThread) break;

               // disposal method #2
               if (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
                if (m_hDispMemDC && (m_arrFrames[m_nCurrFrame].m_nDisposal == 3) )
                {
                 // put it back
                 BitBlt(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 variables
                 SelectObject(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 execution
              WaitForSingleObject(m_hThread,5000);
              CloseHandle(m_hThread);
              m_hThread = NULL;
             }

             // make it possible to Draw() again
             ResetEvent(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 text

             int nStart = m_nCurrOffset;
             int nBlockLen = GetNextBlockLen();

             if (nBlockLen <= 0) return NULL;

             if (nBlock == BLOCK_CONTROLEXT)
             {
              // get the following data
              TGIFControlExt *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 value

             if (nBlock == BLOCK_IMAGE)
             {
              // store size and offsets
              TGIFImageDescriptor *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 trailer

             if (!hGlobal) return NULL;

             int nOffset = 0;

             // GMEM_FIXED means we get a pointer
             unsigned 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; // trailer
             nOffset++;

             *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 painting

             LONG 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 background
             m_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_TRACING
            void 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_CATCH
             
             GlobalUnlock(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_TRACING

            BOOL CPictureEx::SetPaintRect(const RECT *lpRect)
            {
             return CopyRect(&m_PaintRect, lpRect);
            }

            BOOL CPictureEx::GetPaintRect(RECT *lpRect)
            {
             return CopyRect(lpRect, &m_PaintRect);
            }


            void CPictureEx::setPictureSize( int _width,int _height )
            {
             m_PictureSize.cx = _width;
             m_PictureSize.cy = _height;
            }

            這個類可以顯示圖片(類型包括jpg、gif、bmp等),可以播放gif動畫。
            數據庫操作定義了一個類
            CImages::CImages(CDatabase* pdb) : CRecordset(pdb)
            讀取數據:
             int         nIndex = 0;
             CImages   dbImages(&theApp.m_DB);
             dbImages.Open();
             while   (!dbImages.IsEOF())
             {
              m_list.InsertItem(nIndex++,dbImages.m_BLOBName);
              dbImages.MoveNext();
             }

             dbImages.Close();

            查找記錄:
             CImages   dbImages(&theApp.m_DB);
             CString     strFileName = m_list.GetItemText(nIndex,0);
             dbImages.m_strFilter.Format("BLOBName = '%s'",strFileName);
             try
             {
              dbImages.Open();
              if  (dbImages.IsEOF())
               AfxMessageBox("Unable to get image from db");
              else
              {
               if (m_pic.Load(dbImages.m_BLOBImage.m_hData,dbImages.m_BLOBImage.m_dwDataLength))
               {
                m_pic.setPictureSize(300,300);
                m_pic.Draw();
               }
              }

              dbImages.Close();

             }
             catch(CException* pE)
             {
              pE->ReportError();
              pE->Delete();
              return;
             }

            posted on 2005-10-26 09:47 Ipedo 閱讀(1183) 評論(1)  編輯 收藏 引用

            評論:
            # re: 新的開始 2006-10-27 17:55 | ets2008@hotmail.com
            CPictureExWnd,試了沒有,我怎么也編譯不過。  回復  更多評論
              
            国产精品视频久久| 7777精品久久久大香线蕉| 男女久久久国产一区二区三区| 久久精品国产72国产精福利| 久久综合狠狠综合久久激情 | 国内精品九九久久久精品| 婷婷伊人久久大香线蕉AV| 亚洲伊人久久成综合人影院 | 久久精品国产亚洲沈樵| 久久久一本精品99久久精品88| 影音先锋女人AV鲁色资源网久久| 久久久www免费人成精品| 亚洲日本va中文字幕久久| 久久久无码人妻精品无码| AV色综合久久天堂AV色综合在| 国产亚洲欧美成人久久片| 亚洲天堂久久精品| 色婷婷综合久久久久中文字幕| 久久天天躁狠狠躁夜夜avapp| 亚洲精品国产字幕久久不卡| 久久精品人人做人人爽电影蜜月| 97久久精品无码一区二区 | 久久久久免费视频| 中文字幕无码久久人妻| 精品人妻久久久久久888| 国产综合精品久久亚洲| 久久人人爽人人爽人人片AV东京热 | 久久精品国产只有精品2020| 久久久99精品一区二区| 亚洲国产精品无码久久久不卡| 国产精品天天影视久久综合网| 久久精品国产一区二区电影| 97精品依人久久久大香线蕉97 | 欧洲人妻丰满av无码久久不卡| 久久电影网一区| 久久久精品国产免大香伊| 99久久综合国产精品二区| 欧洲人妻丰满av无码久久不卡| 久久强奷乱码老熟女网站| 久久99国产综合精品女同| 亚州日韩精品专区久久久|