GDI+顯示gif動畫ImageEx類

Code:
  1. // GDIPlusHelper.h: interface for the CGDIPlusHelper class.   
  2. //   
  3. //////////////////////////////////////////////////////////////////////   
  4.   
  5. #if !defined(AFX_GDIPLUSHELPER_H__BD5F6266_5686_43E2_B146_5EA1217A56FE__INCLUDED_)   
  6. #define AFX_GDIPLUSHELPER_H__BD5F6266_5686_43E2_B146_5EA1217A56FE__INCLUDED_   
  7.   
  8. #if _MSC_VER > 1000   
  9. #pragma once   
  10. #endif // _MSC_VER > 1000   
  11.   
  12. #include <windows.h>   
  13.   
  14. //注意:此類當創建的圖像對象是多幀動畫時,沒有考慮線程同步問題,不能在其他地方使用,   
  15. //比如所有的Graphics操作函數,以及從基類繼承過來的接口函數,你只能使用ImageEx類的public接口函數;   
  16. //而當創建的是單幀圖像時,線程同步性等價於基類Image的同步性,   
  17. //則你可以像以前使用Image類那樣使用該類,包括所有的Graphics操作函數,以及從基類繼承過來的接口函數。   
  18. //其實你會發現下面的public成員函數操作的成員變量都是新增的成員變量。   
  19.   
  20. class ImageEx : public Image   
  21. {   
  22. public:   
  23. //以長度爲nSize的內存pBuff中的內容構造圖像   
  24.     ImageEx(const void* pBuff, size_t nSize, BOOL useEmbeddedColorManagement = FALSE);   
  25. //以類型爲sResourceType,名稱爲sResource的資源構造圖像   
  26.     ImageEx(LPCTSTR sResourceType, LPCTSTR sResource, BOOL useEmbeddedColorManagement = FALSE);   
  27. //以文件構造圖像   
  28.     ImageEx(LPCTSTR filename, BOOL useEmbeddedColorManagement = FALSE);   
  29. //調用Destroy成員函數   
  30.     ~ImageEx();   
  31. public:   
  32. //如果已經構造的對象是動畫,則創建動畫線程,並返回true,   
  33. //如果爲靜態圖像或已經創建過動畫線程,則也返回false   
  34. // 圖像將繪製在m_hWnd客戶區的rect區域,會拉伸,支持鏡像   
  35.     bool InitAnimation(HWND hWnd, RECT rect);   
  36. //判斷是否爲動畫   
  37.     bool IsAnimatedGIF() { return m_nFrameCount > 1; }   
  38. //設置動畫暫停與否   
  39.     void SetPause(bool bPause);   
  40. //判斷動畫是否處於暫停狀態   
  41.     bool IsPaused() { return m_bPause; }   
  42. //關閉動畫,事實上基類Image中還有的兩個成員變量沒有關閉,因爲析構函數會調用基類析構函數進行關閉的   
  43.     void Destroy();   
  44.   
  45. protected:   
  46. //測試圖像是否爲動畫,是的話成員變量m_pPropertyItem將會malloc分配內存   
  47.     bool TestForAnimatedGIF();   
  48. //給所有成員變量初始化,構造函數中調用   
  49.     void Initialize();   
  50. //在客戶區畫出當前幀,返回值表示是否要退出線程函數   
  51.     bool DrawFrameGIF();   
  52. //把長度爲nSize的內存pBuff中的內容創建爲IStream流保存在類的m_pStream成員變量中,   
  53. //返回成功與否,不檢查參數的非法性   
  54.     bool LoadFromBuffer(const void* pBuff, size_t nSize);   
  55. //裝載名稱爲lpName,類型爲lpType的資源到pResource中,返回裝載成功與否。   
  56. //nBufSize表示pResource緩存的長度。pResource爲NULL時,nBufSize返回所需內存大小,   
  57. //不爲NULL時,返回實際資源大小,長度不夠時,相當於pResource爲NULL時的作用,只是返回值爲false。   
  58.     bool GetResource(LPCTSTR lpName, LPCTSTR lpType, void* pResource, size_t& nBufSize);   
  59. //裝載類型爲sResourceType,名稱爲sResource的資源到流對象成員變量m_pStream中,返回裝載成功與否,   
  60. //m_pStream在該函數中裝載成功與否保存在成員變量m_bIsInitialized中,   
  61. //同時,如果該類的對象是以文件構造的,則m_bIsInitialized表示構造成功與否   
  62.     bool Load(LPCTSTR sResourceType, LPCTSTR sResource); //類型,名字   
  63. //實際的線程函數   
  64.     void ThreadAnimation();   
  65. //代理線程函數,實際調用ThreadAnimation成員函數   
  66.     static UINT WINAPI _ThreadAnimationProc(LPVOID pParam);   
  67.   
  68. protected:   
  69.     IStream*        m_pStream; //記得Release   
  70.     HANDLE          m_hThread; //線程創建時是掛起的,須調用ResumeThread   
  71.     HANDLE          m_hPause; //手工重置,初始有信號   
  72.     HANDLE          m_hExitEvent; //手工重置,初始無信號   
  73.     HINSTANCE       m_hInst;   
  74.     HWND            m_hWnd;   
  75.     UINT            m_nFrameCount;   
  76.     UINT            m_nFramePosition;   
  77.     bool            m_bIsInitialized; //表示對象構造成功與否,不管是以資源還是文件的形式   
  78.     bool            m_bPause;   
  79.     PropertyItem*   m_pPropertyItem; //如果爲動畫,會malloc內存,記得free   
  80.     HDC             m_hdcMem; //雙緩存用,只在是多幀動畫且創建了播放線程時才創建   
  81.     HBITMAP         m_hbmpBack; //雙緩存用,只在是多幀動畫且創建了播放線程時才創建   
  82.     RECT            m_rect; // 圖像在m_hWnd客戶區繪製的區域,會拉伸,支持鏡像   
  83.     //另外,基類Image中還有兩個成員變量:nativeImage(GpImage*類型)和lastResult(Status類型)   
  84. };   
  85.   
  86.   
  87. #endif // !defined(AFX_GDIPLUSHELPER_H__BD5F6266_5686_43E2_B146_5EA1217A56FE__INCLUDED_)   
  88.   
  89.   
  90.   
  91. // GDIPlusHelper.cpp: implementation of the CGDIPlusHelper class.   
  92. //   
  93. //////////////////////////////////////////////////////////////////////   
  94.   
  95. #include "stdafx.h"   
  96. #include "ImageEx.h"   
  97. #include <process.h>   
  98. #include <string>   
  99.   
  100.   
  101. #ifdef _DEBUG   
  102. #undef THIS_FILE   
  103. static char THIS_FILE[]=__FILE__;   
  104. #define new DEBUG_NEW   
  105. #endif   
  106.   
  107.   
  108. ////////////////////////////////////////////////////////////////////////////////   
  109. int A2U(const char* szA,wchar_t* szU,size_t cnt)   
  110. {   
  111.     return MultiByteToWideChar (CP_ACP, 0, szA, -1, szU, cnt) ;   
  112. }   
  113. std::wstring A2U(const char* szA)   
  114. {   
  115.     int nRetCode=A2U(szA,0,0);   
  116.     if(0==nRetCode)   
  117.         return std::wstring();   
  118.     std::wstring str(nRetCode-1,'/0');   
  119.     A2U(szA,(wchar_t*)(str.c_str()),nRetCode);   
  120.     return str;   
  121. }   
  122. ////////////////////////////////////////////////////////////////////////////////   
  123. //以長度爲nSize的內存pBuff中的內容構造圖像   
  124. ////////////////////////////////////////////////////////////////////////////////   
  125. ImageEx::ImageEx(const void* pBuff, size_t nSize, BOOL useEmbeddedColorManagement)   
  126. {   
  127.     Initialize();   
  128.   
  129.     bool bResult = LoadFromBuffer(pBuff, nSize);   
  130.     m_bIsInitialized = bResult;   
  131.   
  132.     if (m_bIsInitialized)   
  133.     {   
  134.         nativeImage = NULL;   
  135.         if (useEmbeddedColorManagement)   
  136.             lastResult = DllExports::GdipLoadImageFromStreamICM(m_pStream, &nativeImage);   
  137.         else  
  138.             lastResult = DllExports::GdipLoadImageFromStream(m_pStream, &nativeImage);   
  139.         TestForAnimatedGIF();   
  140.     }   
  141. }   
  142. ////////////////////////////////////////////////////////////////////////////////   
  143. //以類型爲sResourceType,名稱爲sResource的資源構造圖像   
  144. ////////////////////////////////////////////////////////////////////////////////   
  145. ImageEx::ImageEx(LPCTSTR sResourceType, LPCTSTR sResource, BOOL useEmbeddedColorManagement)   
  146. {   
  147.     Initialize();   
  148.   
  149.     if (Load(sResourceType, sResource))   
  150.     {   
  151.         nativeImage = NULL;   
  152.         if (useEmbeddedColorManagement)   
  153.             lastResult = DllExports::GdipLoadImageFromStreamICM(m_pStream, &nativeImage);   
  154.         else  
  155.             lastResult = DllExports::GdipLoadImageFromStream(m_pStream, &nativeImage);   
  156.         TestForAnimatedGIF();   
  157.     }   
  158. }   
  159.   
  160. ////////////////////////////////////////////////////////////////////////////////   
  161. //以文件構造圖像   
  162. ////////////////////////////////////////////////////////////////////////////////   
  163. ImageEx::ImageEx(LPCTSTR filename, BOOL useEmbeddedColorManagement) :   
  164. #ifndef UNICODE   
  165. Image(A2U(filename).c_str(), useEmbeddedColorManagement)   
  166. #else   
  167. Image(filename, useEmbeddedColorManagement)   
  168. #endif   
  169. {   
  170.     Initialize();   
  171.   
  172.     m_bIsInitialized = (Ok == lastResult);   
  173.   
  174.     if(m_bIsInitialized)   
  175.         TestForAnimatedGIF();   
  176. }   
  177.   
  178. ////////////////////////////////////////////////////////////////////////////////   
  179. //析構函數,調用Destroy成員函數   
  180. ////////////////////////////////////////////////////////////////////////////////   
  181. ImageEx::~ImageEx()   
  182. {   
  183.     this->Destroy();   
  184. }   
  185.   
  186. ////////////////////////////////////////////////////////////////////////////////   
  187. //如果已經構造的對象是動畫,則創建動畫線程,並返回true,   
  188. //如果爲靜態圖像或已經創建過動畫線程,則也返回false   
  189. // 圖像將繪製在m_hWnd客戶區的rect區域,會拉伸,支持鏡像   
  190. ////////////////////////////////////////////////////////////////////////////////   
  191. bool ImageEx::InitAnimation(HWND hWnd, RECT rect)   
  192. {   
  193.     m_hWnd = hWnd;   
  194.     m_rect = rect;   
  195.   
  196.     if (!m_bIsInitialized)   
  197.         return false;   
  198.   
  199.     if (IsAnimatedGIF())   
  200.     {   
  201.         if (m_hThread == NULL)   
  202.         {   
  203.             unsigned int nTID = 0;   
  204.             HDC hDC = GetDC(m_hWnd);   
  205.             m_hdcMem = CreateCompatibleDC(hDC);   
  206.             m_hbmpBack = CreateCompatibleBitmap(hDC,GetWidth(),GetHeight());   
  207.             SelectObject(m_hdcMem,m_hbmpBack);   
  208.             ReleaseDC(m_hWnd, hDC);   
  209.   
  210.             m_hThread = (HANDLE) _beginthreadex( NULL, 0, _ThreadAnimationProc, this, CREATE_SUSPENDED,&nTID);   
  211.                
  212.             if (!m_hThread)   
  213.                 return false;   
  214.             else  
  215.             {   
  216.                 ResumeThread(m_hThread);   
  217.                 return true;   
  218.             }   
  219.         }   
  220.     }    
  221.   
  222.     return false;      
  223. }   
  224.   
  225. ////////////////////////////////////////////////////////////////////////////////   
  226. //把長度爲nSize的內存pBuff中的內容創建爲IStream流保存在類的m_pStream成員變量中,   
  227. //返回成功與否,不檢查參數的非法性   
  228. ////////////////////////////////////////////////////////////////////////////////   
  229. bool ImageEx::LoadFromBuffer(const void* pBuff, size_t nSize)   
  230. {   
  231.     bool bResult = false;   
  232.   
  233.     HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, nSize);   
  234.     if (hGlobal)   
  235.     {   
  236.         void* pData = GlobalLock(hGlobal);   
  237.         if (pData)   
  238.             memcpy(pData, pBuff, nSize);   
  239.            
  240.         GlobalUnlock(hGlobal);   
  241.   
  242.         if (CreateStreamOnHGlobal(hGlobal, TRUE, &m_pStream) == S_OK)   
  243.             bResult = true;   
  244.   
  245.     }   
  246.   
  247.     return bResult;   
  248. }   
  249.   
  250. ////////////////////////////////////////////////////////////////////////////////   
  251. //裝載名稱爲lpName,類型爲lpType的資源到pResource中,返回裝載成功與否。   
  252. //nBufSize表示pResource緩存的長度。pResource爲NULL時,nBufSize返回所需內存大小,   
  253. //不爲NULL時,返回實際資源大小,長度不夠時,相當於pResource爲NULL時的作用,只是返回值爲false。   
  254. ////////////////////////////////////////////////////////////////////////////////   
  255. bool ImageEx::GetResource(LPCTSTR lpName, LPCTSTR lpType, void* pResource, size_t& nBufSize)   
  256. {    
  257.     HRSRC       hResInfo;   
  258.     HGLOBAL     hRes;   
  259.     void*       lpRes   = NULL;    
  260.     size_t      nLen    = 0;   
  261.     bool        bResult = FALSE;   
  262.     // Find the resource   
  263.     hResInfo = FindResource(m_hInst , lpName, lpType);   
  264.     if (hResInfo == NULL)    
  265.     {   
  266.         DWORD dwErr = GetLastError();   
  267.         return false;   
  268.     }   
  269.     // Load the resource   
  270.     hRes = LoadResource(m_hInst , hResInfo);   
  271.     if (hRes == NULL)    
  272.         return false;   
  273.     // Lock the resource   
  274.     lpRes = LockResource(hRes);   
  275.   
  276.     if (lpRes != NULL)   
  277.     {   
  278.         nLen = SizeofResource(m_hInst , hResInfo);   
  279.         if (pResource == NULL)   
  280.         {   
  281.             nBufSize = nLen;   
  282.             bResult = true;   
  283.         }   
  284.         else  
  285.         {   
  286.             if (nBufSize >= nLen)   
  287.             {   
  288.                 memcpy(pResource, lpRes, nLen);   
  289.                 bResult = true;   
  290.             }   
  291.             nBufSize = nLen;   
  292.         }   
  293.         UnlockResource(hRes);     
  294.     }   
  295.     // Free the resource   
  296.     FreeResource(hRes);   
  297.   
  298.     return bResult;   
  299. }   
  300.   
  301. ////////////////////////////////////////////////////////////////////////////////   
  302. //裝載類型爲sResourceType,名稱爲sResource的資源到流對象成員變量m_pStream中,返回裝載成功與否,   
  303. //m_pStream在該函數中裝載成功與否保存在成員變量m_bIsInitialized中,   
  304. //同時,如果該類的對象是以文件構造的,則m_bIsInitialized表示構造成功與否   
  305. ////////////////////////////////////////////////////////////////////////////////   
  306. bool ImageEx::Load(LPCTSTR sResourceType, LPCTSTR sResource)   
  307. {   
  308.     bool bResult = false;   
  309.   
  310.     BYTE*   pBuff = NULL;   
  311.     size_t  nSize = 0;   
  312.     if (GetResource(sResource, sResourceType, pBuff, nSize))   
  313.     {   
  314.         if (nSize > 0)   
  315.         {   
  316.             pBuff = new BYTE[nSize];   
  317.   
  318.             if (GetResource(sResource, sResourceType, (void*)pBuff, nSize))   
  319.             {   
  320.                 bResult = LoadFromBuffer((const void*)pBuff, nSize);   
  321.             }   
  322.   
  323.             delete [] pBuff;   
  324.         }   
  325.     }   
  326.   
  327.     m_bIsInitialized = bResult;   
  328.   
  329.     return bResult;   
  330. }   
  331.   
  332. ////////////////////////////////////////////////////////////////////////////////   
  333. //測試圖像是否爲動畫,是的話成員變量m_pPropertyItem將會malloc分配內存   
  334. ////////////////////////////////////////////////////////////////////////////////   
  335. bool ImageEx::TestForAnimatedGIF()   
  336. {   
  337.     UINT count = 0;   
  338.     count = GetFrameDimensionsCount();   
  339.     GUID* pDimensionIDs = new GUID[count];   
  340.   
  341.     // Get the list of frame dimensions from the Image object.   
  342.     GetFrameDimensionsList(pDimensionIDs, count);   
  343.   
  344.     // Get the number of frames in the first dimension.   
  345.     m_nFrameCount = GetFrameCount(&pDimensionIDs[0]);   
  346.   
  347.     // Assume that the image has a property item of type PropertyItemEquipMake.   
  348.     // Get the size of that property item.   
  349.     if (m_nFrameCount > 1)   
  350.     {   
  351.         int nSize = GetPropertyItemSize(PropertyTagFrameDelay);   
  352.   
  353.         // Allocate a buffer to receive the property item.   
  354.         m_pPropertyItem = (PropertyItem*) malloc(nSize);   
  355.   
  356.         GetPropertyItem(PropertyTagFrameDelay, nSize, m_pPropertyItem);   
  357.     }   
  358.   
  359.     delete pDimensionIDs;   
  360.   
  361.     return m_nFrameCount > 1;   
  362. }   
  363.   
  364. ////////////////////////////////////////////////////////////////////////////////   
  365. //給所有成員變量初始化,構造函數中調用   
  366. ////////////////////////////////////////////////////////////////////////////////   
  367. void ImageEx::Initialize()   
  368. {   
  369.     m_pStream = NULL;   
  370.     m_hThread = NULL;   
  371.     m_hPause = CreateEvent(NULL,TRUE,TRUE,NULL); //手工重置,初始有信號   
  372.     m_hExitEvent = CreateEvent(NULL,TRUE,FALSE,NULL); //手工重置,初始無信號   
  373.     m_hInst = GetModuleHandle(NULL);   
  374.     m_hWnd = NULL;   
  375.     m_nFrameCount = 0;   
  376.     m_nFramePosition = 0;   
  377.     m_bIsInitialized = false;   
  378.     m_bPause = false;   
  379.     m_pPropertyItem = NULL;   
  380.     m_hdcMem = NULL;   
  381.     m_hbmpBack = NULL;   
  382.     SetRect(&m_rect,0,0,0,0);   
  383. //以下兩句不能有,因爲Initialize函數是構造函數中調用,下面兩個屬於基類的成員變量不能再次被修改   
  384. //  nativeImage = NULL;   
  385. //  lastResult = InvalidParameter;   
  386. }   
  387.   
  388. ////////////////////////////////////////////////////////////////////////////////   
  389. //代理線程函數,實際調用ThreadAnimation成員函數   
  390. ////////////////////////////////////////////////////////////////////////////////   
  391. UINT WINAPI ImageEx::_ThreadAnimationProc(LPVOID pParam)   
  392. {   
  393.     ImageEx *pImage = reinterpret_cast<ImageEx *> (pParam);   
  394.     pImage->ThreadAnimation();   
  395.   
  396.     return 0;   
  397. }   
  398.   
  399. ////////////////////////////////////////////////////////////////////////////////   
  400. //實際的線程函數   
  401. ////////////////////////////////////////////////////////////////////////////////   
  402. void ImageEx::ThreadAnimation()   
  403. {   
  404.     m_nFramePosition = 0;   
  405.   
  406.     bool bExit = false;   
  407.     while (!bExit)   
  408.     {   
  409.         bExit = DrawFrameGIF();   
  410.     }   
  411. }   
  412.   
  413. ////////////////////////////////////////////////////////////////////////////////   
  414. //在客戶區畫出當前幀,返回值表示是否要退出線程函數   
  415. ////////////////////////////////////////////////////////////////////////////////   
  416. bool ImageEx::DrawFrameGIF()   
  417. {   
  418.     ::WaitForSingleObject(m_hPause, INFINITE); //m_hPause手工重置,初始有信號   
  419. //pageGuid的值在顯示GIF爲FrameDimensionTime,顯示TIF時爲FrameDimensionPage   
  420.     GUID   pageGuid = FrameDimensionTime;   
  421.   
  422.     RECT rect;   
  423.     UINT width, height;   
  424.     HDC  hDC = GetDC(m_hWnd);   
  425.     int  BltMode = SetStretchBltMode (hDC, COLORONCOLOR) ;   
  426.     if (m_hdcMem)   
  427.     {   
  428.         width = GetWidth();   
  429.         height = GetHeight();   
  430.         SetRect(&rect, 0, 0, width, height);   
  431.         FillRect(m_hdcMem,&rect,(HBRUSH) (COLOR_WINDOW+1));   
  432.         Graphics graphics(m_hdcMem);   
  433.         graphics.DrawImage(this, 0, 0, width, height);   
  434.         StretchBlt(hDC, m_rect.left, m_rect.top,   
  435.                         m_rect.right-m_rect.left, m_rect.bottom-m_rect.top,   
  436.                     m_hdcMem, 0, 0, width, height, SRCCOPY);   
  437.     }   
  438.     SetStretchBltMode (hDC, BltMode) ;   
  439.     ReleaseDC(m_hWnd, hDC);   
  440.   
  441.     long lPause = ((long*) m_pPropertyItem->value)[m_nFramePosition] * 10;   
  442.     if(lPause<10)   
  443.         lPause=80;   
  444.     else if(lPause>5000)   
  445.         lPause=80;   
  446.     DWORD dwErr = WaitForSingleObject(m_hExitEvent, lPause); //m_hExitEvent手工重置,初始無信號   
  447.   
  448.     if(WAIT_OBJECT_0 != dwErr)    
  449.     {   
  450.         if(++m_nFramePosition == m_nFrameCount)   
  451.             m_nFramePosition = 0;   
  452.         SelectActiveFrame(&pageGuid, m_nFramePosition);   
  453.         return false;   
  454.     }   
  455.     else  
  456.         return true// 如果在lPause時間內產生信號,則返回true,表示要退出線程   
  457. }   
  458.   
  459. ////////////////////////////////////////////////////////////////////////////////   
  460. //設置動畫暫停與否   
  461. ////////////////////////////////////////////////////////////////////////////////   
  462. void ImageEx::SetPause(bool bPause)   
  463. {   
  464.     if (!IsAnimatedGIF())   
  465.         return;   
  466.   
  467.     if (!m_bPause && bPause) //本來沒暫停且要設置爲暫停   
  468.     {   
  469.         ResetEvent(m_hPause);   
  470.     }   
  471.     else  
  472.     {   
  473.         if (m_bPause && !bPause) //本來已暫停且要設置爲非暫停   
  474.         {   
  475.             SetEvent(m_hPause);   
  476.         }   
  477.     }   
  478.   
  479.     m_bPause = bPause;   
  480. }   
  481.   
  482. ////////////////////////////////////////////////////////////////////////////////   
  483. //關閉動畫,事實上基類Image中還有的兩個成員變量沒有關閉,因爲析構函數會調用基類析構函數進行關閉的   
  484. ////////////////////////////////////////////////////////////////////////////////   
  485. void ImageEx::Destroy()   
  486. {   
  487.     if (m_hThread)   
  488.     {   
  489.         this->SetPause(false);   
  490.         SetEvent(m_hExitEvent);   
  491.         WaitForSingleObject(m_hThread, INFINITE);   
  492.         CloseHandle(m_hThread);   
  493.         DeleteDC(m_hdcMem);   
  494.         DeleteObject(m_hbmpBack);   
  495.   
  496.         m_hThread = NULL;   
  497.         m_hdcMem = NULL;   
  498.         m_hbmpBack = NULL;   
  499.     }   
  500.     if(m_hExitEvent)   
  501.         CloseHandle(m_hExitEvent);   
  502.     if(m_hPause)   
  503.         CloseHandle(m_hPause);   
  504.     free(m_pPropertyItem);   
  505.   
  506.     m_hExitEvent = NULL;   
  507.     m_hPause = NULL;   
  508.     m_pPropertyItem = NULL;   
  509.   
  510.     if (m_pStream)   
  511.     {   
  512.         m_pStream->Release();   
  513.         m_pStream = NULL;   
  514.     }   
  515. }   

