animate.c 28.3 KB
Newer Older
Eric Pouech's avatar
Eric Pouech committed
1
/* -*- tab-width: 8; c-basic-offset: 4 -*- */
Alexandre Julliard's avatar
Alexandre Julliard committed
2 3 4
/*
 * Animation control
 *
5
 * Copyright 1998, 1999 Eric Kohl
6 7
 * Copyright 1999 Eric Pouech
 * Copyright 2005 Dimitrie O. Paun
Alexandre Julliard's avatar
Alexandre Julliard committed
8
 *
9 10 11 12 13 14 15 16 17 18 19 20
 * 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
21
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
23 24
 * NOTES
 *
25 26 27 28 29 30 31
 * 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.
 * 
Alexandre Julliard's avatar
Alexandre Julliard committed
32
 * TODO:
Eric Pouech's avatar
Eric Pouech committed
33
 *   - check for the 'rec ' list in some AVI files
Alexandre Julliard's avatar
Alexandre Julliard committed
34 35
 */

36
#include <stdarg.h>
37
#include <string.h>
38
#include "windef.h"
39
#include "winbase.h"
40 41 42
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
43
#include "commctrl.h"
44
#include "vfw.h"
Eric Pouech's avatar
Eric Pouech committed
45
#include "mmsystem.h"
46
#include "comctl32.h"
47
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
48

49
WINE_DEFAULT_DEBUG_CHANNEL(animate);
50

51 52
static struct {
    HMODULE	hModule;
53 54
    HIC         (WINAPI *fnICOpen)(DWORD, DWORD, UINT);
    LRESULT     (WINAPI *fnICClose)(HIC);
Frank Richter's avatar
Frank Richter committed
55
    LRESULT     (WINAPI *fnICSendMessage)(HIC, UINT, DWORD_PTR, DWORD_PTR);
56
    DWORD       (WINAPIV *fnICDecompress)(HIC,DWORD,LPBITMAPINFOHEADER,LPVOID,LPBITMAPINFOHEADER,LPVOID);
57 58
} fnIC;

59 60 61 62
typedef struct
{
   /* reference to input stream (file or resource) */
   HGLOBAL 		hRes;
63
   HMMIO		hMMio;	/* handle to mmio stream */
64 65
   HWND			hwndSelf;
   HWND			hwndNotify;
66
   DWORD		dwStyle;
67 68 69 70 71 72 73 74 75 76 77 78
   /* 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;
79
   HANDLE		hStopEvent;
80
   HANDLE		hThread;
81
   DWORD		threadId;
82 83 84 85 86 87
   UINT			uTimer;
   /* data for playing the file */
   int			nFromFrame;
   int			nToFrame;
   int			nLoop;
   int			currFrame;
88
   /* tranparency info*/
89
   COLORREF         	transparentColor;
90
   HBRUSH           	hbrushBG;
91
   HBITMAP  	    	hbmPrevFrame;
92 93
} ANIMATE_INFO;

94
#define ANIMATE_COLOR_NONE  	0xffffffff
Alexandre Julliard's avatar
Alexandre Julliard committed
95

96
static void ANIMATE_Notify(const ANIMATE_INFO *infoPtr, UINT notif)
Alexandre Julliard's avatar
Alexandre Julliard committed
97
{
98
    SendMessageW(infoPtr->hwndNotify, WM_COMMAND,
99 100
		 MAKEWPARAM(GetDlgCtrlID(infoPtr->hwndSelf), notif),
		 (LPARAM)infoPtr->hwndSelf);
Eric Pouech's avatar
Eric Pouech committed
101
}
Alexandre Julliard's avatar
Alexandre Julliard committed
102

