| /* -*- tab-width: 8; c-basic-offset: 4 -*- */ | 
 | /* | 
 |  * Animation control | 
 |  * | 
 |  * Copyright 1998, 1999 Eric Kohl | 
 |  * Copyright 1999 Eric Pouech | 
 |  * Copyright 2005 Dimitrie O. Paun | 
 |  * | 
 |  * This library is free software; you can redistribute it and/or | 
 |  * modify it under the terms of the GNU Lesser General Public | 
 |  * License as published by the Free Software Foundation; either | 
 |  * version 2.1 of the License, or (at your option) any later version. | 
 |  * | 
 |  * This library is distributed in the hope that it will be useful, | 
 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 |  * Lesser General Public License for more details. | 
 |  * | 
 |  * You should have received a copy of the GNU Lesser General Public | 
 |  * License along with this library; if not, write to the Free Software | 
 |  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
 |  * | 
 |  * NOTES | 
 |  * | 
 |  * This code was audited for completeness against the documented features | 
 |  * of Comctl32.dll version 6.0 on Mar. 15, 2005, by Dimitrie O. Paun. | 
 |  *  | 
 |  * Unless otherwise noted, we believe this code to be complete, as per | 
 |  * the specification mentioned above. | 
 |  * If you discover missing features, or bugs, please note them below. | 
 |  *  | 
 |  * TODO: | 
 |  *   - check for the 'rec ' list in some AVI files | 
 |  */ | 
 |  | 
 | #include <stdarg.h> | 
 | #include <string.h> | 
 | #include "windef.h" | 
 | #include "winbase.h" | 
 | #include "wingdi.h" | 
 | #include "winuser.h" | 
 | #include "winnls.h" | 
 | #include "commctrl.h" | 
 | #include "vfw.h" | 
 | #include "mmsystem.h" | 
 | #include "comctl32.h" | 
 | #include "wine/debug.h" | 
 |  | 
 | WINE_DEFAULT_DEBUG_CHANNEL(animate); | 
 |  | 
 | static struct { | 
 |     HMODULE	hModule; | 
 |     HIC         (WINAPI *fnICOpen)(DWORD, DWORD, UINT); | 
 |     LRESULT     (WINAPI *fnICClose)(HIC); | 
 |     LRESULT     (WINAPI *fnICSendMessage)(HIC, UINT, DWORD_PTR, DWORD_PTR); | 
 |     DWORD       (WINAPIV *fnICDecompress)(HIC,DWORD,LPBITMAPINFOHEADER,LPVOID,LPBITMAPINFOHEADER,LPVOID); | 
 | } fnIC; | 
 |  | 
 | typedef struct | 
 | { | 
 |    /* reference to input stream (file or resource) */ | 
 |    HGLOBAL 		hRes; | 
 |    HMMIO		hMMio;	/* handle to mmio stream */ | 
 |    HWND			hwndSelf; | 
 |    HWND			hwndNotify; | 
 |    DWORD		dwStyle; | 
 |    /* information on the loaded AVI file */ | 
 |    MainAVIHeader	mah; | 
 |    AVIStreamHeader	ash; | 
 |    LPBITMAPINFOHEADER	inbih; | 
 |    LPDWORD		lpIndex; | 
 |    /* data for the decompressor */ | 
 |    HIC			hic; | 
 |    LPBITMAPINFOHEADER	outbih; | 
 |    LPVOID		indata; | 
 |    LPVOID		outdata; | 
 |    /* data for the background mechanism */ | 
 |    CRITICAL_SECTION	cs; | 
 |    HANDLE		hStopEvent; | 
 |    HANDLE		hThread; | 
 |    DWORD		threadId; | 
 |    UINT			uTimer; | 
 |    /* data for playing the file */ | 
 |    int			nFromFrame; | 
 |    int			nToFrame; | 
 |    int			nLoop; | 
 |    int			currFrame; | 
 |    /* transparency info*/ | 
 |    COLORREF         	transparentColor; | 
 |    HBRUSH           	hbrushBG; | 
 |    HBITMAP  	    	hbmPrevFrame; | 
 | } ANIMATE_INFO; | 
 |  | 
 | #define ANIMATE_COLOR_NONE  	0xffffffff | 
 |  | 
 | static void ANIMATE_Notify(const ANIMATE_INFO *infoPtr, UINT notif) | 
 | { | 
 |     PostMessageW(infoPtr->hwndNotify, WM_COMMAND, | 
 | 		 MAKEWPARAM(GetDlgCtrlID(infoPtr->hwndSelf), notif), | 
 | 		 (LPARAM)infoPtr->hwndSelf); | 
 | } | 
 |  | 
 | static BOOL ANIMATE_LoadResW(ANIMATE_INFO *infoPtr, HINSTANCE hInst, LPCWSTR lpName) | 
 | { | 
 |     static const WCHAR aviW[] = { 'A', 'V', 'I', 0 }; | 
 |     HRSRC 	hrsrc; | 
 |     MMIOINFO	mminfo; | 
 |     LPVOID	lpAvi; | 
 |  | 
 |     hrsrc = FindResourceW(hInst, lpName, aviW); | 
 |     if (!hrsrc) | 
 | 	return FALSE; | 
 |  | 
 |     infoPtr->hRes = LoadResource(hInst, hrsrc); | 
 |     if (!infoPtr->hRes) | 
 |  	return FALSE; | 
 |  | 
 |     lpAvi = LockResource(infoPtr->hRes); | 
 |     if (!lpAvi) | 
 | 	return FALSE; | 
 |  | 
 |     memset(&mminfo, 0, sizeof(mminfo)); | 
 |     mminfo.fccIOProc = FOURCC_MEM; | 
 |     mminfo.pchBuffer = (LPSTR)lpAvi; | 
 |     mminfo.cchBuffer = SizeofResource(hInst, hrsrc); | 
 |     infoPtr->hMMio = mmioOpenW(NULL, &mminfo, MMIO_READ); | 
 |     if (!infoPtr->hMMio)  | 
 |     { | 
 | 	FreeResource(infoPtr->hRes); | 
 | 	return FALSE; | 
 |     } | 
 |  | 
 |     return TRUE; | 
 | } | 
 |  | 
 |  | 
 | static BOOL ANIMATE_LoadFileW(ANIMATE_INFO *infoPtr, LPWSTR lpName) | 
 | { | 
 |     infoPtr->hMMio = mmioOpenW(lpName, 0, MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE); | 
 |  | 
 |     if(!infoPtr->hMMio) return FALSE; | 
 |     return TRUE; | 
 | } | 
 |  | 
 |  | 
 | static BOOL ANIMATE_DoStop(ANIMATE_INFO *infoPtr) | 
 | { | 
 |     BOOL stopped = FALSE; | 
 |  | 
 |     EnterCriticalSection(&infoPtr->cs); | 
 |  | 
 |     /* should stop playing */ | 
 |     if (infoPtr->hThread) | 
 |     { | 
 |         HANDLE handle = infoPtr->hThread; | 
 |  | 
 |         TRACE("stopping animation thread\n"); | 
 |         infoPtr->hThread = 0; | 
 |         SetEvent( infoPtr->hStopEvent ); | 
 |  | 
 |         if (infoPtr->threadId != GetCurrentThreadId()) | 
 |         { | 
 |             LeaveCriticalSection(&infoPtr->cs);  /* leave it a chance to run */ | 
 |             WaitForSingleObject( handle, INFINITE ); | 
 |             TRACE("animation thread stopped\n"); | 
 |             EnterCriticalSection(&infoPtr->cs); | 
 |         } | 
 |  | 
 |         CloseHandle( handle ); | 
 |         CloseHandle( infoPtr->hStopEvent ); | 
 |         infoPtr->hStopEvent = 0; | 
 |         stopped = TRUE; | 
 |     } | 
 |     if (infoPtr->uTimer) { | 
 | 	KillTimer(infoPtr->hwndSelf, infoPtr->uTimer); | 
 | 	infoPtr->uTimer = 0; | 
 | 	stopped = TRUE; | 
 |     } | 
 |  | 
 |     LeaveCriticalSection(&infoPtr->cs); | 
 |  | 
 |     if (stopped) | 
 |         ANIMATE_Notify(infoPtr, ACN_STOP); | 
 |  | 
 |     return TRUE; | 
 | } | 
 |  | 
 |  | 
 | static void ANIMATE_Free(ANIMATE_INFO *infoPtr) | 
 | { | 
 |     if (infoPtr->hMMio) { | 
 | 	ANIMATE_DoStop(infoPtr); | 
 | 	mmioClose(infoPtr->hMMio, 0); | 
 | 	if (infoPtr->hRes) { | 
 |  	    FreeResource(infoPtr->hRes); | 
 | 	    infoPtr->hRes = 0; | 
 | 	} | 
 |         Free (infoPtr->lpIndex); | 
 |         infoPtr->lpIndex = NULL; | 
 | 	if (infoPtr->hic) { | 
 | 	    fnIC.fnICClose(infoPtr->hic); | 
 | 	    infoPtr->hic = 0; | 
 | 	} | 
 |         Free (infoPtr->inbih); | 
 |         infoPtr->inbih = NULL; | 
 |         Free (infoPtr->outbih); | 
 |         infoPtr->outbih = NULL; | 
 | 	Free (infoPtr->indata); | 
 |         infoPtr->indata = NULL; | 
 | 	Free (infoPtr->outdata); | 
 |         infoPtr->outdata = NULL; | 
 |     	if( infoPtr->hbmPrevFrame ) | 
 |         { | 
 | 	    DeleteObject(infoPtr->hbmPrevFrame); | 
 |             infoPtr->hbmPrevFrame = 0; | 
 |         } | 
 |  | 
 | 	memset(&infoPtr->mah, 0, sizeof(infoPtr->mah)); | 
 | 	memset(&infoPtr->ash, 0, sizeof(infoPtr->ash)); | 
 | 	infoPtr->nFromFrame = infoPtr->nToFrame = infoPtr->nLoop = infoPtr->currFrame = 0; | 
 |     } | 
 |     infoPtr->transparentColor = ANIMATE_COLOR_NONE; | 
 | } | 
 |  | 
 | static void ANIMATE_TransparentBlt(ANIMATE_INFO const *infoPtr, HDC hdcDest, HDC hdcSource) | 
 | { | 
 |     HDC hdcMask; | 
 |     HBITMAP hbmMask; | 
 |     HBITMAP hbmOld; | 
 |  | 
 |     /* create a transparency mask */ | 
 |     hdcMask = CreateCompatibleDC(hdcDest); | 
 |     hbmMask = CreateBitmap(infoPtr->inbih->biWidth, infoPtr->inbih->biHeight, 1,1,NULL); | 
 |     hbmOld = SelectObject(hdcMask, hbmMask); | 
 |  | 
 |     SetBkColor(hdcSource,infoPtr->transparentColor); | 
 |     BitBlt(hdcMask,0,0,infoPtr->inbih->biWidth, infoPtr->inbih->biHeight,hdcSource,0,0,SRCCOPY); | 
 |  | 
 |     /* mask the source bitmap */ | 
 |     SetBkColor(hdcSource, RGB(0,0,0)); | 
 |     SetTextColor(hdcSource, RGB(255,255,255)); | 
 |     BitBlt(hdcSource, 0, 0, infoPtr->inbih->biWidth, infoPtr->inbih->biHeight, hdcMask, 0, 0, SRCAND); | 
 |  | 
 |     /* mask the destination bitmap */ | 
 |     SetBkColor(hdcDest, RGB(255,255,255)); | 
 |     SetTextColor(hdcDest, RGB(0,0,0)); | 
 |     BitBlt(hdcDest, 0, 0, infoPtr->inbih->biWidth, infoPtr->inbih->biHeight, hdcMask, 0, 0, SRCAND); | 
 |  | 
 |     /* combine source and destination */ | 
 |     BitBlt(hdcDest,0,0,infoPtr->inbih->biWidth, infoPtr->inbih->biHeight,hdcSource,0,0,SRCPAINT); | 
 |  | 
 |     SelectObject(hdcMask, hbmOld); | 
 |     DeleteObject(hbmMask); | 
 |     DeleteDC(hdcMask); | 
 | } | 
 |  | 
 | static BOOL ANIMATE_PaintFrame(ANIMATE_INFO* infoPtr, HDC hDC) | 
 | { | 
 |     void const *pBitmapData; | 
 |     BITMAPINFO const *pBitmapInfo; | 
 |     HDC hdcMem; | 
 |     HBITMAP hbmOld; | 
 |     int nOffsetX = 0; | 
 |     int nOffsetY = 0; | 
 |     int nWidth; | 
 |     int nHeight; | 
 |  | 
 |     if (!hDC || !infoPtr->inbih) | 
 | 	return TRUE; | 
 |  | 
 |     if (infoPtr->hic ) | 
 |     { | 
 |         pBitmapData = infoPtr->outdata; | 
 |         pBitmapInfo = (LPBITMAPINFO)infoPtr->outbih; | 
 |  | 
 |         nWidth = infoPtr->outbih->biWidth; | 
 |         nHeight = infoPtr->outbih->biHeight; | 
 |     }  | 
 |     else | 
 |     { | 
 |         pBitmapData = infoPtr->indata; | 
 |         pBitmapInfo = (LPBITMAPINFO)infoPtr->inbih; | 
 |  | 
 |         nWidth = infoPtr->inbih->biWidth; | 
 |         nHeight = infoPtr->inbih->biHeight; | 
 |     } | 
 |  | 
 |     if(!infoPtr->hbmPrevFrame) | 
 |     { | 
 |         infoPtr->hbmPrevFrame=CreateCompatibleBitmap(hDC, nWidth,nHeight ); | 
 |     } | 
 |  | 
 |     hdcMem = CreateCompatibleDC(hDC); | 
 |     hbmOld = SelectObject(hdcMem, infoPtr->hbmPrevFrame); | 
 |  | 
 |     SetDIBits(hdcMem, infoPtr->hbmPrevFrame, 0, nHeight, pBitmapData, pBitmapInfo, DIB_RGB_COLORS); | 
 |  | 
 |     /* | 
 |      * we need to get the transparent color even without ACS_TRANSPARENT, | 
 |      * because the style can be changed later on and the color should always | 
 |      * be obtained in the first frame | 
 |      */ | 
 |     if(infoPtr->transparentColor == ANIMATE_COLOR_NONE) | 
 |     { | 
 |         infoPtr->transparentColor = GetPixel(hdcMem,0,0); | 
 |     } | 
 |  | 
 |     if(infoPtr->dwStyle & ACS_TRANSPARENT) | 
 |     { | 
 |         HDC hdcFinal = CreateCompatibleDC(hDC); | 
 |         HBITMAP hbmFinal = CreateCompatibleBitmap(hDC,nWidth, nHeight); | 
 |         HBITMAP hbmOld2 = SelectObject(hdcFinal, hbmFinal); | 
 |         RECT rect; | 
 |  | 
 |         rect.left = 0; | 
 |         rect.top = 0; | 
 |         rect.right = nWidth; | 
 |         rect.bottom = nHeight; | 
 |  | 
 |         if(!infoPtr->hbrushBG) | 
 |             infoPtr->hbrushBG = GetCurrentObject(hDC, OBJ_BRUSH); | 
 |  | 
 |         FillRect(hdcFinal, &rect, infoPtr->hbrushBG); | 
 |         ANIMATE_TransparentBlt(infoPtr, hdcFinal, hdcMem); | 
 |  | 
 |         SelectObject(hdcFinal, hbmOld2); | 
 |         SelectObject(hdcMem, hbmFinal); | 
 |         DeleteDC(hdcFinal); | 
 |         DeleteObject(infoPtr->hbmPrevFrame); | 
 |         infoPtr->hbmPrevFrame = hbmFinal; | 
 |     } | 
 |  | 
 |     if (infoPtr->dwStyle & ACS_CENTER) | 
 |     { | 
 |         RECT rect; | 
 |  | 
 |         GetWindowRect(infoPtr->hwndSelf, &rect); | 
 |         nOffsetX = ((rect.right - rect.left) - nWidth)/2; | 
 |         nOffsetY = ((rect.bottom - rect.top) - nHeight)/2; | 
 |     } | 
 |     BitBlt(hDC, nOffsetX, nOffsetY, nWidth, nHeight, hdcMem, 0, 0, SRCCOPY); | 
 |  | 
 |     SelectObject(hdcMem, hbmOld); | 
 |     DeleteDC(hdcMem); | 
 |     return TRUE; | 
 | } | 
 |  | 
 | static BOOL ANIMATE_DrawFrame(ANIMATE_INFO *infoPtr, HDC hDC) | 
 | { | 
 |     TRACE("Drawing frame %d (loop %d)\n", infoPtr->currFrame, infoPtr->nLoop); | 
 |  | 
 |     mmioSeek(infoPtr->hMMio, infoPtr->lpIndex[infoPtr->currFrame], SEEK_SET); | 
 |     mmioRead(infoPtr->hMMio, infoPtr->indata, infoPtr->ash.dwSuggestedBufferSize); | 
 |  | 
 |     if (infoPtr->hic && | 
 | 	fnIC.fnICDecompress(infoPtr->hic, 0, infoPtr->inbih, infoPtr->indata, | 
 | 		     infoPtr->outbih, infoPtr->outdata) != ICERR_OK) { | 
 | 	WARN("Decompression error\n"); | 
 | 	return FALSE; | 
 |     } | 
 |  | 
 |     ANIMATE_PaintFrame(infoPtr, hDC); | 
 |  | 
 |     if (infoPtr->currFrame++ >= infoPtr->nToFrame) { | 
 | 	infoPtr->currFrame = infoPtr->nFromFrame; | 
 | 	if (infoPtr->nLoop != -1) { | 
 | 	    if (--infoPtr->nLoop == 0) { | 
 | 		ANIMATE_DoStop(infoPtr); | 
 | 	    } | 
 | 	} | 
 |     } | 
 |  | 
 |     return TRUE; | 
 | } | 
 |  | 
 | static LRESULT ANIMATE_Timer(ANIMATE_INFO *infoPtr) | 
 | { | 
 |     HDC	hDC; | 
 |  | 
 |     if ((hDC = GetDC(infoPtr->hwndSelf)) != 0) | 
 |     { | 
 |         EnterCriticalSection(&infoPtr->cs); | 
 |         ANIMATE_DrawFrame(infoPtr, hDC); | 
 |         LeaveCriticalSection(&infoPtr->cs); | 
 |  | 
 | 	ReleaseDC(infoPtr->hwndSelf, hDC); | 
 |     } | 
 |  | 
 |     return 0; | 
 | } | 
 |  | 
 | static DWORD CALLBACK ANIMATE_AnimationThread(LPVOID ptr_) | 
 | { | 
 |     ANIMATE_INFO *infoPtr = (ANIMATE_INFO *)ptr_; | 
 |     HANDLE event; | 
 |     DWORD timeout; | 
 |  | 
 |     while(1) | 
 |     { | 
 |         HDC hDC = GetDC(infoPtr->hwndSelf); | 
 |  | 
 |         EnterCriticalSection(&infoPtr->cs); | 
 |         ANIMATE_DrawFrame(infoPtr, hDC); | 
 |         timeout = infoPtr->mah.dwMicroSecPerFrame; | 
 |         event = infoPtr->hStopEvent; | 
 |         LeaveCriticalSection(&infoPtr->cs); | 
 |  | 
 |         ReleaseDC(infoPtr->hwndSelf, hDC); | 
 |  | 
 |         /* time is in microseconds, we should convert it to milliseconds */ | 
 |         if ((event == 0) || WaitForSingleObject( event, (timeout+500)/1000) == WAIT_OBJECT_0) | 
 |             break; | 
 |     } | 
 |     return TRUE; | 
 | } | 
 |  | 
 | static LRESULT ANIMATE_Play(ANIMATE_INFO *infoPtr, UINT cRepeat, WORD wFrom, WORD wTo) | 
 | { | 
 |     /* nothing opened */ | 
 |     if (!infoPtr->hMMio) | 
 | 	return FALSE; | 
 |  | 
 |     if (infoPtr->hThread || infoPtr->uTimer) { | 
 | 	TRACE("Already playing\n"); | 
 | 	return TRUE; | 
 |     } | 
 |  | 
 |     infoPtr->nFromFrame = wFrom; | 
 |     infoPtr->nToFrame   = wTo; | 
 |     infoPtr->nLoop      = cRepeat; | 
 |  | 
 |     if (infoPtr->nToFrame == 0xFFFF) | 
 | 	infoPtr->nToFrame = infoPtr->mah.dwTotalFrames - 1; | 
 |  | 
 |     TRACE("(repeat=%d from=%d to=%d);\n", | 
 | 	  infoPtr->nLoop, infoPtr->nFromFrame, infoPtr->nToFrame); | 
 |  | 
 |     if (infoPtr->nFromFrame >= infoPtr->mah.dwTotalFrames && | 
 |         (SHORT)infoPtr->nFromFrame < 0) | 
 |         infoPtr->nFromFrame = 0; | 
 |  | 
 |     if (infoPtr->nFromFrame > infoPtr->nToFrame || | 
 | 	infoPtr->nToFrame >= infoPtr->mah.dwTotalFrames) | 
 | 	return FALSE; | 
 |  | 
 |     infoPtr->currFrame = infoPtr->nFromFrame; | 
 |  | 
 |     /* seek - doesn't need to start a thread or set a timer and neither | 
 |      * does it send a notification */ | 
 |     if (infoPtr->nFromFrame == infoPtr->nToFrame) | 
 |     { | 
 |         HDC hDC; | 
 |  | 
 |         if ((hDC = GetDC(infoPtr->hwndSelf)) != 0) | 
 |         { | 
 |             ANIMATE_DrawFrame(infoPtr, hDC); | 
 |  | 
 | 	    ReleaseDC(infoPtr->hwndSelf, hDC); | 
 |         } | 
 |         return TRUE; | 
 |     } | 
 |  | 
 |     if (infoPtr->dwStyle & ACS_TIMER)  | 
 |     { | 
 | 	TRACE("Using a timer\n"); | 
 | 	/* create a timer to display AVI */ | 
 | 	infoPtr->uTimer = SetTimer(infoPtr->hwndSelf, 1,  | 
 |                                    infoPtr->mah.dwMicroSecPerFrame / 1000, NULL); | 
 |     }  | 
 |     else  | 
 |     { | 
 | 	TRACE("Using an animation thread\n"); | 
 |         infoPtr->hStopEvent = CreateEventW( NULL, TRUE, FALSE, NULL ); | 
 |         infoPtr->hThread = CreateThread(0, 0, ANIMATE_AnimationThread, | 
 |                                         (LPVOID)infoPtr, 0, &infoPtr->threadId); | 
 |         if(!infoPtr->hThread) return FALSE; | 
 |  | 
 |     } | 
 |  | 
 |     ANIMATE_Notify(infoPtr, ACN_START); | 
 |  | 
 |     return TRUE; | 
 | } | 
 |  | 
 |  | 
 | static BOOL ANIMATE_GetAviInfo(ANIMATE_INFO *infoPtr) | 
 | { | 
 |     MMCKINFO		ckMainRIFF; | 
 |     MMCKINFO		mmckHead; | 
 |     MMCKINFO		mmckList; | 
 |     MMCKINFO		mmckInfo; | 
 |     DWORD		numFrame; | 
 |     DWORD		insize; | 
 |  | 
 |     if (mmioDescend(infoPtr->hMMio, &ckMainRIFF, NULL, 0) != 0) { | 
 | 	WARN("Can't find 'RIFF' chunk\n"); | 
 | 	return FALSE; | 
 |     } | 
 |  | 
 |     if ((ckMainRIFF.ckid != FOURCC_RIFF) || | 
 | 	(ckMainRIFF.fccType != mmioFOURCC('A', 'V', 'I', ' '))) { | 
 | 	WARN("Can't find 'AVI ' chunk\n"); | 
 | 	return FALSE; | 
 |     } | 
 |  | 
 |     mmckHead.fccType = mmioFOURCC('h', 'd', 'r', 'l'); | 
 |     if (mmioDescend(infoPtr->hMMio, &mmckHead, &ckMainRIFF, MMIO_FINDLIST) != 0) { | 
 | 	WARN("Can't find 'hdrl' list\n"); | 
 | 	return FALSE; | 
 |     } | 
 |  | 
 |     mmckInfo.ckid = mmioFOURCC('a', 'v', 'i', 'h'); | 
 |     if (mmioDescend(infoPtr->hMMio, &mmckInfo, &mmckHead, MMIO_FINDCHUNK) != 0) { | 
 | 	WARN("Can't find 'avih' chunk\n"); | 
 | 	return FALSE; | 
 |     } | 
 |  | 
 |     mmioRead(infoPtr->hMMio, (LPSTR)&infoPtr->mah, sizeof(infoPtr->mah)); | 
 |  | 
 |     TRACE("mah.dwMicroSecPerFrame=%d\n", 	infoPtr->mah.dwMicroSecPerFrame); | 
 |     TRACE("mah.dwMaxBytesPerSec=%d\n",		infoPtr->mah.dwMaxBytesPerSec); | 
 |     TRACE("mah.dwPaddingGranularity=%d\n", 	infoPtr->mah.dwPaddingGranularity); | 
 |     TRACE("mah.dwFlags=%d\n",			infoPtr->mah.dwFlags); | 
 |     TRACE("mah.dwTotalFrames=%d\n",		infoPtr->mah.dwTotalFrames); | 
 |     TRACE("mah.dwInitialFrames=%d\n",		infoPtr->mah.dwInitialFrames); | 
 |     TRACE("mah.dwStreams=%d\n",			infoPtr->mah.dwStreams); | 
 |     TRACE("mah.dwSuggestedBufferSize=%d\n",	infoPtr->mah.dwSuggestedBufferSize); | 
 |     TRACE("mah.dwWidth=%d\n",			infoPtr->mah.dwWidth); | 
 |     TRACE("mah.dwHeight=%d\n",			infoPtr->mah.dwHeight); | 
 |  | 
 |     mmioAscend(infoPtr->hMMio, &mmckInfo, 0); | 
 |  | 
 |     mmckList.fccType = mmioFOURCC('s', 't', 'r', 'l'); | 
 |     if (mmioDescend(infoPtr->hMMio, &mmckList, &mmckHead, MMIO_FINDLIST) != 0) { | 
 | 	WARN("Can't find 'strl' list\n"); | 
 | 	return FALSE; | 
 |     } | 
 |  | 
 |     mmckInfo.ckid = mmioFOURCC('s', 't', 'r', 'h'); | 
 |     if (mmioDescend(infoPtr->hMMio, &mmckInfo, &mmckList, MMIO_FINDCHUNK) != 0) { | 
 | 	WARN("Can't find 'strh' chunk\n"); | 
 | 	return FALSE; | 
 |     } | 
 |  | 
 |     mmioRead(infoPtr->hMMio, (LPSTR)&infoPtr->ash, sizeof(infoPtr->ash)); | 
 |  | 
 |     TRACE("ash.fccType='%c%c%c%c'\n", 		LOBYTE(LOWORD(infoPtr->ash.fccType)), | 
 | 	                                        HIBYTE(LOWORD(infoPtr->ash.fccType)), | 
 | 	                                        LOBYTE(HIWORD(infoPtr->ash.fccType)), | 
 | 	                                        HIBYTE(HIWORD(infoPtr->ash.fccType))); | 
 |     TRACE("ash.fccHandler='%c%c%c%c'\n",	LOBYTE(LOWORD(infoPtr->ash.fccHandler)), | 
 | 	                                        HIBYTE(LOWORD(infoPtr->ash.fccHandler)), | 
 | 	                                        LOBYTE(HIWORD(infoPtr->ash.fccHandler)), | 
 | 	                                        HIBYTE(HIWORD(infoPtr->ash.fccHandler))); | 
 |     TRACE("ash.dwFlags=%d\n", 			infoPtr->ash.dwFlags); | 
 |     TRACE("ash.wPriority=%d\n", 		infoPtr->ash.wPriority); | 
 |     TRACE("ash.wLanguage=%d\n", 		infoPtr->ash.wLanguage); | 
 |     TRACE("ash.dwInitialFrames=%d\n", 		infoPtr->ash.dwInitialFrames); | 
 |     TRACE("ash.dwScale=%d\n", 			infoPtr->ash.dwScale); | 
 |     TRACE("ash.dwRate=%d\n", 			infoPtr->ash.dwRate); | 
 |     TRACE("ash.dwStart=%d\n", 			infoPtr->ash.dwStart); | 
 |     TRACE("ash.dwLength=%d\n",			infoPtr->ash.dwLength); | 
 |     TRACE("ash.dwSuggestedBufferSize=%d\n", 	infoPtr->ash.dwSuggestedBufferSize); | 
 |     TRACE("ash.dwQuality=%d\n", 		infoPtr->ash.dwQuality); | 
 |     TRACE("ash.dwSampleSize=%d\n", 		infoPtr->ash.dwSampleSize); | 
 |     TRACE("ash.rcFrame=(%d,%d,%d,%d)\n", 	infoPtr->ash.rcFrame.top, infoPtr->ash.rcFrame.left, | 
 | 	  infoPtr->ash.rcFrame.bottom, infoPtr->ash.rcFrame.right); | 
 |  | 
 |     mmioAscend(infoPtr->hMMio, &mmckInfo, 0); | 
 |  | 
 |     mmckInfo.ckid = mmioFOURCC('s', 't', 'r', 'f'); | 
 |     if (mmioDescend(infoPtr->hMMio, &mmckInfo, &mmckList, MMIO_FINDCHUNK) != 0) { | 
 | 	WARN("Can't find 'strh' chunk\n"); | 
 | 	return FALSE; | 
 |     } | 
 |  | 
 |     infoPtr->inbih = Alloc(mmckInfo.cksize); | 
 |     if (!infoPtr->inbih) { | 
 | 	WARN("Can't alloc input BIH\n"); | 
 | 	return FALSE; | 
 |     } | 
 |  | 
 |     mmioRead(infoPtr->hMMio, (LPSTR)infoPtr->inbih, mmckInfo.cksize); | 
 |  | 
 |     TRACE("bih.biSize=%d\n", 		infoPtr->inbih->biSize); | 
 |     TRACE("bih.biWidth=%d\n", 		infoPtr->inbih->biWidth); | 
 |     TRACE("bih.biHeight=%d\n",		infoPtr->inbih->biHeight); | 
 |     TRACE("bih.biPlanes=%d\n", 		infoPtr->inbih->biPlanes); | 
 |     TRACE("bih.biBitCount=%d\n", 	infoPtr->inbih->biBitCount); | 
 |     TRACE("bih.biCompression=%d\n", 	infoPtr->inbih->biCompression); | 
 |     TRACE("bih.biSizeImage=%d\n", 	infoPtr->inbih->biSizeImage); | 
 |     TRACE("bih.biXPelsPerMeter=%d\n", 	infoPtr->inbih->biXPelsPerMeter); | 
 |     TRACE("bih.biYPelsPerMeter=%d\n", 	infoPtr->inbih->biYPelsPerMeter); | 
 |     TRACE("bih.biClrUsed=%d\n", 	infoPtr->inbih->biClrUsed); | 
 |     TRACE("bih.biClrImportant=%d\n", 	infoPtr->inbih->biClrImportant); | 
 |  | 
 |     mmioAscend(infoPtr->hMMio, &mmckInfo, 0); | 
 |  | 
 |     mmioAscend(infoPtr->hMMio, &mmckList, 0); | 
 |  | 
 | #if 0 | 
 |     /* an AVI has 0 or 1 video stream, and to be animated should not contain | 
 |      * an audio stream, so only one strl is allowed | 
 |      */ | 
 |     mmckList.fccType = mmioFOURCC('s', 't', 'r', 'l'); | 
 |     if (mmioDescend(infoPtr->hMMio, &mmckList, &mmckHead, MMIO_FINDLIST) == 0) { | 
 | 	WARN("There should be a single 'strl' list\n"); | 
 | 	return FALSE; | 
 |     } | 
 | #endif | 
 |  | 
 |     mmioAscend(infoPtr->hMMio, &mmckHead, 0); | 
 |  | 
 |     /* no need to read optional JUNK chunk */ | 
 |  | 
 |     mmckList.fccType = mmioFOURCC('m', 'o', 'v', 'i'); | 
 |     if (mmioDescend(infoPtr->hMMio, &mmckList, &ckMainRIFF, MMIO_FINDLIST) != 0) { | 
 | 	WARN("Can't find 'movi' list\n"); | 
 | 	return FALSE; | 
 |     } | 
 |  | 
 |     /* FIXME: should handle the 'rec ' LIST when present */ | 
 |  | 
 |     infoPtr->lpIndex = Alloc(infoPtr->mah.dwTotalFrames * sizeof(DWORD)); | 
 |     if (!infoPtr->lpIndex)  | 
 | 	return FALSE; | 
 |  | 
 |     numFrame = insize = 0; | 
 |     while (mmioDescend(infoPtr->hMMio, &mmckInfo, &mmckList, 0) == 0 && | 
 | 	   numFrame < infoPtr->mah.dwTotalFrames) { | 
 | 	infoPtr->lpIndex[numFrame] = mmckInfo.dwDataOffset; | 
 | 	if (insize < mmckInfo.cksize) | 
 | 	    insize = mmckInfo.cksize; | 
 | 	numFrame++; | 
 | 	mmioAscend(infoPtr->hMMio, &mmckInfo, 0); | 
 |     } | 
 |     if (numFrame != infoPtr->mah.dwTotalFrames) { | 
 | 	WARN("Found %d frames (/%d)\n", numFrame, infoPtr->mah.dwTotalFrames); | 
 | 	return FALSE; | 
 |     } | 
 |     if (insize > infoPtr->ash.dwSuggestedBufferSize) { | 
 | 	WARN("insize=%d suggestedSize=%d\n", insize, infoPtr->ash.dwSuggestedBufferSize); | 
 | 	infoPtr->ash.dwSuggestedBufferSize = insize; | 
 |     } | 
 |  | 
 |     infoPtr->indata = Alloc(infoPtr->ash.dwSuggestedBufferSize); | 
 |     if (!infoPtr->indata)  | 
 | 	return FALSE; | 
 |  | 
 |     return TRUE; | 
 | } | 
 |  | 
 |  | 
 | static BOOL ANIMATE_GetAviCodec(ANIMATE_INFO *infoPtr) | 
 | { | 
 |     DWORD	outSize; | 
 |  | 
 |     /* check uncompressed AVI */ | 
 |     if ((infoPtr->ash.fccHandler == mmioFOURCC('D', 'I', 'B', ' ')) || | 
 |        (infoPtr->ash.fccHandler == mmioFOURCC('R', 'L', 'E', ' ')) || | 
 |        (infoPtr->ash.fccHandler == mmioFOURCC(0, 0, 0, 0))) | 
 |     { | 
 |         infoPtr->hic = 0; | 
 | 	return TRUE; | 
 |     } | 
 |  | 
 |     /* try to get a decompressor for that type */ | 
 |     infoPtr->hic = fnIC.fnICOpen(ICTYPE_VIDEO, infoPtr->ash.fccHandler, ICMODE_DECOMPRESS); | 
 |     if (!infoPtr->hic) { | 
 | 	WARN("Can't load codec for the file\n"); | 
 | 	return FALSE; | 
 |     } | 
 |  | 
 |     outSize = fnIC.fnICSendMessage(infoPtr->hic, ICM_DECOMPRESS_GET_FORMAT, | 
 | 			    (DWORD_PTR)infoPtr->inbih, 0L); | 
 |  | 
 |     infoPtr->outbih = Alloc(outSize); | 
 |     if (!infoPtr->outbih) | 
 | 	return FALSE; | 
 |  | 
 |     if (fnIC.fnICSendMessage(infoPtr->hic, ICM_DECOMPRESS_GET_FORMAT, | 
 | 		      (DWORD_PTR)infoPtr->inbih, (DWORD_PTR)infoPtr->outbih) != ICERR_OK)  | 
 |     { | 
 | 	WARN("Can't get output BIH\n"); | 
 | 	return FALSE; | 
 |     } | 
 |  | 
 |     infoPtr->outdata = Alloc(infoPtr->outbih->biSizeImage); | 
 |     if (!infoPtr->outdata)  | 
 | 	return FALSE; | 
 |  | 
 |     if (fnIC.fnICSendMessage(infoPtr->hic, ICM_DECOMPRESS_BEGIN, | 
 | 		      (DWORD_PTR)infoPtr->inbih, (DWORD_PTR)infoPtr->outbih) != ICERR_OK) { | 
 | 	WARN("Can't begin decompression\n"); | 
 | 	return FALSE; | 
 |     } | 
 |  | 
 |     return TRUE; | 
 | } | 
 |  | 
 |  | 
 | static BOOL ANIMATE_OpenW(ANIMATE_INFO *infoPtr, HINSTANCE hInstance, LPWSTR lpszName) | 
 | { | 
 |     HDC hdc; | 
 |  | 
 |     ANIMATE_Free(infoPtr); | 
 |  | 
 |     if (!lpszName)  | 
 |     { | 
 | 	TRACE("Closing avi!\n"); | 
 |         /* installer of thebat! v1.62 requires FALSE here */ | 
 | 	return (infoPtr->hMMio != 0); | 
 |     } | 
 |  | 
 |     if (!hInstance) | 
 |         hInstance = (HINSTANCE)GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_HINSTANCE); | 
 |  | 
 |     TRACE("(%s)\n", debugstr_w(lpszName)); | 
 |  | 
 |     if (HIWORD(lpszName)) | 
 |     { | 
 | 	if (!ANIMATE_LoadResW(infoPtr, hInstance, lpszName))  | 
 |         { | 
 | 	    TRACE("No AVI resource found!\n"); | 
 | 	    if (!ANIMATE_LoadFileW(infoPtr, lpszName))  | 
 |             { | 
 | 		WARN("No AVI file found!\n"); | 
 | 		return FALSE; | 
 | 	    } | 
 | 	} | 
 |     }  | 
 |     else  | 
 |     { | 
 | 	if (!ANIMATE_LoadResW(infoPtr, hInstance, lpszName)) | 
 |         { | 
 | 	    WARN("No AVI resource found!\n"); | 
 | 	    return FALSE; | 
 | 	} | 
 |     } | 
 |  | 
 |     if (!ANIMATE_GetAviInfo(infoPtr))  | 
 |     { | 
 | 	WARN("Can't get AVI information\n"); | 
 | 	ANIMATE_Free(infoPtr); | 
 | 	return FALSE; | 
 |     } | 
 |  | 
 |     if (!ANIMATE_GetAviCodec(infoPtr))  | 
 |     { | 
 | 	WARN("Can't get AVI Codec\n"); | 
 | 	ANIMATE_Free(infoPtr); | 
 | 	return FALSE; | 
 |     } | 
 |  | 
 |     hdc = GetDC(infoPtr->hwndSelf); | 
 |     /* native looks at the top left pixel of the first frame here too. */ | 
 |     infoPtr->hbrushBG = (HBRUSH)SendMessageW(infoPtr->hwndNotify, WM_CTLCOLORSTATIC, | 
 |                                              (WPARAM)hdc, (LPARAM)infoPtr->hwndSelf); | 
 |     ReleaseDC(infoPtr->hwndSelf, hdc); | 
 |  | 
 |     if (!(infoPtr->dwStyle & ACS_CENTER)) | 
 | 	SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, infoPtr->mah.dwWidth, infoPtr->mah.dwHeight, | 
 | 		     SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER); | 
 |  | 
 |     if (infoPtr->dwStyle & ACS_AUTOPLAY)  | 
 | 	return ANIMATE_Play(infoPtr, -1, 0, infoPtr->mah.dwTotalFrames - 1); | 
 |  | 
 |     return TRUE; | 
 | } | 
 |  | 
 |  | 
 | static BOOL ANIMATE_OpenA(ANIMATE_INFO *infoPtr, HINSTANCE hInstance, LPSTR lpszName) | 
 | { | 
 |     LPWSTR lpwszName; | 
 |     LRESULT result; | 
 |     INT len; | 
 |  | 
 |     if (!HIWORD(lpszName)) | 
 |         return ANIMATE_OpenW(infoPtr, hInstance, (LPWSTR)lpszName); | 
 |  | 
 |     len = MultiByteToWideChar(CP_ACP, 0, lpszName, -1, NULL, 0); | 
 |     lpwszName = Alloc(len * sizeof(WCHAR)); | 
 |     if (!lpwszName) return FALSE; | 
 |     MultiByteToWideChar(CP_ACP, 0, lpszName, -1, lpwszName, len); | 
 |  | 
 |     result = ANIMATE_OpenW(infoPtr, hInstance, lpwszName); | 
 |     Free (lpwszName); | 
 |     return result; | 
 | } | 
 |  | 
 |  | 
 | static BOOL ANIMATE_Stop(ANIMATE_INFO *infoPtr) | 
 | { | 
 |     /* nothing opened */ | 
 |     if (!infoPtr->hMMio) | 
 | 	return FALSE; | 
 |  | 
 |     ANIMATE_DoStop(infoPtr); | 
 |     return TRUE; | 
 | } | 
 |  | 
 |  | 
 | static BOOL ANIMATE_Create(HWND hWnd, const CREATESTRUCTW *lpcs) | 
 | { | 
 |     static const WCHAR msvfw32W[] = { 'm', 's', 'v', 'f', 'w', '3', '2', '.', 'd', 'l', 'l', 0 }; | 
 |     ANIMATE_INFO *infoPtr; | 
 |  | 
 |     if (!fnIC.hModule) | 
 |     { | 
 | 	fnIC.hModule = LoadLibraryW(msvfw32W); | 
 | 	if (!fnIC.hModule) return FALSE; | 
 |  | 
 | 	fnIC.fnICOpen        = (void*)GetProcAddress(fnIC.hModule, "ICOpen"); | 
 | 	fnIC.fnICClose       = (void*)GetProcAddress(fnIC.hModule, "ICClose"); | 
 | 	fnIC.fnICSendMessage = (void*)GetProcAddress(fnIC.hModule, "ICSendMessage"); | 
 | 	fnIC.fnICDecompress  = (void*)GetProcAddress(fnIC.hModule, "ICDecompress"); | 
 |     } | 
 |  | 
 |     /* allocate memory for info structure */ | 
 |     infoPtr = (ANIMATE_INFO *)Alloc(sizeof(ANIMATE_INFO)); | 
 |     if (!infoPtr) return FALSE; | 
 |  | 
 |     /* store crossref hWnd <-> info structure */ | 
 |     SetWindowLongPtrW(hWnd, 0, (DWORD_PTR)infoPtr); | 
 |     infoPtr->hwndSelf = hWnd; | 
 |     infoPtr->hwndNotify = lpcs->hwndParent; | 
 |     infoPtr->transparentColor = ANIMATE_COLOR_NONE; | 
 |     infoPtr->hbmPrevFrame = 0; | 
 |     infoPtr->dwStyle = lpcs->style; | 
 |  | 
 |     TRACE("Animate style=0x%08x, parent=%p\n", infoPtr->dwStyle, infoPtr->hwndNotify); | 
 |  | 
 |     InitializeCriticalSection(&infoPtr->cs); | 
 |     infoPtr->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ANIMATE_INFO*->cs"); | 
 |  | 
 |     return TRUE; | 
 | } | 
 |  | 
 |  | 
 | static LRESULT ANIMATE_Destroy(ANIMATE_INFO *infoPtr) | 
 | { | 
 |     /* free avi data */ | 
 |     ANIMATE_Free(infoPtr); | 
 |  | 
 |     /* free animate info data */ | 
 |     SetWindowLongPtrW(infoPtr->hwndSelf, 0, 0); | 
 |  | 
 |     infoPtr->cs.DebugInfo->Spare[0] = 0; | 
 |     DeleteCriticalSection(&infoPtr->cs); | 
 |     Free(infoPtr); | 
 |  | 
 |     return 0; | 
 | } | 
 |  | 
 |  | 
 | static BOOL ANIMATE_EraseBackground(ANIMATE_INFO const *infoPtr, HDC hdc) | 
 | { | 
 |     RECT rect; | 
 |     HBRUSH hBrush; | 
 |  | 
 |     hBrush = (HBRUSH)SendMessageW(infoPtr->hwndNotify, WM_CTLCOLORSTATIC, | 
 |                                   (WPARAM)hdc, (LPARAM)infoPtr->hwndSelf); | 
 |     GetClientRect(infoPtr->hwndSelf, &rect); | 
 |     FillRect(hdc, &rect, hBrush ? hBrush : GetCurrentObject(hdc, OBJ_BRUSH)); | 
 |  | 
 |     return TRUE; | 
 | } | 
 |  | 
 |  | 
 | static LRESULT ANIMATE_StyleChanged(ANIMATE_INFO *infoPtr, WPARAM wStyleType, const STYLESTRUCT *lpss) | 
 | { | 
 |     TRACE("(styletype=%lx, styleOld=0x%08x, styleNew=0x%08x)\n", | 
 |           wStyleType, lpss->styleOld, lpss->styleNew); | 
 |  | 
 |     if (wStyleType != GWL_STYLE) return 0; | 
 |    | 
 |     infoPtr->dwStyle = lpss->styleNew; | 
 |  | 
 |     InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); | 
 |     return 0; | 
 | } | 
 |  | 
 |  | 
 | static LRESULT WINAPI ANIMATE_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) | 
 | { | 
 |     ANIMATE_INFO *infoPtr = (ANIMATE_INFO *)GetWindowLongPtrW(hWnd, 0); | 
 |  | 
 |     TRACE("hwnd=%p msg=%x wparam=%lx lparam=%lx\n", hWnd, uMsg, wParam, lParam); | 
 |     if (!infoPtr && (uMsg != WM_NCCREATE)) | 
 | 	return DefWindowProcW(hWnd, uMsg, wParam, lParam); | 
 |     switch (uMsg) | 
 |     { | 
 |     case ACM_OPENA: | 
 | 	return ANIMATE_OpenA(infoPtr, (HINSTANCE)wParam, (LPSTR)lParam); | 
 |  | 
 |     case ACM_OPENW: | 
 | 	return ANIMATE_OpenW(infoPtr, (HINSTANCE)wParam, (LPWSTR)lParam); | 
 |  | 
 |     case ACM_PLAY: | 
 | 	return ANIMATE_Play(infoPtr, (INT)wParam, LOWORD(lParam), HIWORD(lParam)); | 
 |  | 
 |     case ACM_STOP: | 
 | 	return ANIMATE_Stop(infoPtr); | 
 |  | 
 |     case WM_CLOSE: | 
 | 	ANIMATE_Free(infoPtr); | 
 | 	return 0; | 
 |  | 
 |     case WM_NCCREATE: | 
 | 	return ANIMATE_Create(hWnd, (LPCREATESTRUCTW)lParam); | 
 |  | 
 |     case WM_NCHITTEST: | 
 | 	return HTTRANSPARENT; | 
 |  | 
 |     case WM_DESTROY: | 
 | 	return ANIMATE_Destroy(infoPtr); | 
 |  | 
 |     case WM_ERASEBKGND: | 
 | 	return ANIMATE_EraseBackground(infoPtr, (HDC)wParam); | 
 |  | 
 |     case WM_STYLECHANGED: | 
 |         return ANIMATE_StyleChanged(infoPtr, wParam, (LPSTYLESTRUCT)lParam); | 
 |  | 
 |     case WM_TIMER: | 
 |         return ANIMATE_Timer(infoPtr); | 
 |  | 
 |     case WM_PRINTCLIENT: | 
 |     case WM_PAINT: | 
 |         { | 
 |             /* the animation has not decompressed | 
 |              * (and displayed) the first frame yet, don't paint | 
 |              */ | 
 |             if (!infoPtr->hbmPrevFrame) | 
 |             { | 
 |                 /* default paint handling */ | 
 |                 return DefWindowProcW(hWnd, uMsg, wParam, lParam); | 
 |             } | 
 |  | 
 |             if (wParam) | 
 |             { | 
 |                 EnterCriticalSection(&infoPtr->cs); | 
 |                 ANIMATE_PaintFrame(infoPtr, (HDC)wParam); | 
 |                 LeaveCriticalSection(&infoPtr->cs); | 
 |             } | 
 |             else | 
 |             { | 
 |                 PAINTSTRUCT ps; | 
 |                 HDC hDC = BeginPaint(infoPtr->hwndSelf, &ps); | 
 |  | 
 |                 EnterCriticalSection(&infoPtr->cs); | 
 |                 ANIMATE_PaintFrame(infoPtr, hDC); | 
 |                 LeaveCriticalSection(&infoPtr->cs); | 
 |  | 
 |                 EndPaint(infoPtr->hwndSelf, &ps); | 
 |             } | 
 |         } | 
 |         break; | 
 |  | 
 |     case WM_SIZE: | 
 |         if (infoPtr->dwStyle & ACS_CENTER)  | 
 | 	    InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); | 
 | 	return DefWindowProcW(hWnd, uMsg, wParam, lParam); | 
 |  | 
 |     default: | 
 | 	if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg)) | 
 | 	    ERR("unknown msg %04x wp=%08lx lp=%08lx\n", uMsg, wParam, lParam); | 
 |  | 
 | 	return DefWindowProcW(hWnd, uMsg, wParam, lParam); | 
 |     } | 
 |     return 0; | 
 | } | 
 |  | 
 | void ANIMATE_Register(void) | 
 | { | 
 |     WNDCLASSW wndClass; | 
 |  | 
 |     ZeroMemory(&wndClass, sizeof(WNDCLASSW)); | 
 |     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS; | 
 |     wndClass.lpfnWndProc   = ANIMATE_WindowProc; | 
 |     wndClass.cbClsExtra    = 0; | 
 |     wndClass.cbWndExtra    = sizeof(ANIMATE_INFO *); | 
 |     wndClass.hCursor       = LoadCursorW(0, (LPCWSTR)IDC_ARROW); | 
 |     wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); | 
 |     wndClass.lpszClassName = ANIMATE_CLASSW; | 
 |  | 
 |     RegisterClassW(&wndClass); | 
 | } | 
 |  | 
 |  | 
 | void ANIMATE_Unregister(void) | 
 | { | 
 |     UnregisterClassW(ANIMATE_CLASSW, NULL); | 
 | } |