2 * Copyright 2000 Eric Pouech
3 * Copyright 2003 Dmitry Timoshkov
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.
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.
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
20 * Add support for all remaining MCI_ and MCIWNDM_ messages.
21 * Add support for MCIWNDF_NOTIFYMODE (all cases), MCIWNDF_NOTIFYPOS.
24 #define COM_NO_WINDOWS_H
39 #include "wine/unicode.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(mci);
44 extern HMODULE MSVFW32_hModule;
45 static const WCHAR mciWndClassW[] = {'M','C','I','W','n','d','C','l','a','s','s',0};
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))
62 #define MCIWND_NOTIFY_SIZE(info) \
63 if ((info)->dwStyle & MCIWNDF_NOTIFYSIZE) \
64 SendMessageW((info)->hwndOwner, MCIWNDM_NOTIFYSIZE, (WPARAM)(info)->hWnd, 0);
66 #define MCIWND_NOTIFY_ERROR(info) \
67 if ((info)->dwStyle & MCIWNDF_NOTIFYERROR) \
68 SendMessageW((info)->hwndOwner, MCIWNDM_NOTIFYERROR, (WPARAM)(info)->hWnd, (LPARAM)(info)->lasterror)
70 #define MCIWND_NOTIFY_MEDIA(info) MCIWND_notify_media(info)
72 static LRESULT WINAPI MCIWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam);
74 #define CTL_PLAYSTOP 0x3200
75 #define CTL_MENU 0x3201
76 #define CTL_TRACKBAR 0x3202
78 /***********************************************************************
79 * MCIWndRegisterClass [MSVFW32.@]
81 * NOTE: Native always uses its own hInstance
83 BOOL VFWAPIV MCIWndRegisterClass(HINSTANCE hInst)
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.
93 wc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS | CS_OWNDC | CS_GLOBALCLASS;
94 wc.lpfnWndProc = MCIWndProc;
96 wc.cbWndExtra = sizeof(MCIWndInfo*);
97 wc.hInstance = MSVFW32_hModule;
99 wc.hCursor = LoadCursorW(0, MAKEINTRESOURCEW(IDC_ARROW));
100 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
101 wc.lpszMenuName = NULL;
102 wc.lpszClassName = mciWndClassW;
104 if (RegisterClassW(&wc)) return TRUE;
105 if (GetLastError() == ERROR_CLASS_ALREADY_EXISTS) return TRUE;
110 /***********************************************************************
111 * MCIWndCreateW [MSVFW32.@]
113 HWND VFWAPIV MCIWndCreateW(HWND hwndParent, HINSTANCE hInstance,
114 DWORD dwStyle, LPCWSTR szFile)
116 TRACE("%p %p %lx %s\n", hwndParent, hInstance, dwStyle, debugstr_w(szFile));
118 MCIWndRegisterClass(hInstance);
120 /* window becomes visible after MCI_PLAY command in the case of MCIWNDF_NOOPEN */
121 if (dwStyle & MCIWNDF_NOOPEN)
122 dwStyle &= ~WS_VISIBLE;
124 return CreateWindowExW(0, mciWndClassW, NULL,
125 dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
127 hwndParent, 0, hInstance, (LPVOID)szFile);
130 /***********************************************************************
131 * MCIWndCreate [MSVFW32.@]
132 * MCIWndCreateA [MSVFW32.@]
134 HWND VFWAPIV MCIWndCreateA(HWND hwndParent, HINSTANCE hInstance,
135 DWORD dwStyle, LPCSTR szFile)
138 UNICODE_STRING fileW;
141 RtlCreateUnicodeStringFromAsciiz(&fileW, szFile);
145 ret = MCIWndCreateW(hwndParent, hInstance, dwStyle, fileW.Buffer);
147 RtlFreeUnicodeString(&fileW);
151 static void MCIWND_UpdateText(MCIWndInfo *mwi)
155 if ((mwi->dwStyle & MCIWNDF_SHOWNAME) && mwi->lpName)
156 strcpyW(buffer, mwi->lpName);
160 if (mwi->dwStyle & (MCIWNDF_SHOWPOS|MCIWNDF_SHOWMODE))
162 static const WCHAR spaceW[] = {' ',0};
163 static const WCHAR l_braceW[] = {'(',0};
165 if (*buffer) strcatW(buffer, spaceW);
166 strcatW(buffer, l_braceW);
169 if (mwi->dwStyle & MCIWNDF_SHOWPOS)
171 static const WCHAR formatW[] = {'%','l','d',0};
172 sprintfW(buffer + strlenW(buffer), formatW, SendMessageW(mwi->hWnd, MCIWNDM_GETPOSITIONW, 0, 0));
175 if ((mwi->dwStyle & (MCIWNDF_SHOWPOS|MCIWNDF_SHOWMODE)) == (MCIWNDF_SHOWPOS|MCIWNDF_SHOWMODE))
177 static const WCHAR dashW[] = {' ','-',' ',0};
178 strcatW(buffer, dashW);
181 if (mwi->dwStyle & MCIWNDF_SHOWMODE)
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};
193 switch (SendMessageW(mwi->hWnd, MCIWNDM_GETMODEW, 0, 0))
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;
206 if (mwi->dwStyle & (MCIWNDF_SHOWPOS|MCIWNDF_SHOWMODE))
208 static const WCHAR r_braceW[] = {' ',')',0};
209 strcatW(buffer, r_braceW);
212 TRACE("=> '%s'\n", debugstr_w(buffer));
213 SetWindowTextW(mwi->hWnd, buffer);
216 static LRESULT MCIWND_Create(HWND hWnd, LPCREATESTRUCTW cs)
220 static const WCHAR buttonW[] = {'b','u','t','t','o','n',0};
222 /* This sets the default window size */
223 SendMessageW(hWnd, MCI_CLOSE, 0, 0);
225 mwi = HeapAlloc(GetProcessHeap(), 0, sizeof(*mwi));
228 SetWindowLongW(hWnd, 0, (LPARAM)mwi);
230 mwi->dwStyle = cs->style;
235 mwi->hwndOwner = cs->hwndParent;
238 if (!(mwi->dwStyle & MCIWNDF_NOMENU))
240 static const WCHAR menuW[] = {'M','e','n','u',0};
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);
247 if (!(mwi->dwStyle & MCIWNDF_NOPLAYBAR))
249 INITCOMMONCONTROLSEX init;
250 static const WCHAR playW[] = {'P','l','a','y',0};
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);
257 init.dwSize = sizeof(init);
258 init.dwICC = ICC_BAR_CLASSES;
259 InitCommonControlsEx(&init);
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);
266 SendMessageW(hWnd, MCIWNDM_OPENW, 0, (LPARAM)cs->lpCreateParams);
268 MCIWND_UpdateText(mwi);
272 static void MCIWND_ToggleState(MCIWndInfo *mwi)
274 switch (SendMessageW(mwi->hWnd, MCIWNDM_GETMODEW, 0, 0))
276 case MCI_MODE_NOT_READY:
277 case MCI_MODE_RECORD:
280 TRACE("Cannot do much...\n");
284 SendMessageW(mwi->hWnd, MCI_RESUME, 0, 0);
288 SendMessageW(mwi->hWnd, MCI_PAUSE, 0, 0);
292 SendMessageW(mwi->hWnd, MCI_STOP, 0, 0);
297 static LRESULT MCIWND_Command(MCIWndInfo *mwi, WPARAM wParam, LPARAM lParam)
299 switch (LOWORD(wParam))
301 case CTL_PLAYSTOP: MCIWND_ToggleState(mwi); break;
305 MessageBoxA(0, "ooch", "NIY", MB_OK);
310 static void MCIWND_Timer(MCIWndInfo *mwi)
312 LONG pos = SendMessageW(mwi->hWnd, MCIWNDM_GETPOSITIONW, 0, 0);
314 SendDlgItemMessageW(mwi->hWnd, CTL_TRACKBAR, TBM_SETPOS, TRUE, pos);
315 MCIWND_UpdateText(mwi);
318 static void MCIWND_notify_media(MCIWndInfo *mwi)
320 if (mwi->dwStyle & (MCIWNDF_NOTIFYMEDIAA | MCIWNDF_NOTIFYMEDIAW))
324 static const WCHAR empty_str[1];
325 SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYMEDIA, (WPARAM)mwi->hWnd, (LPARAM)empty_str);
329 if (mwi->dwStyle & MCIWNDF_NOTIFYANSI)
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);
338 SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYMEDIA, (WPARAM)mwi->hWnd, (LPARAM)ansi_name);
340 HeapFree(GetProcessHeap(), 0, ansi_name);
343 SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYMEDIA, (WPARAM)mwi->hWnd, (LPARAM)mwi->lpName);
348 static LRESULT WINAPI MCIWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
352 if (wMsg == WM_CREATE)
353 return MCIWND_Create(hWnd, (CREATESTRUCTW *)lParam);
355 mwi = (MCIWndInfo*)GetWindowLongW(hWnd, 0);
357 return DefWindowProcW(hWnd, wMsg, wParam, lParam);
363 KillTimer(hWnd, mwi->uTimer);
365 SendMessageW(hWnd, MCI_CLOSE, 0, 0);
368 HeapFree(GetProcessHeap(), 0, mwi->lpName);
369 HeapFree(GetProcessHeap(), 0, mwi);
377 hdc = (wParam) ? (HDC)wParam : BeginPaint(mwi->hWnd, &ps);
378 /* something to do ? */
379 if (!wParam) EndPaint(mwi->hWnd, &ps);
384 return MCIWND_Command(mwi, wParam, lParam);
392 MCIWND_NOTIFY_SIZE(mwi);
394 if (wParam == SIZE_MINIMIZED) return 0;
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);
403 MCIWND_NOTIFY_MODE(mwi);
408 UNICODE_STRING nameW;
409 RtlCreateUnicodeStringFromAsciiz(&nameW, (LPCSTR)lParam);
410 lParam = (LPARAM)nameW.Buffer;
419 KillTimer(hWnd, mwi->uTimer);
426 MCI_OPEN_PARMSW mci_open;
427 MCI_GETDEVCAPS_PARMS mci_devcaps;
429 hCursor = LoadCursorW(0, (LPWSTR)IDC_WAIT);
430 hCursor = SetCursor(hCursor);
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);
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];
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;
451 mwi->mci = mci_open.wDeviceID;
452 mwi->lpName = HeapAlloc(GetProcessHeap(), 0, (strlenW((LPWSTR)lParam) + 1) * sizeof(WCHAR));
453 strcpyW(mwi->lpName, (LPWSTR)lParam);
455 mci_devcaps.dwItem = MCI_GETDEVCAPS_DEVICE_TYPE;
456 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_GETDEVCAPS,
458 (DWORD_PTR)&mci_devcaps);
461 MCIWND_NOTIFY_ERROR(mwi);
462 goto end_of_mci_open;
465 mwi->dev_type = mci_devcaps.dwReturn;
467 if (mwi->dev_type == MCI_DEVTYPE_DIGITAL_VIDEO)
469 MCI_DGV_WINDOW_PARMSW mci_window;
471 mci_window.hWnd = hWnd;
472 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_WINDOW,
474 (DWORD_PTR)&mci_window);
477 MCIWND_NOTIFY_ERROR(mwi);
478 goto end_of_mci_open;
483 if (SendMessageW(hWnd, MCIWNDM_GET_DEST, 0, (LPARAM)&rc) != 0)
485 GetClientRect(hWnd, &rc);
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);
495 MCIWND_NOTIFY_MEDIA(mwi);
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);
502 if (wMsg == MCIWNDM_OPENA)
503 HeapFree(GetProcessHeap(), 0, (void *)lParam);
504 return mwi->lasterror;
507 case MCIWNDM_GETDEVICEID:
510 case MCIWNDM_GET_SOURCE:
512 MCI_DGV_RECT_PARMS mci_rect;
514 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_WHERE,
515 MCI_DGV_WHERE_SOURCE,
516 (DWORD_PTR)&mci_rect);
519 MCIWND_NOTIFY_ERROR(mwi);
520 return mwi->lasterror;
522 *(RECT *)lParam = mci_rect.rc;
526 case MCIWNDM_GET_DEST:
528 MCI_DGV_RECT_PARMS mci_rect;
530 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_WHERE,
531 MCI_DGV_WHERE_DESTINATION,
532 (DWORD_PTR)&mci_rect);
535 MCIWND_NOTIFY_ERROR(mwi);
536 return mwi->lasterror;
538 *(RECT *)lParam = mci_rect.rc;
542 case MCIWNDM_PUT_SOURCE:
544 MCI_DGV_PUT_PARMS mci_put;
546 mci_put.rc = *(RECT *)lParam;
547 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_PUT,
549 (DWORD_PTR)&mci_put);
552 MCIWND_NOTIFY_ERROR(mwi);
553 return mwi->lasterror;
558 case MCIWNDM_PUT_DEST:
560 MCI_DGV_PUT_PARMS mci_put;
562 mci_put.rc = *(RECT *)lParam;
563 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_PUT,
564 MCI_DGV_PUT_DESTINATION,
565 (DWORD_PTR)&mci_put);
568 MCIWND_NOTIFY_ERROR(mwi);
569 return mwi->lasterror;
574 case MCIWNDM_GETLENGTH:
576 MCI_STATUS_PARMS mci_status;
578 mci_status.dwItem = MCI_STATUS_LENGTH;
579 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STATUS,
581 (DWORD_PTR)&mci_status);
584 MCIWND_NOTIFY_ERROR(mwi);
587 return mci_status.dwReturn;
590 case MCIWNDM_GETSTART:
592 MCI_STATUS_PARMS mci_status;
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);
600 MCIWND_NOTIFY_ERROR(mwi);
603 return mci_status.dwReturn;
608 LRESULT start, length;
610 start = SendMessageW(hWnd, MCIWNDM_GETSTART, 0, 0);
611 length = SendMessageW(hWnd, MCIWNDM_GETLENGTH, 0, 0);
612 return (start + length);
615 case MCIWNDM_GETPOSITIONA:
616 case MCIWNDM_GETPOSITIONW:
618 MCI_STATUS_PARMS mci_status;
620 mci_status.dwItem = MCI_STATUS_POSITION;
621 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STATUS,
623 (DWORD_PTR)&mci_status);
626 MCIWND_NOTIFY_ERROR(mwi);
629 return mci_status.dwReturn;
632 case MCIWNDM_GETMODEA:
633 case MCIWNDM_GETMODEW:
635 MCI_STATUS_PARMS mci_status;
637 mci_status.dwItem = MCI_STATUS_MODE;
638 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STATUS,
640 (DWORD_PTR)&mci_status);
642 return MCI_MODE_NOT_READY;
644 return mci_status.dwReturn;
649 MCI_PLAY_PARMS mci_play;
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);
657 MCIWND_NOTIFY_ERROR(mwi);
658 return mwi->lasterror;
663 case MCIWNDM_RETURNSTRINGA:
664 mciGetErrorStringA(mwi->lasterror, (LPSTR)lParam, wParam);
665 return mwi->lasterror;
667 case MCIWNDM_RETURNSTRINGW:
668 mciGetErrorStringW(mwi->lasterror, (LPWSTR)lParam, wParam);
669 return mwi->lasterror;
671 case MCIWNDM_SETOWNER:
672 mwi->hwndOwner = (HWND)wParam;
677 LRESULT end = SendMessageW(hWnd, MCIWNDM_GETEND, 0, 0);
678 return SendMessageW(hWnd, MCIWNDM_PLAYTO, 0, end);
683 MCI_GENERIC_PARMS mci_generic;
685 mci_generic.dwCallback = 0;
686 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STOP, 0, (DWORD_PTR)&mci_generic);
690 MCIWND_NOTIFY_ERROR(mwi);
691 return mwi->lasterror;
698 MCI_SEEK_PARMS mci_seek;
703 lParam = SendMessageW(hWnd, MCIWNDM_GETSTART, 0, 0);
707 lParam = SendMessageW(hWnd, MCIWNDM_GETEND, 0, 0);
711 mci_seek.dwTo = lParam;
712 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_SEEK,
713 MCI_TO, (DWORD_PTR)&mci_seek);
716 MCIWND_NOTIFY_ERROR(mwi);
717 return mwi->lasterror;
724 MCI_GENERIC_PARMS mci_generic;
726 mci_generic.dwCallback = 0;
727 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_CLOSE, 0, (DWORD_PTR)&mci_generic);
731 MCIWND_NOTIFY_ERROR(mwi);
732 return mwi->lasterror;
738 if ((wMsg >= WM_USER) && (wMsg < WM_APP))
740 FIXME("support for MCIWNDM_ message WM_USER+%d not implemented\n", wMsg - WM_USER);
744 return DefWindowProcW(hWnd, wMsg, wParam, lParam);