Sync with trunk r63383 .
[reactos.git] / dll / win32 / msvfw32 / mciwnd.c
1 /*
2 * Copyright 2000 Eric Pouech
3 * Copyright 2003 Dmitry Timoshkov
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 *
19 * FIXME:
20 * Add support for all remaining MCI_ commands and MCIWNDM_ messages.
21 * Add support for MCIWNDF_RECORD.
22 */
23
24 #include "msvideo_private.h"
25
26 #include <winternl.h>
27 #include <digitalv.h>
28 #include <commctrl.h>
29 #include <wine/unicode.h>
30
31 WINE_DEFAULT_DEBUG_CHANNEL(mci);
32
33 extern HMODULE MSVFW32_hModule;
34 static const WCHAR mciWndClassW[] = {'M','C','I','W','n','d','C','l','a','s','s',0};
35
36 typedef struct
37 {
38 DWORD dwStyle;
39 MCIDEVICEID mci;
40 HDRVR hdrv;
41 int alias;
42 UINT dev_type;
43 UINT mode;
44 LONG position;
45 SIZE size; /* size of the original frame rect */
46 int zoom;
47 LPWSTR lpName;
48 HWND hWnd, hwndOwner;
49 UINT uTimer;
50 MCIERROR lasterror;
51 WCHAR return_string[128];
52 WORD active_timer, inactive_timer;
53 } MCIWndInfo;
54
55 static LRESULT WINAPI MCIWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam);
56
57 #define CTL_PLAYSTOP 0x3200
58 #define CTL_MENU 0x3201
59 #define CTL_TRACKBAR 0x3202
60
61 /***********************************************************************
62 * MCIWndRegisterClass [MSVFW32.@]
63 *
64 * NOTE: Native always uses its own hInstance
65 */
66 BOOL VFWAPIV MCIWndRegisterClass(void)
67 {
68 WNDCLASSW wc;
69
70 /* Since we are going to register a class belonging to MSVFW32
71 * and later we will create windows with a different hInstance
72 * CS_GLOBALCLASS is needed. And because the second attempt
73 * to register a global class will fail we need to test whether
74 * the class was already registered.
75 */
76 wc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS | CS_OWNDC | CS_GLOBALCLASS;
77 wc.lpfnWndProc = MCIWndProc;
78 wc.cbClsExtra = 0;
79 wc.cbWndExtra = sizeof(MCIWndInfo*);
80 wc.hInstance = MSVFW32_hModule;
81 wc.hIcon = 0;
82 wc.hCursor = LoadCursorW(0, MAKEINTRESOURCEW(IDC_ARROW));
83 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
84 wc.lpszMenuName = NULL;
85 wc.lpszClassName = mciWndClassW;
86
87 if (RegisterClassW(&wc)) return TRUE;
88 if (GetLastError() == ERROR_CLASS_ALREADY_EXISTS) return TRUE;
89
90 return FALSE;
91 }
92
93 /***********************************************************************
94 * MCIWndCreateW [MSVFW32.@]
95 */
96 HWND VFWAPIV MCIWndCreateW(HWND hwndParent, HINSTANCE hInstance,
97 DWORD dwStyle, LPCWSTR szFile)
98 {
99 TRACE("%p %p %x %s\n", hwndParent, hInstance, dwStyle, debugstr_w(szFile));
100
101 MCIWndRegisterClass();
102
103 if (!hInstance) hInstance = GetModuleHandleW(0);
104
105 if (hwndParent)
106 dwStyle |= WS_VISIBLE | WS_BORDER /*| WS_CHILD*/;
107 else
108 dwStyle |= WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
109
110 return CreateWindowExW(0, mciWndClassW, NULL,
111 dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
112 0, 0, 300, 0,
113 hwndParent, 0, hInstance, (LPVOID)szFile);
114 }
115
116 /***********************************************************************
117 * MCIWndCreate [MSVFW32.@]
118 * MCIWndCreateA [MSVFW32.@]
119 */
120 HWND VFWAPIV MCIWndCreateA(HWND hwndParent, HINSTANCE hInstance,
121 DWORD dwStyle, LPCSTR szFile)
122 {
123 HWND ret;
124 UNICODE_STRING fileW;
125
126 if (szFile)
127 RtlCreateUnicodeStringFromAsciiz(&fileW, szFile);
128 else
129 fileW.Buffer = NULL;
130
131 ret = MCIWndCreateW(hwndParent, hInstance, dwStyle, fileW.Buffer);
132
133 RtlFreeUnicodeString(&fileW);
134 return ret;
135 }
136
137 static inline void MCIWND_notify_mode(MCIWndInfo *mwi)
138 {
139 if (mwi->dwStyle & MCIWNDF_NOTIFYMODE)
140 {
141 UINT new_mode = SendMessageW(mwi->hWnd, MCIWNDM_GETMODEW, 0, 0);
142 if (new_mode != mwi->mode)
143 {
144 mwi->mode = new_mode;
145 SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYMODE, (WPARAM)mwi->hWnd, new_mode);
146 }
147 }
148 }
149
150 static inline void MCIWND_notify_pos(MCIWndInfo *mwi)
151 {
152 if (mwi->dwStyle & MCIWNDF_NOTIFYPOS)
153 {
154 LONG new_pos = SendMessageW(mwi->hWnd, MCIWNDM_GETPOSITIONW, 0, 0);
155 if (new_pos != mwi->position)
156 {
157 mwi->position = new_pos;
158 SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYPOS, (WPARAM)mwi->hWnd, new_pos);
159 }
160 }
161 }
162
163 static inline void MCIWND_notify_size(MCIWndInfo *mwi)
164 {
165 if (mwi->dwStyle & MCIWNDF_NOTIFYSIZE)
166 SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYSIZE, (WPARAM)mwi->hWnd, 0);
167 }
168
169 static inline void MCIWND_notify_error(MCIWndInfo *mwi)
170 {
171 if (mwi->dwStyle & MCIWNDF_NOTIFYERROR)
172 SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYERROR, (WPARAM)mwi->hWnd, (LPARAM)mwi->lasterror);
173 }
174
175 static void MCIWND_UpdateState(MCIWndInfo *mwi)
176 {
177 WCHAR buffer[1024];
178
179 if (!mwi->mci)
180 {
181 /* FIXME: get this from resources */
182 static const WCHAR no_deviceW[] = {'N','o',' ','D','e','v','i','c','e',0};
183 SetWindowTextW(mwi->hWnd, no_deviceW);
184 return;
185 }
186
187 MCIWND_notify_pos(mwi);
188
189 if (!(mwi->dwStyle & MCIWNDF_NOPLAYBAR))
190 SendDlgItemMessageW(mwi->hWnd, CTL_TRACKBAR, TBM_SETPOS, TRUE, mwi->position);
191
192 if (!(mwi->dwStyle & MCIWNDF_SHOWALL))
193 return;
194
195 if ((mwi->dwStyle & MCIWNDF_SHOWNAME) && mwi->lpName)
196 strcpyW(buffer, mwi->lpName);
197 else
198 *buffer = 0;
199
200 if (mwi->dwStyle & (MCIWNDF_SHOWPOS|MCIWNDF_SHOWMODE))
201 {
202 static const WCHAR spaceW[] = {' ',0};
203 static const WCHAR l_braceW[] = {'(',0};
204
205 if (*buffer) strcatW(buffer, spaceW);
206 strcatW(buffer, l_braceW);
207 }
208
209 if (mwi->dwStyle & MCIWNDF_SHOWPOS)
210 {
211 WCHAR posW[64];
212
213 posW[0] = 0;
214 SendMessageW(mwi->hWnd, MCIWNDM_GETPOSITIONW, 64, (LPARAM)posW);
215 strcatW(buffer, posW);
216 }
217
218 if ((mwi->dwStyle & (MCIWNDF_SHOWPOS|MCIWNDF_SHOWMODE)) == (MCIWNDF_SHOWPOS|MCIWNDF_SHOWMODE))
219 {
220 static const WCHAR dashW[] = {' ','-',' ',0};
221 strcatW(buffer, dashW);
222 }
223
224 if (mwi->dwStyle & MCIWNDF_SHOWMODE)
225 {
226 WCHAR modeW[64];
227
228 modeW[0] = 0;
229 SendMessageW(mwi->hWnd, MCIWNDM_GETMODEW, 64, (LPARAM)modeW);
230 strcatW(buffer, modeW);
231 }
232
233 if (mwi->dwStyle & (MCIWNDF_SHOWPOS|MCIWNDF_SHOWMODE))
234 {
235 static const WCHAR r_braceW[] = {')',0};
236 strcatW(buffer, r_braceW);
237 }
238
239 TRACE("=> %s\n", debugstr_w(buffer));
240 SetWindowTextW(mwi->hWnd, buffer);
241 }
242
243 static LRESULT MCIWND_Create(HWND hWnd, LPCREATESTRUCTW cs)
244 {
245 HWND hChld;
246 MCIWndInfo *mwi;
247 static const WCHAR buttonW[] = {'b','u','t','t','o','n',0};
248
249 mwi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*mwi));
250 if (!mwi) return -1;
251
252 SetWindowLongW(hWnd, 0, (LPARAM)mwi);
253
254 mwi->dwStyle = cs->style;
255 /* There is no need to show stats if there is no caption */
256 if ((mwi->dwStyle & WS_CAPTION) != WS_CAPTION)
257 mwi->dwStyle &= ~MCIWNDF_SHOWALL;
258
259 mwi->hWnd = hWnd;
260 mwi->hwndOwner = cs->hwndParent;
261 mwi->active_timer = 500;
262 mwi->inactive_timer = 2000;
263 mwi->mode = MCI_MODE_NOT_READY;
264 mwi->position = -1;
265 mwi->zoom = 100;
266
267 if (!(mwi->dwStyle & MCIWNDF_NOMENU))
268 {
269 static const WCHAR menuW[] = {'M','e','n','u',0};
270
271 hChld = CreateWindowExW(0, buttonW, menuW, WS_CHILD|WS_VISIBLE, 32, cs->cy, 32, 32,
272 hWnd, (HMENU)CTL_MENU, cs->hInstance, 0L);
273 TRACE("Get Button2: %p\n", hChld);
274 }
275
276 if (!(mwi->dwStyle & MCIWNDF_NOPLAYBAR))
277 {
278 INITCOMMONCONTROLSEX init;
279 static const WCHAR playW[] = {'P','l','a','y',0};
280
281 /* adding the other elements: play/stop button, menu button, status */
282 hChld = CreateWindowExW(0, buttonW, playW, WS_CHILD|WS_VISIBLE, 0, cs->cy, 32, 32,
283 hWnd, (HMENU)CTL_PLAYSTOP, cs->hInstance, 0L);
284 TRACE("Get Button1: %p\n", hChld);
285
286 init.dwSize = sizeof(init);
287 init.dwICC = ICC_BAR_CLASSES;
288 InitCommonControlsEx(&init);
289
290 hChld = CreateWindowExW(0, TRACKBAR_CLASSW, NULL, WS_CHILD|WS_VISIBLE, 64, cs->cy, cs->cx - 64, 32,
291 hWnd, (HMENU)CTL_TRACKBAR, cs->hInstance, 0L);
292 TRACE("Get status: %p\n", hChld);
293 }
294
295 /* This sets the default window size */
296 SendMessageW(hWnd, MCI_CLOSE, 0, 0);
297
298 if (cs->lpCreateParams)
299 {
300 LPARAM lParam;
301
302 /* MCI wnd class is prepared to be embedded as an MDI child window */
303 if (cs->dwExStyle & WS_EX_MDICHILD)
304 {
305 MDICREATESTRUCTW *mdics = cs->lpCreateParams;
306 lParam = mdics->lParam;
307 }
308 else
309 lParam = (LPARAM)cs->lpCreateParams;
310
311 /* If it's our internal class pointer, file name is a unicode string */
312 if (cs->lpszClass == mciWndClassW)
313 SendMessageW(hWnd, MCIWNDM_OPENW, 0, lParam);
314 else
315 {
316 /* Otherwise let's try to figure out what string format is used */
317 HWND parent = cs->hwndParent;
318 if (!parent) parent = GetWindow(hWnd, GW_OWNER);
319
320 SendMessageW(hWnd, IsWindowUnicode(parent) ? MCIWNDM_OPENW : MCIWNDM_OPENA, 0, lParam);
321 }
322 }
323
324 return 0;
325 }
326
327 static void MCIWND_ToggleState(MCIWndInfo *mwi)
328 {
329 switch (SendMessageW(mwi->hWnd, MCIWNDM_GETMODEW, 0, 0))
330 {
331 case MCI_MODE_NOT_READY:
332 case MCI_MODE_RECORD:
333 case MCI_MODE_SEEK:
334 case MCI_MODE_OPEN:
335 TRACE("Cannot do much...\n");
336 break;
337
338 case MCI_MODE_PAUSE:
339 SendMessageW(mwi->hWnd, MCI_RESUME, 0, 0);
340 break;
341
342 case MCI_MODE_PLAY:
343 SendMessageW(mwi->hWnd, MCI_PAUSE, 0, 0);
344 break;
345
346 case MCI_MODE_STOP:
347 SendMessageW(mwi->hWnd, MCI_STOP, 0, 0);
348 break;
349 }
350 }
351
352 static LRESULT MCIWND_Command(MCIWndInfo *mwi, WPARAM wParam, LPARAM lParam)
353 {
354 switch (LOWORD(wParam))
355 {
356 case CTL_PLAYSTOP: MCIWND_ToggleState(mwi); break;
357 case CTL_MENU:
358 case CTL_TRACKBAR:
359 default:
360 FIXME("support for command %04x not implement yet\n", LOWORD(wParam));
361 }
362 return 0L;
363 }
364
365 static void MCIWND_notify_media(MCIWndInfo *mwi)
366 {
367 if (mwi->dwStyle & (MCIWNDF_NOTIFYMEDIAA | MCIWNDF_NOTIFYMEDIAW))
368 {
369 if (!mwi->lpName)
370 {
371 static const WCHAR empty_str[1];
372 SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYMEDIA, (WPARAM)mwi->hWnd, (LPARAM)empty_str);
373 }
374 else
375 {
376 if (mwi->dwStyle & MCIWNDF_NOTIFYANSI)
377 {
378 char *ansi_name;
379 int len;
380
381 len = WideCharToMultiByte(CP_ACP, 0, mwi->lpName, -1, NULL, 0, NULL, NULL);
382 ansi_name = HeapAlloc(GetProcessHeap(), 0, len);
383 WideCharToMultiByte(CP_ACP, 0, mwi->lpName, -1, ansi_name, len, NULL, NULL);
384
385 SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYMEDIA, (WPARAM)mwi->hWnd, (LPARAM)ansi_name);
386
387 HeapFree(GetProcessHeap(), 0, ansi_name);
388 }
389 else
390 SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYMEDIA, (WPARAM)mwi->hWnd, (LPARAM)mwi->lpName);
391 }
392 }
393 }
394
395 static MCIERROR mci_generic_command(MCIWndInfo *mwi, UINT cmd)
396 {
397 MCI_GENERIC_PARMS mci_generic;
398
399 mci_generic.dwCallback = 0;
400 mwi->lasterror = mciSendCommandW(mwi->mci, cmd, 0, (DWORD_PTR)&mci_generic);
401
402 if (mwi->lasterror)
403 return mwi->lasterror;
404
405 MCIWND_notify_mode(mwi);
406 MCIWND_UpdateState(mwi);
407 return 0;
408 }
409
410 static LRESULT mci_get_devcaps(MCIWndInfo *mwi, UINT cap)
411 {
412 MCI_GETDEVCAPS_PARMS mci_devcaps;
413
414 mci_devcaps.dwItem = cap;
415 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_GETDEVCAPS,
416 MCI_GETDEVCAPS_ITEM,
417 (DWORD_PTR)&mci_devcaps);
418 if (mwi->lasterror)
419 return 0;
420
421 return mci_devcaps.dwReturn;
422 }
423
424 static LRESULT MCIWND_KeyDown(MCIWndInfo *mwi, UINT key)
425 {
426 TRACE("%p, key %04x\n", mwi->hWnd, key);
427
428 switch(key)
429 {
430 case VK_ESCAPE:
431 SendMessageW(mwi->hWnd, MCI_STOP, 0, 0);
432 return 0;
433
434 default:
435 return 0;
436 }
437 }
438
439 static LRESULT WINAPI MCIWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
440 {
441 MCIWndInfo *mwi;
442
443 TRACE("%p %04x %08lx %08lx\n", hWnd, wMsg, wParam, lParam);
444
445 mwi = (MCIWndInfo*)GetWindowLongPtrW(hWnd, 0);
446 if (!mwi && wMsg != WM_CREATE)
447 return DefWindowProcW(hWnd, wMsg, wParam, lParam);
448
449 switch (wMsg)
450 {
451 case WM_CREATE:
452 MCIWND_Create(hWnd, (CREATESTRUCTW *)lParam);
453 break;
454
455 case WM_DESTROY:
456 if (mwi->uTimer)
457 KillTimer(hWnd, mwi->uTimer);
458
459 if (mwi->mci)
460 SendMessageW(hWnd, MCI_CLOSE, 0, 0);
461
462 HeapFree(GetProcessHeap(), 0, mwi);
463
464 DestroyWindow(GetDlgItem(hWnd, CTL_MENU));
465 DestroyWindow(GetDlgItem(hWnd, CTL_PLAYSTOP));
466 DestroyWindow(GetDlgItem(hWnd, CTL_TRACKBAR));
467 break;
468
469 case WM_PAINT:
470 {
471 MCI_DGV_UPDATE_PARMS mci_update;
472 PAINTSTRUCT ps;
473
474 mci_update.hDC = (wParam) ? (HDC)wParam : BeginPaint(hWnd, &ps);
475
476 mciSendCommandW(mwi->mci, MCI_UPDATE,
477 MCI_DGV_UPDATE_HDC | MCI_DGV_UPDATE_PAINT,
478 (DWORD_PTR)&mci_update);
479
480 if (!wParam) EndPaint(hWnd, &ps);
481 return 1;
482 }
483
484 case WM_COMMAND:
485 return MCIWND_Command(mwi, wParam, lParam);
486
487 case WM_KEYDOWN:
488 return MCIWND_KeyDown(mwi, wParam);
489
490 case WM_NCACTIVATE:
491 if (mwi->uTimer)
492 {
493 KillTimer(hWnd, mwi->uTimer);
494 mwi->uTimer = SetTimer(hWnd, 1, wParam ? mwi->active_timer : mwi->inactive_timer, NULL);
495 }
496 break;
497
498 case WM_TIMER:
499 MCIWND_UpdateState(mwi);
500 return 0;
501
502 case WM_SIZE:
503 SetWindowPos(GetDlgItem(hWnd, CTL_PLAYSTOP), 0, 0, HIWORD(lParam) - 32, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
504 SetWindowPos(GetDlgItem(hWnd, CTL_MENU), 0, 32, HIWORD(lParam) - 32, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
505 SetWindowPos(GetDlgItem(hWnd, CTL_TRACKBAR), 0, 64, HIWORD(lParam) - 32, LOWORD(lParam) - 64, 32, SWP_NOACTIVATE);
506
507 if (!(mwi->dwStyle & MCIWNDF_NOAUTOSIZEMOVIE))
508 {
509 RECT rc;
510
511 rc.left = rc.top = 0;
512 rc.right = LOWORD(lParam);
513 rc.bottom = HIWORD(lParam);
514 if (!(mwi->dwStyle & MCIWNDF_NOPLAYBAR))
515 rc.bottom -= 32; /* subtract the height of the playbar */
516 SendMessageW(hWnd, MCIWNDM_PUT_DEST, 0, (LPARAM)&rc);
517 }
518 MCIWND_notify_size(mwi);
519 break;
520
521 case MM_MCINOTIFY:
522 MCIWND_notify_mode(mwi);
523 MCIWND_UpdateState(mwi);
524 return 0;
525
526 case MCIWNDM_OPENA:
527 {
528 UNICODE_STRING nameW;
529 TRACE("MCIWNDM_OPENA %s\n", debugstr_a((LPSTR)lParam));
530 RtlCreateUnicodeStringFromAsciiz(&nameW, (LPCSTR)lParam);
531 lParam = (LPARAM)nameW.Buffer;
532 }
533 /* fall through */
534 case MCIWNDM_OPENW:
535 {
536 RECT rc;
537 HCURSOR hCursor;
538 MCI_OPEN_PARMSW mci_open;
539 MCI_GETDEVCAPS_PARMS mci_devcaps;
540 WCHAR aliasW[64];
541 WCHAR drv_name[MAX_PATH];
542 static const WCHAR formatW[] = {'%','d',0};
543 static const WCHAR mci32W[] = {'m','c','i','3','2',0};
544 static const WCHAR system_iniW[] = {'s','y','s','t','e','m','.','i','n','i',0};
545
546 TRACE("MCIWNDM_OPENW %s\n", debugstr_w((LPWSTR)lParam));
547
548 if (wParam == MCIWNDOPENF_NEW)
549 {
550 SendMessageW(hWnd, MCIWNDM_NEWW, 0, lParam);
551 goto end_of_mci_open;
552 }
553
554 if (mwi->uTimer)
555 {
556 KillTimer(hWnd, mwi->uTimer);
557 mwi->uTimer = 0;
558 }
559
560 hCursor = LoadCursorW(0, (LPWSTR)IDC_WAIT);
561 hCursor = SetCursor(hCursor);
562
563 mci_open.lpstrElementName = (LPWSTR)lParam;
564 wsprintfW(aliasW, formatW, HandleToLong(hWnd) + 1);
565 mci_open.lpstrAlias = aliasW;
566 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_OPEN,
567 MCI_OPEN_ELEMENT | MCI_OPEN_ALIAS | MCI_WAIT,
568 (DWORD_PTR)&mci_open);
569 SetCursor(hCursor);
570
571 if (mwi->lasterror && !(mwi->dwStyle & MCIWNDF_NOERRORDLG))
572 {
573 /* FIXME: get the caption from resources */
574 static const WCHAR caption[] = {'M','C','I',' ','E','r','r','o','r',0};
575 WCHAR error_str[MAXERRORLENGTH];
576
577 mciGetErrorStringW(mwi->lasterror, error_str, MAXERRORLENGTH);
578 MessageBoxW(hWnd, error_str, caption, MB_ICONEXCLAMATION | MB_OK);
579 MCIWND_notify_error(mwi);
580 goto end_of_mci_open;
581 }
582
583 mwi->mci = mci_open.wDeviceID;
584 mwi->alias = HandleToLong(hWnd) + 1;
585
586 mwi->lpName = HeapAlloc(GetProcessHeap(), 0, (strlenW((LPWSTR)lParam) + 1) * sizeof(WCHAR));
587 strcpyW(mwi->lpName, (LPWSTR)lParam);
588
589 MCIWND_UpdateState(mwi);
590
591 mci_devcaps.dwItem = MCI_GETDEVCAPS_DEVICE_TYPE;
592 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_GETDEVCAPS,
593 MCI_GETDEVCAPS_ITEM,
594 (DWORD_PTR)&mci_devcaps);
595 if (mwi->lasterror)
596 {
597 MCIWND_notify_error(mwi);
598 goto end_of_mci_open;
599 }
600
601 mwi->dev_type = mci_devcaps.dwReturn;
602
603 drv_name[0] = 0;
604 SendMessageW(hWnd, MCIWNDM_GETDEVICEW, 256, (LPARAM)drv_name);
605 if (drv_name[0] && GetPrivateProfileStringW(mci32W, drv_name, NULL,
606 drv_name, MAX_PATH, system_iniW))
607 mwi->hdrv = OpenDriver(drv_name, NULL, 0);
608
609 if (mwi->dev_type == MCI_DEVTYPE_DIGITAL_VIDEO)
610 {
611 MCI_DGV_WINDOW_PARMSW mci_window;
612
613 mci_window.hWnd = hWnd;
614 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_WINDOW,
615 MCI_DGV_WINDOW_HWND,
616 (DWORD_PTR)&mci_window);
617 if (mwi->lasterror)
618 {
619 MCIWND_notify_error(mwi);
620 goto end_of_mci_open;
621 }
622 }
623
624 if (SendMessageW(hWnd, MCIWNDM_GET_DEST, 0, (LPARAM)&rc) == 0)
625 {
626 mwi->size.cx = rc.right - rc.left;
627 mwi->size.cy = rc.bottom - rc.top;
628
629 rc.right = MulDiv(mwi->size.cx, mwi->zoom, 100);
630 rc.bottom = MulDiv(mwi->size.cy, mwi->zoom, 100);
631 SendMessageW(hWnd, MCIWNDM_PUT_DEST, 0, (LPARAM)&rc);
632 }
633 else
634 {
635 GetClientRect(hWnd, &rc);
636 rc.bottom = rc.top;
637 }
638
639 if (!(mwi->dwStyle & MCIWNDF_NOPLAYBAR))
640 rc.bottom += 32; /* add the height of the playbar */
641 AdjustWindowRect(&rc, GetWindowLongW(hWnd, GWL_STYLE), FALSE);
642 SetWindowPos(hWnd, 0, 0, 0, rc.right - rc.left,
643 rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
644
645 SendDlgItemMessageW(hWnd, CTL_TRACKBAR, TBM_SETRANGEMIN, 0L, 0L);
646 SendDlgItemMessageW(hWnd, CTL_TRACKBAR, TBM_SETRANGEMAX, 1,
647 SendMessageW(hWnd, MCIWNDM_GETLENGTH, 0, 0));
648 mwi->uTimer = SetTimer(hWnd, 1, mwi->active_timer, NULL);
649
650 MCIWND_notify_media(mwi);
651
652 end_of_mci_open:
653 if (wMsg == MCIWNDM_OPENA)
654 HeapFree(GetProcessHeap(), 0, (void *)lParam);
655 return mwi->lasterror;
656 }
657
658 case MCIWNDM_GETDEVICEID:
659 TRACE("MCIWNDM_GETDEVICEID\n");
660 return mwi->mci;
661
662 case MCIWNDM_GETALIAS:
663 TRACE("MCIWNDM_GETALIAS\n");
664 return mwi->alias;
665
666 case MCIWNDM_GET_SOURCE:
667 {
668 MCI_DGV_RECT_PARMS mci_rect;
669
670 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_WHERE,
671 MCI_DGV_WHERE_SOURCE,
672 (DWORD_PTR)&mci_rect);
673 if (mwi->lasterror)
674 {
675 MCIWND_notify_error(mwi);
676 return mwi->lasterror;
677 }
678 *(RECT *)lParam = mci_rect.rc;
679 TRACE("MCIWNDM_GET_SOURCE: %s\n", wine_dbgstr_rect(&mci_rect.rc));
680 return 0;
681 }
682
683 case MCIWNDM_GET_DEST:
684 {
685 MCI_DGV_RECT_PARMS mci_rect;
686
687 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_WHERE,
688 MCI_DGV_WHERE_DESTINATION,
689 (DWORD_PTR)&mci_rect);
690 if (mwi->lasterror)
691 {
692 MCIWND_notify_error(mwi);
693 return mwi->lasterror;
694 }
695 *(RECT *)lParam = mci_rect.rc;
696 TRACE("MCIWNDM_GET_DEST: %s\n", wine_dbgstr_rect(&mci_rect.rc));
697 return 0;
698 }
699
700 case MCIWNDM_PUT_SOURCE:
701 {
702 MCI_DGV_PUT_PARMS mci_put;
703
704 mci_put.rc = *(RECT *)lParam;
705 TRACE("MCIWNDM_PUT_SOURCE: %s\n", wine_dbgstr_rect(&mci_put.rc));
706 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_PUT,
707 MCI_DGV_PUT_SOURCE,
708 (DWORD_PTR)&mci_put);
709 if (mwi->lasterror)
710 {
711 MCIWND_notify_error(mwi);
712 return mwi->lasterror;
713 }
714 return 0;
715 }
716
717 case MCIWNDM_PUT_DEST:
718 {
719 MCI_DGV_PUT_PARMS mci_put;
720
721 mci_put.rc = *(RECT *)lParam;
722 TRACE("MCIWNDM_PUT_DEST: %s\n", wine_dbgstr_rect(&mci_put.rc));
723
724 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_PUT,
725 MCI_DGV_PUT_DESTINATION | MCI_DGV_RECT,
726 (DWORD_PTR)&mci_put);
727 if (mwi->lasterror)
728 {
729 MCIWND_notify_error(mwi);
730 return mwi->lasterror;
731 }
732 return 0;
733 }
734
735 case MCIWNDM_GETLENGTH:
736 {
737 MCI_STATUS_PARMS mci_status;
738
739 mci_status.dwItem = MCI_STATUS_LENGTH;
740 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STATUS,
741 MCI_STATUS_ITEM,
742 (DWORD_PTR)&mci_status);
743 if (mwi->lasterror)
744 {
745 MCIWND_notify_error(mwi);
746 return 0;
747 }
748 TRACE("MCIWNDM_GETLENGTH: %ld\n", mci_status.dwReturn);
749 return mci_status.dwReturn;
750 }
751
752 case MCIWNDM_GETSTART:
753 {
754 MCI_STATUS_PARMS mci_status;
755
756 mci_status.dwItem = MCI_STATUS_POSITION;
757 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STATUS,
758 MCI_STATUS_ITEM | MCI_STATUS_START,
759 (DWORD_PTR)&mci_status);
760 if (mwi->lasterror)
761 {
762 MCIWND_notify_error(mwi);
763 return 0;
764 }
765 TRACE("MCIWNDM_GETSTART: %ld\n", mci_status.dwReturn);
766 return mci_status.dwReturn;
767 }
768
769 case MCIWNDM_GETEND:
770 {
771 LRESULT start, length;
772
773 start = SendMessageW(hWnd, MCIWNDM_GETSTART, 0, 0);
774 length = SendMessageW(hWnd, MCIWNDM_GETLENGTH, 0, 0);
775 TRACE("MCIWNDM_GETEND: %ld\n", start + length);
776 return (start + length);
777 }
778
779 case MCIWNDM_GETPOSITIONA:
780 case MCIWNDM_GETPOSITIONW:
781 {
782 MCI_STATUS_PARMS mci_status;
783
784 TRACE("MCIWNDM_GETPOSITION\n");
785
786 /* get position string if requested */
787 if (wParam && lParam)
788 {
789 if (wMsg == MCIWNDM_GETPOSITIONA)
790 {
791 char cmd[64];
792
793 wsprintfA(cmd, "status %d position", mwi->alias);
794 mwi->lasterror = mciSendStringA(cmd, (LPSTR)lParam, wParam, 0);
795 }
796 else
797 {
798
799 WCHAR cmdW[64];
800 static const WCHAR formatW[] = {'s','t','a','t','u','s',' ','%','d',' ','p','o','s','i','t','i','o','n',0};
801
802 wsprintfW(cmdW, formatW, mwi->alias);
803 mwi->lasterror = mciSendStringW(cmdW, (LPWSTR)lParam, wParam, 0);
804 }
805
806 if (mwi->lasterror)
807 return 0;
808 }
809
810 mci_status.dwItem = MCI_STATUS_POSITION;
811 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STATUS,
812 MCI_STATUS_ITEM,
813 (DWORD_PTR)&mci_status);
814 if (mwi->lasterror)
815 return 0;
816
817 return mci_status.dwReturn;
818 }
819
820 case MCIWNDM_GETMODEA:
821 case MCIWNDM_GETMODEW:
822 {
823 MCI_STATUS_PARMS mci_status;
824
825 TRACE("MCIWNDM_GETMODE\n");
826
827 if (!mwi->mci)
828 return MCI_MODE_NOT_READY;
829
830 /* get mode string if requested */
831 if (wParam && lParam)
832 {
833 if (wMsg == MCIWNDM_GETMODEA)
834 {
835 char cmd[64];
836
837 wsprintfA(cmd, "status %d mode", mwi->alias);
838 mwi->lasterror = mciSendStringA(cmd, (LPSTR)lParam, wParam, 0);
839 }
840 else
841 {
842
843 WCHAR cmdW[64];
844 static const WCHAR formatW[] = {'s','t','a','t','u','s',' ','%','d',' ','m','o','d','e',0};
845
846 wsprintfW(cmdW, formatW, mwi->alias);
847 mwi->lasterror = mciSendStringW(cmdW, (LPWSTR)lParam, wParam, 0);
848 }
849
850 if (mwi->lasterror)
851 return MCI_MODE_NOT_READY;
852 }
853
854 mci_status.dwItem = MCI_STATUS_MODE;
855 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STATUS,
856 MCI_STATUS_ITEM,
857 (DWORD_PTR)&mci_status);
858 if (mwi->lasterror)
859 return MCI_MODE_NOT_READY;
860
861 return mci_status.dwReturn;
862 }
863
864 case MCIWNDM_PLAYFROM:
865 {
866 MCI_PLAY_PARMS mci_play;
867
868 TRACE("MCIWNDM_PLAYFROM %08lx\n", lParam);
869
870 mci_play.dwCallback = (DWORD_PTR)hWnd;
871 mci_play.dwFrom = lParam;
872 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_PLAY,
873 MCI_FROM | MCI_NOTIFY,
874 (DWORD_PTR)&mci_play);
875 if (mwi->lasterror)
876 {
877 MCIWND_notify_error(mwi);
878 return mwi->lasterror;
879 }
880
881 MCIWND_notify_mode(mwi);
882 MCIWND_UpdateState(mwi);
883 return 0;
884 }
885
886 case MCIWNDM_PLAYTO:
887 {
888 MCI_PLAY_PARMS mci_play;
889
890 TRACE("MCIWNDM_PLAYTO %08lx\n", lParam);
891
892 mci_play.dwCallback = (DWORD_PTR)hWnd;
893 mci_play.dwTo = lParam;
894 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_PLAY,
895 MCI_TO | MCI_NOTIFY,
896 (DWORD_PTR)&mci_play);
897 if (mwi->lasterror)
898 {
899 MCIWND_notify_error(mwi);
900 return mwi->lasterror;
901 }
902
903 MCIWND_notify_mode(mwi);
904 MCIWND_UpdateState(mwi);
905 return 0;
906 }
907
908 case MCIWNDM_PLAYREVERSE:
909 {
910 MCI_PLAY_PARMS mci_play;
911 DWORD flags = MCI_NOTIFY;
912
913 TRACE("MCIWNDM_PLAYREVERSE %08lx\n", lParam);
914
915 mci_play.dwCallback = (DWORD_PTR)hWnd;
916 mci_play.dwFrom = lParam;
917 switch (mwi->dev_type)
918 {
919 default:
920 case MCI_DEVTYPE_ANIMATION:
921 flags |= MCI_ANIM_PLAY_REVERSE;
922 break;
923
924 case MCI_DEVTYPE_DIGITAL_VIDEO:
925 flags |= MCI_DGV_PLAY_REVERSE;
926 break;
927
928 #ifdef MCI_VCR_PLAY_REVERSE
929 case MCI_DEVTYPE_VCR:
930 flags |= MCI_VCR_PLAY_REVERSE;
931 break;
932 #endif
933
934 case MCI_DEVTYPE_VIDEODISC:
935 flags |= MCI_VD_PLAY_REVERSE;
936 break;
937
938 }
939 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_PLAY,
940 flags, (DWORD_PTR)&mci_play);
941 if (mwi->lasterror)
942 {
943 MCIWND_notify_error(mwi);
944 return mwi->lasterror;
945 }
946
947 MCIWND_notify_mode(mwi);
948 MCIWND_UpdateState(mwi);
949 return 0;
950 }
951
952 case MCIWNDM_GETERRORA:
953 mciGetErrorStringA(mwi->lasterror, (LPSTR)lParam, wParam);
954 TRACE("MCIWNDM_GETERRORA: %s\n", debugstr_an((LPSTR)lParam, wParam));
955 return mwi->lasterror;
956
957 case MCIWNDM_GETERRORW:
958 mciGetErrorStringW(mwi->lasterror, (LPWSTR)lParam, wParam);
959 TRACE("MCIWNDM_GETERRORW: %s\n", debugstr_wn((LPWSTR)lParam, wParam));
960 return mwi->lasterror;
961
962 case MCIWNDM_SETOWNER:
963 TRACE("MCIWNDM_SETOWNER %p\n", (HWND)wParam);
964 mwi->hwndOwner = (HWND)wParam;
965 return 0;
966
967 case MCIWNDM_SENDSTRINGA:
968 {
969 UNICODE_STRING stringW;
970
971 TRACE("MCIWNDM_SENDSTRINGA %s\n", debugstr_a((LPCSTR)lParam));
972
973 RtlCreateUnicodeStringFromAsciiz(&stringW, (LPCSTR)lParam);
974 lParam = (LPARAM)stringW.Buffer;
975 }
976 /* fall through */
977 case MCIWNDM_SENDSTRINGW:
978 {
979 WCHAR *cmdW, *p;
980
981 TRACE("MCIWNDM_SENDSTRINGW %s\n", debugstr_w((LPCWSTR)lParam));
982
983 p = strchrW((LPCWSTR)lParam, ' ');
984 if (p)
985 {
986 static const WCHAR formatW[] = {'%','d',' ',0};
987 int len, pos;
988
989 pos = p - (WCHAR *)lParam + 1;
990 len = lstrlenW((LPCWSTR)lParam) + 64;
991
992 cmdW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
993
994 memcpy(cmdW, (void *)lParam, pos * sizeof(WCHAR));
995 wsprintfW(cmdW + pos, formatW, mwi->alias);
996 strcatW(cmdW, (WCHAR *)lParam + pos);
997 }
998 else
999 cmdW = (LPWSTR)lParam;
1000
1001 mwi->lasterror = mciSendStringW(cmdW, mwi->return_string,
1002 sizeof(mwi->return_string)/sizeof(mwi->return_string[0]),
1003 0);
1004 if (mwi->lasterror)
1005 MCIWND_notify_error(mwi);
1006
1007 if (cmdW != (LPWSTR)lParam)
1008 HeapFree(GetProcessHeap(), 0, cmdW);
1009
1010 if (wMsg == MCIWNDM_SENDSTRINGA)
1011 HeapFree(GetProcessHeap(), 0, (void *)lParam);
1012
1013 MCIWND_UpdateState(mwi);
1014 return mwi->lasterror;
1015 }
1016
1017 case MCIWNDM_RETURNSTRINGA:
1018 WideCharToMultiByte(CP_ACP, 0, mwi->return_string, -1, (LPSTR)lParam, wParam, NULL, NULL);
1019 TRACE("MCIWNDM_RETURNTRINGA %s\n", debugstr_an((LPSTR)lParam, wParam));
1020 return mwi->lasterror;
1021
1022 case MCIWNDM_RETURNSTRINGW:
1023 lstrcpynW((LPWSTR)lParam, mwi->return_string, wParam);
1024 TRACE("MCIWNDM_RETURNTRINGW %s\n", debugstr_wn((LPWSTR)lParam, wParam));
1025 return mwi->lasterror;
1026
1027 case MCIWNDM_SETTIMERS:
1028 TRACE("MCIWNDM_SETTIMERS active %d ms, inactive %d ms\n", (int)wParam, (int)lParam);
1029 mwi->active_timer = (WORD)wParam;
1030 mwi->inactive_timer = (WORD)lParam;
1031 return 0;
1032
1033 case MCIWNDM_SETACTIVETIMER:
1034 TRACE("MCIWNDM_SETACTIVETIMER %d ms\n", (int)wParam);
1035 mwi->active_timer = (WORD)wParam;
1036 return 0;
1037
1038 case MCIWNDM_SETINACTIVETIMER:
1039 TRACE("MCIWNDM_SETINACTIVETIMER %d ms\n", (int)wParam);
1040 mwi->inactive_timer = (WORD)wParam;
1041 return 0;
1042
1043 case MCIWNDM_GETACTIVETIMER:
1044 TRACE("MCIWNDM_GETACTIVETIMER: %d ms\n", mwi->active_timer);
1045 return mwi->active_timer;
1046
1047 case MCIWNDM_GETINACTIVETIMER:
1048 TRACE("MCIWNDM_GETINACTIVETIMER: %d ms\n", mwi->inactive_timer);
1049 return mwi->inactive_timer;
1050
1051 case MCIWNDM_CHANGESTYLES:
1052 TRACE("MCIWNDM_CHANGESTYLES mask %08lx, set %08lx\n", wParam, lParam);
1053 /* FIXME: update the visual window state as well:
1054 * add/remove trackbar, autosize, etc.
1055 */
1056 mwi->dwStyle &= ~wParam;
1057 mwi->dwStyle |= lParam & wParam;
1058 return 0;
1059
1060 case MCIWNDM_GETSTYLES:
1061 TRACE("MCIWNDM_GETSTYLES: %08x\n", mwi->dwStyle & 0xffff);
1062 return mwi->dwStyle & 0xffff;
1063
1064 case MCIWNDM_GETDEVICEA:
1065 {
1066 MCI_SYSINFO_PARMSA mci_sysinfo;
1067
1068 mci_sysinfo.lpstrReturn = (LPSTR)lParam;
1069 mci_sysinfo.dwRetSize = wParam;
1070 mwi->lasterror = mciSendCommandA(mwi->mci, MCI_SYSINFO,
1071 MCI_SYSINFO_INSTALLNAME,
1072 (DWORD_PTR)&mci_sysinfo);
1073 TRACE("MCIWNDM_GETDEVICEA: %s\n", debugstr_an((LPSTR)lParam, wParam));
1074 return 0;
1075 }
1076
1077 case MCIWNDM_GETDEVICEW:
1078 {
1079 MCI_SYSINFO_PARMSW mci_sysinfo;
1080
1081 mci_sysinfo.lpstrReturn = (LPWSTR)lParam;
1082 mci_sysinfo.dwRetSize = wParam;
1083 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_SYSINFO,
1084 MCI_SYSINFO_INSTALLNAME,
1085 (DWORD_PTR)&mci_sysinfo);
1086 TRACE("MCIWNDM_GETDEVICEW: %s\n", debugstr_wn((LPWSTR)lParam, wParam));
1087 return 0;
1088 }
1089
1090 case MCIWNDM_VALIDATEMEDIA:
1091 TRACE("MCIWNDM_VALIDATEMEDIA\n");
1092 if (mwi->mci)
1093 {
1094 SendMessageW(hWnd, MCIWNDM_GETSTART, 0, 0);
1095 SendMessageW(hWnd, MCIWNDM_GETLENGTH, 0, 0);
1096 }
1097 return 0;
1098
1099 case MCIWNDM_GETFILENAMEA:
1100 TRACE("MCIWNDM_GETFILENAMEA: %s\n", debugstr_w(mwi->lpName));
1101 if (mwi->lpName)
1102 WideCharToMultiByte(CP_ACP, 0, mwi->lpName, -1, (LPSTR)lParam, wParam, NULL, NULL);
1103 return 0;
1104
1105 case MCIWNDM_GETFILENAMEW:
1106 TRACE("MCIWNDM_GETFILENAMEW: %s\n", debugstr_w(mwi->lpName));
1107 if (mwi->lpName)
1108 lstrcpynW((LPWSTR)lParam, mwi->lpName, wParam);
1109 return 0;
1110
1111 case MCIWNDM_GETTIMEFORMATA:
1112 case MCIWNDM_GETTIMEFORMATW:
1113 {
1114 MCI_STATUS_PARMS mci_status;
1115
1116 TRACE("MCIWNDM_GETTIMEFORMAT %08lx %08lx\n", wParam, lParam);
1117
1118 /* get format string if requested */
1119 if (wParam && lParam)
1120 {
1121 if (wMsg == MCIWNDM_GETTIMEFORMATA)
1122 {
1123 char cmd[64];
1124
1125 wsprintfA(cmd, "status %d time format", mwi->alias);
1126 mwi->lasterror = mciSendStringA(cmd, (LPSTR)lParam, wParam, 0);
1127 if (mwi->lasterror)
1128 return 0;
1129 }
1130 else
1131 {
1132 WCHAR cmdW[64];
1133 static const WCHAR formatW[] = {'s','t','a','t','u','s',' ','%','d',' ','t','i','m','e',' ','f','o','r','m','a','t',0};
1134
1135 wsprintfW(cmdW, formatW, mwi->alias);
1136 mwi->lasterror = mciSendStringW(cmdW, (LPWSTR)lParam, wParam, 0);
1137 if (mwi->lasterror)
1138 return 0;
1139 }
1140 }
1141
1142 mci_status.dwItem = MCI_STATUS_TIME_FORMAT ;
1143 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STATUS,
1144 MCI_STATUS_ITEM,
1145 (DWORD_PTR)&mci_status);
1146 if (mwi->lasterror)
1147 return 0;
1148
1149 return mci_status.dwReturn;
1150 }
1151
1152 case MCIWNDM_SETTIMEFORMATA:
1153 {
1154 UNICODE_STRING stringW;
1155
1156 TRACE("MCIWNDM_SETTIMEFORMATA %s\n", debugstr_a((LPSTR)lParam));
1157
1158 RtlCreateUnicodeStringFromAsciiz(&stringW, (LPCSTR)lParam);
1159 lParam = (LPARAM)stringW.Buffer;
1160 }
1161 /* fall through */
1162 case MCIWNDM_SETTIMEFORMATW:
1163 {
1164 static const WCHAR formatW[] = {'s','e','t',' ','%','d',' ','t','i','m','e',' ','f','o','r','m','a','t',' ',0};
1165 WCHAR *cmdW;
1166
1167 TRACE("MCIWNDM_SETTIMEFORMATW %s\n", debugstr_w((LPWSTR)lParam));
1168
1169 if (mwi->mci)
1170 {
1171 cmdW = HeapAlloc(GetProcessHeap(), 0, (lstrlenW((LPCWSTR)lParam) + 64) * sizeof(WCHAR));
1172 wsprintfW(cmdW, formatW, mwi->alias);
1173 strcatW(cmdW, (WCHAR *)lParam);
1174
1175 mwi->lasterror = mciSendStringW(cmdW, NULL, 0, 0);
1176
1177 /* fix the range tracking according to the new time format */
1178 if (!mwi->lasterror)
1179 SendDlgItemMessageW(hWnd, CTL_TRACKBAR, TBM_SETRANGEMAX, 1,
1180 SendMessageW(hWnd, MCIWNDM_GETLENGTH, 0, 0));
1181
1182 HeapFree(GetProcessHeap(), 0, cmdW);
1183 }
1184
1185 if (wMsg == MCIWNDM_SETTIMEFORMATA)
1186 HeapFree(GetProcessHeap(), 0, (void *)lParam);
1187
1188 return 0;
1189 }
1190
1191 case MCIWNDM_CAN_PLAY:
1192 TRACE("MCIWNDM_CAN_PLAY\n");
1193 if (mwi->mci)
1194 return mci_get_devcaps(mwi, MCI_GETDEVCAPS_CAN_PLAY);
1195 return 0;
1196
1197 case MCIWNDM_CAN_RECORD:
1198 TRACE("MCIWNDM_CAN_RECORD\n");
1199 if (mwi->mci)
1200 return mci_get_devcaps(mwi, MCI_GETDEVCAPS_CAN_RECORD);
1201 return 0;
1202
1203 case MCIWNDM_CAN_SAVE:
1204 TRACE("MCIWNDM_CAN_SAVE\n");
1205 if (mwi->mci)
1206 return mci_get_devcaps(mwi, MCI_GETDEVCAPS_CAN_SAVE);
1207 return 0;
1208
1209 case MCIWNDM_CAN_EJECT:
1210 TRACE("MCIWNDM_CAN_EJECT\n");
1211 if (mwi->mci)
1212 return mci_get_devcaps(mwi, MCI_GETDEVCAPS_CAN_EJECT);
1213 return 0;
1214
1215 case MCIWNDM_CAN_WINDOW:
1216 TRACE("MCIWNDM_CAN_WINDOW\n");
1217 switch (mwi->dev_type)
1218 {
1219 case MCI_DEVTYPE_ANIMATION:
1220 case MCI_DEVTYPE_DIGITAL_VIDEO:
1221 case MCI_DEVTYPE_OVERLAY:
1222 return 1;
1223 }
1224 return 0;
1225
1226 case MCIWNDM_CAN_CONFIG:
1227 TRACE("MCIWNDM_CAN_CONFIG\n");
1228 if (mwi->hdrv)
1229 return SendDriverMessage(mwi->hdrv, DRV_QUERYCONFIGURE, 0, 0);
1230 return 0;
1231
1232 case MCIWNDM_SETZOOM:
1233 TRACE("MCIWNDM_SETZOOM %ld\n", lParam);
1234 mwi->zoom = lParam;
1235
1236 if (mwi->mci && !(mwi->dwStyle & MCIWNDF_NOAUTOSIZEWINDOW))
1237 {
1238 RECT rc;
1239
1240 rc.left = rc.top = 0;
1241 rc.right = MulDiv(mwi->size.cx, mwi->zoom, 100);
1242 rc.bottom = MulDiv(mwi->size.cy, mwi->zoom, 100);
1243
1244 if (!(mwi->dwStyle & MCIWNDF_NOPLAYBAR))
1245 rc.bottom += 32; /* add the height of the playbar */
1246 AdjustWindowRect(&rc, GetWindowLongW(hWnd, GWL_STYLE), FALSE);
1247 SetWindowPos(hWnd, 0, 0, 0, rc.right - rc.left, rc.bottom - rc.top,
1248 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
1249 }
1250 return 0;
1251
1252 case MCIWNDM_GETZOOM:
1253 TRACE("MCIWNDM_GETZOOM: %d\n", mwi->zoom);
1254 return mwi->zoom;
1255
1256 case MCIWNDM_EJECT:
1257 {
1258 MCI_SET_PARMS mci_set;
1259
1260 TRACE("MCIWNDM_EJECT\n");
1261
1262 mci_set.dwCallback = (DWORD_PTR)hWnd;
1263 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_SET,
1264 MCI_SET_DOOR_OPEN | MCI_NOTIFY,
1265 (DWORD_PTR)&mci_set);
1266 MCIWND_notify_mode(mwi);
1267 MCIWND_UpdateState(mwi);
1268 return mwi->lasterror;
1269 }
1270
1271 case MCIWNDM_SETVOLUME:
1272 case MCIWNDM_GETVOLUME:
1273 case MCIWNDM_SETSPEED:
1274 case MCIWNDM_GETSPEED:
1275 case MCIWNDM_SETREPEAT:
1276 case MCIWNDM_GETREPEAT:
1277 case MCIWNDM_REALIZE:
1278 case MCIWNDM_GETPALETTE:
1279 case MCIWNDM_SETPALETTE:
1280 case MCIWNDM_NEWA:
1281 case MCIWNDM_NEWW:
1282 case MCIWNDM_PALETTEKICK:
1283 case MCIWNDM_OPENINTERFACE:
1284 FIXME("support for MCIWNDM_ message WM_USER+%d not implemented\n", wMsg - WM_USER);
1285 return 0;
1286
1287 case MCI_PLAY:
1288 {
1289 LRESULT end = SendMessageW(hWnd, MCIWNDM_GETEND, 0, 0);
1290 return SendMessageW(hWnd, MCIWNDM_PLAYTO, 0, end);
1291 }
1292
1293 case MCI_SEEK:
1294 case MCI_STEP:
1295 {
1296 MCI_SEEK_PARMS mci_seek; /* Layout is usable as MCI_XYZ_STEP_PARMS */
1297 DWORD flags = MCI_STEP == wMsg ? 0 :
1298 MCIWND_START == lParam ? MCI_SEEK_TO_START :
1299 MCIWND_END == lParam ? MCI_SEEK_TO_END : MCI_TO;
1300
1301 mci_seek.dwTo = lParam;
1302 mwi->lasterror = mciSendCommandW(mwi->mci, wMsg,
1303 flags, (DWORD_PTR)&mci_seek);
1304 if (mwi->lasterror)
1305 {
1306 MCIWND_notify_error(mwi);
1307 return mwi->lasterror;
1308 }
1309 /* update window to reflect the state */
1310 else InvalidateRect(hWnd, NULL, TRUE);
1311 return 0;
1312 }
1313
1314 case MCI_CLOSE:
1315 {
1316 RECT rc;
1317 MCI_GENERIC_PARMS mci_generic;
1318
1319 if (mwi->hdrv)
1320 {
1321 CloseDriver(mwi->hdrv, 0, 0);
1322 mwi->hdrv = 0;
1323 }
1324
1325 if (mwi->mci)
1326 {
1327 mci_generic.dwCallback = 0;
1328 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_CLOSE,
1329 0, (DWORD_PTR)&mci_generic);
1330 mwi->mci = 0;
1331 }
1332
1333 mwi->mode = MCI_MODE_NOT_READY;
1334 mwi->position = -1;
1335
1336 HeapFree(GetProcessHeap(), 0, mwi->lpName);
1337 mwi->lpName = NULL;
1338 MCIWND_UpdateState(mwi);
1339
1340 GetClientRect(hWnd, &rc);
1341 rc.bottom = rc.top;
1342 if (!(mwi->dwStyle & MCIWNDF_NOPLAYBAR))
1343 rc.bottom += 32; /* add the height of the playbar */
1344 AdjustWindowRect(&rc, GetWindowLongW(hWnd, GWL_STYLE), FALSE);
1345 SetWindowPos(hWnd, 0, 0, 0, rc.right - rc.left,
1346 rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
1347
1348 MCIWND_notify_media(mwi);
1349 return 0;
1350 }
1351
1352 case MCI_PAUSE:
1353 case MCI_STOP:
1354 case MCI_RESUME:
1355 mci_generic_command(mwi, wMsg);
1356 return mwi->lasterror;
1357
1358 case MCI_CONFIGURE:
1359 if (mwi->hdrv)
1360 SendDriverMessage(mwi->hdrv, DRV_CONFIGURE, (LPARAM)hWnd, 0);
1361 return 0;
1362
1363 case MCI_BREAK:
1364 case MCI_CAPTURE:
1365 case MCI_COPY:
1366 case MCI_CUE:
1367 case MCI_CUT:
1368 case MCI_DELETE:
1369 case MCI_ESCAPE:
1370 case MCI_FREEZE:
1371 case MCI_GETDEVCAPS:
1372 /*case MCI_INDEX:*/
1373 case MCI_INFO:
1374 case MCI_LIST:
1375 case MCI_LOAD:
1376 /*case MCI_MARK:*/
1377 case MCI_MONITOR:
1378 case MCI_OPEN:
1379 case MCI_PASTE:
1380 case MCI_PUT:
1381 case MCI_QUALITY:
1382 case MCI_REALIZE:
1383 case MCI_RECORD:
1384 case MCI_RESERVE:
1385 case MCI_RESTORE:
1386 case MCI_SAVE:
1387 case MCI_SET:
1388 case MCI_SETAUDIO:
1389 /*case MCI_SETTIMECODE:*/
1390 /*case MCI_SETTUNER:*/
1391 case MCI_SETVIDEO:
1392 case MCI_SIGNAL:
1393 case MCI_SPIN:
1394 case MCI_STATUS:
1395 case MCI_SYSINFO:
1396 case MCI_UNDO:
1397 case MCI_UNFREEZE:
1398 case MCI_UPDATE:
1399 case MCI_WHERE:
1400 case MCI_WINDOW:
1401 FIXME("support for MCI_ command %04x not implemented\n", wMsg);
1402 return 0;
1403 }
1404
1405 if (wMsg >= WM_USER)
1406 {
1407 FIXME("support for MCIWNDM_ message WM_USER+%d not implemented\n", wMsg - WM_USER);
1408 return 0;
1409 }
1410
1411 if (GetWindowLongW(hWnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
1412 return DefMDIChildProcW(hWnd, wMsg, wParam, lParam);
1413
1414 return DefWindowProcW(hWnd, wMsg, wParam, lParam);
1415 }