103
static BOOL ANIMATE_LoadResW(ANIMATE_INFO *infoPtr, HINSTANCE hInst, LPCWSTR lpName)
Eric Pouech's avatar
Eric Pouech committed
104
{
105
    static const WCHAR aviW[] = { 'A', 'V', 'I', 0 };
Eric Pouech's avatar
Eric Pouech committed
106 107 108
    HRSRC 	hrsrc;
    MMIOINFO	mminfo;
    LPVOID	lpAvi;
109

110
    hrsrc = FindResourceW(hInst, lpName, aviW);
Alexandre Julliard's avatar
Alexandre Julliard committed
111 112
    if (!hrsrc)
	return FALSE;
113

Eric Pouech's avatar
Eric Pouech committed
114 115 116
    infoPtr->hRes = LoadResource(hInst, hrsrc);
    if (!infoPtr->hRes)
 	return FALSE;
117

Eric Pouech's avatar
Eric Pouech committed
118 119 120
    lpAvi = LockResource(infoPtr->hRes);
    if (!lpAvi)
	return FALSE;
121

Eric Pouech's avatar
Eric Pouech committed
122 123 124 125
    memset(&mminfo, 0, sizeof(mminfo));
    mminfo.fccIOProc = FOURCC_MEM;
    mminfo.pchBuffer = (LPSTR)lpAvi;
    mminfo.cchBuffer = SizeofResource(hInst, hrsrc);
126 127 128
    infoPtr->hMMio = mmioOpenW(NULL, &mminfo, MMIO_READ);
    if (!infoPtr->hMMio) 
    {
129
	FreeResource(infoPtr->hRes);
Alexandre Julliard's avatar
Alexandre Julliard committed
130
	return FALSE;
Eric Pouech's avatar
Eric Pouech committed
131
    }
132

Eric Pouech's avatar
Eric Pouech committed
133 134 135
    return TRUE;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
136

137
static BOOL ANIMATE_LoadFileW(ANIMATE_INFO *infoPtr, LPWSTR lpName)
Eric Pouech's avatar
Eric Pouech committed
138
{
139
    infoPtr->hMMio = mmioOpenW(lpName, 0, MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
140

Frank Richter's avatar
Frank Richter committed
141 142
    if(!infoPtr->hMMio) return FALSE;
    return TRUE;
Eric Pouech's avatar
Eric Pouech committed
143 144 145
}


146
static BOOL ANIMATE_DoStop(ANIMATE_INFO *infoPtr)
147 148 149 150
{
    EnterCriticalSection(&infoPtr->cs);

    /* should stop playing */
151
    if (infoPtr->hThread)
152
    {
153 154 155
        HANDLE handle = infoPtr->hThread;

        TRACE("stopping animation thread\n");
156
        infoPtr->hThread = 0;
157
        SetEvent( infoPtr->hStopEvent );
158 159 160 161 162 163 164 165 166 167

        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 );
168
        CloseHandle( infoPtr->hStopEvent );
169
        infoPtr->hStopEvent = 0;
170 171
    }
    if (infoPtr->uTimer) {
172
	KillTimer(infoPtr->hwndSelf, infoPtr->uTimer);
173 174 175 176 177 178 179 180 181 182 183
	infoPtr->uTimer = 0;
    }

    LeaveCriticalSection(&infoPtr->cs);

    ANIMATE_Notify(infoPtr, ACN_STOP);

    return TRUE;
}


Eric Pouech's avatar
Eric Pouech committed
184 185 186
static void ANIMATE_Free(ANIMATE_INFO *infoPtr)
{
    if (infoPtr->hMMio) {
187
	ANIMATE_DoStop(infoPtr);
188
	mmioClose(infoPtr->hMMio, 0);
Eric Pouech's avatar
Eric Pouech committed
189 190 191 192
	if (infoPtr->hRes) {
 	    FreeResource(infoPtr->hRes);
	    infoPtr->hRes = 0;
	}
193
        Free (infoPtr->lpIndex);
194
        infoPtr->lpIndex = NULL;
Eric Pouech's avatar
Eric Pouech committed
195
	if (infoPtr->hic) {
196
	    fnIC.fnICClose(infoPtr->hic);
Eric Pouech's avatar
Eric Pouech committed
197 198
	    infoPtr->hic = 0;
	}
199
        Free (infoPtr->inbih);
200
        infoPtr->inbih = NULL;
201
        Free (infoPtr->outbih);
202
        infoPtr->outbih = NULL;
203
	Free (infoPtr->indata);
204
        infoPtr->indata = NULL;
205
	Free (infoPtr->outdata);
206
        infoPtr->outdata = NULL;
207 208 209 210 211
    	if( infoPtr->hbmPrevFrame )
        {
	    DeleteObject(infoPtr->hbmPrevFrame);
            infoPtr->hbmPrevFrame = 0;
        }
212

Eric Pouech's avatar
Eric Pouech committed
213 214 215 216
	memset(&infoPtr->mah, 0, sizeof(infoPtr->mah));
	memset(&infoPtr->ash, 0, sizeof(infoPtr->ash));
	infoPtr->nFromFrame = infoPtr->nToFrame = infoPtr->nLoop = infoPtr->currFrame = 0;
    }
217
    infoPtr->transparentColor = ANIMATE_COLOR_NONE;
Eric Pouech's avatar
Eric Pouech committed
218 219
}

220
static void ANIMATE_TransparentBlt(ANIMATE_INFO const *infoPtr, HDC hdcDest, HDC hdcSource)
221
{
222 223
    HDC hdcMask;
    HBITMAP hbmMask;
224 225
    HBITMAP hbmOld;

226 227
    /* create a transparency mask */
    hdcMask = CreateCompatibleDC(hdcDest);
228 229
    hbmMask = CreateBitmap(infoPtr->inbih->biWidth, infoPtr->inbih->biHeight, 1,1,NULL);
    hbmOld = SelectObject(hdcMask, hbmMask);
230 231 232

    SetBkColor(hdcSource,infoPtr->transparentColor);
    BitBlt(hdcMask,0,0,infoPtr->inbih->biWidth, infoPtr->inbih->biHeight,hdcSource,0,0,SRCCOPY);
233

234
    /* mask the source bitmap */
235 236
    SetBkColor(hdcSource, RGB(0,0,0));
    SetTextColor(hdcSource, RGB(255,255,255));
237 238 239
    BitBlt(hdcSource, 0, 0, infoPtr->inbih->biWidth, infoPtr->inbih->biHeight, hdcMask, 0, 0, SRCAND);

    /* mask the destination bitmap */
240 241
    SetBkColor(hdcDest, RGB(255,255,255));
    SetTextColor(hdcDest, RGB(0,0,0));
242 243 244 245 246 247 248 249 250 251
    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);
}

