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