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