www.gusucode.com > 用VS2008+ATL开发可以显示Gif的ActiveX控件源码源码程序 > 用VS2008+ATL开发可以显示Gif的ActiveX控件源码/用VS2008+ATL开发Gif的ActiveX控件/用VS2008+ATL开发Gif的ActiveX控件/GifSolution/GifAnimate/GifImage.cpp

    #include "StdAfx.h"
#include "GifImage.h"

GifImage::GifImage(void)
{
	m_hDestHwnd = NULL;
	m_hThread   = NULL;

	reset_status();
}

GifImage::~GifImage(void)
{
	free_gif();
}

void GifImage::reset_status()
{
	m_Direction = emForward;
	m_dDelayTimeFactor = 1.0;
	m_nLoop         = -1;
	m_nFrameCount   = 0;
	m_nCurrentFrame = -1;
	m_bStopFlag = false;
	m_bPlaying  = false;
}

//加载文件
bool GifImage::LoadGifFromFile(BSTR bstrFile)
{
	free_gif();

	SharedPtr<Image> pImage(new Image(bstrFile));
	if (pImage->GetLastStatus() != Ok)
		return false;

	return load_gif(pImage);
}

bool GifImage::LoadGifFromStream(IUnknown* pStream)
{
	free_gif();

	CComQIPtr<IStream> pTemp = pStream;
	if (pTemp == NULL)
		return false;

	SharedPtr<Image> pImage(new Image((IStream*)pTemp));
	if (pImage->GetLastStatus() != Ok)
		return false;

	return load_gif(pImage);
}

bool GifImage::load_gif(SharedPtr<Image>& pImage)
{
	m_image = pImage;
	if (m_image == NULL)
		return false;

	// How many frame dimensions does the Image object have?
	int nCount = m_image->GetFrameDimensionsCount();
	if (nCount <= 0)
		return false;

	// Get the list of frame dimensions from the Image object.
	SharedPtr<GUID> pDimensionGUIDs(new GUID[nCount], true);
	if (Ok != m_image->GetFrameDimensionsList(pDimensionGUIDs.GetInternalPtr(), nCount))
		return false;

	// Display the GUID of the first (and only) frame dimension.
	// Get the number of frames in the first dimension.
	WCHAR strGuid[39] = {0};
	StringFromGUID2(pDimensionGUIDs.GetInternalPtr()[0], strGuid, 39);
	m_nFrameCount = m_image->GetFrameCount(pDimensionGUIDs.GetInternalPtr());

	// Assume that the image has a property item of type PropertyTagFrameDelay.
	// Get the size of that property item.
	int nSize = m_image->GetPropertyItemSize(PropertyTagFrameDelay);
	if (nSize > 0)
	{
		// Allocate a buffer to receive the property item.
		m_pDelay = SharedPtr<PropertyItem>((PropertyItem*)malloc(nSize), -1);
		if (m_pDelay)
		{
			m_image->GetPropertyItem(PropertyTagFrameDelay, nSize, m_pDelay.GetInternalPtr());
		}
	}

	return true;
}

void GifImage::free_gif()
{
	Stop();
	reset_status();
	m_image._Release();
	m_pDelay._Release();
}

//播放
void GifImage::Play(void)
{
	if (m_hThread)
	{
		Continue();
	}
	else
	{
		DWORD dwThreadID;
		m_hThread = CreateThread(NULL, 0, &GifThreadProc, this, CREATE_SUSPENDED, &dwThreadID);
		if (m_hThread)
		{
			m_bPlaying = true;
			ResumeThread(m_hThread);
		}
	}
}

void GifImage::Stop(void)
{
	if (m_hThread)
	{
		m_bStopFlag = true;
		Continue();
		if (WAIT_OBJECT_0 == WaitForSingleObject(m_hThread, INFINITE))
		{
			clear_thread();
		}
	}
}

void GifImage::clear_thread()
{
	m_ClearLock.Lock();

	if (m_hThread)
	{
		CloseHandle(m_hThread);
		m_hThread = NULL;
	}
	m_bPlaying = false;
	m_bStopFlag = false;

	m_ClearLock.Unlock();
}

void GifImage::Pause(void)
{
	if (m_hThread && m_bPlaying)
	{
		m_bPlaying = false;
		SuspendThread(m_hThread);
	}
}

void GifImage::Continue(void)
{
	if (m_hThread && !m_bPlaying)
	{
		m_bPlaying = true;
		ResumeThread(m_hThread);
	}
}

void GifImage::PrevFrame(void)
{
	move_frame(m_Direction == emReverse);
}

void GifImage::NextFrame(void)
{
	move_frame(m_Direction == emForward);
}

void GifImage::move_frame(bool bNext)
{
	m_MoveFrameLock.Lock();

	if (bNext)
		++m_nCurrentFrame;
	else
		--m_nCurrentFrame;

	if (m_nCurrentFrame < 0 || m_nCurrentFrame >= m_nFrameCount)
	{
		if (m_nLoop != 0)
		{
			if (m_nCurrentFrame >= m_nFrameCount)
				m_nCurrentFrame = 0;
			if (m_nCurrentFrame < 0)
				m_nCurrentFrame = m_nFrameCount - 1;
		}

		if (m_nLoop > 0)
		{
			--m_nLoop;
		}
	}

	m_MoveFrameLock.Unlock();
}

DWORD WINAPI GifThreadProc(LPVOID lpParameter)
{
	if (lpParameter == NULL)
	{
		ATLASSERT(FALSE);
		return 0;
	}

	GifImage* pGif = (GifImage*)lpParameter;

	if (!pGif->m_image)
	{
		pGif->clear_thread();
		return 0;
	}

	Graphics gp(pGif->m_hDestHwnd);
	UINT nWidth = pGif->m_image->GetWidth();
	UINT nHeight = pGif->m_image->GetHeight();

	while (true)
	{
		if (pGif->m_bStopFlag)
			break;

		if (!::IsWindow(pGif->m_hDestHwnd))
		{
			Sleep(500);
			continue;
		}

		pGif->NextFrame();
		if (pGif->m_nCurrentFrame < 0 || pGif->m_nCurrentFrame >= pGif->m_nFrameCount)
			break;

		pGif->m_image->SelectActiveFrame(&FrameDimensionTime, pGif->m_nCurrentFrame);

		gp.DrawImage(pGif->m_image.GetInternalPtr(), 0, 0, nWidth, nHeight);

		if (pGif->m_pDelay)
			Sleep(((long*)pGif->m_pDelay->value)[pGif->m_nCurrentFrame] * 10 * pGif->m_dDelayTimeFactor);
		else
			Sleep(100 * pGif->m_dDelayTimeFactor);			
	}

	pGif->clear_thread();
	return 0;
}