mciwnd.c 44.3 KB
Newer Older
1
/*
2
 * Copyright 2000 Eric Pouech
3
 * Copyright 2003 Dmitry Timoshkov
4 5 6 7 8 9 10 11 12 13 14 15 16
 *
 * 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
17
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 19
 *
 * FIXME:
20
 * Add support for all remaining MCI_ commands and MCIWNDM_ messages.
21
 * Add support for MCIWNDF_RECORD.
22 23
 */

24
#include <stdarg.h>
25 26

#include "windef.h"
27
#include "winbase.h"
28 29 30
#include "winnls.h"
#include "wingdi.h"
#include "winuser.h"
31
#include "winternl.h"
32 33 34
#include "vfw.h"
#include "digitalv.h"
#include "commctrl.h"
35
#include "wine/debug.h"
36

37
WINE_DEFAULT_DEBUG_CHANNEL(mci);
38

39 40 41 42 43 44 45
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;
46 47
    HDRVR       hdrv;
    int         alias;
48
    UINT        dev_type;
49
    UINT        mode;
50
    LONG        position;
51 52
    SIZE        size; /* size of the original frame rect */
    int         zoom;
53 54 55 56
    LPWSTR      lpName;
    HWND        hWnd, hwndOwner;
    UINT        uTimer;
    MCIERROR    lasterror;
57 58
    WCHAR       return_string[128];
    WORD        active_timer, inactive_timer;
59 60
} MCIWndInfo;

61 62 63 64 65
static LRESULT WINAPI MCIWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam);

#define CTL_PLAYSTOP    0x3200
#define CTL_MENU        0x3201
#define CTL_TRACKBAR    0x3202
66 67

/***********************************************************************
68 69 70
 *                MCIWndRegisterClass                [MSVFW32.@]
 *
 * NOTE: Native always uses its own hInstance
71
 */
72
BOOL VFWAPIV MCIWndRegisterClass(void)
73
{
74 75
    WNDCLASSW wc;

76 77 78 79 80 81 82
    /* 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;
83 84 85 86 87
    wc.lpfnWndProc = MCIWndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = sizeof(MCIWndInfo*);
    wc.hInstance = MSVFW32_hModule;
    wc.hIcon = 0;
88
    wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
89 90 91 92
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = mciWndClassW;

93 94 95 96
    if (RegisterClassW(&wc)) return TRUE;
    if (GetLastError() == ERROR_CLASS_ALREADY_EXISTS) return TRUE;

    return FALSE;
97 98 99
}

/***********************************************************************
100
 *                MCIWndCreateW                                [MSVFW32.@]
101
 */
102 103
HWND VFWAPIV MCIWndCreateW(HWND hwndParent, HINSTANCE hInstance,
                           DWORD dwStyle, LPCWSTR szFile)
104
{
105
    TRACE("%p %p %x %s\n", hwndParent, hInstance, dwStyle, debugstr_w(szFile));
106

107
    MCIWndRegisterClass();
108

109 110
    if (!hInstance) hInstance = GetModuleHandleW(0);

111 112 113 114
    if (hwndParent)
        dwStyle |= WS_VISIBLE | WS_BORDER /*| WS_CHILD*/;
    else
        dwStyle |= WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
115

116 117 118 119
    return CreateWindowExW(0, mciWndClassW, NULL,
                           dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
                           0, 0, 300, 0,
                           hwndParent, 0, hInstance, (LPVOID)szFile);
120 121 122
}

/***********************************************************************
123 124
 *                MCIWndCreate                [MSVFW32.@]
 *                MCIWndCreateA                [MSVFW32.@]
125
 */
126 127
HWND VFWAPIV MCIWndCreateA(HWND hwndParent, HINSTANCE hInstance,
                           DWORD dwStyle, LPCSTR szFile)
128
{
129 130
    HWND ret;
    UNICODE_STRING fileW;
131

132 133 134 135
    if (szFile)
        RtlCreateUnicodeStringFromAsciiz(&fileW, szFile);
    else
        fileW.Buffer = NULL;
136

137
    ret = MCIWndCreateW(hwndParent, hInstance, dwStyle, fileW.Buffer);
138

139 140
    RtlFreeUnicodeString(&fileW);
    return ret;
141 142
}

143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
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)
    {
160
        LONG new_pos = SendMessageW(mwi->hWnd, MCIWNDM_GETPOSITIONW, 0, 0);
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
        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)
