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