📄 mciwnd.c
字号:
/*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 "winreg.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 %lx %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 = (MDICREATESTRUCTW *)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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -