xref: /reactos/dll/win32/msvfw32/mciwnd.c (revision c2c66aff)
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, (LPWSTR)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             int len = 0;
1067             char *str = (char *)lParam;
1068             MCI_SYSINFO_PARMSA mci_sysinfo;
1069 
1070             mci_sysinfo.lpstrReturn = str;
1071             mci_sysinfo.dwRetSize = wParam;
1072             mwi->lasterror = mciSendCommandA(mwi->mci, MCI_SYSINFO,
1073                                              MCI_SYSINFO_INSTALLNAME,
1074                                              (DWORD_PTR)&mci_sysinfo);
1075             while(len < wParam && str[len]) len++;
1076             TRACE("MCIWNDM_GETDEVICEA: %s\n", debugstr_an(str, len));
1077             return 0;
1078         }
1079 
1080     case MCIWNDM_GETDEVICEW:
1081         {
1082             int len = 0;
1083             WCHAR *str = (WCHAR *)lParam;
1084             MCI_SYSINFO_PARMSW mci_sysinfo;
1085 
1086             mci_sysinfo.lpstrReturn = str;
1087             mci_sysinfo.dwRetSize = wParam;
1088             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_SYSINFO,
1089                                              MCI_SYSINFO_INSTALLNAME,
1090                                              (DWORD_PTR)&mci_sysinfo);
1091             while(len < wParam && str[len]) len++;
1092             TRACE("MCIWNDM_GETDEVICEW: %s\n", debugstr_wn(str, len));
1093             return 0;
1094         }
1095 
1096     case MCIWNDM_VALIDATEMEDIA:
1097         TRACE("MCIWNDM_VALIDATEMEDIA\n");
1098         if (mwi->mci)
1099         {
1100             SendMessageW(hWnd, MCIWNDM_GETSTART, 0, 0);
1101             SendMessageW(hWnd, MCIWNDM_GETLENGTH, 0, 0);
1102         }
1103         return 0;
1104 
1105     case MCIWNDM_GETFILENAMEA:
1106         TRACE("MCIWNDM_GETFILENAMEA: %s\n", debugstr_w(mwi->lpName));
1107         if (mwi->lpName)
1108             WideCharToMultiByte(CP_ACP, 0, mwi->lpName, -1, (LPSTR)lParam, wParam, NULL, NULL);
1109         return 0;
1110 
1111     case MCIWNDM_GETFILENAMEW:
1112         TRACE("MCIWNDM_GETFILENAMEW: %s\n", debugstr_w(mwi->lpName));
1113         if (mwi->lpName)
1114             lstrcpynW((LPWSTR)lParam, mwi->lpName, wParam);
1115         return 0;
1116 
1117     case MCIWNDM_GETTIMEFORMATA:
1118     case MCIWNDM_GETTIMEFORMATW:
1119         {
1120             MCI_STATUS_PARMS mci_status;
1121 
1122             TRACE("MCIWNDM_GETTIMEFORMAT %08lx %08lx\n", wParam, lParam);
1123 
1124             /* get format string if requested */
1125             if (wParam && lParam)
1126             {
1127                 if (wMsg == MCIWNDM_GETTIMEFORMATA)
1128                 {
1129                     char cmd[64];
1130 
1131                     wsprintfA(cmd, "status %d time format", mwi->alias);
1132                     mwi->lasterror = mciSendStringA(cmd, (LPSTR)lParam, wParam, 0);
1133                     if (mwi->lasterror)
1134                         return 0;
1135                 }
1136                 else
1137                 {
1138                     WCHAR cmdW[64];
1139                     static const WCHAR formatW[] = {'s','t','a','t','u','s',' ','%','d',' ','t','i','m','e',' ','f','o','r','m','a','t',0};
1140 
1141                     wsprintfW(cmdW, formatW, mwi->alias);
1142                     mwi->lasterror = mciSendStringW(cmdW, (LPWSTR)lParam, wParam, 0);
1143                     if (mwi->lasterror)
1144                         return 0;
1145                 }
1146             }
1147 
1148             mci_status.dwItem = MCI_STATUS_TIME_FORMAT ;
1149             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STATUS,
1150                                              MCI_STATUS_ITEM,
1151                                              (DWORD_PTR)&mci_status);
1152             if (mwi->lasterror)
1153                 return 0;
1154 
1155             return mci_status.dwReturn;
1156         }
1157 
1158     case MCIWNDM_SETTIMEFORMATA:
1159         {
1160             UNICODE_STRING stringW;
1161 
1162             TRACE("MCIWNDM_SETTIMEFORMATA %s\n", debugstr_a((LPSTR)lParam));
1163 
1164             RtlCreateUnicodeStringFromAsciiz(&stringW, (LPCSTR)lParam);
1165             lParam = (LPARAM)stringW.Buffer;
1166         }
1167         /* fall through */
1168     case MCIWNDM_SETTIMEFORMATW:
1169         {
1170             static const WCHAR formatW[] = {'s','e','t',' ','%','d',' ','t','i','m','e',' ','f','o','r','m','a','t',' ',0};
1171             WCHAR *cmdW;
1172 
1173             TRACE("MCIWNDM_SETTIMEFORMATW %s\n", debugstr_w((LPWSTR)lParam));
1174 
1175             if (mwi->mci)
1176             {
1177                 cmdW = HeapAlloc(GetProcessHeap(), 0, (lstrlenW((LPCWSTR)lParam) + 64) * sizeof(WCHAR));
1178                 wsprintfW(cmdW, formatW, mwi->alias);
1179                 strcatW(cmdW, (WCHAR *)lParam);
1180 
1181                 mwi->lasterror = mciSendStringW(cmdW, NULL, 0, 0);
1182 
1183                 /* fix the range tracking according to the new time format */
1184                 if (!mwi->lasterror)
1185                     SendDlgItemMessageW(hWnd, CTL_TRACKBAR, TBM_SETRANGEMAX, 1,
1186                                         SendMessageW(hWnd, MCIWNDM_GETLENGTH, 0, 0));
1187 
1188                 HeapFree(GetProcessHeap(), 0, cmdW);
1189             }
1190 
1191             if (wMsg == MCIWNDM_SETTIMEFORMATA)
1192                 HeapFree(GetProcessHeap(), 0, (void *)lParam);
1193 
1194             return 0;
1195         }
1196 
1197     case MCIWNDM_CAN_PLAY:
1198         TRACE("MCIWNDM_CAN_PLAY\n");
1199         if (mwi->mci)
1200             return mci_get_devcaps(mwi, MCI_GETDEVCAPS_CAN_PLAY);
1201         return 0;
1202 
1203     case MCIWNDM_CAN_RECORD:
1204         TRACE("MCIWNDM_CAN_RECORD\n");
1205         if (mwi->mci)
1206             return mci_get_devcaps(mwi, MCI_GETDEVCAPS_CAN_RECORD);
1207         return 0;
1208 
1209     case MCIWNDM_CAN_SAVE:
1210         TRACE("MCIWNDM_CAN_SAVE\n");
1211         if (mwi->mci)
1212             return mci_get_devcaps(mwi, MCI_GETDEVCAPS_CAN_SAVE);
1213         return 0;
1214 
1215     case MCIWNDM_CAN_EJECT:
1216         TRACE("MCIWNDM_CAN_EJECT\n");
1217         if (mwi->mci)
1218             return mci_get_devcaps(mwi, MCI_GETDEVCAPS_CAN_EJECT);
1219         return 0;
1220 
1221     case MCIWNDM_CAN_WINDOW:
1222         TRACE("MCIWNDM_CAN_WINDOW\n");
1223         switch (mwi->dev_type)
1224         {
1225         case MCI_DEVTYPE_ANIMATION:
1226         case MCI_DEVTYPE_DIGITAL_VIDEO:
1227         case MCI_DEVTYPE_OVERLAY:
1228             return 1;
1229         }
1230         return 0;
1231 
1232     case MCIWNDM_CAN_CONFIG:
1233         TRACE("MCIWNDM_CAN_CONFIG\n");
1234         if (mwi->hdrv)
1235             return SendDriverMessage(mwi->hdrv, DRV_QUERYCONFIGURE, 0, 0);
1236         return 0;
1237 
1238     case MCIWNDM_SETZOOM:
1239         TRACE("MCIWNDM_SETZOOM %ld\n", lParam);
1240         mwi->zoom = lParam;
1241 
1242         if (mwi->mci && !(mwi->dwStyle & MCIWNDF_NOAUTOSIZEWINDOW))
1243         {
1244             RECT rc;
1245 
1246             rc.left = rc.top = 0;
1247             rc.right = MulDiv(mwi->size.cx, mwi->zoom, 100);
1248             rc.bottom = MulDiv(mwi->size.cy, mwi->zoom, 100);
1249 
1250             if (!(mwi->dwStyle & MCIWNDF_NOPLAYBAR))
1251                 rc.bottom += 32; /* add the height of the playbar */
1252             AdjustWindowRect(&rc, GetWindowLongW(hWnd, GWL_STYLE), FALSE);
1253             SetWindowPos(hWnd, 0, 0, 0, rc.right - rc.left, rc.bottom - rc.top,
1254                          SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
1255         }
1256         return 0;
1257 
1258     case MCIWNDM_GETZOOM:
1259         TRACE("MCIWNDM_GETZOOM: %d\n", mwi->zoom);
1260         return mwi->zoom;
1261 
1262     case MCIWNDM_EJECT:
1263         {
1264             MCI_SET_PARMS mci_set;
1265 
1266             TRACE("MCIWNDM_EJECT\n");
1267 
1268             mci_set.dwCallback = (DWORD_PTR)hWnd;
1269             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_SET,
1270                                              MCI_SET_DOOR_OPEN | MCI_NOTIFY,
1271                                              (DWORD_PTR)&mci_set);
1272             MCIWND_notify_mode(mwi);
1273             MCIWND_UpdateState(mwi);
1274             return mwi->lasterror;
1275         }
1276 
1277     case MCIWNDM_SETVOLUME:
1278     case MCIWNDM_GETVOLUME:
1279     case MCIWNDM_SETSPEED:
1280     case MCIWNDM_GETSPEED:
1281     case MCIWNDM_SETREPEAT:
1282     case MCIWNDM_GETREPEAT:
1283     case MCIWNDM_REALIZE:
1284     case MCIWNDM_GETPALETTE:
1285     case MCIWNDM_SETPALETTE:
1286     case MCIWNDM_NEWA:
1287     case MCIWNDM_NEWW:
1288     case MCIWNDM_PALETTEKICK:
1289     case MCIWNDM_OPENINTERFACE:
1290         FIXME("support for MCIWNDM_ message WM_USER+%d not implemented\n", wMsg - WM_USER);
1291         return 0;
1292 
1293     case MCI_PLAY:
1294         {
1295             LRESULT end = SendMessageW(hWnd, MCIWNDM_GETEND, 0, 0);
1296             return SendMessageW(hWnd, MCIWNDM_PLAYTO, 0, end);
1297         }
1298 
1299     case MCI_SEEK:
1300     case MCI_STEP:
1301         {
1302             MCI_SEEK_PARMS mci_seek; /* Layout is usable as MCI_XYZ_STEP_PARMS */
1303             DWORD flags = MCI_STEP == wMsg ? 0 :
1304                           MCIWND_START == lParam ? MCI_SEEK_TO_START :
1305                           MCIWND_END   == lParam ? MCI_SEEK_TO_END : MCI_TO;
1306 
1307             mci_seek.dwTo = lParam;
1308             mwi->lasterror = mciSendCommandW(mwi->mci, wMsg,
1309                                              flags, (DWORD_PTR)&mci_seek);
1310             if (mwi->lasterror)
1311             {
1312                 MCIWND_notify_error(mwi);
1313                 return mwi->lasterror;
1314             }
1315             /* update window to reflect the state */
1316             else InvalidateRect(hWnd, NULL, TRUE);
1317             return 0;
1318         }
1319 
1320     case MCI_CLOSE:
1321         {
1322             RECT rc;
1323             MCI_GENERIC_PARMS mci_generic;
1324 
1325             if (mwi->hdrv)
1326             {
1327                 CloseDriver(mwi->hdrv, 0, 0);
1328                 mwi->hdrv = 0;
1329             }
1330 
1331             if (mwi->mci)
1332             {
1333                 mci_generic.dwCallback = 0;
1334                 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_CLOSE,
1335                                                  0, (DWORD_PTR)&mci_generic);
1336                 mwi->mci = 0;
1337             }
1338 
1339             mwi->mode = MCI_MODE_NOT_READY;
1340             mwi->position = -1;
1341 
1342             HeapFree(GetProcessHeap(), 0, mwi->lpName);
1343             mwi->lpName = NULL;
1344             MCIWND_UpdateState(mwi);
1345 
1346             GetClientRect(hWnd, &rc);
1347             rc.bottom = rc.top;
1348             if (!(mwi->dwStyle & MCIWNDF_NOPLAYBAR))
1349                 rc.bottom += 32; /* add the height of the playbar */
1350             AdjustWindowRect(&rc, GetWindowLongW(hWnd, GWL_STYLE), FALSE);
1351             SetWindowPos(hWnd, 0, 0, 0, rc.right - rc.left,
1352                          rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
1353 
1354             MCIWND_notify_media(mwi);
1355             return 0;
1356         }
1357 
1358     case MCI_PAUSE:
1359     case MCI_STOP:
1360     case MCI_RESUME:
1361         mci_generic_command(mwi, wMsg);
1362         return mwi->lasterror;
1363 
1364     case MCI_CONFIGURE:
1365         if (mwi->hdrv)
1366             SendDriverMessage(mwi->hdrv, DRV_CONFIGURE, (LPARAM)hWnd, 0);
1367         return 0;
1368 
1369     case MCI_BREAK:
1370     case MCI_CAPTURE:
1371     case MCI_COPY:
1372     case MCI_CUE:
1373     case MCI_CUT:
1374     case MCI_DELETE:
1375     case MCI_ESCAPE:
1376     case MCI_FREEZE:
1377     case MCI_GETDEVCAPS:
1378     /*case MCI_INDEX:*/
1379     case MCI_INFO:
1380     case MCI_LIST:
1381     case MCI_LOAD:
1382     /*case MCI_MARK:*/
1383     case MCI_MONITOR:
1384     case MCI_OPEN:
1385     case MCI_PASTE:
1386     case MCI_PUT:
1387     case MCI_QUALITY:
1388     case MCI_REALIZE:
1389     case MCI_RECORD:
1390     case MCI_RESERVE:
1391     case MCI_RESTORE:
1392     case MCI_SAVE:
1393     case MCI_SET:
1394     case MCI_SETAUDIO:
1395     /*case MCI_SETTIMECODE:*/
1396     /*case MCI_SETTUNER:*/
1397     case MCI_SETVIDEO:
1398     case MCI_SIGNAL:
1399     case MCI_SPIN:
1400     case MCI_STATUS:
1401     case MCI_SYSINFO:
1402     case MCI_UNDO:
1403     case MCI_UNFREEZE:
1404     case MCI_UPDATE:
1405     case MCI_WHERE:
1406     case MCI_WINDOW:
1407         FIXME("support for MCI_ command %04x not implemented\n", wMsg);
1408         return 0;
1409     }
1410 
1411     if (wMsg >= WM_USER)
1412     {
1413         FIXME("support for MCIWNDM_ message WM_USER+%d not implemented\n", wMsg - WM_USER);
1414         return 0;
1415     }
1416 
1417     if (GetWindowLongW(hWnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
1418         return DefMDIChildProcW(hWnd, wMsg, wParam, lParam);
1419 
1420     return DefWindowProcW(hWnd, wMsg, wParam, lParam);
1421 }
1422