252
static BOOL ANIMATE_PaintFrame(ANIMATE_INFO* infoPtr, HDC hDC)
253
{
254 255
    void const *pBitmapData;
    BITMAPINFO const *pBitmapInfo;
256 257 258 259 260 261
    HDC hdcMem;
    HBITMAP hbmOld;
    int nOffsetX = 0;
    int nOffsetY = 0;
    int nWidth;
    int nHeight;
262

263 264
    if (!hDC || !infoPtr->inbih)
	return TRUE;
265

266
    if (infoPtr->hic )
267 268 269
    {
        pBitmapData = infoPtr->outdata;
        pBitmapInfo = (LPBITMAPINFO)infoPtr->outbih;
270

271
        nWidth = infoPtr->outbih->biWidth;
272
        nHeight = infoPtr->outbih->biHeight;
273 274
    } 
    else
275
    {
276 277
        pBitmapData = infoPtr->indata;
        pBitmapInfo = (LPBITMAPINFO)infoPtr->inbih;
278

279
        nWidth = infoPtr->inbih->biWidth;
280 281
        nHeight = infoPtr->inbih->biHeight;
    }
282

283 284 285 286
    if(!infoPtr->hbmPrevFrame)
    {
        infoPtr->hbmPrevFrame=CreateCompatibleBitmap(hDC, nWidth,nHeight );
    }
287

288
    hdcMem = CreateCompatibleDC(hDC);
289
    hbmOld = SelectObject(hdcMem, infoPtr->hbmPrevFrame);
290

291 292
    SetDIBits(hdcMem, infoPtr->hbmPrevFrame, 0, nHeight, pBitmapData, pBitmapInfo, DIB_RGB_COLORS);

293 294
    /*
     * we need to get the transparent color even without ACS_TRANSPARENT,
295
     * because the style can be changed later on and the color should always
296
     * be obtained in the first frame
297 298 299 300
     */
    if(infoPtr->transparentColor == ANIMATE_COLOR_NONE)
    {
        infoPtr->transparentColor = GetPixel(hdcMem,0,0);
301
    }
302

303
    if(infoPtr->dwStyle & ACS_TRANSPARENT)
304
    {
305 306 307 308
        HDC hdcFinal = CreateCompatibleDC(hDC);
        HBITMAP hbmFinal = CreateCompatibleBitmap(hDC,nWidth, nHeight);
        HBITMAP hbmOld2 = SelectObject(hdcFinal, hbmFinal);
        RECT rect;
309

310 311 312 313
        rect.left = 0;
        rect.top = 0;
        rect.right = nWidth;
        rect.bottom = nHeight;
314

315 316 317 318 319 320 321 322 323
        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);
324 325
        DeleteObject(infoPtr->hbmPrevFrame);
        infoPtr->hbmPrevFrame = hbmFinal;
326
    }
327

328
    if (infoPtr->dwStyle & ACS_CENTER)
329
    {
330
        RECT rect;
331

332 333 334
        GetWindowRect(infoPtr->hwndSelf, &rect);
        nOffsetX = ((rect.right - rect.left) - nWidth)/2;
        nOffsetY = ((rect.bottom - rect.top) - nHeight)/2;
335
    }
336
    BitBlt(hDC, nOffsetX, nOffsetY, nWidth, nHeight, hdcMem, 0, 0, SRCCOPY);
337

338 339
    SelectObject(hdcMem, hbmOld);
    DeleteDC(hdcMem);
Eric Pouech's avatar
Eric Pouech committed
340 341
    return TRUE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
342

