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