使用GDI+庫顯示gif動態圖片,該類接口如下:
可以看出,該ImageEx完全繼承了基類的接口函數。
說明:
如果打開非多幀圖片,該類幾乎完全等價於基類,比如你可以把該類的對象代入Graphics類系列的成員函數中;
如果打開的是多幀的圖片,你只要打開圖片後不調用InitAnimation函數(它會創建線程),則上述做法依然可以;
但如果調用InitAnimation函數後(單幀圖像沒關係,因爲不會創建線程),則不可以了,
所有的基類繼承過來的接口成員函數和配合gdi+庫其他類的函數調用都是不可以的,因爲沒有作線程同步,
你只能調用下面位數不多的幾個public成員函數,調用Destroy成員函數後,則就可以了,因爲它會關閉線程。
其實你會發現下面的public成員函數操作的成員變量都是新增的成員變量,沒涉及到線程同步問題。

class ImageEx : public Image
{
public:
//以長度爲nSize的內存pBuff中的內容構造圖像
 ImageEx(const void* pBuff, size_t nSize, BOOL useEmbeddedColorManagement = FALSE);
//以類型爲sResourceType,名稱爲sResource的資源構造圖像
 ImageEx(LPCTSTR sResourceType, LPCTSTR sResource, BOOL useEmbeddedColorManagement = FALSE);
//以文件構造圖像
 ImageEx(LPCTSTR filename, BOOL useEmbeddedColorManagement = FALSE);
//調用Destroy成員函數
 ~ImageEx();
public:
//如果已經構造的對象是動畫,則創建動畫線程,並返回true,
//如果爲靜態圖像或已經創建過動畫線程,則也返回false
// 圖像將繪製在m_hWnd客戶區的rect區域,會拉伸,支持鏡像
 bool InitAnimation(HWND hWnd, RECT rect);
//判斷是否爲動畫
 bool IsAnimatedGIF() { return m_nFrameCount > 1; }
//設置動畫暫停與否
 void SetPause(bool bPause);
//判斷動畫是否處於暫停狀態
 bool IsPaused() { return m_bPause; }
//關閉動畫,事實上基類Image中還有的兩個成員變量沒有關閉,因爲析構函數會調用基類析構函數進行關閉的
 void Destroy();
//另外的非public的東西省略..
};

用法:
MFC對話框程序在下面添加:

BOOL CTestDlgDlg::OnInitDialog()
{
 CDialog::OnInitDialog();
 //其它的初始化代碼
 // GDI+
 //m_image爲ImageEx指針類型成員變量,"GIF"爲資源類型,"HEARTS"爲資源名稱
 m_image = new ImageEx( _T("GIF"), _T("HEARTS") );
 RECT rc;
 GetClientRect(&rc);
 m_image->InitAnimation(this->m_hWnd, rc);//創建gif播放線程
 
 return TRUE;  // return TRUE  unless you set the focus to a control
}

CTestDlgDlg::~CTestDlgDlg()
{
 // GDI+
 delete m_image;
}
其中的m_image = new ImageEx( _T("GIF"), _T("HEARTS") );你可以換成ImageEx類的另外兩個構造函數

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章