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