- fix broadcast address for name lookups after iphlpapi change
[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 all MCIWNDF_ flags.
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 (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  */
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
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
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
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
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
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_SHOWNAME) && mwi->lpName)
199         strcpyW(buffer, mwi->lpName);
200     else
201         *buffer = 0;
202
203     if (mwi->dwStyle & (MCIWNDF_SHOWPOS|MCIWNDF_SHOWMODE))
204     {
205         static const WCHAR spaceW[] = {' ',0};
206         static const WCHAR l_braceW[] = {'(',0};
207
208         if (*buffer) strcatW(buffer, spaceW);
209         strcatW(buffer, l_braceW);
210     }
211
212     if (mwi->dwStyle & MCIWNDF_SHOWPOS)
213     {
214         WCHAR posW[64];
215
216         posW[0] = 0;
217         SendMessageW(mwi->hWnd, MCIWNDM_GETPOSITIONW, 64, (LPARAM)posW);
218         strcatW(buffer, posW);
219     }
220
221     if ((mwi->dwStyle & (MCIWNDF_SHOWPOS|MCIWNDF_SHOWMODE)) == (MCIWNDF_SHOWPOS|MCIWNDF_SHOWMODE))
222     {
223         static const WCHAR dashW[] = {' ','-',' ',0};
224         strcatW(buffer, dashW);
225     }
226
227     if (mwi->dwStyle & MCIWNDF_SHOWMODE)
228     {
229         WCHAR modeW[64];
230
231         modeW[0] = 0;
232         SendMessageW(mwi->hWnd, MCIWNDM_GETMODEW, 64, (LPARAM)modeW);
233         strcatW(buffer, modeW);
234     }
235
236     if (mwi->dwStyle & (MCIWNDF_SHOWPOS|MCIWNDF_SHOWMODE))
237     {
238         static const WCHAR r_braceW[] = {')',0};
239         strcatW(buffer, r_braceW);
240     }
241
242     TRACE("=> '%s'\n", debugstr_w(buffer));
243     SetWindowTextW(mwi->hWnd, buffer);
244 }
245
246 static LRESULT MCIWND_Create(HWND hWnd, LPCREATESTRUCTW cs)
247 {
248     HWND hChld;
249     MCIWndInfo *mwi;
250     static const WCHAR buttonW[] = {'b','u','t','t','o','n',0};
251
252     mwi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*mwi));
253     if (!mwi) return -1;
254
255     SetWindowLongW(hWnd, 0, (LPARAM)mwi);
256
257     mwi->dwStyle = cs->style;
258     mwi->hWnd = hWnd;
259     mwi->hwndOwner = cs->hwndParent;
260     mwi->active_timer = 500;
261     mwi->inactive_timer = 2000;
262     mwi->mode = MCI_MODE_NOT_READY;
263     mwi->position = -1;
264     mwi->zoom = 100;
265
266     if (!(mwi->dwStyle & MCIWNDF_NOMENU))
267     {
268         static const WCHAR menuW[] = {'M','e','n','u',0};
269
270         hChld = CreateWindowExW(0, buttonW, menuW, WS_CHILD|WS_VISIBLE, 32, cs->cy, 32, 32,
271                                 hWnd, (HMENU)CTL_MENU, cs->hInstance, 0L);
272         TRACE("Get Button2: %p\n", hChld);
273     }
274
275     if (!(mwi->dwStyle & MCIWNDF_NOPLAYBAR))
276     {
277         INITCOMMONCONTROLSEX init;
278         static const WCHAR playW[] = {'P','l','a','y',0};
279
280         /* adding the other elements: play/stop button, menu button, status */
281         hChld = CreateWindowExW(0, buttonW, playW, WS_CHILD|WS_VISIBLE, 0, cs->cy, 32, 32,
282                                 hWnd, (HMENU)CTL_PLAYSTOP, cs->hInstance, 0L);
283         TRACE("Get Button1: %p\n", hChld);
284
285         init.dwSize = sizeof(init);
286         init.dwICC = ICC_BAR_CLASSES;
287         InitCommonControlsEx(&init);
288
289         hChld = CreateWindowExW(0, TRACKBAR_CLASSW, NULL, WS_CHILD|WS_VISIBLE, 64, cs->cy, cs->cx - 64, 32,
290                                 hWnd, (HMENU)CTL_TRACKBAR, cs->hInstance, 0L);
291         TRACE("Get status: %p\n", hChld);
292     }
293
294     /* This sets the default window size */
295     SendMessageW(hWnd, MCI_CLOSE, 0, 0);
296
297     if (cs->lpCreateParams)
298     {
299         LPARAM lParam;
300
301         /* MCI wnd class is prepared to be embedded as an MDI child window */
302         if (cs->dwExStyle & WS_EX_MDICHILD)
303         {
304             MDICREATESTRUCTW *mdics = (MDICREATESTRUCTW *)cs->lpCreateParams;
305             lParam = mdics->lParam;
306         }
307         else
308             lParam = (LPARAM)cs->lpCreateParams;
309         /* yes, A variant of the message */
310         SendMessageW(hWnd, MCIWNDM_OPENA, 0, lParam);
311     }
312
313     return 0;
314 }
315
316 static void MCIWND_ToggleState(MCIWndInfo *mwi)
317 {
318     switch (SendMessageW(mwi->hWnd, MCIWNDM_GETMODEW, 0, 0))
319     {
320     case MCI_MODE_NOT_READY:
321     case MCI_MODE_RECORD:
322     case MCI_MODE_SEEK:
323     case MCI_MODE_OPEN:
324         TRACE("Cannot do much...\n");
325         break;
326
327     case MCI_MODE_PAUSE:
328         SendMessageW(mwi->hWnd, MCI_RESUME, 0, 0);
329         break;
330
331     case MCI_MODE_PLAY:
332         SendMessageW(mwi->hWnd, MCI_PAUSE, 0, 0);
333         break;
334
335     case MCI_MODE_STOP:
336         SendMessageW(mwi->hWnd, MCI_STOP, 0, 0);
337         break;
338     }
339 }
340
341 static LRESULT MCIWND_Command(MCIWndInfo *mwi, WPARAM wParam, LPARAM lParam)
342 {
343     switch (LOWORD(wParam))
344     {
345     case CTL_PLAYSTOP: MCIWND_ToggleState(mwi); break;
346     case CTL_MENU:
347     case CTL_TRACKBAR:
348     default:
349         FIXME("support for command %04x not implement yet\n", LOWORD(wParam));
350     }
351     return 0L;
352 }
353
354 static void MCIWND_notify_media(MCIWndInfo *mwi)
355 {
356     if (mwi->dwStyle & (MCIWNDF_NOTIFYMEDIAA | MCIWNDF_NOTIFYMEDIAW))
357     {
358         if (!mwi->lpName)
359         {
360             static const WCHAR empty_str[1];
361             SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYMEDIA, (WPARAM)mwi->hWnd, (LPARAM)empty_str);
362         }
363         else
364         {
365             if (mwi->dwStyle & MCIWNDF_NOTIFYANSI)
366             {
367                 char *ansi_name;
368                 int len;
369
370                 len = WideCharToMultiByte(CP_ACP, 0, mwi->lpName, -1, NULL, 0, NULL, NULL);
371                 ansi_name = HeapAlloc(GetProcessHeap(), 0, len);
372                 WideCharToMultiByte(CP_ACP, 0, mwi->lpName, -1, ansi_name, len, NULL, NULL);
373
374                 SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYMEDIA, (WPARAM)mwi->hWnd, (LPARAM)ansi_name);
375
376                 HeapFree(GetProcessHeap(), 0, ansi_name);
377             }
378             else
379                 SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYMEDIA, (WPARAM)mwi->hWnd, (LPARAM)mwi->lpName);
380         }
381     }
382 }
383
384 static MCIERROR mci_generic_command(MCIWndInfo *mwi, UINT cmd)
385 {
386     MCI_GENERIC_PARMS mci_generic;
387
388     mci_generic.dwCallback = 0;
389     mwi->lasterror = mciSendCommandW(mwi->mci, cmd, 0, (DWORD_PTR)&mci_generic);
390
391     if (mwi->lasterror)
392         return mwi->lasterror;
393
394     MCIWND_notify_mode(mwi);
395     MCIWND_UpdateState(mwi);
396     return 0;
397 }
398
399 static LRESULT mci_get_devcaps(MCIWndInfo *mwi, UINT cap)
400 {
401     MCI_GETDEVCAPS_PARMS mci_devcaps;
402
403     mci_devcaps.dwItem = cap;
404     mwi->lasterror = mciSendCommandW(mwi->mci, MCI_GETDEVCAPS,
405                                    MCI_GETDEVCAPS_ITEM,
406                                    (DWORD_PTR)&mci_devcaps);
407     if (mwi->lasterror)
408         return 0;
409
410     return mci_devcaps.dwReturn;
411 }
412
413 static LRESULT WINAPI MCIWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
414 {
415     MCIWndInfo *mwi;
416
417     TRACE("%p %04x %08x %08lx\n", hWnd, wMsg, wParam, lParam);
418
419     mwi = (MCIWndInfo*)GetWindowLongW(hWnd, 0);
420     if (!mwi && wMsg != WM_CREATE)
421         return DefWindowProcW(hWnd, wMsg, wParam, lParam);
422
423     switch (wMsg)
424     {
425     case WM_CREATE:
426         MCIWND_Create(hWnd, (CREATESTRUCTW *)lParam);
427         break;
428
429     case WM_DESTROY:
430         if (mwi->uTimer)
431             KillTimer(hWnd, mwi->uTimer);
432
433         if (mwi->mci)
434             SendMessageW(hWnd, MCI_CLOSE, 0, 0);
435
436         HeapFree(GetProcessHeap(), 0, mwi);
437
438         DestroyWindow(GetDlgItem(hWnd, CTL_MENU));
439         DestroyWindow(GetDlgItem(hWnd, CTL_PLAYSTOP));
440         DestroyWindow(GetDlgItem(hWnd, CTL_TRACKBAR));
441         break;
442
443     case WM_PAINT:
444         {
445             HDC hdc;
446             PAINTSTRUCT ps;
447
448             hdc = (wParam) ? (HDC)wParam : BeginPaint(hWnd, &ps);
449             /* something to do ? */
450             if (!wParam) EndPaint(hWnd, &ps);
451             return 1;
452         }
453
454     case WM_COMMAND:
455         return MCIWND_Command(mwi, wParam, lParam);
456
457     case WM_NCACTIVATE:
458         if (mwi->uTimer)
459         {
460             KillTimer(hWnd, mwi->uTimer);
461             mwi->uTimer = SetTimer(hWnd, 1, wParam ? mwi->active_timer : mwi->inactive_timer, NULL);
462         }
463         break;
464
465     case WM_TIMER:
466         MCIWND_UpdateState(mwi);
467         return 0;
468
469     case WM_SIZE:
470         SetWindowPos(GetDlgItem(hWnd, CTL_PLAYSTOP), 0, 0, HIWORD(lParam) - 32, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
471         SetWindowPos(GetDlgItem(hWnd, CTL_MENU), 0, 32, HIWORD(lParam) - 32, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
472         SetWindowPos(GetDlgItem(hWnd, CTL_TRACKBAR), 0, 64, HIWORD(lParam) - 32, LOWORD(lParam) - 64, 32, SWP_NOACTIVATE);
473
474         MCIWND_notify_size(mwi);
475         break;
476
477     case MM_MCINOTIFY:
478         MCIWND_notify_mode(mwi);
479         MCIWND_UpdateState(mwi);
480         return 0;
481
482     case MCIWNDM_OPENA:
483         {
484             UNICODE_STRING nameW;
485             TRACE("MCIWNDM_OPENA %s\n", debugstr_a((LPSTR)lParam));
486             RtlCreateUnicodeStringFromAsciiz(&nameW, (LPCSTR)lParam);
487             lParam = (LPARAM)nameW.Buffer;
488         }
489         /* fall through */
490     case MCIWNDM_OPENW:
491         {
492             RECT rc;
493             HCURSOR hCursor;
494             MCI_OPEN_PARMSW mci_open;
495             MCI_GETDEVCAPS_PARMS mci_devcaps;
496             WCHAR aliasW[64];
497             WCHAR drv_name[MAX_PATH];
498             static const WCHAR formatW[] = {'%','d',0};
499             static const WCHAR mci32W[] = {'m','c','i','3','2',0};
500             static const WCHAR system_iniW[] = {'s','y','s','t','e','m','.','i','n','i',0};
501
502             TRACE("MCIWNDM_OPENW %s\n", debugstr_w((LPWSTR)lParam));
503
504             if (wParam == MCIWNDOPENF_NEW)
505             {
506                 SendMessageW(hWnd, MCIWNDM_NEWW, 0, lParam);
507                 goto end_of_mci_open;
508             }
509
510             if (mwi->uTimer)
511             {
512                 KillTimer(hWnd, mwi->uTimer);
513                 mwi->uTimer = 0;
514             }
515
516             hCursor = LoadCursorW(0, (LPWSTR)IDC_WAIT);
517             hCursor = SetCursor(hCursor);
518
519             mci_open.lpstrElementName = (LPWSTR)lParam;
520             wsprintfW(aliasW, formatW, (int)hWnd + 1);
521             mci_open.lpstrAlias = aliasW;
522             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_OPEN,
523                                              MCI_OPEN_ELEMENT | MCI_OPEN_ALIAS | MCI_WAIT,
524                                              (DWORD_PTR)&mci_open);
525             SetCursor(hCursor);
526
527             if (mwi->lasterror)
528             {
529                 /* FIXME: get the caption from resources */
530                 static const WCHAR caption[] = {'M','C','I',' ','E','r','r','o','r',0};
531                 WCHAR error_str[MAXERRORLENGTH];
532
533                 mciGetErrorStringW(mwi->lasterror, error_str, MAXERRORLENGTH);
534                 MessageBoxW(hWnd, error_str, caption, MB_ICONEXCLAMATION | MB_OK);
535                 MCIWND_notify_error(mwi);
536                 goto end_of_mci_open;
537             }
538
539             mwi->mci = mci_open.wDeviceID;
540             mwi->alias = (int)hWnd + 1;
541
542             mwi->lpName = HeapAlloc(GetProcessHeap(), 0, (strlenW((LPWSTR)lParam) + 1) * sizeof(WCHAR));
543             strcpyW(mwi->lpName, (LPWSTR)lParam);
544
545             MCIWND_UpdateState(mwi);
546
547             mci_devcaps.dwItem = MCI_GETDEVCAPS_DEVICE_TYPE;
548             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_GETDEVCAPS,
549                                              MCI_GETDEVCAPS_ITEM,
550                                              (DWORD_PTR)&mci_devcaps);
551             if (mwi->lasterror)
552             {
553                 MCIWND_notify_error(mwi);
554                 goto end_of_mci_open;
555             }
556
557             mwi->dev_type = mci_devcaps.dwReturn;
558
559             drv_name[0] = 0;
560             SendMessageW(hWnd, MCIWNDM_GETDEVICEW, 256, (LPARAM)drv_name);
561             if (drv_name[0] && GetPrivateProfileStringW(mci32W, drv_name, NULL,
562                                             drv_name, MAX_PATH, system_iniW))
563                 mwi->hdrv = OpenDriver(drv_name, NULL, 0);
564
565             if (mwi->dev_type == MCI_DEVTYPE_DIGITAL_VIDEO)
566             {
567                 MCI_DGV_WINDOW_PARMSW mci_window;
568
569                 mci_window.hWnd = hWnd;
570                 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_WINDOW,
571                                                  MCI_DGV_WINDOW_HWND,
572                                                  (DWORD_PTR)&mci_window);
573                 if (mwi->lasterror)
574                 {
575                     MCIWND_notify_error(mwi);
576                     goto end_of_mci_open;
577                 }
578             }
579
580             if (SendMessageW(hWnd, MCIWNDM_GET_DEST, 0, (LPARAM)&rc) == 0)
581             {
582                 mwi->size.cx = rc.right - rc.left;
583                 mwi->size.cy = rc.bottom - rc.top;
584
585                 rc.right = MulDiv(mwi->size.cx, mwi->zoom, 100);
586                 rc.bottom = MulDiv(mwi->size.cy, mwi->zoom, 100);
587                 SendMessageW(hWnd, MCIWNDM_PUT_DEST, 0, (LPARAM)&rc);
588             }
589             else
590             {
591                 GetClientRect(hWnd, &rc);
592                 rc.bottom = rc.top;
593             }
594
595             if (!(mwi->dwStyle & MCIWNDF_NOPLAYBAR))
596                 rc.bottom += 32; /* add the height of the playbar */
597             AdjustWindowRect(&rc, GetWindowLongW(hWnd, GWL_STYLE), FALSE);
598             SetWindowPos(hWnd, 0, 0, 0, rc.right - rc.left,
599                          rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
600
601             SendDlgItemMessageW(hWnd, CTL_TRACKBAR, TBM_SETRANGEMIN, 0L, 0L);
602             SendDlgItemMessageW(hWnd, CTL_TRACKBAR, TBM_SETRANGEMAX, 1,
603                                 SendMessageW(hWnd, MCIWNDM_GETLENGTH, 0, 0));
604             mwi->uTimer = SetTimer(hWnd, 1, mwi->active_timer, NULL);
605
606             MCIWND_notify_media(mwi);
607
608 end_of_mci_open:
609             if (wMsg == MCIWNDM_OPENA)
610                 HeapFree(GetProcessHeap(), 0, (void *)lParam);
611             return mwi->lasterror;
612         }
613
614     case MCIWNDM_GETDEVICEID:
615         return mwi->mci;
616
617     case MCIWNDM_GETALIAS:
618         return mwi->alias;
619
620     case MCIWNDM_GET_SOURCE:
621         {
622             MCI_DGV_RECT_PARMS mci_rect;
623
624             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_WHERE,
625                                              MCI_DGV_WHERE_SOURCE,
626                                              (DWORD_PTR)&mci_rect);
627             if (mwi->lasterror)
628             {
629                 MCIWND_notify_error(mwi);
630                 return mwi->lasterror;
631             }
632             *(RECT *)lParam = mci_rect.rc;
633             return 0;
634         }
635
636     case MCIWNDM_GET_DEST:
637         {
638             MCI_DGV_RECT_PARMS mci_rect;
639
640             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_WHERE,
641                                              MCI_DGV_WHERE_DESTINATION,
642                                              (DWORD_PTR)&mci_rect);
643             if (mwi->lasterror)
644             {
645                 MCIWND_notify_error(mwi);
646                 return mwi->lasterror;
647             }
648             *(RECT *)lParam = mci_rect.rc;
649             return 0;
650         }
651
652     case MCIWNDM_PUT_SOURCE:
653         {
654             MCI_DGV_PUT_PARMS mci_put;
655
656             mci_put.rc = *(RECT *)lParam;
657             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_PUT,
658                                              MCI_DGV_PUT_SOURCE,
659                                              (DWORD_PTR)&mci_put);
660             if (mwi->lasterror)
661             {
662                 MCIWND_notify_error(mwi);
663                 return mwi->lasterror;
664             }
665             return 0;
666         }
667
668     case MCIWNDM_PUT_DEST:
669         {
670             MCI_DGV_PUT_PARMS mci_put;
671
672             mci_put.rc = *(RECT *)lParam;
673             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_PUT,
674                                              MCI_DGV_PUT_DESTINATION | MCI_DGV_RECT,
675                                              (DWORD_PTR)&mci_put);
676             if (mwi->lasterror)
677             {
678                 MCIWND_notify_error(mwi);
679                 return mwi->lasterror;
680             }
681             return 0;
682         }
683
684     case MCIWNDM_GETLENGTH:
685         {
686             MCI_STATUS_PARMS mci_status;
687
688             mci_status.dwItem = MCI_STATUS_LENGTH;
689             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STATUS,
690                                              MCI_STATUS_ITEM,
691                                              (DWORD_PTR)&mci_status);
692             if (mwi->lasterror)
693             {
694                 MCIWND_notify_error(mwi);
695                 return 0;
696             }
697             return mci_status.dwReturn;
698         }
699
700     case MCIWNDM_GETSTART:
701         {
702             MCI_STATUS_PARMS mci_status;
703
704             mci_status.dwItem = MCI_STATUS_POSITION;
705             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STATUS,
706                                              MCI_STATUS_ITEM | MCI_STATUS_START,
707                                              (DWORD_PTR)&mci_status);
708             if (mwi->lasterror)
709             {
710                 MCIWND_notify_error(mwi);
711                 return 0;
712             }
713             return mci_status.dwReturn;
714         }
715
716     case MCIWNDM_GETEND:
717         {
718             LRESULT start, length;
719
720             start = SendMessageW(hWnd, MCIWNDM_GETSTART, 0, 0);
721             length = SendMessageW(hWnd, MCIWNDM_GETLENGTH, 0, 0);
722             return (start + length);
723         }
724
725     case MCIWNDM_GETPOSITIONA:
726     case MCIWNDM_GETPOSITIONW:
727         {
728             MCI_STATUS_PARMS mci_status;
729
730             /* get position string if requested */
731             if (wParam && lParam)
732             {
733                 if (wMsg == MCIWNDM_GETPOSITIONA)
734                 {
735                     char cmd[64];
736
737                     wsprintfA(cmd, "status %d position", mwi->alias);
738                     mwi->lasterror = mciSendStringA(cmd, (LPSTR)lParam, wParam, 0);
739                 }
740                 else
741                 {
742
743                     WCHAR cmdW[64];
744                     static const WCHAR formatW[] = {'s','t','a','t','u','s',' ','%','d',' ','p','o','s','i','t','i','o','n',0};
745
746                     wsprintfW(cmdW, formatW, mwi->alias);
747                     mwi->lasterror = mciSendStringW(cmdW, (LPWSTR)lParam, wParam, 0);
748                 }
749
750                 if (mwi->lasterror)
751                     return 0;
752             }
753
754             mci_status.dwItem = MCI_STATUS_POSITION;
755             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STATUS,
756                                              MCI_STATUS_ITEM,
757                                              (DWORD_PTR)&mci_status);
758             if (mwi->lasterror)
759                 return 0;
760
761             return mci_status.dwReturn;
762         }
763
764     case MCIWNDM_GETMODEA:
765     case MCIWNDM_GETMODEW:
766         {
767             MCI_STATUS_PARMS mci_status;
768
769             if (!mwi->mci)
770                 return MCI_MODE_NOT_READY;
771
772             /* get mode string if requested */
773             if (wParam && lParam)
774             {
775                 if (wMsg == MCIWNDM_GETMODEA)
776                 {
777                     char cmd[64];
778
779                     wsprintfA(cmd, "status %d mode", mwi->alias);
780                     mwi->lasterror = mciSendStringA(cmd, (LPSTR)lParam, wParam, 0);
781                 }
782                 else
783                 {
784
785                     WCHAR cmdW[64];
786                     static const WCHAR formatW[] = {'s','t','a','t','u','s',' ','%','d',' ','m','o','d','e',0};
787
788                     wsprintfW(cmdW, formatW, mwi->alias);
789                     mwi->lasterror = mciSendStringW(cmdW, (LPWSTR)lParam, wParam, 0);
790                 }
791
792                 if (mwi->lasterror)
793                     return MCI_MODE_NOT_READY;
794             }
795
796             mci_status.dwItem = MCI_STATUS_MODE;
797             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STATUS,
798                                              MCI_STATUS_ITEM,
799                                              (DWORD_PTR)&mci_status);
800             if (mwi->lasterror)
801                 return MCI_MODE_NOT_READY;
802
803             return mci_status.dwReturn;
804         }
805
806     case MCIWNDM_PLAYFROM:
807         {
808             MCI_PLAY_PARMS mci_play;
809
810             mci_play.dwCallback = (DWORD_PTR)hWnd;
811             mci_play.dwFrom = lParam;
812             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_PLAY,
813                                              MCI_FROM | MCI_NOTIFY,
814                                              (DWORD_PTR)&mci_play);
815             if (mwi->lasterror)
816             {
817                 MCIWND_notify_error(mwi);
818                 return mwi->lasterror;
819             }
820
821             MCIWND_notify_mode(mwi);
822             MCIWND_UpdateState(mwi);
823             return 0;
824         }
825
826     case MCIWNDM_PLAYTO:
827         {
828             MCI_PLAY_PARMS mci_play;
829
830             mci_play.dwCallback = (DWORD_PTR)hWnd;
831             mci_play.dwTo = lParam;
832             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_PLAY,
833                                              MCI_TO | MCI_NOTIFY,
834                                              (DWORD_PTR)&mci_play);
835             if (mwi->lasterror)
836             {
837                 MCIWND_notify_error(mwi);
838                 return mwi->lasterror;
839             }
840
841             MCIWND_notify_mode(mwi);
842             MCIWND_UpdateState(mwi);
843             return 0;
844         }
845
846
847     case MCIWNDM_PLAYREVERSE:
848         {
849             MCI_PLAY_PARMS mci_play;
850             DWORD flags = MCI_NOTIFY;
851
852             mci_play.dwCallback = (DWORD_PTR)hWnd;
853             mci_play.dwFrom = lParam;
854             switch (mwi->dev_type)
855             {
856             default:
857             case MCI_DEVTYPE_ANIMATION:
858                 flags |= MCI_ANIM_PLAY_REVERSE;
859                 break;
860
861             case MCI_DEVTYPE_DIGITAL_VIDEO:
862                 flags |= MCI_DGV_PLAY_REVERSE;
863                 break;
864
865 #ifdef MCI_VCR_PLAY_REVERSE
866             case MCI_DEVTYPE_VCR:
867                 flags |= MCI_VCR_PLAY_REVERSE;
868                 break;
869 #endif
870
871             case MCI_DEVTYPE_VIDEODISC:
872                 flags |= MCI_VD_PLAY_REVERSE;
873                 break;
874
875             }
876             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_PLAY,
877                                              flags, (DWORD_PTR)&mci_play);
878             if (mwi->lasterror)
879             {
880                 MCIWND_notify_error(mwi);
881                 return mwi->lasterror;
882             }
883
884             MCIWND_notify_mode(mwi);
885             MCIWND_UpdateState(mwi);
886             return 0;
887         }
888
889     case MCIWNDM_GETERRORA:
890         mciGetErrorStringA(mwi->lasterror, (LPSTR)lParam, wParam);
891         return mwi->lasterror;
892
893     case MCIWNDM_GETERRORW:
894         mciGetErrorStringW(mwi->lasterror, (LPWSTR)lParam, wParam);
895         return mwi->lasterror;
896
897     case MCIWNDM_SETOWNER:
898         mwi->hwndOwner = (HWND)wParam;
899         return 0;
900
901     case MCIWNDM_SENDSTRINGA:
902         {
903             UNICODE_STRING stringW;
904             RtlCreateUnicodeStringFromAsciiz(&stringW, (LPCSTR)lParam);
905             lParam = (LPARAM)stringW.Buffer;
906         }
907         /* fall through */
908     case MCIWNDM_SENDSTRINGW:
909         {
910             WCHAR *cmdW, *p;
911
912             p = strchrW((LPCWSTR)lParam, ' ');
913             if (p)
914             {
915                 static const WCHAR formatW[] = {'%','d',' ',0};
916                 int len, pos;
917
918                 pos = p - (WCHAR *)lParam + 1;
919                 len = lstrlenW((LPCWSTR)lParam) + 64;
920
921                 cmdW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
922
923                 memcpy(cmdW, (void *)lParam, pos * sizeof(WCHAR));
924                 wsprintfW(cmdW + pos, formatW, mwi->alias);
925                 strcatW(cmdW, (WCHAR *)lParam + pos);
926             }
927             else
928                 cmdW = (LPWSTR)lParam;
929
930             mwi->lasterror = mciSendStringW(cmdW, mwi->return_string,
931                                             sizeof(mwi->return_string)/sizeof(mwi->return_string[0]),
932                                             0);
933             if (mwi->lasterror)
934                 MCIWND_notify_error(mwi);
935
936             if (cmdW != (LPWSTR)lParam)
937                 HeapFree(GetProcessHeap(), 0, cmdW);
938
939             if (wMsg == MCIWNDM_SENDSTRINGA)
940                 HeapFree(GetProcessHeap(), 0, (void *)lParam);
941
942             MCIWND_UpdateState(mwi);
943             return mwi->lasterror;
944         }
945
946     case MCIWNDM_RETURNSTRINGA:
947         WideCharToMultiByte(CP_ACP, 0, mwi->return_string, -1, (LPSTR)lParam, wParam, NULL, NULL);
948         return mwi->lasterror;
949
950     case MCIWNDM_RETURNSTRINGW:
951         strncpyW((LPWSTR)lParam, mwi->return_string, wParam);
952         return mwi->lasterror;
953
954     case MCIWNDM_SETTIMERS:
955         mwi->active_timer = (WORD)wParam;
956         mwi->inactive_timer = (WORD)lParam;
957         return 0;
958
959     case MCIWNDM_SETACTIVETIMER:
960         mwi->active_timer = (WORD)wParam;
961         return 0;
962
963     case MCIWNDM_SETINACTIVETIMER:
964         mwi->inactive_timer = (WORD)wParam;
965         return 0;
966
967     case MCIWNDM_GETACTIVETIMER:
968         return mwi->active_timer;
969
970     case MCIWNDM_GETINACTIVETIMER:
971         return mwi->inactive_timer;
972
973     case MCIWNDM_CHANGESTYLES:
974         /* FIXME: update the visual window state as well:
975          * add/remove trackbar, autosize, etc.
976          */
977         mwi->dwStyle &= ~wParam;
978         mwi->dwStyle |= lParam & wParam;
979         return 0;
980
981     case MCIWNDM_GETSTYLES:
982         return mwi->dwStyle & 0xffff;
983
984     case MCIWNDM_GETDEVICEA:
985         {
986             MCI_SYSINFO_PARMSA mci_sysinfo;
987
988             mci_sysinfo.lpstrReturn = (LPSTR)lParam;
989             mci_sysinfo.dwRetSize = wParam;
990             mwi->lasterror = mciSendCommandA(mwi->mci, MCI_SYSINFO,
991                                              MCI_SYSINFO_INSTALLNAME,
992                                              (DWORD_PTR)&mci_sysinfo);
993             return 0;
994         }
995
996     case MCIWNDM_GETDEVICEW:
997         {
998             MCI_SYSINFO_PARMSW mci_sysinfo;
999
1000             mci_sysinfo.lpstrReturn = (LPWSTR)lParam;
1001             mci_sysinfo.dwRetSize = wParam;
1002             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_SYSINFO,
1003                                              MCI_SYSINFO_INSTALLNAME,
1004                                              (DWORD_PTR)&mci_sysinfo);
1005             return 0;
1006         }
1007
1008     case MCIWNDM_VALIDATEMEDIA:
1009         if (mwi->mci)
1010         {
1011             SendMessageW(hWnd, MCIWNDM_GETSTART, 0, 0);
1012             SendMessageW(hWnd, MCIWNDM_GETLENGTH, 0, 0);
1013         }
1014         return 0;
1015
1016     case MCIWNDM_GETFILENAMEA:
1017         if (mwi->lpName)
1018             WideCharToMultiByte(CP_ACP, 0, mwi->lpName, -1, (LPSTR)lParam, wParam, NULL, NULL);
1019         return 0;
1020
1021     case MCIWNDM_GETFILENAMEW:
1022         if (mwi->lpName)
1023             strncpyW((LPWSTR)lParam, mwi->lpName, wParam);
1024         return 0;
1025
1026     case MCIWNDM_GETTIMEFORMATA:
1027     case MCIWNDM_GETTIMEFORMATW:
1028         {
1029             MCI_STATUS_PARMS mci_status;
1030
1031             /* get format string if requested */
1032             if (wParam && lParam)
1033             {
1034                 if (wMsg == MCIWNDM_GETTIMEFORMATA)
1035                 {
1036                     char cmd[64];
1037
1038                     wsprintfA(cmd, "status %d time format", mwi->alias);
1039                     mwi->lasterror = mciSendStringA(cmd, (LPSTR)lParam, wParam, 0);
1040                     if (mwi->lasterror)
1041                         return 0;
1042                 }
1043                 else
1044                 {
1045                     WCHAR cmdW[64];
1046                     static const WCHAR formatW[] = {'s','t','a','t','u','s',' ','%','d',' ','t','i','m','e',' ','f','o','r','m','a','t',0};
1047
1048                     wsprintfW(cmdW, formatW, mwi->alias);
1049                     mwi->lasterror = mciSendStringW(cmdW, (LPWSTR)lParam, wParam, 0);
1050                     if (mwi->lasterror)
1051                         return 0;
1052                 }
1053             }
1054
1055             mci_status.dwItem = MCI_STATUS_TIME_FORMAT ;
1056             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STATUS,
1057                                              MCI_STATUS_ITEM,
1058                                              (DWORD_PTR)&mci_status);
1059             if (mwi->lasterror)
1060                 return 0;
1061
1062             return mci_status.dwReturn;
1063         }
1064
1065     case MCIWNDM_SETTIMEFORMATA:
1066         {
1067             UNICODE_STRING stringW;
1068
1069             RtlCreateUnicodeStringFromAsciiz(&stringW, (LPCSTR)lParam);
1070             lParam = (LPARAM)stringW.Buffer;
1071         }
1072         /* fall through */
1073     case MCIWNDM_SETTIMEFORMATW:
1074         {
1075             static const WCHAR formatW[] = {'s','e','t',' ','%','d',' ','t','i','m','e',' ','f','o','r','m','a','t',' ',0};
1076             WCHAR *cmdW;
1077
1078             if (mwi->mci)
1079             {
1080                 cmdW = HeapAlloc(GetProcessHeap(), 0, (lstrlenW((LPCWSTR)lParam) + 64) * sizeof(WCHAR));
1081                 wsprintfW(cmdW, formatW, mwi->alias);
1082                 strcatW(cmdW, (WCHAR *)lParam);
1083
1084                 mwi->lasterror = mciSendStringW(cmdW, NULL, 0, 0);
1085
1086                 /* fix the range tracking according to the new time format */
1087                 if (!mwi->lasterror)
1088                     SendDlgItemMessageW(hWnd, CTL_TRACKBAR, TBM_SETRANGEMAX, 1,
1089                                         SendMessageW(hWnd, MCIWNDM_GETLENGTH, 0, 0));
1090             }
1091
1092             if (wMsg == MCIWNDM_SETTIMEFORMATA)
1093                 HeapFree(GetProcessHeap(), 0, (void *)lParam);
1094
1095             return 0;
1096         }
1097
1098     case MCIWNDM_CAN_PLAY:
1099         if (mwi->mci)
1100             return mci_get_devcaps(mwi, MCI_GETDEVCAPS_CAN_PLAY);
1101         return 0;
1102
1103     case MCIWNDM_CAN_RECORD:
1104         if (mwi->mci)
1105             return mci_get_devcaps(mwi, MCI_GETDEVCAPS_CAN_RECORD);
1106         return 0;
1107
1108     case MCIWNDM_CAN_SAVE:
1109         if (mwi->mci)
1110             return mci_get_devcaps(mwi, MCI_GETDEVCAPS_CAN_SAVE);
1111         return 0;
1112
1113     case MCIWNDM_CAN_EJECT:
1114         if (mwi->mci)
1115             return mci_get_devcaps(mwi, MCI_GETDEVCAPS_CAN_EJECT);
1116         return 0;
1117
1118     case MCIWNDM_CAN_WINDOW:
1119         switch (mwi->dev_type)
1120         {
1121         case MCI_DEVTYPE_ANIMATION:
1122         case MCI_DEVTYPE_DIGITAL_VIDEO:
1123         case MCI_DEVTYPE_OVERLAY:
1124             return 1;
1125         }
1126         return 0;
1127
1128     case MCIWNDM_CAN_CONFIG:
1129         if (mwi->hdrv)
1130             return SendDriverMessage(mwi->hdrv, DRV_QUERYCONFIGURE, 0, 0);
1131         return 0;
1132
1133     case MCIWNDM_SETZOOM:
1134         mwi->zoom = lParam;
1135
1136         if (mwi->mci)
1137         {
1138             RECT rc;
1139
1140             SetRectEmpty(&rc);
1141             rc.right = MulDiv(mwi->size.cx, mwi->zoom, 100);
1142             rc.bottom = MulDiv(mwi->size.cy, mwi->zoom, 100);
1143             SendMessageW(hWnd, MCIWNDM_PUT_DEST, 0, (LPARAM)&rc);
1144
1145             if (!(mwi->dwStyle & MCIWNDF_NOPLAYBAR))
1146                 rc.bottom += 32; /* add the height of the playbar */
1147             AdjustWindowRect(&rc, GetWindowLongW(hWnd, GWL_STYLE), FALSE);
1148             SetWindowPos(hWnd, 0, 0, 0, rc.right - rc.left, rc.bottom - rc.top,
1149                          SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
1150         }
1151         return 0;
1152
1153     case MCIWNDM_GETZOOM:
1154         return mwi->zoom;
1155
1156     case MCIWNDM_EJECT:
1157         {
1158             MCI_SET_PARMS mci_set;
1159
1160             mci_set.dwCallback = (DWORD_PTR)hWnd;
1161             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_SET,
1162                                              MCI_SET_DOOR_OPEN | MCI_NOTIFY,
1163                                              (DWORD_PTR)&mci_set);
1164             MCIWND_notify_mode(mwi);
1165             MCIWND_UpdateState(mwi);
1166             return mwi->lasterror;
1167         }
1168
1169     case MCIWNDM_SETVOLUME:
1170     case MCIWNDM_GETVOLUME:
1171     case MCIWNDM_SETSPEED:
1172     case MCIWNDM_GETSPEED:
1173     case MCIWNDM_SETREPEAT:
1174     case MCIWNDM_GETREPEAT:
1175     case MCIWNDM_REALIZE:
1176     case MCIWNDM_GETPALETTE:
1177     case MCIWNDM_SETPALETTE:
1178     case MCIWNDM_NEWA:
1179     case MCIWNDM_NEWW:
1180     case MCIWNDM_PALETTEKICK:
1181     case MCIWNDM_OPENINTERFACE:
1182         FIXME("support for MCIWNDM_ message WM_USER+%d not implemented\n", wMsg - WM_USER);
1183         return 0;
1184
1185     case MCI_PLAY:
1186         {
1187             LRESULT end = SendMessageW(hWnd, MCIWNDM_GETEND, 0, 0);
1188             return SendMessageW(hWnd, MCIWNDM_PLAYTO, 0, end);
1189         }
1190
1191     case MCI_SEEK:
1192         {
1193             MCI_SEEK_PARMS mci_seek;
1194
1195             switch (lParam)
1196             {
1197             case MCIWND_START:
1198                 lParam = SendMessageW(hWnd, MCIWNDM_GETSTART, 0, 0);
1199                 break;
1200
1201             case MCIWND_END:
1202                 lParam = SendMessageW(hWnd, MCIWNDM_GETEND, 0, 0);
1203                 break;
1204             }
1205
1206             mci_seek.dwTo = lParam;
1207             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_SEEK,
1208                                              MCI_TO, (DWORD_PTR)&mci_seek);
1209             if (mwi->lasterror)
1210             {
1211                 MCIWND_notify_error(mwi);
1212                 return mwi->lasterror;
1213             }
1214             return 0;
1215         }
1216
1217     case MCI_CLOSE:
1218         {
1219             RECT rc;
1220             MCI_GENERIC_PARMS mci_generic;
1221
1222             if (mwi->hdrv)
1223             {
1224                 CloseDriver(mwi->hdrv, 0, 0);
1225                 mwi->hdrv = 0;
1226             }
1227
1228             if (mwi->mci)
1229             {
1230                 mci_generic.dwCallback = 0;
1231                 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_CLOSE,
1232                                                  0, (DWORD_PTR)&mci_generic);
1233                 mwi->mci = 0;
1234             }
1235
1236             mwi->mode = MCI_MODE_NOT_READY;
1237             mwi->position = -1;
1238
1239             if (mwi->lpName)
1240             {
1241                 HeapFree(GetProcessHeap(), 0, mwi->lpName);
1242                 mwi->lpName = NULL;
1243             }
1244             MCIWND_UpdateState(mwi);
1245
1246             GetClientRect(hWnd, &rc);
1247             rc.bottom = rc.top;
1248             if (!(mwi->dwStyle & MCIWNDF_NOPLAYBAR))
1249                 rc.bottom += 32; /* add the height of the playbar */
1250             AdjustWindowRect(&rc, GetWindowLongW(hWnd, GWL_STYLE), FALSE);
1251             SetWindowPos(hWnd, 0, 0, 0, rc.right - rc.left,
1252                          rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
1253
1254             MCIWND_notify_media(mwi);
1255             return 0;
1256         }
1257
1258     case MCI_PAUSE:
1259     case MCI_STEP:
1260     case MCI_STOP:
1261     case MCI_RESUME:
1262         return mci_generic_command(mwi, wMsg);
1263
1264     case MCI_CONFIGURE:
1265         if (mwi->hdrv)
1266             SendDriverMessage(mwi->hdrv, DRV_CONFIGURE, (LPARAM)hWnd, 0);
1267         return 0;
1268
1269     case MCI_BREAK:
1270     case MCI_CAPTURE:
1271     case MCI_COPY:
1272     case MCI_CUE:
1273     case MCI_CUT:
1274     case MCI_DELETE:
1275     case MCI_ESCAPE:
1276     case MCI_FREEZE:
1277     case MCI_GETDEVCAPS:
1278     /*case MCI_INDEX:*/
1279     case MCI_INFO:
1280     case MCI_LIST:
1281     case MCI_LOAD:
1282     /*case MCI_MARK:*/
1283     case MCI_MONITOR:
1284     case MCI_OPEN:
1285     case MCI_PASTE:
1286     case MCI_PUT:
1287     case MCI_QUALITY:
1288     case MCI_REALIZE:
1289     case MCI_RECORD:
1290     case MCI_RESERVE:
1291     case MCI_RESTORE:
1292     case MCI_SAVE:
1293     case MCI_SET:
1294     case MCI_SETAUDIO:
1295     /*case MCI_SETTIMECODE:*/
1296     /*case MCI_SETTUNER:*/
1297     case MCI_SETVIDEO:
1298     case MCI_SIGNAL:
1299     case MCI_SPIN:
1300     case MCI_STATUS:
1301     case MCI_SYSINFO:
1302     case MCI_UNDO:
1303     case MCI_UNFREEZE:
1304     case MCI_UPDATE:
1305     case MCI_WHERE:
1306     case MCI_WINDOW:
1307         FIXME("support for MCI_ command %04x not implemented\n", wMsg);
1308         return 0;
1309     }
1310
1311     if (wMsg >= WM_USER)
1312     {
1313         FIXME("support for MCIWNDM_ message WM_USER+%d not implemented\n", wMsg - WM_USER);
1314         return 0;
1315     }
1316
1317     if (GetWindowLongW(hWnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
1318         return DefMDIChildProcW(hWnd, wMsg, wParam, lParam);
1319
1320     return DefWindowProcW(hWnd, wMsg, wParam, lParam);
1321 }