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_ commands and MCIWNDM_ messages.
21 * Add support for MCIWNDF_RECORD.
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(mci);
41 extern HMODULE MSVFW32_hModule;
42 static const WCHAR mciWndClassW[] = {'M','C','I','W','n','d','C','l','a','s','s',0};
53 SIZE size; /* size of the original frame rect */
59 WCHAR return_string[128];
60 WORD active_timer, inactive_timer;
63 static LRESULT WINAPI MCIWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam);
65 #define CTL_PLAYSTOP 0x3200
66 #define CTL_MENU 0x3201
67 #define CTL_TRACKBAR 0x3202
69 /***********************************************************************
70 * MCIWndRegisterClass [MSVFW32.@]
72 * NOTE: Native always uses its own hInstance
74 BOOL VFWAPIV MCIWndRegisterClass(void)
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.
84 wc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS | CS_OWNDC | CS_GLOBALCLASS;
85 wc.lpfnWndProc = MCIWndProc;
87 wc.cbWndExtra = sizeof(MCIWndInfo*);
88 wc.hInstance = MSVFW32_hModule;
90 wc.hCursor = LoadCursorW(0, MAKEINTRESOURCEW(IDC_ARROW));
91 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
92 wc.lpszMenuName = NULL;
93 wc.lpszClassName = mciWndClassW;
95 if (RegisterClassW(&wc)) return TRUE;
96 if (GetLastError() == ERROR_CLASS_ALREADY_EXISTS) return TRUE;
101 /***********************************************************************
102 * MCIWndCreateW [MSVFW32.@]
104 HWND VFWAPIV MCIWndCreateW(HWND hwndParent, HINSTANCE hInstance,
105 DWORD dwStyle, LPCWSTR szFile)
107 TRACE("%p %p %lx %s\n", hwndParent, hInstance, dwStyle, debugstr_w(szFile));
109 MCIWndRegisterClass();
111 if (!hInstance) hInstance = GetModuleHandleW(0);
114 dwStyle |= WS_VISIBLE | WS_BORDER /*| WS_CHILD*/;
116 dwStyle |= WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
118 return CreateWindowExW(0, mciWndClassW, NULL,
119 dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
121 hwndParent, 0, hInstance, (LPVOID)szFile);
124 /***********************************************************************
125 * MCIWndCreate [MSVFW32.@]
126 * MCIWndCreateA [MSVFW32.@]
128 HWND VFWAPIV MCIWndCreateA(HWND hwndParent, HINSTANCE hInstance,
129 DWORD dwStyle, LPCSTR szFile)
132 UNICODE_STRING fileW;
135 RtlCreateUnicodeStringFromAsciiz(&fileW, szFile);
139 ret = MCIWndCreateW(hwndParent, hInstance, dwStyle, fileW.Buffer);
141 RtlFreeUnicodeString(&fileW);
145 static inline void MCIWND_notify_mode(MCIWndInfo *mwi)
147 if (mwi->dwStyle & MCIWNDF_NOTIFYMODE)
149 UINT new_mode = SendMessageW(mwi->hWnd, MCIWNDM_GETMODEW, 0, 0);
150 if (new_mode != mwi->mode)
152 mwi->mode = new_mode;
153 SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYMODE, (WPARAM)mwi->hWnd, new_mode);
158 static inline void MCIWND_notify_pos(MCIWndInfo *mwi)
160 if (mwi->dwStyle & MCIWNDF_NOTIFYPOS)
162 long new_pos = SendMessageW(mwi->hWnd, MCIWNDM_GETPOSITIONW, 0, 0);
163 if (new_pos != mwi->position)
165 mwi->position = new_pos;
166 SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYPOS, (WPARAM)mwi->hWnd, new_pos);
171 static inline void MCIWND_notify_size(MCIWndInfo *mwi)
173 if (mwi->dwStyle & MCIWNDF_NOTIFYSIZE)
174 SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYSIZE, (WPARAM)mwi->hWnd, 0);
177 static inline void MCIWND_notify_error(MCIWndInfo *mwi)
179 if (mwi->dwStyle & MCIWNDF_NOTIFYERROR)
180 SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYERROR, (WPARAM)mwi->hWnd, (LPARAM)mwi->lasterror);
183 static void MCIWND_UpdateState(MCIWndInfo *mwi)
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);
195 MCIWND_notify_pos(mwi);
197 if (!(mwi->dwStyle & MCIWNDF_NOPLAYBAR))
198 SendDlgItemMessageW(mwi->hWnd, CTL_TRACKBAR, TBM_SETPOS, TRUE, mwi->position);
200 if (!(mwi->dwStyle & MCIWNDF_SHOWALL))
203 if ((mwi->dwStyle & MCIWNDF_SHOWNAME) && mwi->lpName)
204 strcpyW(buffer, mwi->lpName);
208 if (mwi->dwStyle & (MCIWNDF_SHOWPOS|MCIWNDF_SHOWMODE))
210 static const WCHAR spaceW[] = {' ',0};
211 static const WCHAR l_braceW[] = {'(',0};
213 if (*buffer) strcatW(buffer, spaceW);
214 strcatW(buffer, l_braceW);
217 if (mwi->dwStyle & MCIWNDF_SHOWPOS)
222 SendMessageW(mwi->hWnd, MCIWNDM_GETPOSITIONW, 64, (LPARAM)posW);
223 strcatW(buffer, posW);
226 if ((mwi->dwStyle & (MCIWNDF_SHOWPOS|MCIWNDF_SHOWMODE)) == (MCIWNDF_SHOWPOS|MCIWNDF_SHOWMODE))
228 static const WCHAR dashW[] = {' ','-',' ',0};
229 strcatW(buffer, dashW);
232 if (mwi->dwStyle & MCIWNDF_SHOWMODE)
237 SendMessageW(mwi->hWnd, MCIWNDM_GETMODEW, 64, (LPARAM)modeW);
238 strcatW(buffer, modeW);
241 if (mwi->dwStyle & (MCIWNDF_SHOWPOS|MCIWNDF_SHOWMODE))
243 static const WCHAR r_braceW[] = {')',0};
244 strcatW(buffer, r_braceW);
247 TRACE("=> '%s'\n", debugstr_w(buffer));
248 SetWindowTextW(mwi->hWnd, buffer);
251 static LRESULT MCIWND_Create(HWND hWnd, LPCREATESTRUCTW cs)
255 static const WCHAR buttonW[] = {'b','u','t','t','o','n',0};
257 mwi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*mwi));
260 SetWindowLongW(hWnd, 0, (LPARAM)mwi);
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;
268 mwi->hwndOwner = cs->hwndParent;
269 mwi->active_timer = 500;
270 mwi->inactive_timer = 2000;
271 mwi->mode = MCI_MODE_NOT_READY;
275 if (!(mwi->dwStyle & MCIWNDF_NOMENU))
277 static const WCHAR menuW[] = {'M','e','n','u',0};
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);
284 if (!(mwi->dwStyle & MCIWNDF_NOPLAYBAR))
286 INITCOMMONCONTROLSEX init;
287 static const WCHAR playW[] = {'P','l','a','y',0};
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);
294 init.dwSize = sizeof(init);
295 init.dwICC = ICC_BAR_CLASSES;
296 InitCommonControlsEx(&init);
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);
303 /* This sets the default window size */
304 SendMessageW(hWnd, MCI_CLOSE, 0, 0);
306 if (cs->lpCreateParams)
310 /* MCI wnd class is prepared to be embedded as an MDI child window */
311 if (cs->dwExStyle & WS_EX_MDICHILD)
313 MDICREATESTRUCTW *mdics = (MDICREATESTRUCTW *)cs->lpCreateParams;
314 lParam = mdics->lParam;
317 lParam = (LPARAM)cs->lpCreateParams;
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);
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);
328 SendMessageW(hWnd, IsWindowUnicode(parent) ? MCIWNDM_OPENW : MCIWNDM_OPENA, 0, lParam);
335 static void MCIWND_ToggleState(MCIWndInfo *mwi)
337 switch (SendMessageW(mwi->hWnd, MCIWNDM_GETMODEW, 0, 0))
339 case MCI_MODE_NOT_READY:
340 case MCI_MODE_RECORD:
343 TRACE("Cannot do much...\n");
347 SendMessageW(mwi->hWnd, MCI_RESUME, 0, 0);
351 SendMessageW(mwi->hWnd, MCI_PAUSE, 0, 0);
355 SendMessageW(mwi->hWnd, MCI_STOP, 0, 0);
360 static LRESULT MCIWND_Command(MCIWndInfo *mwi, WPARAM wParam, LPARAM lParam)
362 switch (LOWORD(wParam))
364 case CTL_PLAYSTOP: MCIWND_ToggleState(mwi); break;
368 FIXME("support for command %04x not implement yet\n", LOWORD(wParam));
373 static void MCIWND_notify_media(MCIWndInfo *mwi)
375 if (mwi->dwStyle & (MCIWNDF_NOTIFYMEDIAA | MCIWNDF_NOTIFYMEDIAW))
379 static const WCHAR empty_str[1];
380 SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYMEDIA, (WPARAM)mwi->hWnd, (LPARAM)empty_str);
384 if (mwi->dwStyle & MCIWNDF_NOTIFYANSI)
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);
393 SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYMEDIA, (WPARAM)mwi->hWnd, (LPARAM)ansi_name);
395 HeapFree(GetProcessHeap(), 0, ansi_name);
398 SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYMEDIA, (WPARAM)mwi->hWnd, (LPARAM)mwi->lpName);
403 static MCIERROR mci_generic_command(MCIWndInfo *mwi, UINT cmd)
405 MCI_GENERIC_PARMS mci_generic;
407 mci_generic.dwCallback = 0;
408 mwi->lasterror = mciSendCommandW(mwi->mci, cmd, 0, (DWORD_PTR)&mci_generic);
411 return mwi->lasterror;
413 MCIWND_notify_mode(mwi);
414 MCIWND_UpdateState(mwi);
418 static LRESULT mci_get_devcaps(MCIWndInfo *mwi, UINT cap)
420 MCI_GETDEVCAPS_PARMS mci_devcaps;
422 mci_devcaps.dwItem = cap;
423 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_GETDEVCAPS,
425 (DWORD_PTR)&mci_devcaps);
429 return mci_devcaps.dwReturn;
432 static LRESULT WINAPI MCIWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
436 TRACE("%p %04x %08x %08lx\n", hWnd, wMsg, wParam, lParam);
438 mwi = (MCIWndInfo*)GetWindowLongW(hWnd, 0);
439 if (!mwi && wMsg != WM_CREATE)
440 return DefWindowProcW(hWnd, wMsg, wParam, lParam);
445 MCIWND_Create(hWnd, (CREATESTRUCTW *)lParam);
450 KillTimer(hWnd, mwi->uTimer);
453 SendMessageW(hWnd, MCI_CLOSE, 0, 0);
455 HeapFree(GetProcessHeap(), 0, mwi);
457 DestroyWindow(GetDlgItem(hWnd, CTL_MENU));
458 DestroyWindow(GetDlgItem(hWnd, CTL_PLAYSTOP));
459 DestroyWindow(GetDlgItem(hWnd, CTL_TRACKBAR));
464 MCI_DGV_UPDATE_PARMS mci_update;
467 mci_update.hDC = (wParam) ? (HDC)wParam : BeginPaint(hWnd, &ps);
469 mciSendCommandW(mwi->mci, MCI_UPDATE,
470 MCI_DGV_UPDATE_HDC | MCI_DGV_UPDATE_PAINT,
471 (DWORD_PTR)&mci_update);
473 if (!wParam) EndPaint(hWnd, &ps);
478 return MCIWND_Command(mwi, wParam, lParam);
483 KillTimer(hWnd, mwi->uTimer);
484 mwi->uTimer = SetTimer(hWnd, 1, wParam ? mwi->active_timer : mwi->inactive_timer, NULL);
489 MCIWND_UpdateState(mwi);
493 SetWindowPos(GetDlgItem(hWnd, CTL_PLAYSTOP), 0, 0, HIWORD(lParam) - 32, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
494 SetWindowPos(GetDlgItem(hWnd, CTL_MENU), 0, 32, HIWORD(lParam) - 32, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
495 SetWindowPos(GetDlgItem(hWnd, CTL_TRACKBAR), 0, 64, HIWORD(lParam) - 32, LOWORD(lParam) - 64, 32, SWP_NOACTIVATE);
497 if (!(mwi->dwStyle & MCIWNDF_NOAUTOSIZEMOVIE))
501 rc.left = rc.top = 0;
502 rc.right = LOWORD(lParam);
503 rc.bottom = HIWORD(lParam);
504 if (!(mwi->dwStyle & MCIWNDF_NOPLAYBAR))
505 rc.bottom -= 32; /* subtract the height of the playbar */
506 SendMessageW(hWnd, MCIWNDM_PUT_DEST, 0, (LPARAM)&rc);
508 MCIWND_notify_size(mwi);
512 MCIWND_notify_mode(mwi);
513 MCIWND_UpdateState(mwi);
518 UNICODE_STRING nameW;
519 TRACE("MCIWNDM_OPENA %s\n", debugstr_a((LPSTR)lParam));
520 RtlCreateUnicodeStringFromAsciiz(&nameW, (LPCSTR)lParam);
521 lParam = (LPARAM)nameW.Buffer;
528 MCI_OPEN_PARMSW mci_open;
529 MCI_GETDEVCAPS_PARMS mci_devcaps;
531 WCHAR drv_name[MAX_PATH];
532 static const WCHAR formatW[] = {'%','d',0};
533 static const WCHAR mci32W[] = {'m','c','i','3','2',0};
534 static const WCHAR system_iniW[] = {'s','y','s','t','e','m','.','i','n','i',0};
536 TRACE("MCIWNDM_OPENW %s\n", debugstr_w((LPWSTR)lParam));
538 if (wParam == MCIWNDOPENF_NEW)
540 SendMessageW(hWnd, MCIWNDM_NEWW, 0, lParam);
541 goto end_of_mci_open;
546 KillTimer(hWnd, mwi->uTimer);
550 hCursor = LoadCursorW(0, (LPWSTR)IDC_WAIT);
551 hCursor = SetCursor(hCursor);
553 mci_open.lpstrElementName = (LPWSTR)lParam;
554 wsprintfW(aliasW, formatW, (int)hWnd + 1);
555 mci_open.lpstrAlias = aliasW;
556 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_OPEN,
557 MCI_OPEN_ELEMENT | MCI_OPEN_ALIAS | MCI_WAIT,
558 (DWORD_PTR)&mci_open);
561 if (mwi->lasterror && !(mwi->dwStyle & MCIWNDF_NOERRORDLG))
563 /* FIXME: get the caption from resources */
564 static const WCHAR caption[] = {'M','C','I',' ','E','r','r','o','r',0};
565 WCHAR error_str[MAXERRORLENGTH];
567 mciGetErrorStringW(mwi->lasterror, error_str, MAXERRORLENGTH);
568 MessageBoxW(hWnd, error_str, caption, MB_ICONEXCLAMATION | MB_OK);
569 MCIWND_notify_error(mwi);
570 goto end_of_mci_open;
573 mwi->mci = mci_open.wDeviceID;
574 mwi->alias = (int)hWnd + 1;
576 mwi->lpName = HeapAlloc(GetProcessHeap(), 0, (strlenW((LPWSTR)lParam) + 1) * sizeof(WCHAR));
577 strcpyW(mwi->lpName, (LPWSTR)lParam);
579 MCIWND_UpdateState(mwi);
581 mci_devcaps.dwItem = MCI_GETDEVCAPS_DEVICE_TYPE;
582 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_GETDEVCAPS,
584 (DWORD_PTR)&mci_devcaps);
587 MCIWND_notify_error(mwi);
588 goto end_of_mci_open;
591 mwi->dev_type = mci_devcaps.dwReturn;
594 SendMessageW(hWnd, MCIWNDM_GETDEVICEW, 256, (LPARAM)drv_name);
595 if (drv_name[0] && GetPrivateProfileStringW(mci32W, drv_name, NULL,
596 drv_name, MAX_PATH, system_iniW))
597 mwi->hdrv = OpenDriver(drv_name, NULL, 0);
599 if (mwi->dev_type == MCI_DEVTYPE_DIGITAL_VIDEO)
601 MCI_DGV_WINDOW_PARMSW mci_window;
603 mci_window.hWnd = hWnd;
604 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_WINDOW,
606 (DWORD_PTR)&mci_window);
609 MCIWND_notify_error(mwi);
610 goto end_of_mci_open;
614 if (SendMessageW(hWnd, MCIWNDM_GET_DEST, 0, (LPARAM)&rc) == 0)
616 mwi->size.cx = rc.right - rc.left;
617 mwi->size.cy = rc.bottom - rc.top;
619 rc.right = MulDiv(mwi->size.cx, mwi->zoom, 100);
620 rc.bottom = MulDiv(mwi->size.cy, mwi->zoom, 100);
621 SendMessageW(hWnd, MCIWNDM_PUT_DEST, 0, (LPARAM)&rc);
625 GetClientRect(hWnd, &rc);
629 if (!(mwi->dwStyle & MCIWNDF_NOPLAYBAR))
630 rc.bottom += 32; /* add the height of the playbar */
631 AdjustWindowRect(&rc, GetWindowLongW(hWnd, GWL_STYLE), FALSE);
632 SetWindowPos(hWnd, 0, 0, 0, rc.right - rc.left,
633 rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
635 SendDlgItemMessageW(hWnd, CTL_TRACKBAR, TBM_SETRANGEMIN, 0L, 0L);
636 SendDlgItemMessageW(hWnd, CTL_TRACKBAR, TBM_SETRANGEMAX, 1,
637 SendMessageW(hWnd, MCIWNDM_GETLENGTH, 0, 0));
638 mwi->uTimer = SetTimer(hWnd, 1, mwi->active_timer, NULL);
640 MCIWND_notify_media(mwi);
643 if (wMsg == MCIWNDM_OPENA)
644 HeapFree(GetProcessHeap(), 0, (void *)lParam);
645 return mwi->lasterror;
648 case MCIWNDM_GETDEVICEID:
649 TRACE("MCIWNDM_GETDEVICEID\n");
652 case MCIWNDM_GETALIAS:
653 TRACE("MCIWNDM_GETALIAS\n");
656 case MCIWNDM_GET_SOURCE:
658 MCI_DGV_RECT_PARMS mci_rect;
660 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_WHERE,
661 MCI_DGV_WHERE_SOURCE,
662 (DWORD_PTR)&mci_rect);
665 MCIWND_notify_error(mwi);
666 return mwi->lasterror;
668 *(RECT *)lParam = mci_rect.rc;
669 TRACE("MCIWNDM_GET_SOURCE: %s\n", wine_dbgstr_rect(&mci_rect.rc));
673 case MCIWNDM_GET_DEST:
675 MCI_DGV_RECT_PARMS mci_rect;
677 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_WHERE,
678 MCI_DGV_WHERE_DESTINATION,
679 (DWORD_PTR)&mci_rect);
682 MCIWND_notify_error(mwi);
683 return mwi->lasterror;
685 *(RECT *)lParam = mci_rect.rc;
686 TRACE("MCIWNDM_GET_DEST: %s\n", wine_dbgstr_rect(&mci_rect.rc));
690 case MCIWNDM_PUT_SOURCE:
692 MCI_DGV_PUT_PARMS mci_put;
694 mci_put.rc = *(RECT *)lParam;
695 TRACE("MCIWNDM_PUT_SOURCE: %s\n", wine_dbgstr_rect(&mci_put.rc));
696 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_PUT,
698 (DWORD_PTR)&mci_put);
701 MCIWND_notify_error(mwi);
702 return mwi->lasterror;
707 case MCIWNDM_PUT_DEST:
709 MCI_DGV_PUT_PARMS mci_put;
711 mci_put.rc = *(RECT *)lParam;
712 TRACE("MCIWNDM_PUT_DEST: %s\n", wine_dbgstr_rect(&mci_put.rc));
714 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_PUT,
715 MCI_DGV_PUT_DESTINATION | MCI_DGV_RECT,
716 (DWORD_PTR)&mci_put);
719 MCIWND_notify_error(mwi);
720 return mwi->lasterror;
725 case MCIWNDM_GETLENGTH:
727 MCI_STATUS_PARMS mci_status;
729 mci_status.dwItem = MCI_STATUS_LENGTH;
730 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STATUS,
732 (DWORD_PTR)&mci_status);
735 MCIWND_notify_error(mwi);
738 TRACE("MCIWNDM_GETLENGTH: %ld\n", mci_status.dwReturn);
739 return mci_status.dwReturn;
742 case MCIWNDM_GETSTART:
744 MCI_STATUS_PARMS mci_status;
746 mci_status.dwItem = MCI_STATUS_POSITION;
747 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STATUS,
748 MCI_STATUS_ITEM | MCI_STATUS_START,
749 (DWORD_PTR)&mci_status);
752 MCIWND_notify_error(mwi);
755 TRACE("MCIWNDM_GETSTART: %ld\n", mci_status.dwReturn);
756 return mci_status.dwReturn;
761 LRESULT start, length;
763 start = SendMessageW(hWnd, MCIWNDM_GETSTART, 0, 0);
764 length = SendMessageW(hWnd, MCIWNDM_GETLENGTH, 0, 0);
765 TRACE("MCIWNDM_GETEND: %ld\n", start + length);
766 return (start + length);
769 case MCIWNDM_GETPOSITIONA:
770 case MCIWNDM_GETPOSITIONW:
772 MCI_STATUS_PARMS mci_status;
774 TRACE("MCIWNDM_GETPOSITION\n");
776 /* get position string if requested */
777 if (wParam && lParam)
779 if (wMsg == MCIWNDM_GETPOSITIONA)
783 wsprintfA(cmd, "status %d position", mwi->alias);
784 mwi->lasterror = mciSendStringA(cmd, (LPSTR)lParam, wParam, 0);
790 static const WCHAR formatW[] = {'s','t','a','t','u','s',' ','%','d',' ','p','o','s','i','t','i','o','n',0};
792 wsprintfW(cmdW, formatW, mwi->alias);
793 mwi->lasterror = mciSendStringW(cmdW, (LPWSTR)lParam, wParam, 0);
800 mci_status.dwItem = MCI_STATUS_POSITION;
801 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STATUS,
803 (DWORD_PTR)&mci_status);
807 return mci_status.dwReturn;
810 case MCIWNDM_GETMODEA:
811 case MCIWNDM_GETMODEW:
813 MCI_STATUS_PARMS mci_status;
815 TRACE("MCIWNDM_GETMODE\n");
818 return MCI_MODE_NOT_READY;
820 /* get mode string if requested */
821 if (wParam && lParam)
823 if (wMsg == MCIWNDM_GETMODEA)
827 wsprintfA(cmd, "status %d mode", mwi->alias);
828 mwi->lasterror = mciSendStringA(cmd, (LPSTR)lParam, wParam, 0);
834 static const WCHAR formatW[] = {'s','t','a','t','u','s',' ','%','d',' ','m','o','d','e',0};
836 wsprintfW(cmdW, formatW, mwi->alias);
837 mwi->lasterror = mciSendStringW(cmdW, (LPWSTR)lParam, wParam, 0);
841 return MCI_MODE_NOT_READY;
844 mci_status.dwItem = MCI_STATUS_MODE;
845 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STATUS,
847 (DWORD_PTR)&mci_status);
849 return MCI_MODE_NOT_READY;
851 return mci_status.dwReturn;
854 case MCIWNDM_PLAYFROM:
856 MCI_PLAY_PARMS mci_play;
858 TRACE("MCIWNDM_PLAYFROM %08lx\n", lParam);
860 mci_play.dwCallback = (DWORD_PTR)hWnd;
861 mci_play.dwFrom = lParam;
862 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_PLAY,
863 MCI_FROM | MCI_NOTIFY,
864 (DWORD_PTR)&mci_play);
867 MCIWND_notify_error(mwi);
868 return mwi->lasterror;
871 MCIWND_notify_mode(mwi);
872 MCIWND_UpdateState(mwi);
878 MCI_PLAY_PARMS mci_play;
880 TRACE("MCIWNDM_PLAYTO %08lx\n", lParam);
882 mci_play.dwCallback = (DWORD_PTR)hWnd;
883 mci_play.dwTo = lParam;
884 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_PLAY,
886 (DWORD_PTR)&mci_play);
889 MCIWND_notify_error(mwi);
890 return mwi->lasterror;
893 MCIWND_notify_mode(mwi);
894 MCIWND_UpdateState(mwi);
898 case MCIWNDM_PLAYREVERSE:
900 MCI_PLAY_PARMS mci_play;
901 DWORD flags = MCI_NOTIFY;
903 TRACE("MCIWNDM_PLAYREVERSE %08lx\n", lParam);
905 mci_play.dwCallback = (DWORD_PTR)hWnd;
906 mci_play.dwFrom = lParam;
907 switch (mwi->dev_type)
910 case MCI_DEVTYPE_ANIMATION:
911 flags |= MCI_ANIM_PLAY_REVERSE;
914 case MCI_DEVTYPE_DIGITAL_VIDEO:
915 flags |= MCI_DGV_PLAY_REVERSE;
918 #ifdef MCI_VCR_PLAY_REVERSE
919 case MCI_DEVTYPE_VCR:
920 flags |= MCI_VCR_PLAY_REVERSE;
924 case MCI_DEVTYPE_VIDEODISC:
925 flags |= MCI_VD_PLAY_REVERSE;
929 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_PLAY,
930 flags, (DWORD_PTR)&mci_play);
933 MCIWND_notify_error(mwi);
934 return mwi->lasterror;
937 MCIWND_notify_mode(mwi);
938 MCIWND_UpdateState(mwi);
942 case MCIWNDM_GETERRORA:
943 mciGetErrorStringA(mwi->lasterror, (LPSTR)lParam, wParam);
944 TRACE("MCIWNDM_GETERRORA: %s\n", debugstr_an((LPSTR)lParam, wParam));
945 return mwi->lasterror;
947 case MCIWNDM_GETERRORW:
948 mciGetErrorStringW(mwi->lasterror, (LPWSTR)lParam, wParam);
949 TRACE("MCIWNDM_GETERRORW: %s\n", debugstr_wn((LPWSTR)lParam, wParam));
950 return mwi->lasterror;
952 case MCIWNDM_SETOWNER:
953 TRACE("MCIWNDM_SETOWNER %p\n", (HWND)wParam);
954 mwi->hwndOwner = (HWND)wParam;
957 case MCIWNDM_SENDSTRINGA:
959 UNICODE_STRING stringW;
961 TRACE("MCIWNDM_SENDSTRINGA %s\n", debugstr_a((LPCSTR)lParam));
963 RtlCreateUnicodeStringFromAsciiz(&stringW, (LPCSTR)lParam);
964 lParam = (LPARAM)stringW.Buffer;
967 case MCIWNDM_SENDSTRINGW:
971 TRACE("MCIWNDM_SENDSTRINGW %s\n", debugstr_w((LPCWSTR)lParam));
973 p = strchrW((LPCWSTR)lParam, ' ');
976 static const WCHAR formatW[] = {'%','d',' ',0};
979 pos = p - (WCHAR *)lParam + 1;
980 len = lstrlenW((LPCWSTR)lParam) + 64;
982 cmdW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
984 memcpy(cmdW, (void *)lParam, pos * sizeof(WCHAR));
985 wsprintfW(cmdW + pos, formatW, mwi->alias);
986 strcatW(cmdW, (WCHAR *)lParam + pos);
989 cmdW = (LPWSTR)lParam;
991 mwi->lasterror = mciSendStringW(cmdW, mwi->return_string,
992 sizeof(mwi->return_string)/sizeof(mwi->return_string[0]),
995 MCIWND_notify_error(mwi);
997 if (cmdW != (LPWSTR)lParam)
998 HeapFree(GetProcessHeap(), 0, cmdW);
1000 if (wMsg == MCIWNDM_SENDSTRINGA)
1001 HeapFree(GetProcessHeap(), 0, (void *)lParam);
1003 MCIWND_UpdateState(mwi);
1004 return mwi->lasterror;
1007 case MCIWNDM_RETURNSTRINGA:
1008 WideCharToMultiByte(CP_ACP, 0, mwi->return_string, -1, (LPSTR)lParam, wParam, NULL, NULL);
1009 TRACE("MCIWNDM_RETURNTRINGA %s\n", debugstr_an((LPSTR)lParam, wParam));
1010 return mwi->lasterror;
1012 case MCIWNDM_RETURNSTRINGW:
1013 lstrcpynW((LPWSTR)lParam, mwi->return_string, wParam);
1014 TRACE("MCIWNDM_RETURNTRINGW %s\n", debugstr_wn((LPWSTR)lParam, wParam));
1015 return mwi->lasterror;
1017 case MCIWNDM_SETTIMERS:
1018 TRACE("MCIWNDM_SETTIMERS active %d ms, inactive %d ms\n", (int)wParam, (int)lParam);
1019 mwi->active_timer = (WORD)wParam;
1020 mwi->inactive_timer = (WORD)lParam;
1023 case MCIWNDM_SETACTIVETIMER:
1024 TRACE("MCIWNDM_SETACTIVETIMER %d ms\n", (int)wParam);
1025 mwi->active_timer = (WORD)wParam;
1028 case MCIWNDM_SETINACTIVETIMER:
1029 TRACE("MCIWNDM_SETINACTIVETIMER %d ms\n", (int)wParam);
1030 mwi->inactive_timer = (WORD)wParam;
1033 case MCIWNDM_GETACTIVETIMER:
1034 TRACE("MCIWNDM_GETACTIVETIMER: %d ms\n", mwi->active_timer);
1035 return mwi->active_timer;
1037 case MCIWNDM_GETINACTIVETIMER:
1038 TRACE("MCIWNDM_GETINACTIVETIMER: %d ms\n", mwi->inactive_timer);
1039 return mwi->inactive_timer;
1041 case MCIWNDM_CHANGESTYLES:
1042 TRACE("MCIWNDM_CHANGESTYLES mask %08x, set %08lx\n", wParam, lParam);
1043 /* FIXME: update the visual window state as well:
1044 * add/remove trackbar, autosize, etc.
1046 mwi->dwStyle &= ~wParam;
1047 mwi->dwStyle |= lParam & wParam;
1050 case MCIWNDM_GETSTYLES:
1051 TRACE("MCIWNDM_GETSTYLES: %08lx\n", mwi->dwStyle & 0xffff);
1052 return mwi->dwStyle & 0xffff;
1054 case MCIWNDM_GETDEVICEA:
1056 MCI_SYSINFO_PARMSA mci_sysinfo;
1058 mci_sysinfo.lpstrReturn = (LPSTR)lParam;
1059 mci_sysinfo.dwRetSize = wParam;
1060 mwi->lasterror = mciSendCommandA(mwi->mci, MCI_SYSINFO,
1061 MCI_SYSINFO_INSTALLNAME,
1062 (DWORD_PTR)&mci_sysinfo);
1063 TRACE("MCIWNDM_GETDEVICEA: %s\n", debugstr_an((LPSTR)lParam, wParam));
1067 case MCIWNDM_GETDEVICEW:
1069 MCI_SYSINFO_PARMSW mci_sysinfo;
1071 mci_sysinfo.lpstrReturn = (LPWSTR)lParam;
1072 mci_sysinfo.dwRetSize = wParam;
1073 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_SYSINFO,
1074 MCI_SYSINFO_INSTALLNAME,
1075 (DWORD_PTR)&mci_sysinfo);
1076 TRACE("MCIWNDM_GETDEVICEW: %s\n", debugstr_wn((LPWSTR)lParam, wParam));
1080 case MCIWNDM_VALIDATEMEDIA:
1081 TRACE("MCIWNDM_VALIDATEMEDIA\n");
1084 SendMessageW(hWnd, MCIWNDM_GETSTART, 0, 0);
1085 SendMessageW(hWnd, MCIWNDM_GETLENGTH, 0, 0);
1089 case MCIWNDM_GETFILENAMEA:
1090 TRACE("MCIWNDM_GETFILENAMEA: %s\n", debugstr_w(mwi->lpName));
1092 WideCharToMultiByte(CP_ACP, 0, mwi->lpName, -1, (LPSTR)lParam, wParam, NULL, NULL);
1095 case MCIWNDM_GETFILENAMEW:
1096 TRACE("MCIWNDM_GETFILENAMEW: %s\n", debugstr_w(mwi->lpName));
1098 lstrcpynW((LPWSTR)lParam, mwi->lpName, wParam);
1101 case MCIWNDM_GETTIMEFORMATA:
1102 case MCIWNDM_GETTIMEFORMATW:
1104 MCI_STATUS_PARMS mci_status;
1106 TRACE("MCIWNDM_GETTIMEFORMAT %08x %08lx\n", wParam, lParam);
1108 /* get format string if requested */
1109 if (wParam && lParam)
1111 if (wMsg == MCIWNDM_GETTIMEFORMATA)
1115 wsprintfA(cmd, "status %d time format", mwi->alias);
1116 mwi->lasterror = mciSendStringA(cmd, (LPSTR)lParam, wParam, 0);
1123 static const WCHAR formatW[] = {'s','t','a','t','u','s',' ','%','d',' ','t','i','m','e',' ','f','o','r','m','a','t',0};
1125 wsprintfW(cmdW, formatW, mwi->alias);
1126 mwi->lasterror = mciSendStringW(cmdW, (LPWSTR)lParam, wParam, 0);
1132 mci_status.dwItem = MCI_STATUS_TIME_FORMAT ;
1133 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STATUS,
1135 (DWORD_PTR)&mci_status);
1139 return mci_status.dwReturn;
1142 case MCIWNDM_SETTIMEFORMATA:
1144 UNICODE_STRING stringW;
1146 TRACE("MCIWNDM_SETTIMEFORMATA %s\n", debugstr_a((LPSTR)lParam));
1148 RtlCreateUnicodeStringFromAsciiz(&stringW, (LPCSTR)lParam);
1149 lParam = (LPARAM)stringW.Buffer;
1152 case MCIWNDM_SETTIMEFORMATW:
1154 static const WCHAR formatW[] = {'s','e','t',' ','%','d',' ','t','i','m','e',' ','f','o','r','m','a','t',' ',0};
1157 TRACE("MCIWNDM_SETTIMEFORMATW %s\n", debugstr_w((LPWSTR)lParam));
1161 cmdW = HeapAlloc(GetProcessHeap(), 0, (lstrlenW((LPCWSTR)lParam) + 64) * sizeof(WCHAR));
1162 wsprintfW(cmdW, formatW, mwi->alias);
1163 strcatW(cmdW, (WCHAR *)lParam);
1165 mwi->lasterror = mciSendStringW(cmdW, NULL, 0, 0);
1167 /* fix the range tracking according to the new time format */
1168 if (!mwi->lasterror)
1169 SendDlgItemMessageW(hWnd, CTL_TRACKBAR, TBM_SETRANGEMAX, 1,
1170 SendMessageW(hWnd, MCIWNDM_GETLENGTH, 0, 0));
1173 if (wMsg == MCIWNDM_SETTIMEFORMATA)
1174 HeapFree(GetProcessHeap(), 0, (void *)lParam);
1179 case MCIWNDM_CAN_PLAY:
1180 TRACE("MCIWNDM_CAN_PLAY\n");
1182 return mci_get_devcaps(mwi, MCI_GETDEVCAPS_CAN_PLAY);
1185 case MCIWNDM_CAN_RECORD:
1186 TRACE("MCIWNDM_CAN_RECORD\n");
1188 return mci_get_devcaps(mwi, MCI_GETDEVCAPS_CAN_RECORD);
1191 case MCIWNDM_CAN_SAVE:
1192 TRACE("MCIWNDM_CAN_SAVE\n");
1194 return mci_get_devcaps(mwi, MCI_GETDEVCAPS_CAN_SAVE);
1197 case MCIWNDM_CAN_EJECT:
1198 TRACE("MCIWNDM_CAN_EJECT\n");
1200 return mci_get_devcaps(mwi, MCI_GETDEVCAPS_CAN_EJECT);
1203 case MCIWNDM_CAN_WINDOW:
1204 TRACE("MCIWNDM_CAN_WINDOW\n");
1205 switch (mwi->dev_type)
1207 case MCI_DEVTYPE_ANIMATION:
1208 case MCI_DEVTYPE_DIGITAL_VIDEO:
1209 case MCI_DEVTYPE_OVERLAY:
1214 case MCIWNDM_CAN_CONFIG:
1215 TRACE("MCIWNDM_CAN_CONFIG\n");
1217 return SendDriverMessage(mwi->hdrv, DRV_QUERYCONFIGURE, 0, 0);
1220 case MCIWNDM_SETZOOM:
1221 TRACE("MCIWNDM_SETZOOM %ld\n", lParam);
1224 if (mwi->mci && !(mwi->dwStyle & MCIWNDF_NOAUTOSIZEWINDOW))
1228 rc.left = rc.top = 0;
1229 rc.right = MulDiv(mwi->size.cx, mwi->zoom, 100);
1230 rc.bottom = MulDiv(mwi->size.cy, mwi->zoom, 100);
1232 if (!(mwi->dwStyle & MCIWNDF_NOPLAYBAR))
1233 rc.bottom += 32; /* add the height of the playbar */
1234 AdjustWindowRect(&rc, GetWindowLongW(hWnd, GWL_STYLE), FALSE);
1235 SetWindowPos(hWnd, 0, 0, 0, rc.right - rc.left, rc.bottom - rc.top,
1236 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
1240 case MCIWNDM_GETZOOM:
1241 TRACE("MCIWNDM_GETZOOM: %d\n", mwi->zoom);
1246 MCI_SET_PARMS mci_set;
1248 TRACE("MCIWNDM_EJECT\n");
1250 mci_set.dwCallback = (DWORD_PTR)hWnd;
1251 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_SET,
1252 MCI_SET_DOOR_OPEN | MCI_NOTIFY,
1253 (DWORD_PTR)&mci_set);
1254 MCIWND_notify_mode(mwi);
1255 MCIWND_UpdateState(mwi);
1256 return mwi->lasterror;
1259 case MCIWNDM_SETVOLUME:
1260 case MCIWNDM_GETVOLUME:
1261 case MCIWNDM_SETSPEED:
1262 case MCIWNDM_GETSPEED:
1263 case MCIWNDM_SETREPEAT:
1264 case MCIWNDM_GETREPEAT:
1265 case MCIWNDM_REALIZE:
1266 case MCIWNDM_GETPALETTE:
1267 case MCIWNDM_SETPALETTE:
1270 case MCIWNDM_PALETTEKICK:
1271 case MCIWNDM_OPENINTERFACE:
1272 FIXME("support for MCIWNDM_ message WM_USER+%d not implemented\n", wMsg - WM_USER);
1277 LRESULT end = SendMessageW(hWnd, MCIWNDM_GETEND, 0, 0);
1278 return SendMessageW(hWnd, MCIWNDM_PLAYTO, 0, end);
1283 MCI_SEEK_PARMS mci_seek;
1288 lParam = SendMessageW(hWnd, MCIWNDM_GETSTART, 0, 0);
1292 lParam = SendMessageW(hWnd, MCIWNDM_GETEND, 0, 0);
1296 mci_seek.dwTo = lParam;
1297 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_SEEK,
1298 MCI_TO, (DWORD_PTR)&mci_seek);
1301 MCIWND_notify_error(mwi);
1302 return mwi->lasterror;
1304 /* update window to reflect the state */
1305 InvalidateRect(hWnd, NULL, TRUE);
1312 MCI_GENERIC_PARMS mci_generic;
1316 CloseDriver(mwi->hdrv, 0, 0);
1322 mci_generic.dwCallback = 0;
1323 mwi->lasterror = mciSendCommandW(mwi->mci, MCI_CLOSE,
1324 0, (DWORD_PTR)&mci_generic);
1328 mwi->mode = MCI_MODE_NOT_READY;
1331 HeapFree(GetProcessHeap(), 0, mwi->lpName);
1333 MCIWND_UpdateState(mwi);
1335 GetClientRect(hWnd, &rc);
1337 if (!(mwi->dwStyle & MCIWNDF_NOPLAYBAR))
1338 rc.bottom += 32; /* add the height of the playbar */
1339 AdjustWindowRect(&rc, GetWindowLongW(hWnd, GWL_STYLE), FALSE);
1340 SetWindowPos(hWnd, 0, 0, 0, rc.right - rc.left,
1341 rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
1343 MCIWND_notify_media(mwi);
1351 mci_generic_command(mwi, wMsg);
1352 if (wMsg == MCI_STEP && !mwi->lasterror)
1354 /* update window to reflect the state */
1355 InvalidateRect(hWnd, NULL, TRUE);
1357 return mwi->lasterror;
1361 SendDriverMessage(mwi->hdrv, DRV_CONFIGURE, (LPARAM)hWnd, 0);
1372 case MCI_GETDEVCAPS:
1390 /*case MCI_SETTIMECODE:*/
1391 /*case MCI_SETTUNER:*/
1402 FIXME("support for MCI_ command %04x not implemented\n", wMsg);
1406 if (wMsg >= WM_USER)
1408 FIXME("support for MCIWNDM_ message WM_USER+%d not implemented\n", wMsg - WM_USER);
1412 if (GetWindowLongW(hWnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
1413 return DefMDIChildProcW(hWnd, wMsg, wParam, lParam);
1415 return DefWindowProcW(hWnd, wMsg, wParam, lParam);