343
static BOOL ANIMATE_DrawFrame(ANIMATE_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
344
{
Eric Pouech's avatar
Eric Pouech committed
345
    HDC		hDC;
Alexandre Julliard's avatar
Alexandre Julliard committed
346

Eric Pouech's avatar
Eric Pouech committed
347 348
    TRACE("Drawing frame %d (loop %d)\n", infoPtr->currFrame, infoPtr->nLoop);

349 350
    mmioSeek(infoPtr->hMMio, infoPtr->lpIndex[infoPtr->currFrame], SEEK_SET);
    mmioRead(infoPtr->hMMio, infoPtr->indata, infoPtr->ash.dwSuggestedBufferSize);
351

352
    if (infoPtr->hic &&
353
	fnIC.fnICDecompress(infoPtr->hic, 0, infoPtr->inbih, infoPtr->indata,
354
		     infoPtr->outbih, infoPtr->outdata) != ICERR_OK) {
Eric Pouech's avatar
Eric Pouech committed
355
	WARN("Decompression error\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
356 357 358
	return FALSE;
    }

359
    if ((hDC = GetDC(infoPtr->hwndSelf)) != 0) {
Eric Pouech's avatar
Eric Pouech committed
360
	ANIMATE_PaintFrame(infoPtr, hDC);
361
	ReleaseDC(infoPtr->hwndSelf, hDC);
Eric Pouech's avatar
Eric Pouech committed
362 363 364 365 366 367 368 369 370
    }

    if (infoPtr->currFrame++ >= infoPtr->nToFrame) {
	infoPtr->currFrame = infoPtr->nFromFrame;
	if (infoPtr->nLoop != -1) {
	    if (--infoPtr->nLoop == 0) {
		ANIMATE_DoStop(infoPtr);
	    }
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
371 372 373 374 375
    }

    return TRUE;
}

376 377 378 379 380 381 382 383 384 385 386 387 388 389
static LRESULT ANIMATE_Timer(ANIMATE_INFO *infoPtr)
{
   /* FIXME: we should pass the hDC instead of 0 to WM_CTLCOLORSTATIC */
   if (infoPtr->dwStyle & ACS_TRANSPARENT)
        infoPtr->hbrushBG = (HBRUSH)SendMessageW(infoPtr->hwndNotify,
                                                 WM_CTLCOLORSTATIC,
                                                 0, (LPARAM)infoPtr->hwndSelf);
    EnterCriticalSection(&infoPtr->cs);
    ANIMATE_DrawFrame(infoPtr);
    LeaveCriticalSection(&infoPtr->cs);

    return 0;
}

390
static DWORD CALLBACK ANIMATE_AnimationThread(LPVOID ptr_)
Eric Pouech's avatar
Eric Pouech committed
391
{
392
    ANIMATE_INFO *infoPtr = (ANIMATE_INFO *)ptr_;
393 394
    HANDLE event;
    DWORD timeout;
Eric Pouech's avatar
Eric Pouech committed
395

396
    while(1)
397
    {
Andreas Mohr's avatar
Andreas Mohr committed
398 399
        EnterCriticalSection(&infoPtr->cs);
        ANIMATE_DrawFrame(infoPtr);
400 401
        timeout = infoPtr->mah.dwMicroSecPerFrame;
        event = infoPtr->hStopEvent;
Andreas Mohr's avatar
Andreas Mohr committed
402
        LeaveCriticalSection(&infoPtr->cs);
403

404
        /* time is in microseconds, we should convert it to milliseconds */
405
        if ((event == 0) || WaitForSingleObject( event, (timeout+500)/1000) == WAIT_OBJECT_0)
406
            break;
Andreas Mohr's avatar
Andreas Mohr committed
407
    }
408
    return TRUE;
Eric Pouech's avatar
Eric Pouech committed
409
}
Alexandre Julliard's avatar
Alexandre Julliard committed
410

411
static LRESULT ANIMATE_Play(ANIMATE_INFO *infoPtr, UINT cRepeat, WORD wFrom, WORD wTo)
Alexandre Julliard's avatar
Alexandre Julliard committed
412
{
Eric Pouech's avatar
Eric Pouech committed
413 414 415 416
    /* nothing opened */
    if (!infoPtr->hMMio)
	return FALSE;

417
    if (infoPtr->hThread || infoPtr->uTimer) {
418 419
	TRACE("Already playing\n");
	return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
420
    }
Eric Pouech's avatar
Eric Pouech committed
421

422 423 424
    infoPtr->nFromFrame = wFrom;
    infoPtr->nToFrame   = wTo;
    infoPtr->nLoop      = cRepeat;
Eric Pouech's avatar
Eric Pouech committed
425 426 427 428

    if (infoPtr->nToFrame == 0xFFFF)
	infoPtr->nToFrame = infoPtr->mah.dwTotalFrames - 1;

429
    TRACE("(repeat=%d from=%d to=%d);\n",
Eric Pouech's avatar
Eric Pouech committed
430 431 432 433 434 435 436 437
	  infoPtr->nLoop, infoPtr->nFromFrame, infoPtr->nToFrame);

    if (infoPtr->nFromFrame >= infoPtr->nToFrame ||
	infoPtr->nToFrame >= infoPtr->mah.dwTotalFrames)
	return FALSE;

    infoPtr->currFrame = infoPtr->nFromFrame;

438
    if (infoPtr->dwStyle & ACS_TIMER) 
439
    {
Eric Pouech's avatar
Eric Pouech committed
440 441
	TRACE("Using a timer\n");
	/* create a timer to display AVI */
442 443 444 445 446
	infoPtr->uTimer = SetTimer(infoPtr->hwndSelf, 1, 
                                   infoPtr->mah.dwMicroSecPerFrame / 1000, NULL);
    } 
    else 
    {
447 448 449 450 451
        if(infoPtr->dwStyle & ACS_TRANSPARENT)
            infoPtr->hbrushBG = (HBRUSH)SendMessageW(infoPtr->hwndNotify,
                                                     WM_CTLCOLORSTATIC, 0,
                                                     (LPARAM)infoPtr->hwndSelf);

452
	TRACE("Using an animation thread\n");
453
        infoPtr->hStopEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
454 455
        infoPtr->hThread = CreateThread(0, 0, ANIMATE_AnimationThread,
                                        (LPVOID)infoPtr, 0, &infoPtr->threadId);
456
        if(!infoPtr->hThread) return FALSE;
457

Alexandre Julliard's avatar
Alexandre Julliard committed
458
    }
459

Eric Pouech's avatar
Eric Pouech committed
460 461 462
    ANIMATE_Notify(infoPtr, ACN_START);

    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
463 464 465
}


Eric Pouech's avatar
Eric Pouech committed
466
static BOOL ANIMATE_GetAviInfo(ANIMATE_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
467
{
Eric Pouech's avatar
Eric Pouech committed
468 469 470 471 472 473 474
    MMCKINFO		ckMainRIFF;
    MMCKINFO		mmckHead;
    MMCKINFO		mmckList;
    MMCKINFO		mmckInfo;
    DWORD		numFrame;
    DWORD		insize;

475
    if (mmioDescend(infoPtr->hMMio, &ckMainRIFF, NULL, 0) != 0) {
Eric Pouech's avatar
Eric Pouech committed
476 477 478
	WARN("Can't find 'RIFF' chunk\n");
	return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
479

Eric Pouech's avatar
Eric Pouech committed
480 481 482 483 484
    if ((ckMainRIFF.ckid != FOURCC_RIFF) ||
	(ckMainRIFF.fccType != mmioFOURCC('A', 'V', 'I', ' '))) {
	WARN("Can't find 'AVI ' chunk\n");
	return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
485

Eric Pouech's avatar
Eric Pouech committed
486
    mmckHead.fccType = mmioFOURCC('h', 'd', 'r', 'l');
487
    if (mmioDescend(infoPtr->hMMio, &mmckHead, &ckMainRIFF, MMIO_FINDLIST) != 0) {
Eric Pouech's avatar
Eric Pouech committed
488 489 490
	WARN("Can't find 'hdrl' list\n");
	return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
491

Eric Pouech's avatar
Eric Pouech committed
492
    mmckInfo.ckid = mmioFOURCC('a', 'v', 'i', 'h');
493
    if (mmioDescend(infoPtr->hMMio, &mmckInfo, &mmckHead, MMIO_FINDCHUNK) != 0) {
Eric Pouech's avatar
Eric Pouech committed
494 495 496
	WARN("Can't find 'avih' chunk\n");
	return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
497

498 499
    mmioRead(infoPtr->hMMio, (LPSTR)&infoPtr->mah, sizeof(infoPtr->mah));

500 501 502 503 504 505 506 507 508 509
    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);
510 511

    mmioAscend(infoPtr->hMMio, &mmckInfo, 0);
Eric Pouech's avatar
Eric Pouech committed
512 513

    mmckList.fccType = mmioFOURCC('s', 't', 'r', 'l');
514
    if (mmioDescend(infoPtr->hMMio, &mmckList, &mmckHead, MMIO_FINDLIST) != 0) {
Eric Pouech's avatar
Eric Pouech committed
515 516 517
	WARN("Can't find 'strl' list\n");
	return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
518

Eric Pouech's avatar
Eric Pouech committed
519
    mmckInfo.ckid = mmioFOURCC('s', 't', 'r', 'h');
520
    if (mmioDescend(infoPtr->hMMio, &mmckInfo, &mmckList, MMIO_FINDCHUNK) != 0) {
Eric Pouech's avatar
Eric Pouech committed
521 522 523
	WARN("Can't find 'strh' chunk\n");
	return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
524

525 526
    mmioRead(infoPtr->hMMio, (LPSTR)&infoPtr->ash, sizeof(infoPtr->ash));

527 528 529
    TRACE("ash.fccType='%c%c%c%c'\n", 		LOBYTE(LOWORD(infoPtr->ash.fccType)),
	                                        HIBYTE(LOWORD(infoPtr->ash.fccType)),
	                                        LOBYTE(HIWORD(infoPtr->ash.fccType)),
Eric Pouech's avatar
Eric Pouech committed
530
	                                        HIBYTE(HIWORD(infoPtr->ash.fccType)));
531 532 533
    TRACE("ash.fccHandler='%c%c%c%c'\n",	LOBYTE(LOWORD(infoPtr->ash.fccHandler)),
	                                        HIBYTE(LOWORD(infoPtr->ash.fccHandler)),
	                                        LOBYTE(HIWORD(infoPtr->ash.fccHandler)),
Eric Pouech's avatar
Eric Pouech committed
534
	                                        HIBYTE(HIWORD(infoPtr->ash.fccHandler)));
535
    TRACE("ash.dwFlags=%d\n", 			infoPtr->ash.dwFlags);
Eric Pouech's avatar
Eric Pouech committed
536 537
    TRACE("ash.wPriority=%d\n", 		infoPtr->ash.wPriority);
    TRACE("ash.wLanguage=%d\n", 		infoPtr->ash.wLanguage);
538 539 540 541 542 543 544 545
    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);
546
    TRACE("ash.rcFrame=(%d,%d,%d,%d)\n", 	infoPtr->ash.rcFrame.top, infoPtr->ash.rcFrame.left,
Eric Pouech's avatar
Eric Pouech committed
547
	  infoPtr->ash.rcFrame.bottom, infoPtr->ash.rcFrame.right);
548 549

    mmioAscend(infoPtr->hMMio, &mmckInfo, 0);
Eric Pouech's avatar
Eric Pouech committed
550 551

    mmckInfo.ckid = mmioFOURCC('s', 't', 'r', 'f');
552
    if (mmioDescend(infoPtr->hMMio, &mmckInfo, &mmckList, MMIO_FINDCHUNK) != 0) {
Eric Pouech's avatar
Eric Pouech committed
553 554 555 556
	WARN("Can't find 'strh' chunk\n");
	return FALSE;
    }

557
    infoPtr->inbih = Alloc(mmckInfo.cksize);
Eric Pouech's avatar
Eric Pouech committed
558 559 560
    if (!infoPtr->inbih) {
	WARN("Can't alloc input BIH\n");
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
561
    }
Eric Pouech's avatar
Eric Pouech committed
562

563 564
    mmioRead(infoPtr->hMMio, (LPSTR)infoPtr->inbih, mmckInfo.cksize);

565 566 567
    TRACE("bih.biSize=%d\n", 		infoPtr->inbih->biSize);
    TRACE("bih.biWidth=%d\n", 		infoPtr->inbih->biWidth);
    TRACE("bih.biHeight=%d\n",		infoPtr->inbih->biHeight);
Eric Pouech's avatar
Eric Pouech committed
568 569
    TRACE("bih.biPlanes=%d\n", 		infoPtr->inbih->biPlanes);
    TRACE("bih.biBitCount=%d\n", 	infoPtr->inbih->biBitCount);
570 571 572 573 574 575
    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);
Eric Pouech's avatar
Eric Pouech committed
576

577 578 579
    mmioAscend(infoPtr->hMMio, &mmckInfo, 0);

    mmioAscend(infoPtr->hMMio, &mmckList, 0);
580

Eric Pouech's avatar
Eric Pouech committed
581 582
#if 0
    /* an AVI has 0 or 1 video stream, and to be animated should not contain
583
     * an audio stream, so only one strl is allowed
Eric Pouech's avatar
Eric Pouech committed
584 585
     */
    mmckList.fccType = mmioFOURCC('s', 't', 'r', 'l');
586
    if (mmioDescend(infoPtr->hMMio, &mmckList, &mmckHead, MMIO_FINDLIST) == 0) {
Eric Pouech's avatar
Eric Pouech committed
587 588 589 590
	WARN("There should be a single 'strl' list\n");
	return FALSE;
    }
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
591

592
    mmioAscend(infoPtr->hMMio, &mmckHead, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
593

Eric Pouech's avatar
Eric Pouech committed
594
    /* no need to read optional JUNK chunk */
Alexandre Julliard's avatar
Alexandre Julliard committed
595

Eric Pouech's avatar
Eric Pouech committed
596
    mmckList.fccType = mmioFOURCC('m', 'o', 'v', 'i');
597
    if (mmioDescend(infoPtr->hMMio, &mmckList, &ckMainRIFF, MMIO_FINDLIST) != 0) {
Eric Pouech's avatar
Eric Pouech committed
598 599
	WARN("Can't find 'movi' list\n");
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
600 601
    }

Eric Pouech's avatar
Eric Pouech committed
602 603
    /* FIXME: should handle the 'rec ' LIST when present */

604
    infoPtr->lpIndex = Alloc(infoPtr->mah.dwTotalFrames * sizeof(DWORD));
605
    if (!infoPtr->lpIndex) 
Eric Pouech's avatar
Eric Pouech committed
606
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
607

Eric Pouech's avatar
Eric Pouech committed
608
    numFrame = insize = 0;
609
    while (mmioDescend(infoPtr->hMMio, &mmckInfo, &mmckList, 0) == 0 &&
Eric Pouech's avatar
Eric Pouech committed
610 611 612 613 614
	   numFrame < infoPtr->mah.dwTotalFrames) {
	infoPtr->lpIndex[numFrame] = mmckInfo.dwDataOffset;
	if (insize < mmckInfo.cksize)
	    insize = mmckInfo.cksize;
	numFrame++;
615
	mmioAscend(infoPtr->hMMio, &mmckInfo, 0);
Eric Pouech's avatar
Eric Pouech committed
616 617
    }
    if (numFrame != infoPtr->mah.dwTotalFrames) {
618
	WARN("Found %d frames (/%d)\n", numFrame, infoPtr->mah.dwTotalFrames);
Eric Pouech's avatar
Eric Pouech committed
619 620 621
	return FALSE;
    }
    if (insize > infoPtr->ash.dwSuggestedBufferSize) {
622
	WARN("insize=%d suggestedSize=%d\n", insize, infoPtr->ash.dwSuggestedBufferSize);
Eric Pouech's avatar
Eric Pouech committed
623 624 625
	infoPtr->ash.dwSuggestedBufferSize = insize;
    }

626
    infoPtr->indata = Alloc(infoPtr->ash.dwSuggestedBufferSize);
627
    if (!infoPtr->indata) 
Eric Pouech's avatar
Eric Pouech committed
628
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
629 630 631 632 633

    return TRUE;
}


634
static BOOL ANIMATE_GetAviCodec(ANIMATE_INFO *infoPtr)
Eric Pouech's avatar
Eric Pouech committed
635 636
{
    DWORD	outSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
637

638
    /* check uncompressed AVI */
639
    if ((infoPtr->ash.fccHandler == mmioFOURCC('D', 'I', 'B', ' ')) ||
640 641
       (infoPtr->ash.fccHandler == mmioFOURCC('R', 'L', 'E', ' ')) ||
       (infoPtr->ash.fccHandler == mmioFOURCC(0, 0, 0, 0)))
642
    {
643
        infoPtr->hic = 0;
644 645
	return TRUE;
    }
646 647

    /* try to get a decompressor for that type */
648
    infoPtr->hic = fnIC.fnICOpen(ICTYPE_VIDEO, infoPtr->ash.fccHandler, ICMODE_DECOMPRESS);
Eric Pouech's avatar
Eric Pouech committed
649 650 651 652
    if (!infoPtr->hic) {
	WARN("Can't load codec for the file\n");
	return FALSE;
    }
653 654

    outSize = fnIC.fnICSendMessage(infoPtr->hic, ICM_DECOMPRESS_GET_FORMAT,
Frank Richter's avatar
Frank Richter committed
655
			    (DWORD_PTR)infoPtr->inbih, 0L);
656

657
    infoPtr->outbih = Alloc(outSize);
658
    if (!infoPtr->outbih)
Eric Pouech's avatar
Eric Pouech committed
659
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
660

661
    if (fnIC.fnICSendMessage(infoPtr->hic, ICM_DECOMPRESS_GET_FORMAT,
662
		      (DWORD_PTR)infoPtr->inbih, (DWORD_PTR)infoPtr->outbih) != ICERR_OK) 
663
    {
Eric Pouech's avatar
Eric Pouech committed
664 665 666
	WARN("Can't get output BIH\n");
	return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
667

668
    infoPtr->outdata = Alloc(infoPtr->outbih->biSizeImage);
669
    if (!infoPtr->outdata) 
Alexandre Julliard's avatar
Alexandre Julliard committed
670
	return FALSE;
Eric Pouech's avatar
Eric Pouech committed
671

672
    if (fnIC.fnICSendMessage(infoPtr->hic, ICM_DECOMPRESS_BEGIN,
Frank Richter's avatar
Frank Richter committed
673
		      (DWORD_PTR)infoPtr->inbih, (DWORD_PTR)infoPtr->outbih) != ICERR_OK) {
Eric Pouech's avatar
Eric Pouech committed
674 675 676 677 678 679 680
	WARN("Can't begin decompression\n");
	return FALSE;
    }

    return TRUE;
}

681

682
static BOOL ANIMATE_OpenW(ANIMATE_INFO *infoPtr, HINSTANCE hInstance, LPWSTR lpszName)
Eric Pouech's avatar
Eric Pouech committed
683 684 685
{
    ANIMATE_Free(infoPtr);

686 687
    if (!lpszName) 
    {
Eric Pouech's avatar
Eric Pouech committed
688
	TRACE("Closing avi!\n");
689 690
        /* installer of thebat! v1.62 requires FALSE here */
	return (infoPtr->hMMio != 0);
Eric Pouech's avatar
Eric Pouech committed
691
    }
692

Eric Pouech's avatar
Eric Pouech committed
693
    if (!hInstance)
694
        hInstance = (HINSTANCE)GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_HINSTANCE);
Eric Pouech's avatar
Eric Pouech committed
695

Frank Richter's avatar
Frank Richter committed
696
    TRACE("(%s)\n", debugstr_w(lpszName));
Alexandre Julliard's avatar
Alexandre Julliard committed
697

Frank Richter's avatar
Frank Richter committed
698 699
    if (HIWORD(lpszName))
    {
700 701
	if (!ANIMATE_LoadResW(infoPtr, hInstance, lpszName)) 
        {
Eric Pouech's avatar
Eric Pouech committed
702
	    TRACE("No AVI resource found!\n");
703 704
	    if (!ANIMATE_LoadFileW(infoPtr, lpszName)) 
            {
Eric Pouech's avatar
Eric Pouech committed
705 706 707 708
		WARN("No AVI file found!\n");
		return FALSE;
	    }
	}
709 710 711
    } 
    else 
    {
Frank Richter's avatar
Frank Richter committed
712
	if (!ANIMATE_LoadResW(infoPtr, hInstance, lpszName))
713
        {
Eric Pouech's avatar
Eric Pouech committed
714 715 716
	    WARN("No AVI resource found!\n");
	    return FALSE;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
717 718
    }

719 720
    if (!ANIMATE_GetAviInfo(infoPtr)) 
    {
Eric Pouech's avatar
Eric Pouech committed
721 722 723 724
	WARN("Can't get AVI information\n");
	ANIMATE_Free(infoPtr);
	return FALSE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
725

726 727
    if (!ANIMATE_GetAviCodec(infoPtr)) 
    {
Eric Pouech's avatar
Eric Pouech committed
728 729 730
	WARN("Can't get AVI Codec\n");
	ANIMATE_Free(infoPtr);
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
731 732
    }

733
    if (!(infoPtr->dwStyle & ACS_CENTER))
734
	SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, infoPtr->mah.dwWidth, infoPtr->mah.dwHeight,
Eric Pouech's avatar
Eric Pouech committed
735 736
		     SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);

737
    if (infoPtr->dwStyle & ACS_AUTOPLAY) 
738
	return ANIMATE_Play(infoPtr, -1, 0, infoPtr->mah.dwTotalFrames - 1);
Alexandre Julliard's avatar
Alexandre Julliard committed
739 740 741 742 743

    return TRUE;
}


744
static BOOL ANIMATE_OpenA(ANIMATE_INFO *infoPtr, HINSTANCE hInstance, LPSTR lpszName)
Alexandre Julliard's avatar
Alexandre Julliard committed
745
{
746 747 748 749 750 751
    LPWSTR lpwszName;
    LRESULT result;
    INT len;

    if (!HIWORD(lpszName))
        return ANIMATE_OpenW(infoPtr, hInstance, (LPWSTR)lpszName);
Alexandre Julliard's avatar
Alexandre Julliard committed
752

753
    len = MultiByteToWideChar(CP_ACP, 0, lpszName, -1, NULL, 0);
754
    lpwszName = Alloc(len * sizeof(WCHAR));
755 756 757 758
    if (!lpwszName) return FALSE;
    MultiByteToWideChar(CP_ACP, 0, lpszName, -1, lpwszName, len);

    result = ANIMATE_OpenW(infoPtr, hInstance, lpwszName);
759
    Free (lpwszName);
760 761 762 763 764 765
    return result;
}


static BOOL ANIMATE_Stop(ANIMATE_INFO *infoPtr)
{
Alexandre Julliard's avatar
Alexandre Julliard committed
766
    /* nothing opened */
Eric Pouech's avatar
Eric Pouech committed
767
    if (!infoPtr->hMMio)
Alexandre Julliard's avatar
Alexandre Julliard committed
768
	return FALSE;
Eric Pouech's avatar
Eric Pouech committed
769 770

    ANIMATE_DoStop(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
771 772 773 774
    return TRUE;
}


775
static BOOL ANIMATE_Create(HWND hWnd, const CREATESTRUCTW *lpcs)
Alexandre Julliard's avatar
Alexandre Julliard committed
776
{
777 778
    static const WCHAR msvfw32W[] = { 'm', 's', 'v', 'f', 'w', '3', '2', '.', 'd', 'l', 'l', 0 };
    ANIMATE_INFO *infoPtr;
Alexandre Julliard's avatar
Alexandre Julliard committed
779

780
    if (!fnIC.hModule)
781
    {
782
	fnIC.hModule = LoadLibraryW(msvfw32W);
783 784 785 786 787 788 789 790
	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");
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
791
    /* allocate memory for info structure */
792
    infoPtr = (ANIMATE_INFO *)Alloc(sizeof(ANIMATE_INFO));
793
    if (!infoPtr) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
794

Eric Pouech's avatar
Eric Pouech committed
795
    /* store crossref hWnd <-> info structure */
796
    SetWindowLongPtrW(hWnd, 0, (DWORD_PTR)infoPtr);
797
    infoPtr->hwndSelf = hWnd;
798
    infoPtr->hwndNotify = lpcs->hwndParent;
799
    infoPtr->transparentColor = ANIMATE_COLOR_NONE;
800
    infoPtr->hbmPrevFrame = 0;
801
    infoPtr->dwStyle = lpcs->style;
802

803
    TRACE("Animate style=0x%08x, parent=%p\n", infoPtr->dwStyle, infoPtr->hwndNotify);
804

Eric Pouech's avatar
Eric Pouech committed
805
    InitializeCriticalSection(&infoPtr->cs);
806
    infoPtr->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ANIMATE_INFO*->cs");
807

808
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
809 810 811
}


812
static LRESULT ANIMATE_Destroy(ANIMATE_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
813
{
Alexandre Julliard's avatar
Alexandre Julliard committed
814
    /* free avi data */
Eric Pouech's avatar
Eric Pouech committed
815
    ANIMATE_Free(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
816 817

    /* free animate info data */
818
    SetWindowLongPtrW(infoPtr->hwndSelf, 0, 0);
819

820
    infoPtr->cs.DebugInfo->Spare[0] = 0;
821
    DeleteCriticalSection(&infoPtr->cs);
822
    Free(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
823 824 825 826 827

    return 0;
}


828
static BOOL ANIMATE_EraseBackground(ANIMATE_INFO const *infoPtr, HDC hdc)
Alexandre Julliard's avatar
Alexandre Julliard committed
829
{
Eric Pouech's avatar
Eric Pouech committed
830
    RECT rect;
831
    HBRUSH hBrush = 0;
832

833
    if(infoPtr->dwStyle & ACS_TRANSPARENT)
834
    {
835 836
        hBrush = (HBRUSH)SendMessageW(infoPtr->hwndNotify, WM_CTLCOLORSTATIC,
				      (WPARAM)hdc, (LPARAM)infoPtr->hwndSelf);
837
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
838

839 840
    GetClientRect(infoPtr->hwndSelf, &rect);
    FillRect(hdc, &rect, hBrush ? hBrush : GetCurrentObject(hdc, OBJ_BRUSH));
Eric Pouech's avatar
Eric Pouech committed
841

Alexandre Julliard's avatar
Alexandre Julliard committed
842 843 844
    return TRUE;
}

845

846
static LRESULT ANIMATE_StyleChanged(ANIMATE_INFO *infoPtr, WPARAM wStyleType, const STYLESTRUCT *lpss)
Eric Pouech's avatar
Eric Pouech committed
847
{
848
    TRACE("(styletype=%x, styleOld=0x%08x, styleNew=0x%08x)\n",
849 850 851 852 853 854 855 856
          wStyleType, lpss->styleOld, lpss->styleNew);

    if (wStyleType != GWL_STYLE) return 0;
  
    infoPtr->dwStyle = lpss->styleNew;

    InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
    return 0;
Eric Pouech's avatar
Eric Pouech committed
857
}
Alexandre Julliard's avatar
Alexandre Julliard committed
858

859

Eric Pouech's avatar
Eric Pouech committed
860
static LRESULT WINAPI ANIMATE_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
861
{
862 863
    ANIMATE_INFO *infoPtr = (ANIMATE_INFO *)GetWindowLongPtrW(hWnd, 0);

864
    TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n", hWnd, uMsg, wParam, lParam);
865 866
    if (!infoPtr && (uMsg != WM_NCCREATE))
	return DefWindowProcW(hWnd, uMsg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
867 868
    switch (uMsg)
    {
Eric Pouech's avatar
Eric Pouech committed
869
    case ACM_OPENA:
870
	return ANIMATE_OpenA(infoPtr, (HINSTANCE)wParam, (LPSTR)lParam);
871

872
    case ACM_OPENW:
873
	return ANIMATE_OpenW(infoPtr, (HINSTANCE)wParam, (LPWSTR)lParam);
874

Eric Pouech's avatar
Eric Pouech committed
875
    case ACM_PLAY:
876
	return ANIMATE_Play(infoPtr, (INT)wParam, LOWORD(lParam), HIWORD(lParam));
877

Eric Pouech's avatar
Eric Pouech committed
878
    case ACM_STOP:
879
	return ANIMATE_Stop(infoPtr);
880

881 882 883 884
    case WM_CLOSE:
	ANIMATE_Free(infoPtr);
	return 0;

Eric Pouech's avatar
Eric Pouech committed
885
    case WM_NCCREATE:
886
	return ANIMATE_Create(hWnd, (LPCREATESTRUCTW)lParam);
887

Eric Pouech's avatar
Eric Pouech committed
888 889 890 891
    case WM_NCHITTEST:
	return HTTRANSPARENT;

    case WM_DESTROY:
892
	return ANIMATE_Destroy(infoPtr);
893

Eric Pouech's avatar
Eric Pouech committed
894
    case WM_ERASEBKGND:
895
	return ANIMATE_EraseBackground(infoPtr, (HDC)wParam);
Eric Pouech's avatar
Eric Pouech committed
896

897 898
    case WM_STYLECHANGED:
        return ANIMATE_StyleChanged(infoPtr, wParam, (LPSTYLESTRUCT)lParam);
Eric Pouech's avatar
Eric Pouech committed
899 900

    case WM_TIMER:
901
        return ANIMATE_Timer(infoPtr);
902

903
    case WM_PRINTCLIENT:
Eric Pouech's avatar
Eric Pouech committed
904
    case WM_PAINT:
905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939
        {
            /* the animation isn't playing, or has not decompressed
             * (and displayed) the first frame yet, don't paint
             */
            if ((!infoPtr->uTimer && !infoPtr->hThread) ||
                !infoPtr->hbmPrevFrame)
            {
                /* default paint handling */
                return DefWindowProcW(hWnd, uMsg, wParam, lParam);
            }

            if (infoPtr->dwStyle & ACS_TRANSPARENT)
                infoPtr->hbrushBG = (HBRUSH)SendMessageW(infoPtr->hwndNotify,
                                                         WM_CTLCOLORSTATIC,
                                                         wParam, (LPARAM)infoPtr->hwndSelf);

            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;
Alexandre Julliard's avatar
Alexandre Julliard committed
940

Eric Pouech's avatar
Eric Pouech committed
941
    case WM_SIZE:
942 943 944
        if (infoPtr->dwStyle & ACS_CENTER) 
	    InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
	return DefWindowProcW(hWnd, uMsg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
945

Eric Pouech's avatar
Eric Pouech committed
946
    default:
947
	if ((uMsg >= WM_USER) && (uMsg < WM_APP))
Eric Pouech's avatar
Eric Pouech committed
948
	    ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam, lParam);
949

950
	return DefWindowProcW(hWnd, uMsg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
951 952 953 954
    }
    return 0;
}

Eric Pouech's avatar
Eric Pouech committed
955
void ANIMATE_Register(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
956
{
957
    WNDCLASSW wndClass;
Alexandre Julliard's avatar
Alexandre Julliard committed
958

959
    ZeroMemory(&wndClass, sizeof(WNDCLASSW));
Alexandre Julliard's avatar
Alexandre Julliard committed
960
    wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS;
961
    wndClass.lpfnWndProc   = ANIMATE_WindowProc;
Alexandre Julliard's avatar
Alexandre Julliard committed
962 963
    wndClass.cbClsExtra    = 0;
    wndClass.cbWndExtra    = sizeof(ANIMATE_INFO *);
964
    wndClass.hCursor       = LoadCursorW(0, (LPCWSTR)IDC_ARROW);
965
    wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
966
    wndClass.lpszClassName = ANIMATE_CLASSW;
967

968
    RegisterClassW(&wndClass);
Alexandre Julliard's avatar
Alexandre Julliard committed
969
}
970 971


Eric Pouech's avatar
Eric Pouech committed
972
void ANIMATE_Unregister(void)
973
{
974
    UnregisterClassW(ANIMATE_CLASSW, NULL);
975
}