182
{
183 184
    WCHAR buffer[1024];

185 186 187 188 189 190 191 192 193 194 195 196 197
    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);

198 199 200
    if (!(mwi->dwStyle & MCIWNDF_SHOWALL))
        return;

201
    if ((mwi->dwStyle & MCIWNDF_SHOWNAME) && mwi->lpName)
202
        lstrcpyW(buffer, mwi->lpName);
203 204 205 206 207 208 209 210
    else
        *buffer = 0;

    if (mwi->dwStyle & (MCIWNDF_SHOWPOS|MCIWNDF_SHOWMODE))
    {
        static const WCHAR spaceW[] = {' ',0};
        static const WCHAR l_braceW[] = {'(',0};

211 212
        if (*buffer) lstrcatW(buffer, spaceW);
        lstrcatW(buffer, l_braceW);
213 214 215 216
    }

    if (mwi->dwStyle & MCIWNDF_SHOWPOS)
    {
217 218 219 220
        WCHAR posW[64];

        posW[0] = 0;
        SendMessageW(mwi->hWnd, MCIWNDM_GETPOSITIONW, 64, (LPARAM)posW);
221
        lstrcatW(buffer, posW);
222 223 224 225 226
    }

    if ((mwi->dwStyle & (MCIWNDF_SHOWPOS|MCIWNDF_SHOWMODE)) == (MCIWNDF_SHOWPOS|MCIWNDF_SHOWMODE))
    {
        static const WCHAR dashW[] = {' ','-',' ',0};
227
        lstrcatW(buffer, dashW);
228 229 230 231
    }

    if (mwi->dwStyle & MCIWNDF_SHOWMODE)
    {
232 233 234 235
        WCHAR modeW[64];

        modeW[0] = 0;
        SendMessageW(mwi->hWnd, MCIWNDM_GETMODEW, 64, (LPARAM)modeW);
236
        lstrcatW(buffer, modeW);
237 238 239 240
    }

    if (mwi->dwStyle & (MCIWNDF_SHOWPOS|MCIWNDF_SHOWMODE))
    {
241
        static const WCHAR r_braceW[] = {')',0};
242
        lstrcatW(buffer, r_braceW);
243 244
    }

245
    TRACE("=> %s\n", debugstr_w(buffer));
246
    SetWindowTextW(mwi->hWnd, buffer);
247 248
}

249
static LRESULT MCIWND_Create(HWND hWnd, LPCREATESTRUCTW cs)
250
{
251 252 253 254
    HWND hChld;
    MCIWndInfo *mwi;
    static const WCHAR buttonW[] = {'b','u','t','t','o','n',0};

255
    mwi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*mwi));
256 257 258 259 260
    if (!mwi) return -1;

    SetWindowLongW(hWnd, 0, (LPARAM)mwi);

    mwi->dwStyle = cs->style;
261 262 263 264
    /* There is no need to show stats if there is no caption */
    if ((mwi->dwStyle & WS_CAPTION) != WS_CAPTION)
        mwi->dwStyle &= ~MCIWNDF_SHOWALL;

265 266
    mwi->hWnd = hWnd;
    mwi->hwndOwner = cs->hwndParent;
267 268 269 270 271
    mwi->active_timer = 500;
    mwi->inactive_timer = 2000;
    mwi->mode = MCI_MODE_NOT_READY;
    mwi->position = -1;
    mwi->zoom = 100;
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300

    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);
    }

301 302 303 304 305 306 307 308 309 310
    /* 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)
        {
311
            MDICREATESTRUCTW *mdics = cs->lpCreateParams;
312 313 314 315
            lParam = mdics->lParam;
        }
        else
            lParam = (LPARAM)cs->lpCreateParams;
316

317
        /* If it's our internal class pointer, file name is a unicode string */
318 319 320 321 322 323 324 325 326 327
        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);
        }
328
    }
329 330

    return 0;
331 332
}

333
static void MCIWND_ToggleState(MCIWndInfo *mwi)
334
{
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
    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;
    }
356 357
}

