Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/dlls/comctl32/animate.c
4389 views
1
/* -*- tab-width: 8; c-basic-offset: 4 -*- */
2
/*
3
* Animation control
4
*
5
* Copyright 1998, 1999 Eric Kohl
6
* Copyright 1999 Eric Pouech
7
* Copyright 2005 Dimitrie O. Paun
8
*
9
* This library is free software; you can redistribute it and/or
10
* modify it under the terms of the GNU Lesser General Public
11
* License as published by the Free Software Foundation; either
12
* version 2.1 of the License, or (at your option) any later version.
13
*
14
* This library is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
* Lesser General Public License for more details.
18
*
19
* You should have received a copy of the GNU Lesser General Public
20
* 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
*
23
* TODO:
24
* - check for the 'rec ' list in some AVI files
25
*/
26
27
#include <stdarg.h>
28
#include <string.h>
29
#include "windef.h"
30
#include "winbase.h"
31
#include "wingdi.h"
32
#include "winuser.h"
33
#include "winnls.h"
34
#include "commctrl.h"
35
#include "vfw.h"
36
#include "mmsystem.h"
37
#include "comctl32.h"
38
#include "wine/debug.h"
39
40
WINE_DEFAULT_DEBUG_CHANNEL(animate);
41
42
static struct {
43
HMODULE hModule;
44
HIC (WINAPI *fnICOpen)(DWORD, DWORD, UINT);
45
LRESULT (WINAPI *fnICClose)(HIC);
46
LRESULT (WINAPI *fnICSendMessage)(HIC, UINT, DWORD_PTR, DWORD_PTR);
47
DWORD (WINAPIV *fnICDecompress)(HIC,DWORD,LPBITMAPINFOHEADER,LPVOID,LPBITMAPINFOHEADER,LPVOID);
48
} fnIC;
49
50
typedef struct
51
{
52
/* reference to input stream (file or resource) */
53
HGLOBAL hRes;
54
HMMIO hMMio; /* handle to mmio stream */
55
HWND hwndSelf;
56
HWND hwndNotify;
57
DWORD dwStyle;
58
/* information on the loaded AVI file */
59
MainAVIHeader mah;
60
AVIStreamHeader ash;
61
LPBITMAPINFOHEADER inbih;
62
LPDWORD lpIndex;
63
/* data for the decompressor */
64
HIC hic;
65
LPBITMAPINFOHEADER outbih;
66
LPVOID indata;
67
LPVOID outdata;
68
/* data for the background mechanism */
69
CRITICAL_SECTION cs;
70
HANDLE hStopEvent;
71
HANDLE hThread;
72
DWORD threadId;
73
UINT uTimer;
74
/* data for playing the file */
75
int nFromFrame;
76
int nToFrame;
77
int nLoop;
78
int currFrame;
79
/* transparency info*/
80
COLORREF transparentColor;
81
HBRUSH hbrushBG;
82
HBITMAP hbmPrevFrame;
83
} ANIMATE_INFO;
84
85
#define ANIMATE_COLOR_NONE 0xffffffff
86
87
static void ANIMATE_Notify(const ANIMATE_INFO *infoPtr, UINT notif)
88
{
89
PostMessageW(infoPtr->hwndNotify, WM_COMMAND,
90
MAKEWPARAM(GetDlgCtrlID(infoPtr->hwndSelf), notif),
91
(LPARAM)infoPtr->hwndSelf);
92
}
93
94
static BOOL ANIMATE_LoadResW(ANIMATE_INFO *infoPtr, HINSTANCE hInst, LPCWSTR lpName)
95
{
96
HRSRC hrsrc;
97
MMIOINFO mminfo;
98
LPVOID lpAvi;
99
100
hrsrc = FindResourceW(hInst, lpName, L"AVI");
101
if (!hrsrc)
102
return FALSE;
103
104
infoPtr->hRes = LoadResource(hInst, hrsrc);
105
if (!infoPtr->hRes)
106
return FALSE;
107
108
lpAvi = LockResource(infoPtr->hRes);
109
if (!lpAvi)
110
return FALSE;
111
112
memset(&mminfo, 0, sizeof(mminfo));
113
mminfo.fccIOProc = FOURCC_MEM;
114
mminfo.pchBuffer = lpAvi;
115
mminfo.cchBuffer = SizeofResource(hInst, hrsrc);
116
infoPtr->hMMio = mmioOpenW(NULL, &mminfo, MMIO_READ);
117
if (!infoPtr->hMMio)
118
{
119
FreeResource(infoPtr->hRes);
120
return FALSE;
121
}
122
123
return TRUE;
124
}
125
126
127
static BOOL ANIMATE_LoadFileW(ANIMATE_INFO *infoPtr, LPWSTR lpName)
128
{
129
infoPtr->hMMio = mmioOpenW(lpName, 0, MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
130
131
if(!infoPtr->hMMio) return FALSE;
132
return TRUE;
133
}
134
135
136
static BOOL ANIMATE_DoStop(ANIMATE_INFO *infoPtr)
137
{
138
BOOL stopped = FALSE;
139
140
EnterCriticalSection(&infoPtr->cs);
141
142
/* should stop playing */
143
if (infoPtr->hThread)
144
{
145
HANDLE handle = infoPtr->hThread;
146
147
TRACE("stopping animation thread\n");
148
infoPtr->hThread = 0;
149
SetEvent( infoPtr->hStopEvent );
150
151
if (infoPtr->threadId != GetCurrentThreadId())
152
{
153
LeaveCriticalSection(&infoPtr->cs); /* leave it a chance to run */
154
WaitForSingleObject( handle, INFINITE );
155
TRACE("animation thread stopped\n");
156
EnterCriticalSection(&infoPtr->cs);
157
}
158
159
CloseHandle( handle );
160
CloseHandle( infoPtr->hStopEvent );
161
infoPtr->hStopEvent = 0;
162
stopped = TRUE;
163
}
164
if (infoPtr->uTimer) {
165
KillTimer(infoPtr->hwndSelf, infoPtr->uTimer);
166
infoPtr->uTimer = 0;
167
stopped = TRUE;
168
}
169
170
LeaveCriticalSection(&infoPtr->cs);
171
172
if (stopped)
173
ANIMATE_Notify(infoPtr, ACN_STOP);
174
175
return TRUE;
176
}
177
178
179
static void ANIMATE_Free(ANIMATE_INFO *infoPtr)
180
{
181
if (infoPtr->hMMio)
182
{
183
ANIMATE_DoStop(infoPtr);
184
mmioClose(infoPtr->hMMio, 0);
185
if (infoPtr->hRes)
186
{
187
FreeResource(infoPtr->hRes);
188
infoPtr->hRes = 0;
189
}
190
Free (infoPtr->lpIndex);
191
infoPtr->lpIndex = NULL;
192
if (infoPtr->hic)
193
{
194
fnIC.fnICClose(infoPtr->hic);
195
infoPtr->hic = 0;
196
}
197
Free (infoPtr->inbih);
198
infoPtr->inbih = NULL;
199
Free (infoPtr->outbih);
200
infoPtr->outbih = NULL;
201
Free (infoPtr->indata);
202
infoPtr->indata = NULL;
203
Free (infoPtr->outdata);
204
infoPtr->outdata = NULL;
205
if (infoPtr->hbmPrevFrame)
206
{
207
DeleteObject(infoPtr->hbmPrevFrame);
208
infoPtr->hbmPrevFrame = 0;
209
}
210
211
memset(&infoPtr->mah, 0, sizeof(infoPtr->mah));
212
memset(&infoPtr->ash, 0, sizeof(infoPtr->ash));
213
infoPtr->nFromFrame = infoPtr->nToFrame = infoPtr->nLoop = infoPtr->currFrame = 0;
214
}
215
infoPtr->transparentColor = ANIMATE_COLOR_NONE;
216
}
217
218
static void ANIMATE_TransparentBlt(ANIMATE_INFO const *infoPtr, HDC hdcDest, HDC hdcSource)
219
{
220
HDC hdcMask;
221
HBITMAP hbmMask;
222
HBITMAP hbmOld;
223
224
/* create a transparency mask */
225
hdcMask = CreateCompatibleDC(hdcDest);
226
hbmMask = CreateBitmap(infoPtr->inbih->biWidth, infoPtr->inbih->biHeight, 1,1,NULL);
227
hbmOld = SelectObject(hdcMask, hbmMask);
228
229
SetBkColor(hdcSource,infoPtr->transparentColor);
230
BitBlt(hdcMask,0,0,infoPtr->inbih->biWidth, infoPtr->inbih->biHeight,hdcSource,0,0,SRCCOPY);
231
232
/* mask the source bitmap */
233
SetBkColor(hdcSource, RGB(0,0,0));
234
SetTextColor(hdcSource, RGB(255,255,255));
235
BitBlt(hdcSource, 0, 0, infoPtr->inbih->biWidth, infoPtr->inbih->biHeight, hdcMask, 0, 0, SRCAND);
236
237
/* mask the destination bitmap */
238
SetBkColor(hdcDest, RGB(255,255,255));
239
SetTextColor(hdcDest, RGB(0,0,0));
240
BitBlt(hdcDest, 0, 0, infoPtr->inbih->biWidth, infoPtr->inbih->biHeight, hdcMask, 0, 0, SRCAND);
241
242
/* combine source and destination */
243
BitBlt(hdcDest,0,0,infoPtr->inbih->biWidth, infoPtr->inbih->biHeight,hdcSource,0,0,SRCPAINT);
244
245
SelectObject(hdcMask, hbmOld);
246
DeleteObject(hbmMask);
247
DeleteDC(hdcMask);
248
}
249
250
static BOOL ANIMATE_PaintFrame(ANIMATE_INFO* infoPtr, HDC hDC)
251
{
252
void const *pBitmapData;
253
BITMAPINFO const *pBitmapInfo;
254
HDC hdcMem;
255
HBITMAP hbmOld;
256
int nOffsetX = 0;
257
int nOffsetY = 0;
258
int nWidth;
259
int nHeight;
260
261
if (!hDC || !infoPtr->inbih)
262
return TRUE;
263
264
if (infoPtr->hic )
265
{
266
pBitmapData = infoPtr->outdata;
267
pBitmapInfo = (LPBITMAPINFO)infoPtr->outbih;
268
269
nWidth = infoPtr->outbih->biWidth;
270
nHeight = infoPtr->outbih->biHeight;
271
}
272
else
273
{
274
pBitmapData = infoPtr->indata;
275
pBitmapInfo = (LPBITMAPINFO)infoPtr->inbih;
276
277
nWidth = infoPtr->inbih->biWidth;
278
nHeight = infoPtr->inbih->biHeight;
279
}
280
281
if(!infoPtr->hbmPrevFrame)
282
{
283
infoPtr->hbmPrevFrame=CreateCompatibleBitmap(hDC, nWidth,nHeight );
284
}
285
286
hdcMem = CreateCompatibleDC(hDC);
287
hbmOld = SelectObject(hdcMem, infoPtr->hbmPrevFrame);
288
289
SetDIBits(hdcMem, infoPtr->hbmPrevFrame, 0, nHeight, pBitmapData, pBitmapInfo, DIB_RGB_COLORS);
290
291
/*
292
* we need to get the transparent color even without ACS_TRANSPARENT,
293
* because the style can be changed later on and the color should always
294
* be obtained in the first frame
295
*/
296
if(infoPtr->transparentColor == ANIMATE_COLOR_NONE)
297
{
298
infoPtr->transparentColor = GetPixel(hdcMem,0,0);
299
}
300
301
if(infoPtr->dwStyle & ACS_TRANSPARENT)
302
{
303
HDC hdcFinal = CreateCompatibleDC(hDC);
304
HBITMAP hbmFinal = CreateCompatibleBitmap(hDC,nWidth, nHeight);
305
HBITMAP hbmOld2 = SelectObject(hdcFinal, hbmFinal);
306
RECT rect;
307
308
SetRect(&rect, 0, 0, nWidth, nHeight);
309
310
if(!infoPtr->hbrushBG)
311
infoPtr->hbrushBG = GetCurrentObject(hDC, OBJ_BRUSH);
312
313
FillRect(hdcFinal, &rect, infoPtr->hbrushBG);
314
ANIMATE_TransparentBlt(infoPtr, hdcFinal, hdcMem);
315
316
SelectObject(hdcFinal, hbmOld2);
317
SelectObject(hdcMem, hbmFinal);
318
DeleteDC(hdcFinal);
319
DeleteObject(infoPtr->hbmPrevFrame);
320
infoPtr->hbmPrevFrame = hbmFinal;
321
}
322
323
if (infoPtr->dwStyle & ACS_CENTER)
324
{
325
RECT rect;
326
327
GetWindowRect(infoPtr->hwndSelf, &rect);
328
nOffsetX = ((rect.right - rect.left) - nWidth)/2;
329
nOffsetY = ((rect.bottom - rect.top) - nHeight)/2;
330
}
331
BitBlt(hDC, nOffsetX, nOffsetY, nWidth, nHeight, hdcMem, 0, 0, SRCCOPY);
332
333
SelectObject(hdcMem, hbmOld);
334
DeleteDC(hdcMem);
335
return TRUE;
336
}
337
338
static BOOL ANIMATE_DrawFrame(ANIMATE_INFO *infoPtr, HDC hDC)
339
{
340
TRACE("Drawing frame %d (loop %d)\n", infoPtr->currFrame, infoPtr->nLoop);
341
342
mmioSeek(infoPtr->hMMio, infoPtr->lpIndex[infoPtr->currFrame], SEEK_SET);
343
mmioRead(infoPtr->hMMio, infoPtr->indata, infoPtr->ash.dwSuggestedBufferSize);
344
345
if (infoPtr->hic &&
346
fnIC.fnICDecompress(infoPtr->hic, 0, infoPtr->inbih, infoPtr->indata,
347
infoPtr->outbih, infoPtr->outdata) != ICERR_OK) {
348
WARN("Decompression error\n");
349
return FALSE;
350
}
351
352
ANIMATE_PaintFrame(infoPtr, hDC);
353
354
if (infoPtr->currFrame++ >= infoPtr->nToFrame) {
355
infoPtr->currFrame = infoPtr->nFromFrame;
356
if (infoPtr->nLoop != -1) {
357
if (--infoPtr->nLoop == 0) {
358
ANIMATE_DoStop(infoPtr);
359
}
360
}
361
}
362
363
return TRUE;
364
}
365
366
static LRESULT ANIMATE_Timer(ANIMATE_INFO *infoPtr)
367
{
368
HDC hDC;
369
370
if ((hDC = GetDC(infoPtr->hwndSelf)) != 0)
371
{
372
EnterCriticalSection(&infoPtr->cs);
373
ANIMATE_DrawFrame(infoPtr, hDC);
374
LeaveCriticalSection(&infoPtr->cs);
375
376
ReleaseDC(infoPtr->hwndSelf, hDC);
377
}
378
379
return 0;
380
}
381
382
static DWORD CALLBACK ANIMATE_AnimationThread(LPVOID ptr_)
383
{
384
ANIMATE_INFO *infoPtr = ptr_;
385
HANDLE event;
386
DWORD timeout;
387
388
while(1)
389
{
390
HDC hDC = GetDC(infoPtr->hwndSelf);
391
392
EnterCriticalSection(&infoPtr->cs);
393
ANIMATE_DrawFrame(infoPtr, hDC);
394
timeout = infoPtr->mah.dwMicroSecPerFrame;
395
event = infoPtr->hStopEvent;
396
LeaveCriticalSection(&infoPtr->cs);
397
398
ReleaseDC(infoPtr->hwndSelf, hDC);
399
400
/* time is in microseconds, we should convert it to milliseconds */
401
if ((event == 0) || WaitForSingleObject( event, (timeout+500)/1000) == WAIT_OBJECT_0)
402
break;
403
}
404
return TRUE;
405
}
406
407
static LRESULT ANIMATE_Play(ANIMATE_INFO *infoPtr, UINT cRepeat, WORD wFrom, WORD wTo)
408
{
409
/* nothing opened */
410
if (!infoPtr->hMMio)
411
return FALSE;
412
413
if (infoPtr->hThread || infoPtr->uTimer) {
414
TRACE("Already playing\n");
415
return TRUE;
416
}
417
418
infoPtr->nFromFrame = wFrom;
419
infoPtr->nToFrame = wTo;
420
infoPtr->nLoop = cRepeat;
421
422
if (infoPtr->nToFrame == 0xFFFF)
423
infoPtr->nToFrame = infoPtr->mah.dwTotalFrames - 1;
424
425
TRACE("(repeat=%d from=%d to=%d);\n",
426
infoPtr->nLoop, infoPtr->nFromFrame, infoPtr->nToFrame);
427
428
if (infoPtr->nFromFrame >= infoPtr->mah.dwTotalFrames &&
429
(SHORT)infoPtr->nFromFrame < 0)
430
infoPtr->nFromFrame = 0;
431
432
if (infoPtr->nFromFrame > infoPtr->nToFrame ||
433
infoPtr->nToFrame >= infoPtr->mah.dwTotalFrames)
434
return FALSE;
435
436
infoPtr->currFrame = infoPtr->nFromFrame;
437
438
/* seek - doesn't need to start a thread or set a timer and neither
439
* does it send a notification */
440
if (infoPtr->nFromFrame == infoPtr->nToFrame)
441
{
442
HDC hDC;
443
444
if ((hDC = GetDC(infoPtr->hwndSelf)) != 0)
445
{
446
ANIMATE_DrawFrame(infoPtr, hDC);
447
448
ReleaseDC(infoPtr->hwndSelf, hDC);
449
}
450
return TRUE;
451
}
452
453
if (infoPtr->dwStyle & ACS_TIMER)
454
{
455
TRACE("Using a timer\n");
456
/* create a timer to display AVI */
457
infoPtr->uTimer = SetTimer(infoPtr->hwndSelf, 1,
458
infoPtr->mah.dwMicroSecPerFrame / 1000, NULL);
459
}
460
else
461
{
462
TRACE("Using an animation thread\n");
463
infoPtr->hStopEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
464
infoPtr->hThread = CreateThread(0, 0, ANIMATE_AnimationThread,
465
infoPtr, 0, &infoPtr->threadId);
466
if(!infoPtr->hThread) return FALSE;
467
468
}
469
470
ANIMATE_Notify(infoPtr, ACN_START);
471
472
return TRUE;
473
}
474
475
476
static BOOL ANIMATE_GetAviInfo(ANIMATE_INFO *infoPtr)
477
{
478
MMCKINFO ckMainRIFF;
479
MMCKINFO mmckHead;
480
MMCKINFO mmckList;
481
MMCKINFO mmckInfo;
482
DWORD numFrame;
483
DWORD insize;
484
485
if (mmioDescend(infoPtr->hMMio, &ckMainRIFF, NULL, 0) != 0) {
486
WARN("Can't find 'RIFF' chunk\n");
487
return FALSE;
488
}
489
490
if ((ckMainRIFF.ckid != FOURCC_RIFF) ||
491
(ckMainRIFF.fccType != mmioFOURCC('A', 'V', 'I', ' '))) {
492
WARN("Can't find 'AVI ' chunk\n");
493
return FALSE;
494
}
495
496
mmckHead.fccType = mmioFOURCC('h', 'd', 'r', 'l');
497
if (mmioDescend(infoPtr->hMMio, &mmckHead, &ckMainRIFF, MMIO_FINDLIST) != 0) {
498
WARN("Can't find 'hdrl' list\n");
499
return FALSE;
500
}
501
502
mmckInfo.ckid = mmioFOURCC('a', 'v', 'i', 'h');
503
if (mmioDescend(infoPtr->hMMio, &mmckInfo, &mmckHead, MMIO_FINDCHUNK) != 0) {
504
WARN("Can't find 'avih' chunk\n");
505
return FALSE;
506
}
507
508
mmioRead(infoPtr->hMMio, (LPSTR)&infoPtr->mah, sizeof(infoPtr->mah));
509
510
TRACE("mah.dwMicroSecPerFrame=%ld\n", infoPtr->mah.dwMicroSecPerFrame);
511
TRACE("mah.dwMaxBytesPerSec=%ld\n", infoPtr->mah.dwMaxBytesPerSec);
512
TRACE("mah.dwPaddingGranularity=%ld\n", infoPtr->mah.dwPaddingGranularity);
513
TRACE("mah.dwFlags=%ld\n", infoPtr->mah.dwFlags);
514
TRACE("mah.dwTotalFrames=%ld\n", infoPtr->mah.dwTotalFrames);
515
TRACE("mah.dwInitialFrames=%ld\n", infoPtr->mah.dwInitialFrames);
516
TRACE("mah.dwStreams=%ld\n", infoPtr->mah.dwStreams);
517
TRACE("mah.dwSuggestedBufferSize=%ld\n", infoPtr->mah.dwSuggestedBufferSize);
518
TRACE("mah.dwWidth=%ld\n", infoPtr->mah.dwWidth);
519
TRACE("mah.dwHeight=%ld\n", infoPtr->mah.dwHeight);
520
521
mmioAscend(infoPtr->hMMio, &mmckInfo, 0);
522
523
mmckList.fccType = mmioFOURCC('s', 't', 'r', 'l');
524
if (mmioDescend(infoPtr->hMMio, &mmckList, &mmckHead, MMIO_FINDLIST) != 0) {
525
WARN("Can't find 'strl' list\n");
526
return FALSE;
527
}
528
529
mmckInfo.ckid = mmioFOURCC('s', 't', 'r', 'h');
530
if (mmioDescend(infoPtr->hMMio, &mmckInfo, &mmckList, MMIO_FINDCHUNK) != 0) {
531
WARN("Can't find 'strh' chunk\n");
532
return FALSE;
533
}
534
535
mmioRead(infoPtr->hMMio, (LPSTR)&infoPtr->ash, sizeof(infoPtr->ash));
536
537
TRACE("ash.fccType=%s\n", debugstr_fourcc(infoPtr->ash.fccType));
538
TRACE("ash.fccHandler=%s\n", debugstr_fourcc(infoPtr->ash.fccHandler));
539
TRACE("ash.dwFlags=%ld\n", infoPtr->ash.dwFlags);
540
TRACE("ash.wPriority=%d\n", infoPtr->ash.wPriority);
541
TRACE("ash.wLanguage=%d\n", infoPtr->ash.wLanguage);
542
TRACE("ash.dwInitialFrames=%ld\n", infoPtr->ash.dwInitialFrames);
543
TRACE("ash.dwScale=%ld\n", infoPtr->ash.dwScale);
544
TRACE("ash.dwRate=%ld\n", infoPtr->ash.dwRate);
545
TRACE("ash.dwStart=%ld\n", infoPtr->ash.dwStart);
546
TRACE("ash.dwLength=%lu\n", infoPtr->ash.dwLength);
547
TRACE("ash.dwSuggestedBufferSize=%lu\n", infoPtr->ash.dwSuggestedBufferSize);
548
TRACE("ash.dwQuality=%lu\n", infoPtr->ash.dwQuality);
549
TRACE("ash.dwSampleSize=%lu\n", infoPtr->ash.dwSampleSize);
550
TRACE("ash.rcFrame=(%d,%d,%d,%d)\n", infoPtr->ash.rcFrame.top, infoPtr->ash.rcFrame.left,
551
infoPtr->ash.rcFrame.bottom, infoPtr->ash.rcFrame.right);
552
553
mmioAscend(infoPtr->hMMio, &mmckInfo, 0);
554
555
mmckInfo.ckid = mmioFOURCC('s', 't', 'r', 'f');
556
if (mmioDescend(infoPtr->hMMio, &mmckInfo, &mmckList, MMIO_FINDCHUNK) != 0) {
557
WARN("Can't find 'strh' chunk\n");
558
return FALSE;
559
}
560
561
infoPtr->inbih = Alloc(mmckInfo.cksize);
562
if (!infoPtr->inbih) {
563
WARN("Can't alloc input BIH\n");
564
return FALSE;
565
}
566
567
mmioRead(infoPtr->hMMio, (LPSTR)infoPtr->inbih, mmckInfo.cksize);
568
569
TRACE("bih.biSize=%lu\n", infoPtr->inbih->biSize);
570
TRACE("bih.biWidth=%ld\n", infoPtr->inbih->biWidth);
571
TRACE("bih.biHeight=%ld\n", infoPtr->inbih->biHeight);
572
TRACE("bih.biPlanes=%d\n", infoPtr->inbih->biPlanes);
573
TRACE("bih.biBitCount=%d\n", infoPtr->inbih->biBitCount);
574
TRACE("bih.biCompression=%lu\n", infoPtr->inbih->biCompression);
575
TRACE("bih.biSizeImage=%lu\n", infoPtr->inbih->biSizeImage);
576
TRACE("bih.biXPelsPerMeter=%lu\n", infoPtr->inbih->biXPelsPerMeter);
577
TRACE("bih.biYPelsPerMeter=%lu\n", infoPtr->inbih->biYPelsPerMeter);
578
TRACE("bih.biClrUsed=%lu\n", infoPtr->inbih->biClrUsed);
579
TRACE("bih.biClrImportant=%lu\n", infoPtr->inbih->biClrImportant);
580
581
mmioAscend(infoPtr->hMMio, &mmckInfo, 0);
582
583
mmioAscend(infoPtr->hMMio, &mmckList, 0);
584
585
#if 0
586
/* an AVI has 0 or 1 video stream, and to be animated should not contain
587
* an audio stream, so only one strl is allowed
588
*/
589
mmckList.fccType = mmioFOURCC('s', 't', 'r', 'l');
590
if (mmioDescend(infoPtr->hMMio, &mmckList, &mmckHead, MMIO_FINDLIST) == 0) {
591
WARN("There should be a single 'strl' list\n");
592
return FALSE;
593
}
594
#endif
595
596
mmioAscend(infoPtr->hMMio, &mmckHead, 0);
597
598
/* no need to read optional JUNK chunk */
599
600
mmckList.fccType = mmioFOURCC('m', 'o', 'v', 'i');
601
if (mmioDescend(infoPtr->hMMio, &mmckList, &ckMainRIFF, MMIO_FINDLIST) != 0) {
602
WARN("Can't find 'movi' list\n");
603
return FALSE;
604
}
605
606
/* FIXME: should handle the 'rec ' LIST when present */
607
608
infoPtr->lpIndex = Alloc(infoPtr->mah.dwTotalFrames * sizeof(DWORD));
609
if (!infoPtr->lpIndex)
610
return FALSE;
611
612
numFrame = insize = 0;
613
while (mmioDescend(infoPtr->hMMio, &mmckInfo, &mmckList, 0) == 0 &&
614
numFrame < infoPtr->mah.dwTotalFrames) {
615
infoPtr->lpIndex[numFrame] = mmckInfo.dwDataOffset;
616
if (insize < mmckInfo.cksize)
617
insize = mmckInfo.cksize;
618
numFrame++;
619
mmioAscend(infoPtr->hMMio, &mmckInfo, 0);
620
}
621
if (numFrame != infoPtr->mah.dwTotalFrames)
622
{
623
WARN("Found %lu frames (/%lu)\n", numFrame, infoPtr->mah.dwTotalFrames);
624
return FALSE;
625
}
626
if (insize > infoPtr->ash.dwSuggestedBufferSize)
627
{
628
WARN("insize %lu suggestedSize %lu\n", insize, infoPtr->ash.dwSuggestedBufferSize);
629
infoPtr->ash.dwSuggestedBufferSize = insize;
630
}
631
632
infoPtr->indata = Alloc(infoPtr->ash.dwSuggestedBufferSize);
633
if (!infoPtr->indata)
634
return FALSE;
635
636
return TRUE;
637
}
638
639
640
static BOOL ANIMATE_GetAviCodec(ANIMATE_INFO *infoPtr)
641
{
642
DWORD outSize;
643
644
/* check uncompressed AVI */
645
if ((infoPtr->ash.fccHandler == mmioFOURCC('D', 'I', 'B', ' ')) ||
646
(infoPtr->ash.fccHandler == mmioFOURCC('R', 'L', 'E', ' ')) ||
647
(infoPtr->ash.fccHandler == mmioFOURCC(0, 0, 0, 0)))
648
{
649
infoPtr->hic = 0;
650
return TRUE;
651
}
652
653
/* try to get a decompressor for that type */
654
infoPtr->hic = fnIC.fnICOpen(ICTYPE_VIDEO, infoPtr->ash.fccHandler, ICMODE_DECOMPRESS);
655
if (!infoPtr->hic) {
656
WARN("Can't load codec for the file\n");
657
return FALSE;
658
}
659
660
outSize = fnIC.fnICSendMessage(infoPtr->hic, ICM_DECOMPRESS_GET_FORMAT,
661
(DWORD_PTR)infoPtr->inbih, 0L);
662
663
if (!(infoPtr->outbih = Alloc(outSize)))
664
return FALSE;
665
666
if (fnIC.fnICSendMessage(infoPtr->hic, ICM_DECOMPRESS_GET_FORMAT,
667
(DWORD_PTR)infoPtr->inbih, (DWORD_PTR)infoPtr->outbih) != ICERR_OK)
668
{
669
WARN("Can't get output BIH\n");
670
return FALSE;
671
}
672
673
if (!(infoPtr->outdata = Alloc(infoPtr->outbih->biSizeImage)))
674
return FALSE;
675
676
if (fnIC.fnICSendMessage(infoPtr->hic, ICM_DECOMPRESS_BEGIN,
677
(DWORD_PTR)infoPtr->inbih, (DWORD_PTR)infoPtr->outbih) != ICERR_OK) {
678
WARN("Can't begin decompression\n");
679
return FALSE;
680
}
681
682
return TRUE;
683
}
684
685
686
static BOOL ANIMATE_OpenW(ANIMATE_INFO *infoPtr, HINSTANCE hInstance, LPWSTR lpszName)
687
{
688
HDC hdc;
689
690
ANIMATE_Free(infoPtr);
691
692
if (!lpszName)
693
{
694
TRACE("Closing avi.\n");
695
/* installer of thebat! v1.62 requires FALSE here */
696
return (infoPtr->hMMio != 0);
697
}
698
699
if (!hInstance)
700
hInstance = (HINSTANCE)GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_HINSTANCE);
701
702
TRACE("(%s)\n", debugstr_w(lpszName));
703
704
if (!IS_INTRESOURCE(lpszName))
705
{
706
if (!ANIMATE_LoadResW(infoPtr, hInstance, lpszName))
707
{
708
TRACE("No AVI resource found.\n");
709
if (!ANIMATE_LoadFileW(infoPtr, lpszName))
710
{
711
WARN("No AVI file found.\n");
712
return FALSE;
713
}
714
}
715
}
716
else
717
{
718
if (!ANIMATE_LoadResW(infoPtr, hInstance, lpszName))
719
{
720
WARN("No AVI resource found.\n");
721
return FALSE;
722
}
723
}
724
725
if (!ANIMATE_GetAviInfo(infoPtr))
726
{
727
WARN("Can't get AVI information\n");
728
ANIMATE_Free(infoPtr);
729
return FALSE;
730
}
731
732
if (!ANIMATE_GetAviCodec(infoPtr))
733
{
734
WARN("Can't get AVI Codec\n");
735
ANIMATE_Free(infoPtr);
736
return FALSE;
737
}
738
739
hdc = GetDC(infoPtr->hwndSelf);
740
/* native looks at the top left pixel of the first frame here too. */
741
infoPtr->hbrushBG = (HBRUSH)SendMessageW(infoPtr->hwndNotify, WM_CTLCOLORSTATIC,
742
(WPARAM)hdc, (LPARAM)infoPtr->hwndSelf);
743
ReleaseDC(infoPtr->hwndSelf, hdc);
744
745
if (!(infoPtr->dwStyle & ACS_CENTER))
746
SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, infoPtr->mah.dwWidth, infoPtr->mah.dwHeight,
747
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
748
749
if (infoPtr->dwStyle & ACS_AUTOPLAY)
750
return ANIMATE_Play(infoPtr, -1, 0, infoPtr->mah.dwTotalFrames - 1);
751
752
return TRUE;
753
}
754
755
756
static BOOL ANIMATE_OpenA(ANIMATE_INFO *infoPtr, HINSTANCE hInstance, LPSTR lpszName)
757
{
758
LPWSTR lpwszName;
759
LRESULT result;
760
INT len;
761
762
if (IS_INTRESOURCE(lpszName))
763
return ANIMATE_OpenW(infoPtr, hInstance, (LPWSTR)lpszName);
764
765
len = MultiByteToWideChar(CP_ACP, 0, lpszName, -1, NULL, 0);
766
lpwszName = Alloc(len * sizeof(WCHAR));
767
if (!lpwszName) return FALSE;
768
MultiByteToWideChar(CP_ACP, 0, lpszName, -1, lpwszName, len);
769
770
result = ANIMATE_OpenW(infoPtr, hInstance, lpwszName);
771
Free (lpwszName);
772
return result;
773
}
774
775
776
static BOOL ANIMATE_Stop(ANIMATE_INFO *infoPtr)
777
{
778
/* nothing opened */
779
if (!infoPtr->hMMio)
780
return FALSE;
781
782
ANIMATE_DoStop(infoPtr);
783
return TRUE;
784
}
785
786
787
static BOOL ANIMATE_Create(HWND hWnd, const CREATESTRUCTW *lpcs)
788
{
789
ANIMATE_INFO *infoPtr;
790
791
if (!fnIC.hModule)
792
{
793
fnIC.hModule = LoadLibraryW(L"msvfw32.dll");
794
if (!fnIC.hModule) return FALSE;
795
796
fnIC.fnICOpen = (void*)GetProcAddress(fnIC.hModule, "ICOpen");
797
fnIC.fnICClose = (void*)GetProcAddress(fnIC.hModule, "ICClose");
798
fnIC.fnICSendMessage = (void*)GetProcAddress(fnIC.hModule, "ICSendMessage");
799
fnIC.fnICDecompress = (void*)GetProcAddress(fnIC.hModule, "ICDecompress");
800
}
801
802
/* allocate memory for info structure */
803
infoPtr = Alloc(sizeof(*infoPtr));
804
if (!infoPtr) return FALSE;
805
806
/* store crossref hWnd <-> info structure */
807
SetWindowLongPtrW(hWnd, 0, (DWORD_PTR)infoPtr);
808
infoPtr->hwndSelf = hWnd;
809
infoPtr->hwndNotify = lpcs->hwndParent;
810
infoPtr->transparentColor = ANIMATE_COLOR_NONE;
811
infoPtr->hbmPrevFrame = 0;
812
infoPtr->dwStyle = lpcs->style;
813
814
TRACE("Animate style %#lx, parent %p\n", infoPtr->dwStyle, infoPtr->hwndNotify);
815
816
InitializeCriticalSectionEx(&infoPtr->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO);
817
infoPtr->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ANIMATE_INFO*->cs");
818
819
return TRUE;
820
}
821
822
823
static LRESULT ANIMATE_Destroy(ANIMATE_INFO *infoPtr)
824
{
825
/* free avi data */
826
ANIMATE_Free(infoPtr);
827
828
/* free animate info data */
829
SetWindowLongPtrW(infoPtr->hwndSelf, 0, 0);
830
831
infoPtr->cs.DebugInfo->Spare[0] = 0;
832
DeleteCriticalSection(&infoPtr->cs);
833
Free(infoPtr);
834
835
return 0;
836
}
837
838
839
static BOOL ANIMATE_EraseBackground(ANIMATE_INFO const *infoPtr, HDC hdc)
840
{
841
RECT rect;
842
HBRUSH hBrush;
843
844
hBrush = (HBRUSH)SendMessageW(infoPtr->hwndNotify, WM_CTLCOLORSTATIC,
845
(WPARAM)hdc, (LPARAM)infoPtr->hwndSelf);
846
GetClientRect(infoPtr->hwndSelf, &rect);
847
FillRect(hdc, &rect, hBrush ? hBrush : GetCurrentObject(hdc, OBJ_BRUSH));
848
849
return TRUE;
850
}
851
852
853
static LRESULT ANIMATE_StyleChanged(ANIMATE_INFO *infoPtr, WPARAM wStyleType, const STYLESTRUCT *lpss)
854
{
855
TRACE("%#Ix, styleOld %#lx, styleNew %#lx.\n", wStyleType, lpss->styleOld, lpss->styleNew);
856
857
if (wStyleType != GWL_STYLE) return 0;
858
859
infoPtr->dwStyle = lpss->styleNew;
860
return 0;
861
}
862
863
864
static LRESULT WINAPI ANIMATE_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
865
{
866
ANIMATE_INFO *infoPtr = (ANIMATE_INFO *)GetWindowLongPtrW(hWnd, 0);
867
868
TRACE("hwnd %p, msg %x, wparam %#Ix, lparam %#Ix.\n", hWnd, uMsg, wParam, lParam);
869
870
if (!infoPtr && (uMsg != WM_NCCREATE))
871
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
872
switch (uMsg)
873
{
874
case ACM_OPENA:
875
return ANIMATE_OpenA(infoPtr, (HINSTANCE)wParam, (LPSTR)lParam);
876
877
case ACM_OPENW:
878
return ANIMATE_OpenW(infoPtr, (HINSTANCE)wParam, (LPWSTR)lParam);
879
880
case ACM_PLAY:
881
return ANIMATE_Play(infoPtr, (INT)wParam, LOWORD(lParam), HIWORD(lParam));
882
883
case ACM_STOP:
884
return ANIMATE_Stop(infoPtr);
885
886
case WM_CLOSE:
887
ANIMATE_Free(infoPtr);
888
return 0;
889
890
case WM_NCCREATE:
891
return ANIMATE_Create(hWnd, (LPCREATESTRUCTW)lParam);
892
893
case WM_NCHITTEST:
894
return HTTRANSPARENT;
895
896
case WM_DESTROY:
897
return ANIMATE_Destroy(infoPtr);
898
899
case WM_ERASEBKGND:
900
return ANIMATE_EraseBackground(infoPtr, (HDC)wParam);
901
902
case WM_GETOBJECT:
903
if ((LONG)lParam == OBJID_QUERYCLASSNAMEIDX)
904
return 0x1000e;
905
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
906
907
case WM_STYLECHANGED:
908
return ANIMATE_StyleChanged(infoPtr, wParam, (LPSTYLESTRUCT)lParam);
909
910
case WM_TIMER:
911
return ANIMATE_Timer(infoPtr);
912
913
case WM_PRINTCLIENT:
914
case WM_PAINT:
915
{
916
/* the animation has not decompressed
917
* (and displayed) the first frame yet, don't paint
918
*/
919
if (!infoPtr->hbmPrevFrame)
920
{
921
/* default paint handling */
922
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
923
}
924
925
if (wParam)
926
{
927
EnterCriticalSection(&infoPtr->cs);
928
ANIMATE_PaintFrame(infoPtr, (HDC)wParam);
929
LeaveCriticalSection(&infoPtr->cs);
930
}
931
else
932
{
933
PAINTSTRUCT ps;
934
HDC hDC = BeginPaint(infoPtr->hwndSelf, &ps);
935
936
EnterCriticalSection(&infoPtr->cs);
937
ANIMATE_PaintFrame(infoPtr, hDC);
938
LeaveCriticalSection(&infoPtr->cs);
939
940
EndPaint(infoPtr->hwndSelf, &ps);
941
}
942
}
943
break;
944
945
case WM_SIZE:
946
if (infoPtr->dwStyle & ACS_CENTER)
947
InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
948
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
949
950
default:
951
if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg))
952
ERR("unknown msg %#x, wp %#Ix, lp %#Ix.\n", uMsg, wParam, lParam);
953
954
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
955
}
956
return 0;
957
}
958
959
void ANIMATE_Register(void)
960
{
961
WNDCLASSW wndClass;
962
963
ZeroMemory(&wndClass, sizeof(WNDCLASSW));
964
wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
965
wndClass.lpfnWndProc = ANIMATE_WindowProc;
966
wndClass.cbClsExtra = 0;
967
wndClass.cbWndExtra = sizeof(ANIMATE_INFO *);
968
wndClass.hCursor = LoadCursorW(0, (LPCWSTR)IDC_ARROW);
969
wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
970
wndClass.lpszClassName = ANIMATE_CLASSW;
971
972
RegisterClassW(&wndClass);
973
}
974
975
976
void ANIMATE_Unregister(void)
977
{
978
UnregisterClassW(ANIMATE_CLASSW, NULL);
979
}
980
981