|  | /* | 
|  | * Copyright 2000 Eric Pouech | 
|  | * Copyright 2003 Dmitry Timoshkov | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | * | 
|  | * FIXME: | 
|  | * Add support for all remaining MCI_ commands and MCIWNDM_ messages. | 
|  | * Add support for MCIWNDF_RECORD. | 
|  | */ | 
|  |  | 
|  | #include <stdarg.h> | 
|  |  | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "winnls.h" | 
|  | #include "wingdi.h" | 
|  | #include "winuser.h" | 
|  | #include "winternl.h" | 
|  | #include "vfw.h" | 
|  | #include "digitalv.h" | 
|  | #include "commctrl.h" | 
|  | #include "wine/unicode.h" | 
|  | #include "wine/debug.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(mci); | 
|  |  | 
|  | extern HMODULE MSVFW32_hModule; | 
|  | static const WCHAR mciWndClassW[] = {'M','C','I','W','n','d','C','l','a','s','s',0}; | 
|  |  | 
|  | typedef struct | 
|  | { | 
|  | DWORD       dwStyle; | 
|  | MCIDEVICEID mci; | 
|  | HDRVR       hdrv; | 
|  | int         alias; | 
|  | UINT        dev_type; | 
|  | UINT        mode; | 
|  | long        position; | 
|  | SIZE        size; /* size of the original frame rect */ | 
|  | int         zoom; | 
|  | LPWSTR      lpName; | 
|  | HWND        hWnd, hwndOwner; | 
|  | UINT        uTimer; | 
|  | MCIERROR    lasterror; | 
|  | WCHAR       return_string[128]; | 
|  | WORD        active_timer, inactive_timer; | 
|  | } MCIWndInfo; | 
|  |  | 
|  | static LRESULT WINAPI MCIWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam); | 
|  |  | 
|  | #define CTL_PLAYSTOP    0x3200 | 
|  | #define CTL_MENU        0x3201 | 
|  | #define CTL_TRACKBAR    0x3202 | 
|  |  | 
|  | /*********************************************************************** | 
|  | *                MCIWndRegisterClass                [MSVFW32.@] | 
|  | * | 
|  | * NOTE: Native always uses its own hInstance | 
|  | */ | 
|  | BOOL VFWAPIV MCIWndRegisterClass(void) | 
|  | { | 
|  | WNDCLASSW wc; | 
|  |  | 
|  | /* Since we are going to register a class belonging to MSVFW32 | 
|  | * and later we will create windows with a different hInstance | 
|  | * CS_GLOBALCLASS is needed. And because the second attempt | 
|  | * to register a global class will fail we need to test whether | 
|  | * the class was already registered. | 
|  | */ | 
|  | wc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS | CS_OWNDC | CS_GLOBALCLASS; | 
|  | wc.lpfnWndProc = MCIWndProc; | 
|  | wc.cbClsExtra = 0; | 
|  | wc.cbWndExtra = sizeof(MCIWndInfo*); | 
|  | wc.hInstance = MSVFW32_hModule; | 
|  | wc.hIcon = 0; | 
|  | wc.hCursor = LoadCursorW(0, MAKEINTRESOURCEW(IDC_ARROW)); | 
|  | wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); | 
|  | wc.lpszMenuName = NULL; | 
|  | wc.lpszClassName = mciWndClassW; | 
|  |  | 
|  | if (RegisterClassW(&wc)) return TRUE; | 
|  | if (GetLastError() == ERROR_CLASS_ALREADY_EXISTS) return TRUE; | 
|  |  | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *                MCIWndCreateW                                [MSVFW32.@] | 
|  | */ | 
|  | HWND VFWAPIV MCIWndCreateW(HWND hwndParent, HINSTANCE hInstance, | 
|  | DWORD dwStyle, LPCWSTR szFile) | 
|  | { | 
|  | TRACE("%p %p %x %s\n", hwndParent, hInstance, dwStyle, debugstr_w(szFile)); | 
|  |  | 
|  | MCIWndRegisterClass(); | 
|  |  | 
|  | if (!hInstance) hInstance = GetModuleHandleW(0); | 
|  |  | 
|  | if (hwndParent) | 
|  | dwStyle |= WS_VISIBLE | WS_BORDER /*| WS_CHILD*/; | 
|  | else | 
|  | dwStyle |= WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX; | 
|  |  | 
|  | return CreateWindowExW(0, mciWndClassW, NULL, | 
|  | dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, | 
|  | 0, 0, 300, 0, | 
|  | hwndParent, 0, hInstance, (LPVOID)szFile); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *                MCIWndCreate                [MSVFW32.@] | 
|  | *                MCIWndCreateA                [MSVFW32.@] | 
|  | */ | 
|  | HWND VFWAPIV MCIWndCreateA(HWND hwndParent, HINSTANCE hInstance, | 
|  | DWORD dwStyle, LPCSTR szFile) | 
|  | { | 
|  | HWND ret; | 
|  | UNICODE_STRING fileW; | 
|  |  | 
|  | if (szFile) | 
|  | RtlCreateUnicodeStringFromAsciiz(&fileW, szFile); | 
|  | else | 
|  | fileW.Buffer = NULL; | 
|  |  | 
|  | ret = MCIWndCreateW(hwndParent, hInstance, dwStyle, fileW.Buffer); | 
|  |  | 
|  | RtlFreeUnicodeString(&fileW); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static inline void MCIWND_notify_mode(MCIWndInfo *mwi) | 
|  | { | 
|  | if (mwi->dwStyle & MCIWNDF_NOTIFYMODE) | 
|  | { | 
|  | UINT new_mode = SendMessageW(mwi->hWnd, MCIWNDM_GETMODEW, 0, 0); | 
|  | if (new_mode != mwi->mode) | 
|  | { | 
|  | mwi->mode = new_mode; | 
|  | SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYMODE, (WPARAM)mwi->hWnd, new_mode); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static inline void MCIWND_notify_pos(MCIWndInfo *mwi) | 
|  | { | 
|  | if (mwi->dwStyle & MCIWNDF_NOTIFYPOS) | 
|  | { | 
|  | long new_pos = SendMessageW(mwi->hWnd, MCIWNDM_GETPOSITIONW, 0, 0); | 
|  | if (new_pos != mwi->position) | 
|  | { | 
|  | mwi->position = new_pos; | 
|  | SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYPOS, (WPARAM)mwi->hWnd, new_pos); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static inline void MCIWND_notify_size(MCIWndInfo *mwi) | 
|  | { | 
|  | if (mwi->dwStyle & MCIWNDF_NOTIFYSIZE) | 
|  | SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYSIZE, (WPARAM)mwi->hWnd, 0); | 
|  | } | 
|  |  | 
|  | static inline void MCIWND_notify_error(MCIWndInfo *mwi) | 
|  | { | 
|  | if (mwi->dwStyle & MCIWNDF_NOTIFYERROR) | 
|  | SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYERROR, (WPARAM)mwi->hWnd, (LPARAM)mwi->lasterror); | 
|  | } | 
|  |  | 
|  | static void MCIWND_UpdateState(MCIWndInfo *mwi) | 
|  | { | 
|  | WCHAR buffer[1024]; | 
|  |  | 
|  | if (!mwi->mci) | 
|  | { | 
|  | /* FIXME: get this from resources */ | 
|  | static const WCHAR no_deviceW[] = {'N','o',' ','D','e','v','i','c','e',0}; | 
|  | SetWindowTextW(mwi->hWnd, no_deviceW); | 
|  | return; | 
|  | } | 
|  |  | 
|  | MCIWND_notify_pos(mwi); | 
|  |  | 
|  | if (!(mwi->dwStyle & MCIWNDF_NOPLAYBAR)) | 
|  | SendDlgItemMessageW(mwi->hWnd, CTL_TRACKBAR, TBM_SETPOS, TRUE, mwi->position); | 
|  |  | 
|  | if (!(mwi->dwStyle & MCIWNDF_SHOWALL)) | 
|  | return; | 
|  |  | 
|  | if ((mwi->dwStyle & MCIWNDF_SHOWNAME) && mwi->lpName) | 
|  | strcpyW(buffer, mwi->lpName); | 
|  | else | 
|  | *buffer = 0; | 
|  |  | 
|  | if (mwi->dwStyle & (MCIWNDF_SHOWPOS|MCIWNDF_SHOWMODE)) | 
|  | { | 
|  | static const WCHAR spaceW[] = {' ',0}; | 
|  | static const WCHAR l_braceW[] = {'(',0}; | 
|  |  | 
|  | if (*buffer) strcatW(buffer, spaceW); | 
|  | strcatW(buffer, l_braceW); | 
|  | } | 
|  |  | 
|  | if (mwi->dwStyle & MCIWNDF_SHOWPOS) | 
|  | { | 
|  | WCHAR posW[64]; | 
|  |  | 
|  | posW[0] = 0; | 
|  | SendMessageW(mwi->hWnd, MCIWNDM_GETPOSITIONW, 64, (LPARAM)posW); | 
|  | strcatW(buffer, posW); | 
|  | } | 
|  |  | 
|  | if ((mwi->dwStyle & (MCIWNDF_SHOWPOS|MCIWNDF_SHOWMODE)) == (MCIWNDF_SHOWPOS|MCIWNDF_SHOWMODE)) | 
|  | { | 
|  | static const WCHAR dashW[] = {' ','-',' ',0}; | 
|  | strcatW(buffer, dashW); | 
|  | } | 
|  |  | 
|  | if (mwi->dwStyle & MCIWNDF_SHOWMODE) | 
|  | { | 
|  | WCHAR modeW[64]; | 
|  |  | 
|  | modeW[0] = 0; | 
|  | SendMessageW(mwi->hWnd, MCIWNDM_GETMODEW, 64, (LPARAM)modeW); | 
|  | strcatW(buffer, modeW); | 
|  | } | 
|  |  | 
|  | if (mwi->dwStyle & (MCIWNDF_SHOWPOS|MCIWNDF_SHOWMODE)) | 
|  | { | 
|  | static const WCHAR r_braceW[] = {')',0}; | 
|  | strcatW(buffer, r_braceW); | 
|  | } | 
|  |  | 
|  | TRACE("=> %s\n", debugstr_w(buffer)); | 
|  | SetWindowTextW(mwi->hWnd, buffer); | 
|  | } | 
|  |  | 
|  | static LRESULT MCIWND_Create(HWND hWnd, LPCREATESTRUCTW cs) | 
|  | { | 
|  | HWND hChld; | 
|  | MCIWndInfo *mwi; | 
|  | static const WCHAR buttonW[] = {'b','u','t','t','o','n',0}; | 
|  |  | 
|  | mwi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*mwi)); | 
|  | if (!mwi) return -1; | 
|  |  | 
|  | SetWindowLongW(hWnd, 0, (LPARAM)mwi); | 
|  |  | 
|  | mwi->dwStyle = cs->style; | 
|  | /* There is no need to show stats if there is no caption */ | 
|  | if ((mwi->dwStyle & WS_CAPTION) != WS_CAPTION) | 
|  | mwi->dwStyle &= ~MCIWNDF_SHOWALL; | 
|  |  | 
|  | mwi->hWnd = hWnd; | 
|  | mwi->hwndOwner = cs->hwndParent; | 
|  | mwi->active_timer = 500; | 
|  | mwi->inactive_timer = 2000; | 
|  | mwi->mode = MCI_MODE_NOT_READY; | 
|  | mwi->position = -1; | 
|  | mwi->zoom = 100; | 
|  |  | 
|  | if (!(mwi->dwStyle & MCIWNDF_NOMENU)) | 
|  | { | 
|  | static const WCHAR menuW[] = {'M','e','n','u',0}; | 
|  |  | 
|  | hChld = CreateWindowExW(0, buttonW, menuW, WS_CHILD|WS_VISIBLE, 32, cs->cy, 32, 32, | 
|  | hWnd, (HMENU)CTL_MENU, cs->hInstance, 0L); | 
|  | TRACE("Get Button2: %p\n", hChld); | 
|  | } | 
|  |  | 
|  | if (!(mwi->dwStyle & MCIWNDF_NOPLAYBAR)) | 
|  | { | 
|  | INITCOMMONCONTROLSEX init; | 
|  | static const WCHAR playW[] = {'P','l','a','y',0}; | 
|  |  | 
|  | /* adding the other elements: play/stop button, menu button, status */ | 
|  | hChld = CreateWindowExW(0, buttonW, playW, WS_CHILD|WS_VISIBLE, 0, cs->cy, 32, 32, | 
|  | hWnd, (HMENU)CTL_PLAYSTOP, cs->hInstance, 0L); | 
|  | TRACE("Get Button1: %p\n", hChld); | 
|  |  | 
|  | init.dwSize = sizeof(init); | 
|  | init.dwICC = ICC_BAR_CLASSES; | 
|  | InitCommonControlsEx(&init); | 
|  |  | 
|  | hChld = CreateWindowExW(0, TRACKBAR_CLASSW, NULL, WS_CHILD|WS_VISIBLE, 64, cs->cy, cs->cx - 64, 32, | 
|  | hWnd, (HMENU)CTL_TRACKBAR, cs->hInstance, 0L); | 
|  | TRACE("Get status: %p\n", hChld); | 
|  | } | 
|  |  | 
|  | /* This sets the default window size */ | 
|  | SendMessageW(hWnd, MCI_CLOSE, 0, 0); | 
|  |  | 
|  | if (cs->lpCreateParams) | 
|  | { | 
|  | LPARAM lParam; | 
|  |  | 
|  | /* MCI wnd class is prepared to be embedded as an MDI child window */ | 
|  | if (cs->dwExStyle & WS_EX_MDICHILD) | 
|  | { | 
|  | MDICREATESTRUCTW *mdics = cs->lpCreateParams; | 
|  | lParam = mdics->lParam; | 
|  | } | 
|  | else | 
|  | lParam = (LPARAM)cs->lpCreateParams; | 
|  |  | 
|  | /* If it's our internal class pointer, file name is a unicode string */ | 
|  | if (cs->lpszClass == mciWndClassW) | 
|  | SendMessageW(hWnd, MCIWNDM_OPENW, 0, lParam); | 
|  | else | 
|  | { | 
|  | /* Otherwise let's try to figure out what string format is used */ | 
|  | HWND parent = cs->hwndParent; | 
|  | if (!parent) parent = GetWindow(hWnd, GW_OWNER); | 
|  |  | 
|  | SendMessageW(hWnd, IsWindowUnicode(parent) ? MCIWNDM_OPENW : MCIWNDM_OPENA, 0, lParam); | 
|  | } | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void MCIWND_ToggleState(MCIWndInfo *mwi) | 
|  | { | 
|  | switch (SendMessageW(mwi->hWnd, MCIWNDM_GETMODEW, 0, 0)) | 
|  | { | 
|  | case MCI_MODE_NOT_READY: | 
|  | case MCI_MODE_RECORD: | 
|  | case MCI_MODE_SEEK: | 
|  | case MCI_MODE_OPEN: | 
|  | TRACE("Cannot do much...\n"); | 
|  | break; | 
|  |  | 
|  | case MCI_MODE_PAUSE: | 
|  | SendMessageW(mwi->hWnd, MCI_RESUME, 0, 0); | 
|  | break; | 
|  |  | 
|  | case MCI_MODE_PLAY: | 
|  | SendMessageW(mwi->hWnd, MCI_PAUSE, 0, 0); | 
|  | break; | 
|  |  | 
|  | case MCI_MODE_STOP: | 
|  | SendMessageW(mwi->hWnd, MCI_STOP, 0, 0); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | static LRESULT MCIWND_Command(MCIWndInfo *mwi, WPARAM wParam, LPARAM lParam) | 
|  | { | 
|  | switch (LOWORD(wParam)) | 
|  | { | 
|  | case CTL_PLAYSTOP: MCIWND_ToggleState(mwi); break; | 
|  | case CTL_MENU: | 
|  | case CTL_TRACKBAR: | 
|  | default: | 
|  | FIXME("support for command %04x not implement yet\n", LOWORD(wParam)); | 
|  | } | 
|  | return 0L; | 
|  | } | 
|  |  | 
|  | static void MCIWND_notify_media(MCIWndInfo *mwi) | 
|  | { | 
|  | if (mwi->dwStyle & (MCIWNDF_NOTIFYMEDIAA | MCIWNDF_NOTIFYMEDIAW)) | 
|  | { | 
|  | if (!mwi->lpName) | 
|  | { | 
|  | static const WCHAR empty_str[1]; | 
|  | SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYMEDIA, (WPARAM)mwi->hWnd, (LPARAM)empty_str); | 
|  | } | 
|  | else | 
|  | { | 
|  | if (mwi->dwStyle & MCIWNDF_NOTIFYANSI) | 
|  | { | 
|  | char *ansi_name; | 
|  | int len; | 
|  |  | 
|  | len = WideCharToMultiByte(CP_ACP, 0, mwi->lpName, -1, NULL, 0, NULL, NULL); | 
|  | ansi_name = HeapAlloc(GetProcessHeap(), 0, len); | 
|  | WideCharToMultiByte(CP_ACP, 0, mwi->lpName, -1, ansi_name, len, NULL, NULL); | 
|  |  | 
|  | SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYMEDIA, (WPARAM)mwi->hWnd, (LPARAM)ansi_name); | 
|  |  | 
|  | HeapFree(GetProcessHeap(), 0, ansi_name); | 
|  | } | 
|  | else | 
|  | SendMessageW(mwi->hwndOwner, MCIWNDM_NOTIFYMEDIA, (WPARAM)mwi->hWnd, (LPARAM)mwi->lpName); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static MCIERROR mci_generic_command(MCIWndInfo *mwi, UINT cmd) | 
|  | { | 
|  | MCI_GENERIC_PARMS mci_generic; | 
|  |  | 
|  | mci_generic.dwCallback = 0; | 
|  | mwi->lasterror = mciSendCommandW(mwi->mci, cmd, 0, (DWORD_PTR)&mci_generic); | 
|  |  | 
|  | if (mwi->lasterror) | 
|  | return mwi->lasterror; | 
|  |  | 
|  | MCIWND_notify_mode(mwi); | 
|  | MCIWND_UpdateState(mwi); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static LRESULT mci_get_devcaps(MCIWndInfo *mwi, UINT cap) | 
|  | { | 
|  | MCI_GETDEVCAPS_PARMS mci_devcaps; | 
|  |  | 
|  | mci_devcaps.dwItem = cap; | 
|  | mwi->lasterror = mciSendCommandW(mwi->mci, MCI_GETDEVCAPS, | 
|  | MCI_GETDEVCAPS_ITEM, | 
|  | (DWORD_PTR)&mci_devcaps); | 
|  | if (mwi->lasterror) | 
|  | return 0; | 
|  |  | 
|  | return mci_devcaps.dwReturn; | 
|  | } | 
|  |  | 
|  | static LRESULT MCIWND_KeyDown(MCIWndInfo *mwi, UINT key) | 
|  | { | 
|  | TRACE("%p, key %04x\n", mwi->hWnd, key); | 
|  |  | 
|  | switch(key) | 
|  | { | 
|  | case VK_ESCAPE: | 
|  | SendMessageW(mwi->hWnd, MCI_STOP, 0, 0); | 
|  | return 0; | 
|  |  | 
|  | default: | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | static LRESULT WINAPI MCIWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam) | 
|  | { | 
|  | MCIWndInfo *mwi; | 
|  |  | 
|  | TRACE("%p %04x %08lx %08lx\n", hWnd, wMsg, wParam, lParam); | 
|  |  | 
|  | mwi = (MCIWndInfo*)GetWindowLongPtrW(hWnd, 0); | 
|  | if (!mwi && wMsg != WM_CREATE) | 
|  | return DefWindowProcW(hWnd, wMsg, wParam, lParam); | 
|  |  | 
|  | switch (wMsg) | 
|  | { | 
|  | case WM_CREATE: | 
|  | MCIWND_Create(hWnd, (CREATESTRUCTW *)lParam); | 
|  | break; | 
|  |  | 
|  | case WM_DESTROY: | 
|  | if (mwi->uTimer) | 
|  | KillTimer(hWnd, mwi->uTimer); | 
|  |  | 
|  | if (mwi->mci) | 
|  | SendMessageW(hWnd, MCI_CLOSE, 0, 0); | 
|  |  | 
|  | HeapFree(GetProcessHeap(), 0, mwi); | 
|  |  | 
|  | DestroyWindow(GetDlgItem(hWnd, CTL_MENU)); | 
|  | DestroyWindow(GetDlgItem(hWnd, CTL_PLAYSTOP)); | 
|  | DestroyWindow(GetDlgItem(hWnd, CTL_TRACKBAR)); | 
|  | break; | 
|  |  | 
|  | case WM_PAINT: | 
|  | { | 
|  | MCI_DGV_UPDATE_PARMS mci_update; | 
|  | PAINTSTRUCT ps; | 
|  |  | 
|  | mci_update.hDC = (wParam) ? (HDC)wParam : BeginPaint(hWnd, &ps); | 
|  |  | 
|  | mciSendCommandW(mwi->mci, MCI_UPDATE, | 
|  | MCI_DGV_UPDATE_HDC | MCI_DGV_UPDATE_PAINT, | 
|  | (DWORD_PTR)&mci_update); | 
|  |  | 
|  | if (!wParam) EndPaint(hWnd, &ps); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | case WM_COMMAND: | 
|  | return MCIWND_Command(mwi, wParam, lParam); | 
|  |  | 
|  | case WM_KEYDOWN: | 
|  | return MCIWND_KeyDown(mwi, wParam); | 
|  |  | 
|  | case WM_NCACTIVATE: | 
|  | if (mwi->uTimer) | 
|  | { | 
|  | KillTimer(hWnd, mwi->uTimer); | 
|  | mwi->uTimer = SetTimer(hWnd, 1, wParam ? mwi->active_timer : mwi->inactive_timer, NULL); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case WM_TIMER: | 
|  | MCIWND_UpdateState(mwi); | 
|  | return 0; | 
|  |  | 
|  | case WM_SIZE: | 
|  | SetWindowPos(GetDlgItem(hWnd, CTL_PLAYSTOP), 0, 0, HIWORD(lParam) - 32, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE); | 
|  | SetWindowPos(GetDlgItem(hWnd, CTL_MENU), 0, 32, HIWORD(lParam) - 32, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE); | 
|  | SetWindowPos(GetDlgItem(hWnd, CTL_TRACKBAR), 0, 64, HIWORD(lParam) - 32, LOWORD(lParam) - 64, 32, SWP_NOACTIVATE); | 
|  |  | 
|  | if (!(mwi->dwStyle & MCIWNDF_NOAUTOSIZEMOVIE)) | 
|  | { | 
|  | RECT rc; | 
|  |  | 
|  | rc.left = rc.top = 0; | 
|  | rc.right = LOWORD(lParam); | 
|  | rc.bottom = HIWORD(lParam); | 
|  | if (!(mwi->dwStyle & MCIWNDF_NOPLAYBAR)) | 
|  | rc.bottom -= 32; /* subtract the height of the playbar */ | 
|  | SendMessageW(hWnd, MCIWNDM_PUT_DEST, 0, (LPARAM)&rc); | 
|  | } | 
|  | MCIWND_notify_size(mwi); | 
|  | break; | 
|  |  | 
|  | case MM_MCINOTIFY: | 
|  | MCIWND_notify_mode(mwi); | 
|  | MCIWND_UpdateState(mwi); | 
|  | return 0; | 
|  |  | 
|  | case MCIWNDM_OPENA: | 
|  | { | 
|  | UNICODE_STRING nameW; | 
|  | TRACE("MCIWNDM_OPENA %s\n", debugstr_a((LPSTR)lParam)); | 
|  | RtlCreateUnicodeStringFromAsciiz(&nameW, (LPCSTR)lParam); | 
|  | lParam = (LPARAM)nameW.Buffer; | 
|  | } | 
|  | /* fall through */ | 
|  | case MCIWNDM_OPENW: | 
|  | { | 
|  | RECT rc; | 
|  | HCURSOR hCursor; | 
|  | MCI_OPEN_PARMSW mci_open; | 
|  | MCI_GETDEVCAPS_PARMS mci_devcaps; | 
|  | WCHAR aliasW[64]; | 
|  | WCHAR drv_name[MAX_PATH]; | 
|  | static const WCHAR formatW[] = {'%','d',0}; | 
|  | static const WCHAR mci32W[] = {'m','c','i','3','2',0}; | 
|  | static const WCHAR system_iniW[] = {'s','y','s','t','e','m','.','i','n','i',0}; | 
|  |  | 
|  | TRACE("MCIWNDM_OPENW %s\n", debugstr_w((LPWSTR)lParam)); | 
|  |  | 
|  | if (wParam == MCIWNDOPENF_NEW) | 
|  | { | 
|  | SendMessageW(hWnd, MCIWNDM_NEWW, 0, lParam); | 
|  | goto end_of_mci_open; | 
|  | } | 
|  |  | 
|  | if (mwi->uTimer) | 
|  | { | 
|  | KillTimer(hWnd, mwi->uTimer); | 
|  | mwi->uTimer = 0; | 
|  | } | 
|  |  | 
|  | hCursor = LoadCursorW(0, (LPWSTR)IDC_WAIT); | 
|  | hCursor = SetCursor(hCursor); | 
|  |  | 
|  | mci_open.lpstrElementName = (LPWSTR)lParam; | 
|  | wsprintfW(aliasW, formatW, HandleToLong(hWnd) + 1); | 
|  | mci_open.lpstrAlias = aliasW; | 
|  | mwi->lasterror = mciSendCommandW(mwi->mci, MCI_OPEN, | 
|  | MCI_OPEN_ELEMENT | MCI_OPEN_ALIAS | MCI_WAIT, | 
|  | (DWORD_PTR)&mci_open); | 
|  | SetCursor(hCursor); | 
|  |  | 
|  | if (mwi->lasterror && !(mwi->dwStyle & MCIWNDF_NOERRORDLG)) | 
|  | { | 
|  | /* FIXME: get the caption from resources */ | 
|  | static const WCHAR caption[] = {'M','C','I',' ','E','r','r','o','r',0}; | 
|  | WCHAR error_str[MAXERRORLENGTH]; | 
|  |  | 
|  | mciGetErrorStringW(mwi->lasterror, error_str, MAXERRORLENGTH); | 
|  | MessageBoxW(hWnd, error_str, caption, MB_ICONEXCLAMATION | MB_OK); | 
|  | MCIWND_notify_error(mwi); | 
|  | goto end_of_mci_open; | 
|  | } | 
|  |  | 
|  | mwi->mci = mci_open.wDeviceID; | 
|  | mwi->alias = HandleToLong(hWnd) + 1; | 
|  |  | 
|  | mwi->lpName = HeapAlloc(GetProcessHeap(), 0, (strlenW((LPWSTR)lParam) + 1) * sizeof(WCHAR)); | 
|  | strcpyW(mwi->lpName, (LPWSTR)lParam); | 
|  |  | 
|  | MCIWND_UpdateState(mwi); | 
|  |  | 
|  | mci_devcaps.dwItem = MCI_GETDEVCAPS_DEVICE_TYPE; | 
|  | mwi->lasterror = mciSendCommandW(mwi->mci, MCI_GETDEVCAPS, | 
|  | MCI_GETDEVCAPS_ITEM, | 
|  | (DWORD_PTR)&mci_devcaps); | 
|  | if (mwi->lasterror) | 
|  | { | 
|  | MCIWND_notify_error(mwi); | 
|  | goto end_of_mci_open; | 
|  | } | 
|  |  | 
|  | mwi->dev_type = mci_devcaps.dwReturn; | 
|  |  | 
|  | drv_name[0] = 0; | 
|  | SendMessageW(hWnd, MCIWNDM_GETDEVICEW, 256, (LPARAM)drv_name); | 
|  | if (drv_name[0] && GetPrivateProfileStringW(mci32W, drv_name, NULL, | 
|  | drv_name, MAX_PATH, system_iniW)) | 
|  | mwi->hdrv = OpenDriver(drv_name, NULL, 0); | 
|  |  | 
|  | if (mwi->dev_type == MCI_DEVTYPE_DIGITAL_VIDEO) | 
|  | { | 
|  | MCI_DGV_WINDOW_PARMSW mci_window; | 
|  |  | 
|  | mci_window.hWnd = hWnd; | 
|  | mwi->lasterror = mciSendCommandW(mwi->mci, MCI_WINDOW, | 
|  | MCI_DGV_WINDOW_HWND, | 
|  | (DWORD_PTR)&mci_window); | 
|  | if (mwi->lasterror) | 
|  | { | 
|  | MCIWND_notify_error(mwi); | 
|  | goto end_of_mci_open; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (SendMessageW(hWnd, MCIWNDM_GET_DEST, 0, (LPARAM)&rc) == 0) | 
|  | { | 
|  | mwi->size.cx = rc.right - rc.left; | 
|  | mwi->size.cy = rc.bottom - rc.top; | 
|  |  | 
|  | rc.right = MulDiv(mwi->size.cx, mwi->zoom, 100); | 
|  | rc.bottom = MulDiv(mwi->size.cy, mwi->zoom, 100); | 
|  | SendMessageW(hWnd, MCIWNDM_PUT_DEST, 0, (LPARAM)&rc); | 
|  | } | 
|  | else | 
|  | { | 
|  | GetClientRect(hWnd, &rc); | 
|  | rc.bottom = rc.top; | 
|  | } | 
|  |  | 
|  | if (!(mwi->dwStyle & MCIWNDF_NOPLAYBAR)) | 
|  | rc.bottom += 32; /* add the height of the playbar */ | 
|  | AdjustWindowRect(&rc, GetWindowLongW(hWnd, GWL_STYLE), FALSE); | 
|  | SetWindowPos(hWnd, 0, 0, 0, rc.right - rc.left, | 
|  | rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); | 
|  |  | 
|  | SendDlgItemMessageW(hWnd, CTL_TRACKBAR, TBM_SETRANGEMIN, 0L, 0L); | 
|  | SendDlgItemMessageW(hWnd, CTL_TRACKBAR, TBM_SETRANGEMAX, 1, | 
|  | SendMessageW(hWnd, MCIWNDM_GETLENGTH, 0, 0)); | 
|  | mwi->uTimer = SetTimer(hWnd, 1, mwi->active_timer, NULL); | 
|  |  | 
|  | MCIWND_notify_media(mwi); | 
|  |  | 
|  | end_of_mci_open: | 
|  | if (wMsg == MCIWNDM_OPENA) | 
|  | HeapFree(GetProcessHeap(), 0, (void *)lParam); | 
|  | return mwi->lasterror; | 
|  | } | 
|  |  | 
|  | case MCIWNDM_GETDEVICEID: | 
|  | TRACE("MCIWNDM_GETDEVICEID\n"); | 
|  | return mwi->mci; | 
|  |  | 
|  | case MCIWNDM_GETALIAS: | 
|  | TRACE("MCIWNDM_GETALIAS\n"); | 
|  | return mwi->alias; | 
|  |  | 
|  | case MCIWNDM_GET_SOURCE: | 
|  | { | 
|  | MCI_DGV_RECT_PARMS mci_rect; | 
|  |  | 
|  | mwi->lasterror = mciSendCommandW(mwi->mci, MCI_WHERE, | 
|  | MCI_DGV_WHERE_SOURCE, | 
|  | (DWORD_PTR)&mci_rect); | 
|  | if (mwi->lasterror) | 
|  | { | 
|  | MCIWND_notify_error(mwi); | 
|  | return mwi->lasterror; | 
|  | } | 
|  | *(RECT *)lParam = mci_rect.rc; | 
|  | TRACE("MCIWNDM_GET_SOURCE: %s\n", wine_dbgstr_rect(&mci_rect.rc)); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | case MCIWNDM_GET_DEST: | 
|  | { | 
|  | MCI_DGV_RECT_PARMS mci_rect; | 
|  |  | 
|  | mwi->lasterror = mciSendCommandW(mwi->mci, MCI_WHERE, | 
|  | MCI_DGV_WHERE_DESTINATION, | 
|  | (DWORD_PTR)&mci_rect); | 
|  | if (mwi->lasterror) | 
|  | { | 
|  | MCIWND_notify_error(mwi); | 
|  | return mwi->lasterror; | 
|  | } | 
|  | *(RECT *)lParam = mci_rect.rc; | 
|  | TRACE("MCIWNDM_GET_DEST: %s\n", wine_dbgstr_rect(&mci_rect.rc)); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | case MCIWNDM_PUT_SOURCE: | 
|  | { | 
|  | MCI_DGV_PUT_PARMS mci_put; | 
|  |  | 
|  | mci_put.rc = *(RECT *)lParam; | 
|  | TRACE("MCIWNDM_PUT_SOURCE: %s\n", wine_dbgstr_rect(&mci_put.rc)); | 
|  | mwi->lasterror = mciSendCommandW(mwi->mci, MCI_PUT, | 
|  | MCI_DGV_PUT_SOURCE, | 
|  | (DWORD_PTR)&mci_put); | 
|  | if (mwi->lasterror) | 
|  | { | 
|  | MCIWND_notify_error(mwi); | 
|  | return mwi->lasterror; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | case MCIWNDM_PUT_DEST: | 
|  | { | 
|  | MCI_DGV_PUT_PARMS mci_put; | 
|  |  | 
|  | mci_put.rc = *(RECT *)lParam; | 
|  | TRACE("MCIWNDM_PUT_DEST: %s\n", wine_dbgstr_rect(&mci_put.rc)); | 
|  |  | 
|  | mwi->lasterror = mciSendCommandW(mwi->mci, MCI_PUT, | 
|  | MCI_DGV_PUT_DESTINATION | MCI_DGV_RECT, | 
|  | (DWORD_PTR)&mci_put); | 
|  | if (mwi->lasterror) | 
|  | { | 
|  | MCIWND_notify_error(mwi); | 
|  | return mwi->lasterror; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | case MCIWNDM_GETLENGTH: | 
|  | { | 
|  | MCI_STATUS_PARMS mci_status; | 
|  |  | 
|  | mci_status.dwItem = MCI_STATUS_LENGTH; | 
|  | mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STATUS, | 
|  | MCI_STATUS_ITEM, | 
|  | (DWORD_PTR)&mci_status); | 
|  | if (mwi->lasterror) | 
|  | { | 
|  | MCIWND_notify_error(mwi); | 
|  | return 0; | 
|  | } | 
|  | TRACE("MCIWNDM_GETLENGTH: %ld\n", mci_status.dwReturn); | 
|  | return mci_status.dwReturn; | 
|  | } | 
|  |  | 
|  | case MCIWNDM_GETSTART: | 
|  | { | 
|  | MCI_STATUS_PARMS mci_status; | 
|  |  | 
|  | mci_status.dwItem = MCI_STATUS_POSITION; | 
|  | mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STATUS, | 
|  | MCI_STATUS_ITEM | MCI_STATUS_START, | 
|  | (DWORD_PTR)&mci_status); | 
|  | if (mwi->lasterror) | 
|  | { | 
|  | MCIWND_notify_error(mwi); | 
|  | return 0; | 
|  | } | 
|  | TRACE("MCIWNDM_GETSTART: %ld\n", mci_status.dwReturn); | 
|  | return mci_status.dwReturn; | 
|  | } | 
|  |  | 
|  | case MCIWNDM_GETEND: | 
|  | { | 
|  | LRESULT start, length; | 
|  |  | 
|  | start = SendMessageW(hWnd, MCIWNDM_GETSTART, 0, 0); | 
|  | length = SendMessageW(hWnd, MCIWNDM_GETLENGTH, 0, 0); | 
|  | TRACE("MCIWNDM_GETEND: %ld\n", start + length); | 
|  | return (start + length); | 
|  | } | 
|  |  | 
|  | case MCIWNDM_GETPOSITIONA: | 
|  | case MCIWNDM_GETPOSITIONW: | 
|  | { | 
|  | MCI_STATUS_PARMS mci_status; | 
|  |  | 
|  | TRACE("MCIWNDM_GETPOSITION\n"); | 
|  |  | 
|  | /* get position string if requested */ | 
|  | if (wParam && lParam) | 
|  | { | 
|  | if (wMsg == MCIWNDM_GETPOSITIONA) | 
|  | { | 
|  | char cmd[64]; | 
|  |  | 
|  | wsprintfA(cmd, "status %d position", mwi->alias); | 
|  | mwi->lasterror = mciSendStringA(cmd, (LPSTR)lParam, wParam, 0); | 
|  | } | 
|  | else | 
|  | { | 
|  |  | 
|  | WCHAR cmdW[64]; | 
|  | static const WCHAR formatW[] = {'s','t','a','t','u','s',' ','%','d',' ','p','o','s','i','t','i','o','n',0}; | 
|  |  | 
|  | wsprintfW(cmdW, formatW, mwi->alias); | 
|  | mwi->lasterror = mciSendStringW(cmdW, (LPWSTR)lParam, wParam, 0); | 
|  | } | 
|  |  | 
|  | if (mwi->lasterror) | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | mci_status.dwItem = MCI_STATUS_POSITION; | 
|  | mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STATUS, | 
|  | MCI_STATUS_ITEM, | 
|  | (DWORD_PTR)&mci_status); | 
|  | if (mwi->lasterror) | 
|  | return 0; | 
|  |  | 
|  | return mci_status.dwReturn; | 
|  | } | 
|  |  | 
|  | case MCIWNDM_GETMODEA: | 
|  | case MCIWNDM_GETMODEW: | 
|  | { | 
|  | MCI_STATUS_PARMS mci_status; | 
|  |  | 
|  | TRACE("MCIWNDM_GETMODE\n"); | 
|  |  | 
|  | if (!mwi->mci) | 
|  | return MCI_MODE_NOT_READY; | 
|  |  | 
|  | /* get mode string if requested */ | 
|  | if (wParam && lParam) | 
|  | { | 
|  | if (wMsg == MCIWNDM_GETMODEA) | 
|  | { | 
|  | char cmd[64]; | 
|  |  | 
|  | wsprintfA(cmd, "status %d mode", mwi->alias); | 
|  | mwi->lasterror = mciSendStringA(cmd, (LPSTR)lParam, wParam, 0); | 
|  | } | 
|  | else | 
|  | { | 
|  |  | 
|  | WCHAR cmdW[64]; | 
|  | static const WCHAR formatW[] = {'s','t','a','t','u','s',' ','%','d',' ','m','o','d','e',0}; | 
|  |  | 
|  | wsprintfW(cmdW, formatW, mwi->alias); | 
|  | mwi->lasterror = mciSendStringW(cmdW, (LPWSTR)lParam, wParam, 0); | 
|  | } | 
|  |  | 
|  | if (mwi->lasterror) | 
|  | return MCI_MODE_NOT_READY; | 
|  | } | 
|  |  | 
|  | mci_status.dwItem = MCI_STATUS_MODE; | 
|  | mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STATUS, | 
|  | MCI_STATUS_ITEM, | 
|  | (DWORD_PTR)&mci_status); | 
|  | if (mwi->lasterror) | 
|  | return MCI_MODE_NOT_READY; | 
|  |  | 
|  | return mci_status.dwReturn; | 
|  | } | 
|  |  | 
|  | case MCIWNDM_PLAYFROM: | 
|  | { | 
|  | MCI_PLAY_PARMS mci_play; | 
|  |  | 
|  | TRACE("MCIWNDM_PLAYFROM %08lx\n", lParam); | 
|  |  | 
|  | mci_play.dwCallback = (DWORD_PTR)hWnd; | 
|  | mci_play.dwFrom = lParam; | 
|  | mwi->lasterror = mciSendCommandW(mwi->mci, MCI_PLAY, | 
|  | MCI_FROM | MCI_NOTIFY, | 
|  | (DWORD_PTR)&mci_play); | 
|  | if (mwi->lasterror) | 
|  | { | 
|  | MCIWND_notify_error(mwi); | 
|  | return mwi->lasterror; | 
|  | } | 
|  |  | 
|  | MCIWND_notify_mode(mwi); | 
|  | MCIWND_UpdateState(mwi); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | case MCIWNDM_PLAYTO: | 
|  | { | 
|  | MCI_PLAY_PARMS mci_play; | 
|  |  | 
|  | TRACE("MCIWNDM_PLAYTO %08lx\n", lParam); | 
|  |  | 
|  | mci_play.dwCallback = (DWORD_PTR)hWnd; | 
|  | mci_play.dwTo = lParam; | 
|  | mwi->lasterror = mciSendCommandW(mwi->mci, MCI_PLAY, | 
|  | MCI_TO | MCI_NOTIFY, | 
|  | (DWORD_PTR)&mci_play); | 
|  | if (mwi->lasterror) | 
|  | { | 
|  | MCIWND_notify_error(mwi); | 
|  | return mwi->lasterror; | 
|  | } | 
|  |  | 
|  | MCIWND_notify_mode(mwi); | 
|  | MCIWND_UpdateState(mwi); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | case MCIWNDM_PLAYREVERSE: | 
|  | { | 
|  | MCI_PLAY_PARMS mci_play; | 
|  | DWORD flags = MCI_NOTIFY; | 
|  |  | 
|  | TRACE("MCIWNDM_PLAYREVERSE %08lx\n", lParam); | 
|  |  | 
|  | mci_play.dwCallback = (DWORD_PTR)hWnd; | 
|  | mci_play.dwFrom = lParam; | 
|  | switch (mwi->dev_type) | 
|  | { | 
|  | default: | 
|  | case MCI_DEVTYPE_ANIMATION: | 
|  | flags |= MCI_ANIM_PLAY_REVERSE; | 
|  | break; | 
|  |  | 
|  | case MCI_DEVTYPE_DIGITAL_VIDEO: | 
|  | flags |= MCI_DGV_PLAY_REVERSE; | 
|  | break; | 
|  |  | 
|  | #ifdef MCI_VCR_PLAY_REVERSE | 
|  | case MCI_DEVTYPE_VCR: | 
|  | flags |= MCI_VCR_PLAY_REVERSE; | 
|  | break; | 
|  | #endif | 
|  |  | 
|  | case MCI_DEVTYPE_VIDEODISC: | 
|  | flags |= MCI_VD_PLAY_REVERSE; | 
|  | break; | 
|  |  | 
|  | } | 
|  | mwi->lasterror = mciSendCommandW(mwi->mci, MCI_PLAY, | 
|  | flags, (DWORD_PTR)&mci_play); | 
|  | if (mwi->lasterror) | 
|  | { | 
|  | MCIWND_notify_error(mwi); | 
|  | return mwi->lasterror; | 
|  | } | 
|  |  | 
|  | MCIWND_notify_mode(mwi); | 
|  | MCIWND_UpdateState(mwi); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | case MCIWNDM_GETERRORA: | 
|  | mciGetErrorStringA(mwi->lasterror, (LPSTR)lParam, wParam); | 
|  | TRACE("MCIWNDM_GETERRORA: %s\n", debugstr_an((LPSTR)lParam, wParam)); | 
|  | return mwi->lasterror; | 
|  |  | 
|  | case MCIWNDM_GETERRORW: | 
|  | mciGetErrorStringW(mwi->lasterror, (LPWSTR)lParam, wParam); | 
|  | TRACE("MCIWNDM_GETERRORW: %s\n", debugstr_wn((LPWSTR)lParam, wParam)); | 
|  | return mwi->lasterror; | 
|  |  | 
|  | case MCIWNDM_SETOWNER: | 
|  | TRACE("MCIWNDM_SETOWNER %p\n", (HWND)wParam); | 
|  | mwi->hwndOwner = (HWND)wParam; | 
|  | return 0; | 
|  |  | 
|  | case MCIWNDM_SENDSTRINGA: | 
|  | { | 
|  | UNICODE_STRING stringW; | 
|  |  | 
|  | TRACE("MCIWNDM_SENDSTRINGA %s\n", debugstr_a((LPCSTR)lParam)); | 
|  |  | 
|  | RtlCreateUnicodeStringFromAsciiz(&stringW, (LPCSTR)lParam); | 
|  | lParam = (LPARAM)stringW.Buffer; | 
|  | } | 
|  | /* fall through */ | 
|  | case MCIWNDM_SENDSTRINGW: | 
|  | { | 
|  | WCHAR *cmdW, *p; | 
|  |  | 
|  | TRACE("MCIWNDM_SENDSTRINGW %s\n", debugstr_w((LPCWSTR)lParam)); | 
|  |  | 
|  | p = strchrW((LPCWSTR)lParam, ' '); | 
|  | if (p) | 
|  | { | 
|  | static const WCHAR formatW[] = {'%','d',' ',0}; | 
|  | int len, pos; | 
|  |  | 
|  | pos = p - (WCHAR *)lParam + 1; | 
|  | len = lstrlenW((LPCWSTR)lParam) + 64; | 
|  |  | 
|  | cmdW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); | 
|  |  | 
|  | memcpy(cmdW, (void *)lParam, pos * sizeof(WCHAR)); | 
|  | wsprintfW(cmdW + pos, formatW, mwi->alias); | 
|  | strcatW(cmdW, (WCHAR *)lParam + pos); | 
|  | } | 
|  | else | 
|  | cmdW = (LPWSTR)lParam; | 
|  |  | 
|  | mwi->lasterror = mciSendStringW(cmdW, mwi->return_string, | 
|  | sizeof(mwi->return_string)/sizeof(mwi->return_string[0]), | 
|  | 0); | 
|  | if (mwi->lasterror) | 
|  | MCIWND_notify_error(mwi); | 
|  |  | 
|  | if (cmdW != (LPWSTR)lParam) | 
|  | HeapFree(GetProcessHeap(), 0, cmdW); | 
|  |  | 
|  | if (wMsg == MCIWNDM_SENDSTRINGA) | 
|  | HeapFree(GetProcessHeap(), 0, (void *)lParam); | 
|  |  | 
|  | MCIWND_UpdateState(mwi); | 
|  | return mwi->lasterror; | 
|  | } | 
|  |  | 
|  | case MCIWNDM_RETURNSTRINGA: | 
|  | WideCharToMultiByte(CP_ACP, 0, mwi->return_string, -1, (LPSTR)lParam, wParam, NULL, NULL); | 
|  | TRACE("MCIWNDM_RETURNTRINGA %s\n", debugstr_an((LPSTR)lParam, wParam)); | 
|  | return mwi->lasterror; | 
|  |  | 
|  | case MCIWNDM_RETURNSTRINGW: | 
|  | lstrcpynW((LPWSTR)lParam, mwi->return_string, wParam); | 
|  | TRACE("MCIWNDM_RETURNTRINGW %s\n", debugstr_wn((LPWSTR)lParam, wParam)); | 
|  | return mwi->lasterror; | 
|  |  | 
|  | case MCIWNDM_SETTIMERS: | 
|  | TRACE("MCIWNDM_SETTIMERS active %d ms, inactive %d ms\n", (int)wParam, (int)lParam); | 
|  | mwi->active_timer = (WORD)wParam; | 
|  | mwi->inactive_timer = (WORD)lParam; | 
|  | return 0; | 
|  |  | 
|  | case MCIWNDM_SETACTIVETIMER: | 
|  | TRACE("MCIWNDM_SETACTIVETIMER %d ms\n", (int)wParam); | 
|  | mwi->active_timer = (WORD)wParam; | 
|  | return 0; | 
|  |  | 
|  | case MCIWNDM_SETINACTIVETIMER: | 
|  | TRACE("MCIWNDM_SETINACTIVETIMER %d ms\n", (int)wParam); | 
|  | mwi->inactive_timer = (WORD)wParam; | 
|  | return 0; | 
|  |  | 
|  | case MCIWNDM_GETACTIVETIMER: | 
|  | TRACE("MCIWNDM_GETACTIVETIMER: %d ms\n", mwi->active_timer); | 
|  | return mwi->active_timer; | 
|  |  | 
|  | case MCIWNDM_GETINACTIVETIMER: | 
|  | TRACE("MCIWNDM_GETINACTIVETIMER: %d ms\n", mwi->inactive_timer); | 
|  | return mwi->inactive_timer; | 
|  |  | 
|  | case MCIWNDM_CHANGESTYLES: | 
|  | TRACE("MCIWNDM_CHANGESTYLES mask %08lx, set %08lx\n", wParam, lParam); | 
|  | /* FIXME: update the visual window state as well: | 
|  | * add/remove trackbar, autosize, etc. | 
|  | */ | 
|  | mwi->dwStyle &= ~wParam; | 
|  | mwi->dwStyle |= lParam & wParam; | 
|  | return 0; | 
|  |  | 
|  | case MCIWNDM_GETSTYLES: | 
|  | TRACE("MCIWNDM_GETSTYLES: %08x\n", mwi->dwStyle & 0xffff); | 
|  | return mwi->dwStyle & 0xffff; | 
|  |  | 
|  | case MCIWNDM_GETDEVICEA: | 
|  | { | 
|  | MCI_SYSINFO_PARMSA mci_sysinfo; | 
|  |  | 
|  | mci_sysinfo.lpstrReturn = (LPSTR)lParam; | 
|  | mci_sysinfo.dwRetSize = wParam; | 
|  | mwi->lasterror = mciSendCommandA(mwi->mci, MCI_SYSINFO, | 
|  | MCI_SYSINFO_INSTALLNAME, | 
|  | (DWORD_PTR)&mci_sysinfo); | 
|  | TRACE("MCIWNDM_GETDEVICEA: %s\n", debugstr_an((LPSTR)lParam, wParam)); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | case MCIWNDM_GETDEVICEW: | 
|  | { | 
|  | MCI_SYSINFO_PARMSW mci_sysinfo; | 
|  |  | 
|  | mci_sysinfo.lpstrReturn = (LPWSTR)lParam; | 
|  | mci_sysinfo.dwRetSize = wParam; | 
|  | mwi->lasterror = mciSendCommandW(mwi->mci, MCI_SYSINFO, | 
|  | MCI_SYSINFO_INSTALLNAME, | 
|  | (DWORD_PTR)&mci_sysinfo); | 
|  | TRACE("MCIWNDM_GETDEVICEW: %s\n", debugstr_wn((LPWSTR)lParam, wParam)); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | case MCIWNDM_VALIDATEMEDIA: | 
|  | TRACE("MCIWNDM_VALIDATEMEDIA\n"); | 
|  | if (mwi->mci) | 
|  | { | 
|  | SendMessageW(hWnd, MCIWNDM_GETSTART, 0, 0); | 
|  | SendMessageW(hWnd, MCIWNDM_GETLENGTH, 0, 0); | 
|  | } | 
|  | return 0; | 
|  |  | 
|  | case MCIWNDM_GETFILENAMEA: | 
|  | TRACE("MCIWNDM_GETFILENAMEA: %s\n", debugstr_w(mwi->lpName)); | 
|  | if (mwi->lpName) | 
|  | WideCharToMultiByte(CP_ACP, 0, mwi->lpName, -1, (LPSTR)lParam, wParam, NULL, NULL); | 
|  | return 0; | 
|  |  | 
|  | case MCIWNDM_GETFILENAMEW: | 
|  | TRACE("MCIWNDM_GETFILENAMEW: %s\n", debugstr_w(mwi->lpName)); | 
|  | if (mwi->lpName) | 
|  | lstrcpynW((LPWSTR)lParam, mwi->lpName, wParam); | 
|  | return 0; | 
|  |  | 
|  | case MCIWNDM_GETTIMEFORMATA: | 
|  | case MCIWNDM_GETTIMEFORMATW: | 
|  | { | 
|  | MCI_STATUS_PARMS mci_status; | 
|  |  | 
|  | TRACE("MCIWNDM_GETTIMEFORMAT %08lx %08lx\n", wParam, lParam); | 
|  |  | 
|  | /* get format string if requested */ | 
|  | if (wParam && lParam) | 
|  | { | 
|  | if (wMsg == MCIWNDM_GETTIMEFORMATA) | 
|  | { | 
|  | char cmd[64]; | 
|  |  | 
|  | wsprintfA(cmd, "status %d time format", mwi->alias); | 
|  | mwi->lasterror = mciSendStringA(cmd, (LPSTR)lParam, wParam, 0); | 
|  | if (mwi->lasterror) | 
|  | return 0; | 
|  | } | 
|  | else | 
|  | { | 
|  | WCHAR cmdW[64]; | 
|  | static const WCHAR formatW[] = {'s','t','a','t','u','s',' ','%','d',' ','t','i','m','e',' ','f','o','r','m','a','t',0}; | 
|  |  | 
|  | wsprintfW(cmdW, formatW, mwi->alias); | 
|  | mwi->lasterror = mciSendStringW(cmdW, (LPWSTR)lParam, wParam, 0); | 
|  | if (mwi->lasterror) | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | mci_status.dwItem = MCI_STATUS_TIME_FORMAT ; | 
|  | mwi->lasterror = mciSendCommandW(mwi->mci, MCI_STATUS, | 
|  | MCI_STATUS_ITEM, | 
|  | (DWORD_PTR)&mci_status); | 
|  | if (mwi->lasterror) | 
|  | return 0; | 
|  |  | 
|  | return mci_status.dwReturn; | 
|  | } | 
|  |  | 
|  | case MCIWNDM_SETTIMEFORMATA: | 
|  | { | 
|  | UNICODE_STRING stringW; | 
|  |  | 
|  | TRACE("MCIWNDM_SETTIMEFORMATA %s\n", debugstr_a((LPSTR)lParam)); | 
|  |  | 
|  | RtlCreateUnicodeStringFromAsciiz(&stringW, (LPCSTR)lParam); | 
|  | lParam = (LPARAM)stringW.Buffer; | 
|  | } | 
|  | /* fall through */ | 
|  | case MCIWNDM_SETTIMEFORMATW: | 
|  | { | 
|  | static const WCHAR formatW[] = {'s','e','t',' ','%','d',' ','t','i','m','e',' ','f','o','r','m','a','t',' ',0}; | 
|  | WCHAR *cmdW; | 
|  |  | 
|  | TRACE("MCIWNDM_SETTIMEFORMATW %s\n", debugstr_w((LPWSTR)lParam)); | 
|  |  | 
|  | if (mwi->mci) | 
|  | { | 
|  | cmdW = HeapAlloc(GetProcessHeap(), 0, (lstrlenW((LPCWSTR)lParam) + 64) * sizeof(WCHAR)); | 
|  | wsprintfW(cmdW, formatW, mwi->alias); | 
|  | strcatW(cmdW, (WCHAR *)lParam); | 
|  |  | 
|  | mwi->lasterror = mciSendStringW(cmdW, NULL, 0, 0); | 
|  |  | 
|  | /* fix the range tracking according to the new time format */ | 
|  | if (!mwi->lasterror) | 
|  | SendDlgItemMessageW(hWnd, CTL_TRACKBAR, TBM_SETRANGEMAX, 1, | 
|  | SendMessageW(hWnd, MCIWNDM_GETLENGTH, 0, 0)); | 
|  |  | 
|  | HeapFree(GetProcessHeap(), 0, cmdW); | 
|  | } | 
|  |  | 
|  | if (wMsg == MCIWNDM_SETTIMEFORMATA) | 
|  | HeapFree(GetProcessHeap(), 0, (void *)lParam); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | case MCIWNDM_CAN_PLAY: | 
|  | TRACE("MCIWNDM_CAN_PLAY\n"); | 
|  | if (mwi->mci) | 
|  | return mci_get_devcaps(mwi, MCI_GETDEVCAPS_CAN_PLAY); | 
|  | return 0; | 
|  |  | 
|  | case MCIWNDM_CAN_RECORD: | 
|  | TRACE("MCIWNDM_CAN_RECORD\n"); | 
|  | if (mwi->mci) | 
|  | return mci_get_devcaps(mwi, MCI_GETDEVCAPS_CAN_RECORD); | 
|  | return 0; | 
|  |  | 
|  | case MCIWNDM_CAN_SAVE: | 
|  | TRACE("MCIWNDM_CAN_SAVE\n"); | 
|  | if (mwi->mci) | 
|  | return mci_get_devcaps(mwi, MCI_GETDEVCAPS_CAN_SAVE); | 
|  | return 0; | 
|  |  | 
|  | case MCIWNDM_CAN_EJECT: | 
|  | TRACE("MCIWNDM_CAN_EJECT\n"); | 
|  | if (mwi->mci) | 
|  | return mci_get_devcaps(mwi, MCI_GETDEVCAPS_CAN_EJECT); | 
|  | return 0; | 
|  |  | 
|  | case MCIWNDM_CAN_WINDOW: | 
|  | TRACE("MCIWNDM_CAN_WINDOW\n"); | 
|  | switch (mwi->dev_type) | 
|  | { | 
|  | case MCI_DEVTYPE_ANIMATION: | 
|  | case MCI_DEVTYPE_DIGITAL_VIDEO: | 
|  | case MCI_DEVTYPE_OVERLAY: | 
|  | return 1; | 
|  | } | 
|  | return 0; | 
|  |  | 
|  | case MCIWNDM_CAN_CONFIG: | 
|  | TRACE("MCIWNDM_CAN_CONFIG\n"); | 
|  | if (mwi->hdrv) | 
|  | return SendDriverMessage(mwi->hdrv, DRV_QUERYCONFIGURE, 0, 0); | 
|  | return 0; | 
|  |  | 
|  | case MCIWNDM_SETZOOM: | 
|  | TRACE("MCIWNDM_SETZOOM %ld\n", lParam); | 
|  | mwi->zoom = lParam; | 
|  |  | 
|  | if (mwi->mci && !(mwi->dwStyle & MCIWNDF_NOAUTOSIZEWINDOW)) | 
|  | { | 
|  | RECT rc; | 
|  |  | 
|  | rc.left = rc.top = 0; | 
|  | rc.right = MulDiv(mwi->size.cx, mwi->zoom, 100); | 
|  | rc.bottom = MulDiv(mwi->size.cy, mwi->zoom, 100); | 
|  |  | 
|  | if (!(mwi->dwStyle & MCIWNDF_NOPLAYBAR)) | 
|  | rc.bottom += 32; /* add the height of the playbar */ | 
|  | AdjustWindowRect(&rc, GetWindowLongW(hWnd, GWL_STYLE), FALSE); | 
|  | SetWindowPos(hWnd, 0, 0, 0, rc.right - rc.left, rc.bottom - rc.top, | 
|  | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); | 
|  | } | 
|  | return 0; | 
|  |  | 
|  | case MCIWNDM_GETZOOM: | 
|  | TRACE("MCIWNDM_GETZOOM: %d\n", mwi->zoom); | 
|  | return mwi->zoom; | 
|  |  | 
|  | case MCIWNDM_EJECT: | 
|  | { | 
|  | MCI_SET_PARMS mci_set; | 
|  |  | 
|  | TRACE("MCIWNDM_EJECT\n"); | 
|  |  | 
|  | mci_set.dwCallback = (DWORD_PTR)hWnd; | 
|  | mwi->lasterror = mciSendCommandW(mwi->mci, MCI_SET, | 
|  | MCI_SET_DOOR_OPEN | MCI_NOTIFY, | 
|  | (DWORD_PTR)&mci_set); | 
|  | MCIWND_notify_mode(mwi); | 
|  | MCIWND_UpdateState(mwi); | 
|  | return mwi->lasterror; | 
|  | } | 
|  |  | 
|  | case MCIWNDM_SETVOLUME: | 
|  | case MCIWNDM_GETVOLUME: | 
|  | case MCIWNDM_SETSPEED: | 
|  | case MCIWNDM_GETSPEED: | 
|  | case MCIWNDM_SETREPEAT: | 
|  | case MCIWNDM_GETREPEAT: | 
|  | case MCIWNDM_REALIZE: | 
|  | case MCIWNDM_GETPALETTE: | 
|  | case MCIWNDM_SETPALETTE: | 
|  | case MCIWNDM_NEWA: | 
|  | case MCIWNDM_NEWW: | 
|  | case MCIWNDM_PALETTEKICK: | 
|  | case MCIWNDM_OPENINTERFACE: | 
|  | FIXME("support for MCIWNDM_ message WM_USER+%d not implemented\n", wMsg - WM_USER); | 
|  | return 0; | 
|  |  | 
|  | case MCI_PLAY: | 
|  | { | 
|  | LRESULT end = SendMessageW(hWnd, MCIWNDM_GETEND, 0, 0); | 
|  | return SendMessageW(hWnd, MCIWNDM_PLAYTO, 0, end); | 
|  | } | 
|  |  | 
|  | case MCI_SEEK: | 
|  | { | 
|  | MCI_SEEK_PARMS mci_seek; | 
|  |  | 
|  | switch (lParam) | 
|  | { | 
|  | case MCIWND_START: | 
|  | lParam = SendMessageW(hWnd, MCIWNDM_GETSTART, 0, 0); | 
|  | break; | 
|  |  | 
|  | case MCIWND_END: | 
|  | lParam = SendMessageW(hWnd, MCIWNDM_GETEND, 0, 0); | 
|  | break; | 
|  | } | 
|  |  | 
|  | mci_seek.dwTo = lParam; | 
|  | mwi->lasterror = mciSendCommandW(mwi->mci, MCI_SEEK, | 
|  | MCI_TO, (DWORD_PTR)&mci_seek); | 
|  | if (mwi->lasterror) | 
|  | { | 
|  | MCIWND_notify_error(mwi); | 
|  | return mwi->lasterror; | 
|  | } | 
|  | /* update window to reflect the state */ | 
|  | InvalidateRect(hWnd, NULL, TRUE); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | case MCI_CLOSE: | 
|  | { | 
|  | RECT rc; | 
|  | MCI_GENERIC_PARMS mci_generic; | 
|  |  | 
|  | if (mwi->hdrv) | 
|  | { | 
|  | CloseDriver(mwi->hdrv, 0, 0); | 
|  | mwi->hdrv = 0; | 
|  | } | 
|  |  | 
|  | if (mwi->mci) | 
|  | { | 
|  | mci_generic.dwCallback = 0; | 
|  | mwi->lasterror = mciSendCommandW(mwi->mci, MCI_CLOSE, | 
|  | 0, (DWORD_PTR)&mci_generic); | 
|  | mwi->mci = 0; | 
|  | } | 
|  |  | 
|  | mwi->mode = MCI_MODE_NOT_READY; | 
|  | mwi->position = -1; | 
|  |  | 
|  | HeapFree(GetProcessHeap(), 0, mwi->lpName); | 
|  | mwi->lpName = NULL; | 
|  | MCIWND_UpdateState(mwi); | 
|  |  | 
|  | GetClientRect(hWnd, &rc); | 
|  | rc.bottom = rc.top; | 
|  | if (!(mwi->dwStyle & MCIWNDF_NOPLAYBAR)) | 
|  | rc.bottom += 32; /* add the height of the playbar */ | 
|  | AdjustWindowRect(&rc, GetWindowLongW(hWnd, GWL_STYLE), FALSE); | 
|  | SetWindowPos(hWnd, 0, 0, 0, rc.right - rc.left, | 
|  | rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); | 
|  |  | 
|  | MCIWND_notify_media(mwi); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | case MCI_PAUSE: | 
|  | case MCI_STEP: | 
|  | case MCI_STOP: | 
|  | case MCI_RESUME: | 
|  | mci_generic_command(mwi, wMsg); | 
|  | if (wMsg == MCI_STEP && !mwi->lasterror) | 
|  | { | 
|  | /* update window to reflect the state */ | 
|  | InvalidateRect(hWnd, NULL, TRUE); | 
|  | } | 
|  | return mwi->lasterror; | 
|  |  | 
|  | case MCI_CONFIGURE: | 
|  | if (mwi->hdrv) | 
|  | SendDriverMessage(mwi->hdrv, DRV_CONFIGURE, (LPARAM)hWnd, 0); | 
|  | return 0; | 
|  |  | 
|  | case MCI_BREAK: | 
|  | case MCI_CAPTURE: | 
|  | case MCI_COPY: | 
|  | case MCI_CUE: | 
|  | case MCI_CUT: | 
|  | case MCI_DELETE: | 
|  | case MCI_ESCAPE: | 
|  | case MCI_FREEZE: | 
|  | case MCI_GETDEVCAPS: | 
|  | /*case MCI_INDEX:*/ | 
|  | case MCI_INFO: | 
|  | case MCI_LIST: | 
|  | case MCI_LOAD: | 
|  | /*case MCI_MARK:*/ | 
|  | case MCI_MONITOR: | 
|  | case MCI_OPEN: | 
|  | case MCI_PASTE: | 
|  | case MCI_PUT: | 
|  | case MCI_QUALITY: | 
|  | case MCI_REALIZE: | 
|  | case MCI_RECORD: | 
|  | case MCI_RESERVE: | 
|  | case MCI_RESTORE: | 
|  | case MCI_SAVE: | 
|  | case MCI_SET: | 
|  | case MCI_SETAUDIO: | 
|  | /*case MCI_SETTIMECODE:*/ | 
|  | /*case MCI_SETTUNER:*/ | 
|  | case MCI_SETVIDEO: | 
|  | case MCI_SIGNAL: | 
|  | case MCI_SPIN: | 
|  | case MCI_STATUS: | 
|  | case MCI_SYSINFO: | 
|  | case MCI_UNDO: | 
|  | case MCI_UNFREEZE: | 
|  | case MCI_UPDATE: | 
|  | case MCI_WHERE: | 
|  | case MCI_WINDOW: | 
|  | FIXME("support for MCI_ command %04x not implemented\n", wMsg); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if (wMsg >= WM_USER) | 
|  | { | 
|  | FIXME("support for MCIWNDM_ message WM_USER+%d not implemented\n", wMsg - WM_USER); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if (GetWindowLongW(hWnd, GWL_EXSTYLE) & WS_EX_MDICHILD) | 
|  | return DefMDIChildProcW(hWnd, wMsg, wParam, lParam); | 
|  |  | 
|  | return DefWindowProcW(hWnd, wMsg, wParam, lParam); | 
|  | } |