358
static LRESULT MCIWND_Command(MCIWndInfo *mwi, WPARAM wParam, LPARAM lParam)
359
{
360 361 362 363 364 365
    switch (LOWORD(wParam))
    {
    case CTL_PLAYSTOP: MCIWND_ToggleState(mwi); break;
    case CTL_MENU:
    case CTL_TRACKBAR:
    default:
366
        FIXME("support for command %04x not implement yet\n", LOWORD(wParam));
367 368
    }
    return 0L;
369 370
}

371
static void MCIWND_notify_media(MCIWndInfo *mwi)
372
{
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398
    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);
        }
    }
399 400
}

401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
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;
}

430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
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;
    }
}

445
static LRESULT WINAPI MCIWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
446
{
447
    MCIWndInfo *mwi;
448

449
    TRACE("%p %04x %08lx %08lx\n", hWnd, wMsg, wParam, lParam);
450

451
    mwi = (MCIWndInfo*)GetWindowLongPtrW(hWnd, 0);
452
    if (!mwi && wMsg != WM_CREATE)
453
        return DefWindowProcW(hWnd, wMsg, wParam, lParam);
454

455 456
    switch (wMsg)
    {
457 458 459 460
    case WM_CREATE:
        MCIWND_Create(hWnd, (CREATESTRUCTW *)lParam);
        break;

461 462 463
    case WM_DESTROY:
        if (mwi->uTimer)
            KillTimer(hWnd, mwi->uTimer);
464

465 466
        if (mwi->mci)
            SendMessageW(hWnd, MCI_CLOSE, 0, 0);
467 468

        HeapFree(GetProcessHeap(), 0, mwi);
469 470 471 472

        DestroyWindow(GetDlgItem(hWnd, CTL_MENU));
        DestroyWindow(GetDlgItem(hWnd, CTL_PLAYSTOP));
        DestroyWindow(GetDlgItem(hWnd, CTL_TRACKBAR));
473
        break;
474 475 476

    case WM_PAINT:
        {
477
            MCI_DGV_UPDATE_PARMS mci_update;
478 479
            PAINTSTRUCT ps;

480 481 482 483 484 485
            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);

486
            if (!wParam) EndPaint(hWnd, &ps);
487 488 489 490 491 492
            return 1;
        }

    case WM_COMMAND:
        return MCIWND_Command(mwi, wParam, lParam);

493 494 495
    case WM_KEYDOWN:
        return MCIWND_KeyDown(mwi, wParam);

496 497 498 499 500 501 502 503
    case WM_NCACTIVATE:
        if (mwi->uTimer)
        {
            KillTimer(hWnd, mwi->uTimer);
            mwi->uTimer = SetTimer(hWnd, 1, wParam ? mwi->active_timer : mwi->inactive_timer, NULL);
        }
        break;

504
    case WM_TIMER:
505
        MCIWND_UpdateState(mwi);
506 507 508
        return 0;

    case WM_SIZE:
509 510 511
        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);
512

513 514 515 516 517 518 519 520 521 522 523
        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);
        }
524 525
        MCIWND_notify_size(mwi);
        break;
526 527

    case MM_MCINOTIFY:
528 529
        MCIWND_notify_mode(mwi);
        MCIWND_UpdateState(mwi);
530 531 532 533 534
        return 0;

    case MCIWNDM_OPENA:
        {
            UNICODE_STRING nameW;
535
            TRACE("MCIWNDM_OPENA %s\n", debugstr_a((LPSTR)lParam));
536 537 538 539 540 541 542
            RtlCreateUnicodeStringFromAsciiz(&nameW, (LPCSTR)lParam);
            lParam = (LPARAM)nameW.Buffer;
        }
        /* fall through */
    case MCIWNDM_OPENW:
        {
            RECT rc;
543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
            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;
            }
559 560 561 562 563 564 565

            if (mwi->uTimer)
            {
                KillTimer(hWnd, mwi->uTimer);
                mwi->uTimer = 0;
            }

566 567 568 569
            hCursor = LoadCursorW(0, (LPWSTR)IDC_WAIT);
            hCursor = SetCursor(hCursor);

            mci_open.lpstrElementName = (LPWSTR)lParam;
570
            wsprintfW(aliasW, formatW, HandleToLong(hWnd) + 1);
571 572 573 574 575 576
            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);

577
            if (mwi->lasterror && !(mwi->dwStyle & MCIWNDF_NOERRORDLG))
578
            {
579 580 581 582 583 584 585 586 587
                /* 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;
            }
588

589
            mwi->mci = mci_open.wDeviceID;
590
            mwi->alias = HandleToLong(hWnd) + 1;
591

592 593
            mwi->lpName = HeapAlloc(GetProcessHeap(), 0, (lstrlenW((LPWSTR)lParam) + 1) * sizeof(WCHAR));
            lstrcpyW(mwi->lpName, (LPWSTR)lParam);
594

595
            MCIWND_UpdateState(mwi);
596

597 598 599 600 601 602 603 604 605
            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;
            }
606

607
            mwi->dev_type = mci_devcaps.dwReturn;
608

609 610 611 612 613
            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);
614

615 616 617 618 619 620 621 622
            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);
623 624
                if (mwi->lasterror)
                {
625
                    MCIWND_notify_error(mwi);
626 627
                    goto end_of_mci_open;
                }
628
            }
629

630 631 632 633
            if (SendMessageW(hWnd, MCIWNDM_GET_DEST, 0, (LPARAM)&rc) == 0)
            {
                mwi->size.cx = rc.right - rc.left;
                mwi->size.cy = rc.bottom - rc.top;
634

635 636 637
                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);
638
            }
639
            else
640 641 642 643 644 645 646
            {
                GetClientRect(hWnd, &rc);
                rc.bottom = rc.top;
            }

            if (!(mwi->dwStyle & MCIWNDF_NOPLAYBAR))
                rc.bottom += 32; /* add the height of the playbar */
647
            AdjustWindowRect(&rc, GetWindowLongW(hWnd, GWL_STYLE), FALSE);
648
            SetWindowPos(hWnd, 0, 0, 0, rc.right - rc.left,
649
                         rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
650 651

            SendDlgItemMessageW(hWnd, CTL_TRACKBAR, TBM_SETRANGEMIN, 0L, 0L);
652 653 654 655 656
            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);
657 658 659 660 661 662 663 664

end_of_mci_open:
            if (wMsg == MCIWNDM_OPENA)
                HeapFree(GetProcessHeap(), 0, (void *)lParam);
            return mwi->lasterror;
        }

    case MCIWNDM_GETDEVICEID:
665
        TRACE("MCIWNDM_GETDEVICEID\n");
666 667
        return mwi->mci;

668
    case MCIWNDM_GETALIAS:
669
        TRACE("MCIWNDM_GETALIAS\n");
670 671
        return mwi->alias;

672 673 674 675 676 677 678 679 680
    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)
            {
681
                MCIWND_notify_error(mwi);
682 683 684
                return mwi->lasterror;
            }
            *(RECT *)lParam = mci_rect.rc;
685
            TRACE("MCIWNDM_GET_SOURCE: %s\n", wine_dbgstr_rect(&mci_rect.rc));
686 687 688 689 690 691 692 693 694 695 696 697
            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)
            {
698
                MCIWND_notify_error(mwi);
699 700 701
                return mwi->lasterror;
            }
            *(RECT *)lParam = mci_rect.rc;
702
            TRACE("MCIWNDM_GET_DEST: %s\n", wine_dbgstr_rect(&mci_rect.rc));
703 704 705 706 707 708 709 710
            return 0;
        }

    case MCIWNDM_PUT_SOURCE:
        {
            MCI_DGV_PUT_PARMS mci_put;

            mci_put.rc = *(RECT *)lParam;
711
            TRACE("MCIWNDM_PUT_SOURCE: %s\n", wine_dbgstr_rect(&mci_put.rc));
712 713 714 715 716
            mwi->lasterror = mciSendCommandW(mwi->mci, MCI_PUT,
                                             MCI_DGV_PUT_SOURCE,
                                             (DWORD_PTR)&mci_put);
            if (mwi->lasterror)
            {
717
                MCIWND_notify_error(mwi);
718 719 720 721 722 723 724 725 726 727
                return mwi->lasterror;
            }
            return 0;
        }

    case MCIWNDM_PUT_DEST:
        {
            MCI_DGV_PUT_PARMS mci_put;

            mci_put.rc = *(RECT *)lParam;
728 729
            TRACE("MCIWNDM_PUT_DEST: %s\n", wine_dbgstr_rect(&mci_put.rc));

730
            mwi->lasterror = mciSendCommandW(mwi->mci, MCI_PUT,
731
                                             MCI_DGV_PUT_DESTINATION | MCI_DGV_RECT,
732 733 734
                                             (DWORD_PTR)&mci_put);
            if (mwi->lasterror)
            {
735
                MCIWND_notify_error(mwi);
736 737 738 739 740 741 742 743 744 745 746 747 748 749 750
                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)
            {
751
                MCIWND_notify_error(mwi);
752 753
                return 0;
            }
754
            TRACE("MCIWNDM_GETLENGTH: %ld\n", mci_status.dwReturn);
755 756 757 758 759 760 761 762 763 764 765 766 767
            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)
            {
768
                MCIWND_notify_error(mwi);
769 770
                return 0;
            }
