Add Unicode->ANSI MCI message mapping, implement mciSendCommandW, fix
[wine] / dlls / msvideo / mciwnd.c
1 /*
2  * Copyright 2000 Eric Pouech
3  * Copyright 2003 Dmitry Timoshkov
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  * FIXME:
20  * Add support for all remaining MCI_ and MCIWNDM_ messages.
21  * Add support for MCIWNDF_NOTIFYMODE (all cases), MCIWNDF_NOTIFYPOS.
22  */
23
24 #define COM_NO_WINDOWS_H
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <string.h>
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winnls.h"
32 #include "wingdi.h"
33 #include "winuser.h"
34 #include "winreg.h"
35 #include "winternl.h"
36 #include "vfw.h"
37 #include "digitalv.h"
38 #include "commctrl.h"
39 #include "wine/unicode.h"
40 #include "wine/debug.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(mci);
43
44 extern HMODULE MSVFW32_hModule;
45 static const WCHAR mciWndClassW[] = {'M','C','I','W','n','d','C','l','a','s','s',0};
46
47 typedef struct
48 {
49     DWORD       dwStyle;
50     MCIDEVICEID mci;
51     UINT        dev_type;
52     LPWSTR      lpName;
53     HWND        hWnd, hwndOwner;
54     UINT        uTimer;
55     MCIERROR    lasterror;
56 } MCIWndInfo;
57
58 #define MCIWND_NOTIFY_MODE(info) \
59     if ((info)->dwStyle & MCIWNDF_NOTIFYMODE) \
60         SendMessageW((info)->hwndOwner, MCIWNDM_NOTIFYMODE, (WPARAM)(info)->hWnd, (LPARAM)SendMessageW((info)->hWnd, MCIWNDM_GETMODEW, 0, 0))
61
62 #define MCIWND_NOTIFY_SIZE(info) \
63     if ((info)->dwStyle & MCIWNDF_NOTIFYSIZE) \
64         SendMessageW((info)->hwndOwner, MCIWNDM_NOTIFYSIZE, (WPARAM)(info)->hWnd, 0);
65
66 #define MCIWND_NOTIFY_ERROR(info) \
67     if ((info)->dwStyle & MCIWNDF_NOTIFYERROR) \
68         SendMessageW((info)->hwndOwner, MCIWNDM_NOTIFYERROR, (WPARAM)(info)->hWnd, (LPARAM)(info)->lasterror)
69
70 #define MCIWND_NOTIFY_MEDIA(info) MCIWND_notify_media(info)
71
72 static LRESULT WINAPI MCIWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam);
73
74 #define CTL_PLAYSTOP    0x3200
75 #define CTL_MENU        0x3201
76 #define CTL_TRACKBAR    0x3202
77
78 /***********************************************************************
79  *                MCIWndRegisterClass                [MSVFW32.@]
80  *
81  * NOTE: Native always uses its own hInstance
82  */
83 BOOL VFWAPIV MCIWndRegisterClass(HINSTANCE hInst)
84 {
85     WNDCLASSW wc;
86
87     /* Since we are going to register a class belonging to MSVFW32
88      * and later we will create windows with a different hInstance
89      * CS_GLOBALCLASS is needed. And because the second attempt
90      * to register a global class will fail we need to test whether
91      * the class was already registered.
92      */
93     wc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS | CS_OWNDC | CS_GLOBALCLASS;
94     wc.lpfnWndProc = MCIWndProc;
95     wc.cbClsExtra = 0;
96     wc.cbWndExtra = sizeof(MCIWndInfo*);
97     wc.hInstance = MSVFW32_hModule;
98     wc.hIcon = 0;
99     wc.hCursor = LoadCursorW(0, MAKEINTRESOURCEW(IDC_ARROW));
100     wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
101     wc.lpszMenuName = NULL;
102     wc.lpszClassName = mciWndClassW;
103
104     if (RegisterClassW(&wc)) return TRUE;
105     if (GetLastError() == ERROR_CLASS_ALREADY_EXISTS) return TRUE;
106
107     return FALSE;
108 }
109
110 /***********************************************************************
111  *                MCIWndCreateW                                [MSVFW32.@]
112  */
113 HWND VFWAPIV MCIWndCreateW(HWND hwndParent, HINSTANCE hInstance,
114                            DWORD dwStyle, LPCWSTR szFile)
115 {
116     TRACE("%p %p %lx %s\n", hwndParent, hInstance, dwStyle, debugstr_w(szFile));
117
118     MCIWndRegisterClass(hInstance);
119
120     /* window becomes visible after MCI_PLAY command in the case of MCIWNDF_NOOPEN */
121     if (dwStyle & MCIWNDF_NOOPEN)
122         dwStyle &= ~WS_VISIBLE;
123
124     return CreateWindowExW(0, mciWndClassW, NULL,
125                            dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
126                            0, 0, 300, 0,
127                            hwndParent, 0, hInstance, (LPVOID)szFile);
128 }
129
130 /***********************************************************************
131  *                MCIWndCreate                [MSVFW32.@]
132  *                MCIWndCreateA                [MSVFW32.@]
133  */
134 HWND VFWAPIV MCIWndCreateA(HWND hwndParent, HINSTANCE hInstance,
135                            DWORD dwStyle, LPCSTR szFile)
136 {
137     HWND ret;
138     UNICODE_STRING fileW;
139
140     if (szFile)
141         RtlCreateUnicodeStringFromAsciiz(&fileW, szFile);
142     else
143         fileW.Buffer = NULL;
144
145     ret = MCIWndCreateW(hwndParent, hInstance, dwStyle, fileW.Buffer);
146
147     RtlFreeUnicodeString(&fileW);
148     return ret;
149 }
150
151 static void MCIWND_UpdateText(MCIWndInfo *mwi)
152 {
153     WCHAR buffer[1024];
154
155     if ((mwi->dwStyle & MCIWNDF_SHOWNAME) && mwi->lpName)
156         strcpyW(buffer, mwi->lpName);
157     else
158         *buffer = 0;
159
160     if (mwi->dwStyle & (MCIWNDF_SHOWPOS|MCIWNDF_SHOWMODE))
161     {
162         static const WCHAR spaceW[] = {' ',0};
163         static const WCHAR l_braceW[] = {'(',0};
164
165         if (*buffer) strcatW(buffer, spaceW);
166         strcatW(buffer, l_braceW);
167     }
168
169     if (mwi->dwStyle & MCIWNDF_SHOWPOS)
170     {
171         static const WCHAR formatW[] = {'%','l','d',0};
172         sprintfW(buffer + strlenW(buffer), formatW, SendMessageW(mwi->hWnd, MCIWNDM_GETPOSITIONW, 0, 0));
173     }
174
175     if ((mwi->dwStyle & (MCIWNDF_SHOWPOS|MCIWNDF_SHOWMODE)) == (MCIWNDF_SHOWPOS|MCIWNDF_SHOWMODE))
176     {
177         static const WCHAR dashW[] = {' ','-',' ',0};
178         strcatW(buffer, dashW);
179     }
180
181     if (mwi->dwStyle & MCIWNDF_SHOWMODE)
182     {
183         /* FIXME: get the status string from resources */
184         static const WCHAR not_readyW[] = {'n','o','t',' ','r','e','a','d','y',0};
185         static const WCHAR pausedW[] = {'p','a','u','s','e','d',0};
186         static const WCHAR playingW[] = {'p','l','a','y','i','n','g',0};
187         static const WCHAR stoppedW[] = {'s','t','o','p','p','e','d',0};
188         static const WCHAR openW[] = {'o','p','e','n',0};
189         static const WCHAR recordingW[] = {'r','e','c','o','r','d','i','n','g',0};
190         static const WCHAR seekingW[] = {'s','e','e','k','i','n','g',0};
191         static const WCHAR unknownW[] = {'?','?','?',0};
192
193         switch (SendMessageW(mwi->hWnd, MCIWNDM_GETMODEW, 0, 0))
194         {
195             case MCI_MODE_NOT_READY: strcatW(buffer, not_readyW); break;
196             case MCI_MODE_PAUSE: strcatW(buffer, pausedW); break;
197             case MCI_MODE_PLAY: strcatW(buffer, playingW); break;
198             case MCI_MODE_STOP: strcatW(buffer, stoppedW); break;
199             case MCI_MODE_OPEN: strcatW(buffer, openW); break;
200             case MCI_MODE_RECORD: strcatW(buffer, recordingW); break;
201             case MCI_MODE_SEEK: strcatW(buffer, seekingW); break;
202             default: strcatW(buffer, unknownW); break;
203         }
204     }
205
206     if (mwi->dwStyle & (MCIWNDF_SHOWPOS|MCIWNDF_SHOWMODE))
207     {
208         static const WCHAR r_braceW[] = {' ',')',0};
209         strcatW(buffer, r_braceW);
210     }
211
212     TRACE("=> '%s'\n", debugstr_w(buffer));
213     SetWindowTextW(mwi->hWnd, buffer);
214 }
215
216 static LRESULT MCIWND_Create(HWND hWnd, LPCREATESTRUCTW cs)
217 {
218     HWND hChld;
219     MCIWndInfo *mwi;
220     static const WCHAR buttonW[] = {'b','u','t','t','o','n',0};
221
222     /* This sets the default window size */
223     SendMessageW(hWnd, MCI_CLOSE, 0, 0);
224
225     mwi = HeapAlloc(GetProcessHeap(), 0, sizeof(*mwi));
226     if (!mwi) return -1;
227
228     SetWindowLongW(hWnd, 0, (LPARAM)mwi);
229
230     mwi->dwStyle = cs->style;
231     mwi->mci = 0;
232     mwi->lpName = NULL;
233     mwi->uTimer = 0;
234     mwi->hWnd = hWnd;
235     mwi->hwndOwner = cs->hwndParent;
236     mwi->lasterror = 0;
237
238     if (!(mwi->dwStyle & MCIWNDF_NOMENU))
239     {
240         static const WCHAR menuW[] = {'M','e','n','u',0};
241
242         hChld = CreateWindowExW(0, buttonW, menuW, WS_CHILD|WS_VISIBLE, 32, cs->cy, 32, 32,
243                                 hWnd, (HMENU)CTL_MENU, cs->hInstance, 0L);
244         TRACE("Get Button2: %p\n", hChld);
245     }
246
247     if (!(mwi->dwStyle & MCIWNDF_NOPLAYBAR))
248     {
249         INITCOMMONCONTROLSEX init;
250         static const WCHAR playW[] = {'P','l','a','y',0};
251
252         /* adding the other elements: play/stop button, menu button, status */
253         hChld = CreateWindowExW(0, buttonW, playW, WS_CHILD|WS_VISIBLE, 0, cs->cy, 32, 32,
254                                 hWnd, (HMENU)CTL_PLAYSTOP, cs->hInstance, 0L);
255         TRACE("Get Button1: %p\n", hChld);
256
257         init.dwSize = sizeof(init);
258         init.dwICC = ICC_BAR_CLASSES;
259         InitCommonControlsEx(&init);
260
261         hChld = CreateWindowExW(0, TRACKBAR_CLASSW, NULL, WS_CHILD|WS_VISIBLE, 64, cs->cy, cs->cx - 64, 32,
262                                 hWnd, (HMENU)CTL_TRACKBAR, cs->hInstance, 0L);
263         TRACE("Get status: %p\n", hChld);
264     }
265
266     SendMessageW(hWnd, MCIWNDM_OPENW, 0, (LPARAM)cs->lpCreateParams);
267
268     MCIWND_UpdateText(mwi);
269     return 0;
270 }
271
272 static void MCIWND_ToggleState(MCIWndInfo *mwi)
273 {
274     switch (SendMessageW(mwi->hWnd, MCIWNDM_GETMODEW, 0, 0))
275     {
276     case MCI_MODE_NOT_READY:
277     case MCI_MODE_RECORD:
278     case MCI_MODE_SEEK:
279     case MCI_MODE_OPEN:
280         TRACE("Cannot do much...\n");
281         break;
282
283     case MCI_MODE_PAUSE:
284         SendMessageW(mwi->hWnd, MCI_RESUME, 0, 0);
285         break;
286
287     case MCI_MODE_PLAY:
288         SendMessageW(mwi->hWnd, MCI_PAUSE, 0, 0);
289         break;
290
291     case MCI_MODE_STOP:
292         SendMessageW(mwi->hWnd, MCI_STOP, 0, 0);
293         break;
294     }
295 }
296
297 static LRESULT MCIWND_Command(MCIWndInfo *mwi, WPARAM wParam, LPARAM lParam)
298 {
299     switch (LOWORD(wParam))
300     {
301     case CTL_PLAYSTOP: MCIWND_ToggleState(mwi); break;
302     case CTL_MENU:
303     case CTL_TRACKBAR:
304     default:
305         MessageBoxA(0, "ooch", "NIY", MB_OK);
306     }
307     return 0L;
308 }
309
310 static void MCIWND_Timer(MCIWndInfo *mwi)
311 {
312     LONG pos = SendMessageW(mwi->hWnd, MCIWNDM_GETPOSITIONW, 0, 0);
313     TRACE("%ld\n", pos);
314     SendDlgItemMessageW(mwi->hWnd, CTL_TRACKBAR, TBM_SETPOS, TRUE, pos);
315     MCIWND_UpdateText(mwi);
316 }
317
318 static void MCIWND_notify_media(MCIWndInfo *mwi)
319 {
320     if (mwi->dwStyle & (MCIWNDF_NOTIFYMEDIAA | MCIWNDF_NOTIFYMEDIAW))
321     {
322         if (!mwi->lpName)
323         {
324             static const WCHAR empty_str[1];
325             SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYMEDIA, (WPARAM)mwi->hWnd, (LPARAM)empty_str);
326         }
327         else
328         {
329             if (mwi->dwStyle & MCIWNDF_NOTIFYANSI)
330             {
331                 char *ansi_name;
332                 int len;
333
334                 len = WideCharToMultiByte(CP_ACP, 0, mwi->lpName, -1, NULL, 0, NULL, NULL);
335                 ansi_name = HeapAlloc(GetProcessHeap(), 0, len);
336                 WideCharToMultiByte(CP_ACP, 0, mwi->lpName, -1, ansi_name, len, NULL, NULL);
337
338                 SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYMEDIA, (WPARAM)mwi->hWnd, (LPARAM)ansi_name);
339
340                 HeapFree(GetProcessHeap(), 0, ansi_name);
341             }
342             else
343                 SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYMEDIA, (WPARAM)mwi->hWnd, (LPARAM)mwi->lpName);
344         }
345     }
346 }
347
348 static LRESULT WINAPI MCIWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
349 {
350     MCIWndInfo *mwi;
351
352     if (wMsg == WM_CREATE)
353         return MCIWND_Create(hWnd, (CREATESTRUCTW *)lParam);
354
355     mwi = (MCIWndInfo*)GetWindowLongW(hWnd, 0);
356     if (!mwi)
357         return DefWindowProcW(hWnd, wMsg, wParam, lParam);
358
359     switch (wMsg)
360     {
361     case WM_DESTROY:
362         if (mwi->uTimer)
363             KillTimer(hWnd, mwi->uTimer);
364
365         SendMessageW(hWnd, MCI_CLOSE, 0, 0);
366
367         if (mwi->lpName)
368             HeapFree(GetProcessHeap(), 0, mwi->lpName);
369         HeapFree(GetProcessHeap(), 0, mwi);
370         return 0;
371
372     case WM_PAINT:
373         {
374             HDC hdc;
375             PAINTSTRUCT ps;
376
377             hdc = (wParam) ? (HDC)wParam : BeginPaint(mwi->hWnd, &ps);
378             /* something to do ? */
379             if (!wParam) EndPaint(mwi->hWnd, &ps);
380             return 1;
381         }
382
383     case WM_COMMAND:
384         return MCIWND_Command(mwi, wParam, lParam);
385
386     case WM_TIMER:
387         MCIWND_Timer(mwi);
388         return 0;
389
390     case WM_SIZE:
391         {
392             MCIWND_NOTIFY_SIZE(mwi);
393
394             if (wParam == SIZE_MINIMIZED) return 0;
395
396             SetWindowPos(GetDlgItem(hWnd, CTL_PLAYSTOP), 0, 0, HIWORD(lParam) - 32, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
397             SetWindowPos(GetDlgItem(hWnd, CTL_MENU), 0, 32, HIWORD(lParam) - 32, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
398             SetWindowPos(GetDlgItem(hWnd, CTL_TRACKBAR), 0, 64, HIWORD(lParam) - 32, LOWORD(lParam) - 64, 32, SWP_NOACTIVATE);
399             return 0;
400         }
401
402     case MM_MCINOTIFY:
403         MCIWND_NOTIFY_MODE(mwi);
404         return 0;
405
406     case MCIWNDM_OPENA:
407         {
408             UNICODE_STRING nameW;
409             RtlCreateUnicodeStringFromAsciiz(&nameW, (LPCSTR)lParam);
410             lParam = (LPARAM)nameW.Buffer;
411         }
412         /* fall through */
413     case MCIWNDM_OPENW:
414         {
415             RECT rc;
416
417             if (mwi->uTimer)
418             {
419                 KillTimer(hWnd, mwi->uTimer);
420                 mwi->uTimer = 0;
421             }
422
423             if (lParam)
424             {
425                 HCURSOR hCursor;
426                 MCI_OPEN_PARMSW mci_open;
427                 MCI_GETDEVCAPS_PARMS mci_devcaps;
428
429                 hCursor = LoadCursorW(0, (LPWSTR)IDC_WAIT);
430                 hCursor = SetCursor(hCursor);
431
432                 mci_open.lpstrElementName = (LPWSTR)lParam;
433                 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_OPEN,
434                                                  MCI_OPEN_ELEMENT | MCI_WAIT,
435                                                  (DWORD_PTR)&mci_open);
436                 SetCursor(hCursor);
437
438                 if (mwi->lasterror)
439                 {
440                     /* FIXME: get the caption from resources */
441                     static const WCHAR caption[] = {'M','C','I',' ','E','r','r','o','r',0};
442                     WCHAR error_str[MAXERRORLENGTH];
443
444                     mciGetErrorStringW(mwi->lasterror, error_str, MAXERRORLENGTH);
445                     MessageBoxW(hWnd, error_str, caption, MB_ICONEXCLAMATION | MB_OK);
446                     MCIWND_NOTIFY_ERROR(mwi);
447                     goto end_of_mci_open;
448                 }
449
450
451                 mwi->mci = mci_open.wDeviceID;
452                 mwi->lpName = HeapAlloc(GetProcessHeap(), 0, (strlenW((LPWSTR)lParam) + 1) * sizeof(WCHAR));
453                 strcpyW(mwi->lpName, (LPWSTR)lParam);
454
455                 mci_devcaps.dwItem = MCI_GETDEVCAPS_DEVICE_TYPE;
456                 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_GETDEVCAPS,
457                                                  MCI_GETDEVCAPS_ITEM,
458                                                  (DWORD_PTR)&mci_devcaps);
459                 if (mwi->lasterror)
460                 {
461                     MCIWND_NOTIFY_ERROR(mwi);
462                     goto end_of_mci_open;
463                 }
464
465                 mwi->dev_type = mci_devcaps.dwReturn;
466
467                 if (mwi->dev_type == MCI_DEVTYPE_DIGITAL_VIDEO)
468                 {
469                     MCI_DGV_WINDOW_PARMSW mci_window;
470
471                     mci_window.hWnd = hWnd;
472                     mwi->lasterror = mciSendCommandW(mwi->mci, MCI_WINDOW,
473                                                      MCI_DGV_WINDOW_HWND,
474                                                      (DWORD_PTR)&mci_window);
475                     if (mwi->lasterror)
476                     {
477                         MCIWND_NOTIFY_ERROR(mwi);
478                         goto end_of_mci_open;
479                     }
480                 }
481             }
482
483             if (SendMessageW(hWnd, MCIWNDM_GET_DEST, 0, (LPARAM)&rc) != 0)
484             {
485                 GetClientRect(hWnd, &rc);
486                 rc.bottom = rc.top;
487             }
488
489             AdjustWindowRect(&rc, GetWindowLongW(hWnd, GWL_STYLE), FALSE);
490             if (!(mwi->dwStyle & MCIWNDF_NOPLAYBAR))
491                 rc.bottom += 32; /* add the height of the playbar */
492             SetWindowPos(hWnd, 0, 0, 0, rc.right - rc.left,
493                 rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
494
495             MCIWND_NOTIFY_MEDIA(mwi);
496
497             SendDlgItemMessageW(hWnd, CTL_TRACKBAR, TBM_SETRANGEMIN, 0L, 0L);
498             SendDlgItemMessageW(hWnd, CTL_TRACKBAR, TBM_SETRANGEMAX, 1L, SendMessageW(mwi->hWnd, MCIWNDM_GETLENGTH, 0, 0));
499             SetTimer(hWnd, 1, 500, NULL);
500
501 end_of_mci_open:
502             if (wMsg == MCIWNDM_OPENA)
503                 HeapFree(GetProcessHeap(), 0, (void *)lParam);
504             return mwi->lasterror;
505         }
506
507     case MCIWNDM_GETDEVICEID:
508         return mwi->mci;
509
510     case MCIWNDM_GET_SOURCE:
511         {
512             MCI_DGV_RECT_PARMS mci_rect;
513
514             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_WHERE,
515                                              MCI_DGV_WHERE_SOURCE,
516                                              (DWORD_PTR)&mci_rect);
517             if (mwi->lasterror)
518             {
519                 MCIWND_NOTIFY_ERROR(mwi);
520                 return mwi->lasterror;
521             }
522             *(RECT *)lParam = mci_rect.rc;
523             return 0;
524         }
525
526     case MCIWNDM_GET_DEST:
527         {
528             MCI_DGV_RECT_PARMS mci_rect;
529
530             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_WHERE,
531                                              MCI_DGV_WHERE_DESTINATION,
532                                              (DWORD_PTR)&mci_rect);
533             if (mwi->lasterror)
534             {
535                 MCIWND_NOTIFY_ERROR(mwi);
536                 return mwi->lasterror;
537             }
538             *(RECT *)lParam = mci_rect.rc;
539             return 0;
540         }
541
542     case MCIWNDM_PUT_SOURCE:
543         {
544             MCI_DGV_PUT_PARMS mci_put;
545
546             mci_put.rc = *(RECT *)lParam;
547             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_PUT,
548                                              MCI_DGV_PUT_SOURCE,
549                                              (DWORD_PTR)&mci_put);
550             if (mwi->lasterror)
551             {
552                 MCIWND_NOTIFY_ERROR(mwi);
553                 return mwi->lasterror;
554             }
555             return 0;
556         }
557
558     case MCIWNDM_PUT_DEST:
559         {
560             MCI_DGV_PUT_PARMS mci_put;
561
562             mci_put.rc = *(RECT *)lParam;
563             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_PUT,
564                                              MCI_DGV_PUT_DESTINATION,
565                                              (DWORD_PTR)&mci_put);
566             if (mwi->lasterror)
567             {
568                 MCIWND_NOTIFY_ERROR(mwi);
569                 return mwi->lasterror;
570             }
571             return 0;
572         }
573
574     case MCIWNDM_GETLENGTH:
575         {
576             MCI_STATUS_PARMS mci_status;
577
578             mci_status.dwItem = MCI_STATUS_LENGTH;
579             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STATUS,
580                                              MCI_STATUS_ITEM,
581                                              (DWORD_PTR)&mci_status);
582             if (mwi->lasterror)
583             {
584                 MCIWND_NOTIFY_ERROR(mwi);
585                 return 0;
586             }
587             return mci_status.dwReturn;
588         }
589
590     case MCIWNDM_GETSTART:
591         {
592             MCI_STATUS_PARMS mci_status;
593
594             mci_status.dwItem = MCI_STATUS_POSITION;
595             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STATUS,
596                                              MCI_STATUS_ITEM | MCI_STATUS_START,
597                                              (DWORD_PTR)&mci_status);
598             if (mwi->lasterror)
599             {
600                 MCIWND_NOTIFY_ERROR(mwi);
601                 return 0;
602             }
603             return mci_status.dwReturn;
604         }
605
606     case MCIWNDM_GETEND:
607         {
608             LRESULT start, length;
609
610             start = SendMessageW(hWnd, MCIWNDM_GETSTART, 0, 0);
611             length = SendMessageW(hWnd, MCIWNDM_GETLENGTH, 0, 0);
612             return (start + length);
613         }
614
615     case MCIWNDM_GETPOSITIONA:
616     case MCIWNDM_GETPOSITIONW:
617         {
618             MCI_STATUS_PARMS mci_status;
619
620             mci_status.dwItem = MCI_STATUS_POSITION;
621             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STATUS,
622                                              MCI_STATUS_ITEM,
623                                              (DWORD_PTR)&mci_status);
624             if (mwi->lasterror)
625             {
626                 MCIWND_NOTIFY_ERROR(mwi);
627                 return 0;
628             }
629             return mci_status.dwReturn;
630         }
631
632     case MCIWNDM_GETMODEA:
633     case MCIWNDM_GETMODEW:
634         {
635             MCI_STATUS_PARMS mci_status;
636
637             mci_status.dwItem = MCI_STATUS_MODE;
638             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STATUS,
639                                              MCI_STATUS_ITEM,
640                                              (DWORD_PTR)&mci_status);
641             if (mwi->lasterror)
642                 return MCI_MODE_NOT_READY;
643
644             return mci_status.dwReturn;
645         }
646
647     case MCIWNDM_PLAYTO:
648         {
649             MCI_PLAY_PARMS mci_play;
650
651             mci_play.dwCallback = (DWORD_PTR)hWnd;
652             mci_play.dwTo = lParam;
653             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_PLAY,
654                                              MCI_TO | MCI_NOTIFY, (DWORD_PTR)&mci_play);
655             if (mwi->lasterror)
656             {
657                 MCIWND_NOTIFY_ERROR(mwi);
658                 return mwi->lasterror;
659             }
660             return 0;
661         }
662
663     case MCIWNDM_RETURNSTRINGA:
664         mciGetErrorStringA(mwi->lasterror, (LPSTR)lParam, wParam);
665         return mwi->lasterror;
666
667     case MCIWNDM_RETURNSTRINGW:
668         mciGetErrorStringW(mwi->lasterror, (LPWSTR)lParam, wParam);
669         return mwi->lasterror;
670
671     case MCIWNDM_SETOWNER:
672         mwi->hwndOwner = (HWND)wParam;
673         return 0;
674
675     case MCI_PLAY:
676         {
677             LRESULT end = SendMessageW(hWnd, MCIWNDM_GETEND, 0, 0);
678             return SendMessageW(hWnd, MCIWNDM_PLAYTO, 0, end);
679         }
680
681     case MCI_STOP:
682         {
683             MCI_GENERIC_PARMS mci_generic;
684
685             mci_generic.dwCallback = 0;
686             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STOP, 0, (DWORD_PTR)&mci_generic);
687
688             if (mwi->lasterror)
689             {
690                 MCIWND_NOTIFY_ERROR(mwi);
691                 return mwi->lasterror;
692             }
693             return 0;
694         }
695
696     case MCI_SEEK:
697         {
698             MCI_SEEK_PARMS mci_seek;
699
700             switch (lParam)
701             {
702             case MCIWND_START:
703                 lParam = SendMessageW(hWnd, MCIWNDM_GETSTART, 0, 0);
704                 break;
705
706             case MCIWND_END:
707                 lParam = SendMessageW(hWnd, MCIWNDM_GETEND, 0, 0);
708                 break;
709             }
710
711             mci_seek.dwTo = lParam;
712             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_SEEK,
713                                              MCI_TO, (DWORD_PTR)&mci_seek);
714             if (mwi->lasterror)
715             {
716                 MCIWND_NOTIFY_ERROR(mwi);
717                 return mwi->lasterror;
718             }
719             return 0;
720         }
721
722     case MCI_CLOSE:
723         {
724             MCI_GENERIC_PARMS mci_generic;
725
726             mci_generic.dwCallback = 0;
727             mwi->lasterror = mciSendCommandW(mwi->mci, MCI_CLOSE, 0, (DWORD_PTR)&mci_generic);
728
729             if (mwi->lasterror)
730             {
731                 MCIWND_NOTIFY_ERROR(mwi);
732                 return mwi->lasterror;
733             }
734             return 0;
735         }
736     }
737
738     if ((wMsg >= WM_USER) && (wMsg < WM_APP))
739     {
740         FIXME("support for MCIWNDM_ message WM_USER+%d not implemented\n", wMsg - WM_USER);
741         return 0;
742     }
743
744     return DefWindowProcW(hWnd, wMsg, wParam, lParam);
745 }