771
            TRACE("MCIWNDM_GETSTART: %ld\n", mci_status.dwReturn);
772 773 774 775 776 777 778 779 780
            return mci_status.dwReturn;
        }

    case MCIWNDM_GETEND:
        {
            LRESULT start, length;

            start = SendMessageW(hWnd, MCIWNDM_GETSTART, 0, 0);
            length = SendMessageW(hWnd, MCIWNDM_GETLENGTH, 0, 0);
781
            TRACE("MCIWNDM_GETEND: %ld\n", start + length);
782 783 784 785 786 787 788 789
            return (start + length);
        }

    case MCIWNDM_GETPOSITIONA:
    case MCIWNDM_GETPOSITIONW:
        {
            MCI_STATUS_PARMS mci_status;

790 791
            TRACE("MCIWNDM_GETPOSITION\n");

792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815
            /* 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;
            }

816 817 818 819 820 821
            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;
822

823 824 825 826 827 828 829 830
            return mci_status.dwReturn;
        }

    case MCIWNDM_GETMODEA:
    case MCIWNDM_GETMODEW:
        {
            MCI_STATUS_PARMS mci_status;

831 832
            TRACE("MCIWNDM_GETMODE\n");

833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859
            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;
            }

860 861 862 863 864 865 866 867 868 869
            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;
        }

870 871 872 873
    case MCIWNDM_PLAYFROM:
        {
            MCI_PLAY_PARMS mci_play;

874 875
            TRACE("MCIWNDM_PLAYFROM %08lx\n", lParam);

876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891
            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;
        }

892 893 894 895
    case MCIWNDM_PLAYTO:
        {
            MCI_PLAY_PARMS mci_play;

896 897
            TRACE("MCIWNDM_PLAYTO %08lx\n", lParam);

898 899 900
            mci_play.dwCallback = (DWORD_PTR)hWnd;
            mci_play.dwTo = lParam;
            mwi->lasterror = mciSendCommandW(mwi->mci, MCI_PLAY,
901 902
                                             MCI_TO | MCI_NOTIFY,
                                             (DWORD_PTR)&mci_play);
903 904
            if (mwi->lasterror)
            {
905
                MCIWND_notify_error(mwi);
906 907
                return mwi->lasterror;
            }
908 909 910

            MCIWND_notify_mode(mwi);
            MCIWND_UpdateState(mwi);
911 912 913
            return 0;
        }

914 915 916 917 918
    case MCIWNDM_PLAYREVERSE:
        {
            MCI_PLAY_PARMS mci_play;
            DWORD flags = MCI_NOTIFY;

919 920
            TRACE("MCIWNDM_PLAYREVERSE %08lx\n", lParam);

921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958
            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:
959
        mciGetErrorStringA(mwi->lasterror, (LPSTR)lParam, wParam);
960
        TRACE("MCIWNDM_GETERRORA: %s\n", debugstr_an((LPSTR)lParam, wParam));
961 962
        return mwi->lasterror;

963
    case MCIWNDM_GETERRORW:
964
        mciGetErrorStringW(mwi->lasterror, (LPWSTR)lParam, wParam);
965
        TRACE("MCIWNDM_GETERRORW: %s\n", debugstr_wn((LPWSTR)lParam, wParam));
966 967 968
        return mwi->lasterror;

    case MCIWNDM_SETOWNER:
969
        TRACE("MCIWNDM_SETOWNER %p\n", (HWND)wParam);
970 971 972
        mwi->hwndOwner = (HWND)wParam;
        return 0;

973
    case MCIWNDM_SENDSTRINGA:
974
        {
975
            UNICODE_STRING stringW;
976 977 978

            TRACE("MCIWNDM_SENDSTRINGA %s\n", debugstr_a((LPCSTR)lParam));

979 980
            RtlCreateUnicodeStringFromAsciiz(&stringW, (LPCSTR)lParam);
            lParam = (LPARAM)stringW.Buffer;
981
        }
982 983 984 985
        /* fall through */
    case MCIWNDM_SENDSTRINGW:
        {
            WCHAR *cmdW, *p;
986

987 988
            TRACE("MCIWNDM_SENDSTRINGW %s\n", debugstr_w((LPCWSTR)lParam));

989
            p = wcschr((LPCWSTR)lParam, ' ');
990 991 992 993 994 995 996 997 998 999 1000 1001
            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);
1002
                lstrcatW(cmdW, (WCHAR *)lParam + pos);
1003 1004 1005 1006 1007
            }
            else
                cmdW = (LPWSTR)lParam;

            mwi->lasterror = mciSendStringW(cmdW, mwi->return_string,
1008
                                            ARRAY_SIZE(mwi->return_string), 0);
1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
            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);
1024
        TRACE("MCIWNDM_RETURNTRINGA %s\n", debugstr_an((LPSTR)lParam, wParam));
1025 1026 1027
        return mwi->lasterror;

    case MCIWNDM_RETURNSTRINGW:
1028
        lstrcpynW((LPWSTR)lParam, mwi->return_string, wParam);
1029
        TRACE("MCIWNDM_RETURNTRINGW %s\n", debugstr_wn((LPWSTR)lParam, wParam));
1030 1031 1032
        return mwi->lasterror;

    case MCIWNDM_SETTIMERS:
1033
        TRACE("MCIWNDM_SETTIMERS active %d ms, inactive %d ms\n", (int)wParam, (int)lParam);
1034 1035 1036 1037 1038
        mwi->active_timer = (WORD)wParam;
        mwi->inactive_timer = (WORD)lParam;
        return 0;

    case MCIWNDM_SETACTIVETIMER:
1039
        TRACE("MCIWNDM_SETACTIVETIMER %d ms\n", (int)wParam);
1040 1041 1042 1043
        mwi->active_timer = (WORD)wParam;
        return 0;

    case MCIWNDM_SETINACTIVETIMER:
1044
        TRACE("MCIWNDM_SETINACTIVETIMER %d ms\n", (int)wParam);
1045 1046 1047 1048
        mwi->inactive_timer = (WORD)wParam;
        return 0;

    case MCIWNDM_GETACTIVETIMER:
1049
        TRACE("MCIWNDM_GETACTIVETIMER: %d ms\n", mwi->active_timer);
1050 1051 1052
        return mwi->active_timer;

    case MCIWNDM_GETINACTIVETIMER:
1053
        TRACE("MCIWNDM_GETINACTIVETIMER: %d ms\n", mwi->inactive_timer);
1054 1055 1056
        return mwi->inactive_timer;

    case MCIWNDM_CHANGESTYLES:
1057
        TRACE("MCIWNDM_CHANGESTYLES mask %08lx, set %08lx\n", wParam, lParam);
1058 1059 1060 1061 1062 1063 1064 1065
        /* 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:
1066
        TRACE("MCIWNDM_GETSTYLES: %08x\n", mwi->dwStyle & 0xffff);
1067 1068 1069
        return mwi->dwStyle & 0xffff;

    case MCIWNDM_GETDEVICEA:
1070
        {
1071 1072
            int len = 0;
            char *str = (char *)lParam;
1073
            MCI_SYSINFO_PARMSA mci_sysinfo;
1074

1075
            mci_sysinfo.lpstrReturn = str;
1076 1077 1078 1079
            mci_sysinfo.dwRetSize = wParam;
            mwi->lasterror = mciSendCommandA(mwi->mci, MCI_SYSINFO,
                                             MCI_SYSINFO_INSTALLNAME,
                                             (DWORD_PTR)&mci_sysinfo);
1080 1081
            while(len < wParam && str[len]) len++;
            TRACE("MCIWNDM_GETDEVICEA: %s\n", debugstr_an(str, len));
1082 1083
            return 0;
        }
1084

1085 1086
    case MCIWNDM_GETDEVICEW:
        {
1087 1088
            int len = 0;
            WCHAR *str = (WCHAR *)lParam;
1089 1090
            MCI_SYSINFO_PARMSW mci_sysinfo;

1091
            mci_sysinfo.lpstrReturn = str;
1092 1093 1094 1095
            mci_sysinfo.dwRetSize = wParam;
            mwi->lasterror = mciSendCommandW(mwi->mci, MCI_SYSINFO,
                                             MCI_SYSINFO_INSTALLNAME,
                                             (DWORD_PTR)&mci_sysinfo);
1096 1097
            while(len < wParam && str[len]) len++;
            TRACE("MCIWNDM_GETDEVICEW: %s\n", debugstr_wn(str, len));
1098 1099 1100 1101
            return 0;
        }

    case MCIWNDM_VALIDATEMEDIA:
1102
        TRACE("MCIWNDM_VALIDATEMEDIA\n");
1103 1104 1105 1106 1107 1108 1109 1110
        if (mwi->mci)
        {
            SendMessageW(hWnd, MCIWNDM_GETSTART, 0, 0);
            SendMessageW(hWnd, MCIWNDM_GETLENGTH, 0, 0);
        }
        return 0;

    case MCIWNDM_GETFILENAMEA:
1111
        TRACE("MCIWNDM_GETFILENAMEA: %s\n", debugstr_w(mwi->lpName));
1112 1113 1114 1115 1116
        if (mwi->lpName)
            WideCharToMultiByte(CP_ACP, 0, mwi->lpName, -1, (LPSTR)lParam, wParam, NULL, NULL);
        return 0;

    case MCIWNDM_GETFILENAMEW:
1117
        TRACE("MCIWNDM_GETFILENAMEW: %s\n", debugstr_w(mwi->lpName));
1118
        if (mwi->lpName)
1119
            lstrcpynW((LPWSTR)lParam, mwi->lpName, wParam);
1120 1121 1122 1123 1124 1125 1126
        return 0;

    case MCIWNDM_GETTIMEFORMATA:
    case MCIWNDM_GETTIMEFORMATW:
        {
            MCI_STATUS_PARMS mci_status;

1127
            TRACE("MCIWNDM_GETTIMEFORMAT %08lx %08lx\n", wParam, lParam);
1128

1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156
            /* 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);
1157
            if (mwi->lasterror)
1158 1159 1160 1161 1162 1163 1164 1165 1166
                return 0;

            return mci_status.dwReturn;
        }

    case MCIWNDM_SETTIMEFORMATA:
        {
            UNICODE_STRING stringW;

1167 1168
            TRACE("MCIWNDM_SETTIMEFORMATA %s\n", debugstr_a((LPSTR)lParam));

1169 1170 1171 1172 1173 1174 1175 1176 1177
            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;

1178 1179
            TRACE("MCIWNDM_SETTIMEFORMATW %s\n", debugstr_w((LPWSTR)lParam));

1180
            if (mwi->mci)
1181
            {
1182 1183
                cmdW = HeapAlloc(GetProcessHeap(), 0, (lstrlenW((LPCWSTR)lParam) + 64) * sizeof(WCHAR));
                wsprintfW(cmdW, formatW, mwi->alias);
1184
                lstrcatW(cmdW, (WCHAR *)lParam);
1185 1186

                mwi->lasterror = mciSendStringW(cmdW, NULL, 0, 0);
1187 1188 1189 1190 1191

                /* 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));
1192 1193

                HeapFree(GetProcessHeap(), 0, cmdW);
1194
            }
1195 1196 1197 1198

            if (wMsg == MCIWNDM_SETTIMEFORMATA)
                HeapFree(GetProcessHeap(), 0, (void *)lParam);

1199 1200 1201
            return 0;
        }

1202
    case MCIWNDM_CAN_PLAY:
1203
        TRACE("MCIWNDM_CAN_PLAY\n");
1204 1205 1206 1207 1208
        if (mwi->mci)
            return mci_get_devcaps(mwi, MCI_GETDEVCAPS_CAN_PLAY);
        return 0;

    case MCIWNDM_CAN_RECORD:
1209
        TRACE("MCIWNDM_CAN_RECORD\n");
1210 1211 1212 1213 1214
        if (mwi->mci)
            return mci_get_devcaps(mwi, MCI_GETDEVCAPS_CAN_RECORD);
        return 0;

    case MCIWNDM_CAN_SAVE:
1215
        TRACE("MCIWNDM_CAN_SAVE\n");
1216 1217 1218 1219 1220
        if (mwi->mci)
            return mci_get_devcaps(mwi, MCI_GETDEVCAPS_CAN_SAVE);
        return 0;

    case MCIWNDM_CAN_EJECT:
1221
        TRACE("MCIWNDM_CAN_EJECT\n");
1222 1223 1224 1225 1226
        if (mwi->mci)
            return mci_get_devcaps(mwi, MCI_GETDEVCAPS_CAN_EJECT);
        return 0;

    case MCIWNDM_CAN_WINDOW:
1227
        TRACE("MCIWNDM_CAN_WINDOW\n");
1228 1229 1230 1231 1232 1233 1234 1235 1236 1237
        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:
1238
        TRACE("MCIWNDM_CAN_CONFIG\n");
1239 1240 1241 1242 1243
        if (mwi->hdrv)
            return SendDriverMessage(mwi->hdrv, DRV_QUERYCONFIGURE, 0, 0);
        return 0;

    case MCIWNDM_SETZOOM:
1244
        TRACE("MCIWNDM_SETZOOM %ld\n", lParam);
1245 1246
        mwi->zoom = lParam;

1247
        if (mwi->mci && !(mwi->dwStyle & MCIWNDF_NOAUTOSIZEWINDOW))
1248 1249 1250
        {
            RECT rc;

1251
            rc.left = rc.top = 0;
1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263
            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:
1264
        TRACE("MCIWNDM_GETZOOM: %d\n", mwi->zoom);
1265 1266 1267 1268 1269 1270
        return mwi->zoom;

    case MCIWNDM_EJECT:
        {
            MCI_SET_PARMS mci_set;

1271 1272
            TRACE("MCIWNDM_EJECT\n");

1273
            mci_set.dwCallback = (DWORD_PTR)hWnd;
1274 1275 1276
            mwi->lasterror = mciSendCommandW(mwi->mci, MCI_SET,
                                             MCI_SET_DOOR_OPEN | MCI_NOTIFY,
                                             (DWORD_PTR)&mci_set);
1277 1278
            MCIWND_notify_mode(mwi);
            MCIWND_UpdateState(mwi);
1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303
            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);
        }

1304
    case MCI_SEEK:
1305
    case MCI_STEP:
1306
        {
1307
            MCI_SEEK_PARMS mci_seek; /* Layout is usable as MCI_XYZ_STEP_PARMS */
1308 1309 1310
            DWORD flags = MCI_STEP == wMsg ? 0 :
                          MCIWND_START == lParam ? MCI_SEEK_TO_START :
                          MCIWND_END   == lParam ? MCI_SEEK_TO_END : MCI_TO;
1311 1312

            mci_seek.dwTo = lParam;
1313 1314
            mwi->lasterror = mciSendCommandW(mwi->mci, wMsg,
                                             flags, (DWORD_PTR)&mci_seek);
1315 1316
            if (mwi->lasterror)
            {
1317
                MCIWND_notify_error(mwi);
1318 1319
                return mwi->lasterror;
            }
1320
            /* update window to reflect the state */
1321
            else InvalidateRect(hWnd, NULL, TRUE);
1322 1323 1324 1325 1326
            return 0;
        }

    case MCI_CLOSE:
        {
1327
            RECT rc;
1328 1329
            MCI_GENERIC_PARMS mci_generic;

1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342
            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;
            }
1343

1344 1345 1346
            mwi->mode = MCI_MODE_NOT_READY;
            mwi->position = -1;

1347 1348
            HeapFree(GetProcessHeap(), 0, mwi->lpName);
            mwi->lpName = NULL;
1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359
            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);
1360
            return 0;
1361
        }
1362 1363 1364 1365

    case MCI_PAUSE:
    case MCI_STOP:
    case MCI_RESUME:
1366 1367
        mci_generic_command(mwi, wMsg);
        return mwi->lasterror;
1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413

    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;
1414 1415
    }

1416
    if (wMsg >= WM_USER)
1417
    {
1418 1419
        FIXME("support for MCIWNDM_ message WM_USER+%d not implemented\n", wMsg - WM_USER);
        return 0;
1420
    }
1421

1422 1423 1424
    if (GetWindowLongW(hWnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
        return DefMDIChildProcW(hWnd, wMsg, wParam, lParam);

1425
    return DefWindowProcW(hWnd, wMsg, wParam, lParam);
1426
}