📄 mmio.c
字号:
/*
* MMIO functions
*
* Copyright 1998 Andrew Taylor
* Copyright 1998 Ove K鍁en
* Copyright 2000,2002 Eric Pouech
*
* 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
*/
/* Still to be done:
* + correct handling of global/local IOProcs (and temporary IOProcs)
* + mode of mmio objects is not used (read vs write vs readwrite)
* + thread safeness
* + 32 A <=> W message mapping
*/
#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "windef.h"
#include "winbase.h"
#include "winnls.h"
#include "mmsystem.h"
#include "winemm.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(mmio);
LRESULT (*pFnMmioCallback16)(DWORD,LPMMIOINFO,UINT,LPARAM,LPARAM) /* = NULL */;
/**************************************************************************
* mmioDosIOProc [internal]
*/
static LRESULT CALLBACK mmioDosIOProc(LPMMIOINFO lpmmioinfo, UINT uMessage,
LPARAM lParam1, LPARAM lParam2)
{
LRESULT ret = MMSYSERR_NOERROR;
TRACE("(%p, %X, 0x%lx, 0x%lx);\n", lpmmioinfo, uMessage, lParam1, lParam2);
switch (uMessage) {
case MMIOM_OPEN:
{
/* Parameters:
* lParam1 = szFileName parameter from mmioOpen
* lParam2 = reserved
* Returns: zero on success, error code on error
* NOTE: lDiskOffset automatically set to zero
*/
LPCSTR szFileName = (LPCSTR)lParam1;
if (lpmmioinfo->dwFlags & MMIO_GETTEMP) {
FIXME("MMIO_GETTEMP not implemented\n");
return MMIOERR_CANNOTOPEN;
}
/* if filename NULL, assume open file handle in adwInfo[0] */
if (szFileName) {
OFSTRUCT ofs;
lpmmioinfo->adwInfo[0] = (DWORD)OpenFile(szFileName, &ofs, lpmmioinfo->dwFlags & 0xFFFF);
}
if (lpmmioinfo->adwInfo[0] == (DWORD)HFILE_ERROR)
ret = MMIOERR_CANNOTOPEN;
}
break;
case MMIOM_CLOSE:
/* Parameters:
* lParam1 = wFlags parameter from mmioClose
* lParam2 = unused
* Returns: zero on success, error code on error
*/
if (!(lParam1 & MMIO_FHOPEN))
_lclose((HFILE)lpmmioinfo->adwInfo[0]);
break;
case MMIOM_READ:
/* Parameters:
* lParam1 = huge pointer to read buffer
* lParam2 = number of bytes to read
* Returns: number of bytes read, 0 for EOF, -1 for error (error code
* in wErrorRet)
*/
ret = _lread((HFILE)lpmmioinfo->adwInfo[0], (HPSTR)lParam1, (LONG)lParam2);
if (ret != -1)
lpmmioinfo->lDiskOffset += ret;
break;
case MMIOM_WRITE:
case MMIOM_WRITEFLUSH:
/* no internal buffering, so WRITEFLUSH handled same as WRITE */
/* Parameters:
* lParam1 = huge pointer to write buffer
* lParam2 = number of bytes to write
* Returns: number of bytes written, -1 for error (error code in
* wErrorRet)
*/
ret = _hwrite((HFILE)lpmmioinfo->adwInfo[0], (HPSTR)lParam1, (LONG)lParam2);
if (ret != -1)
lpmmioinfo->lDiskOffset += ret;
break;
case MMIOM_SEEK:
/* Parameters:
* lParam1 = new position
* lParam2 = from whence to seek (SEEK_SET, SEEK_CUR, SEEK_END)
* Returns: new file postion, -1 on error
*/
ret = _llseek((HFILE)lpmmioinfo->adwInfo[0], (LONG)lParam1, (LONG)lParam2);
if (ret != -1)
lpmmioinfo->lDiskOffset = ret;
return ret;
case MMIOM_RENAME:
/* Parameters:
* lParam1 = old name
* lParam2 = new name
* Returns: zero on success, non-zero on failure
*/
if (!MoveFileA((const char*)lParam1, (const char*)lParam2))
ret = MMIOERR_FILENOTFOUND;
break;
default:
FIXME("unexpected message %u\n", uMessage);
return 0;
}
return ret;
}
/**************************************************************************
* mmioMemIOProc [internal]
*/
static LRESULT CALLBACK mmioMemIOProc(LPMMIOINFO lpmmioinfo, UINT uMessage,
LPARAM lParam1, LPARAM lParam2)
{
TRACE("(%p,0x%04x,0x%08lx,0x%08lx)\n", lpmmioinfo, uMessage, lParam1, lParam2);
switch (uMessage) {
case MMIOM_OPEN:
/* Parameters:
* lParam1 = filename (must be NULL)
* lParam2 = reserved
* Returns: zero on success, error code on error
* NOTE: lDiskOffset automatically set to zero
*/
/* FIXME: io proc shouldn't change it */
if (!(lpmmioinfo->dwFlags & MMIO_CREATE))
lpmmioinfo->pchEndRead = lpmmioinfo->pchEndWrite;
lpmmioinfo->adwInfo[0] = HFILE_ERROR;
return 0;
case MMIOM_CLOSE:
/* Parameters:
* lParam1 = wFlags parameter from mmioClose
* lParam2 = unused
* Returns: zero on success, error code on error
*/
return 0;
case MMIOM_READ:
/* Parameters:
* lParam1 = huge pointer to read buffer
* lParam2 = number of bytes to read
* Returns: number of bytes read, 0 for EOF, -1 for error (error code
* in wErrorRet)
* NOTE: lDiskOffset should be updated
*/
FIXME("MMIOM_READ on memory files should not occur, buffer may be lost!\n");
return 0;
case MMIOM_WRITE:
case MMIOM_WRITEFLUSH:
/* no internal buffering, so WRITEFLUSH handled same as WRITE */
/* Parameters:
* lParam1 = huge pointer to write buffer
* lParam2 = number of bytes to write
* Returns: number of bytes written, -1 for error (error code in
* wErrorRet)
* NOTE: lDiskOffset should be updated
*/
FIXME("MMIOM_WRITE on memory files should not occur, buffer may be lost!\n");
return 0;
case MMIOM_SEEK:
/* Parameters:
* lParam1 = new position
* lParam2 = from whence to seek (SEEK_SET, SEEK_CUR, SEEK_END)
* Returns: new file postion, -1 on error
* NOTE: lDiskOffset should be updated
*/
FIXME("MMIOM_SEEK on memory files should not occur, buffer may be lost!\n");
return -1;
default:
FIXME("unexpected message %u\n", uMessage);
return 0;
}
}
/* This array will be the entire list for most apps
* Note that temporary ioProcs will be stored with a 0 fourCC code
*/
static struct IOProcList defaultProcs[] = {
{&defaultProcs[1], FOURCC_DOS, (LPMMIOPROC)mmioDosIOProc, MMIO_PROC_32A, 0},
{NULL, FOURCC_MEM, (LPMMIOPROC)mmioMemIOProc, MMIO_PROC_32A, 0},
};
static struct IOProcList* pIOProcListAnchor = &defaultProcs[0];
/****************************************************************
* MMIO_FindProcNode [INTERNAL]
*
* Finds the ProcList node associated with a given FOURCC code.
*/
static struct IOProcList* MMIO_FindProcNode(FOURCC fccIOProc)
{
struct IOProcList* pListNode;
for (pListNode = pIOProcListAnchor; pListNode; pListNode = pListNode->pNext) {
if (pListNode->fourCC == fccIOProc) {
return pListNode;
}
}
return NULL;
}
/****************************************************************
* MMIO_InstallIOProc [INTERNAL]
*/
LPMMIOPROC MMIO_InstallIOProc(FOURCC fccIOProc, LPMMIOPROC pIOProc,
DWORD dwFlags, enum mmioProcType type)
{
LPMMIOPROC lpProc = NULL;
struct IOProcList* pListNode;
struct IOProcList** ppListNode;
TRACE("(%08lx, %p, %08lX, %i)\n", fccIOProc, pIOProc, dwFlags, type);
if (dwFlags & MMIO_GLOBALPROC)
FIXME("Global procedures not implemented\n");
/* just handle the known procedures for now */
switch (dwFlags & (MMIO_INSTALLPROC|MMIO_REMOVEPROC|MMIO_FINDPROC)) {
case MMIO_INSTALLPROC:
/* Create new entry for the IOProc list */
pListNode = HeapAlloc(GetProcessHeap(), 0, sizeof(*pListNode));
if (pListNode) {
/* Fill in this node */
pListNode->fourCC = fccIOProc;
pListNode->pIOProc = pIOProc;
pListNode->type = type;
pListNode->count = 0;
/* Stick it on the end of the list */
pListNode->pNext = pIOProcListAnchor;
pIOProcListAnchor = pListNode;
/* Return this IOProc - that's how the caller knows we succeeded */
lpProc = pIOProc;
}
break;
case MMIO_REMOVEPROC:
/*
* Search for the node that we're trying to remove
* We search for a matching fourCC code if it's non null, or the proc
* address otherwise
* note that this method won't find the first item on the list, but
* since the first two items on this list are ones we won't
* let the user delete anyway, that's okay
*/
ppListNode = &pIOProcListAnchor;
while ((*ppListNode) &&
((fccIOProc != 0) ?
(*ppListNode)->fourCC != fccIOProc :
(*ppListNode)->pIOProc != pIOProc))
ppListNode = &((*ppListNode)->pNext);
if (*ppListNode) { /* found it */
/* FIXME: what should be done if an open mmio object uses this proc ?
* shall we return an error, nuke the mmio object ?
*/
if ((*ppListNode)->count) {
ERR("Cannot remove a mmIOProc while in use\n");
break;
}
/* remove it, but only if it isn't builtin */
if ((*ppListNode) >= defaultProcs &&
(*ppListNode) < defaultProcs + sizeof(defaultProcs)) {
WARN("Tried to remove built-in mmio proc. Skipping\n");
} else {
/* Okay, nuke it */
struct IOProcList* ptmpNode = *ppListNode;
lpProc = (*ppListNode)->pIOProc;
*ppListNode = (*ppListNode)->pNext;
HeapFree(GetProcessHeap(), 0, ptmpNode);
}
}
break;
case MMIO_FINDPROC:
if ((pListNode = MMIO_FindProcNode(fccIOProc))) {
lpProc = pListNode->pIOProc;
}
break;
}
return lpProc;
}
/****************************************************************
* send_message [INTERNAL]
*/
static LRESULT send_message(struct IOProcList* ioProc, LPMMIOINFO mmioinfo,
DWORD wMsg, LPARAM lParam1,
LPARAM lParam2, enum mmioProcType type)
{
LRESULT result = MMSYSERR_ERROR;
LPARAM lp1 = lParam1, lp2 = lParam2;
if (!ioProc) {
ERR("brrr\n");
result = MMSYSERR_INVALPARAM;
}
switch (ioProc->type) {
case MMIO_PROC_16:
if (pFnMmioCallback16)
result = pFnMmioCallback16((DWORD)ioProc->pIOProc,
mmioinfo, wMsg, lp1, lp2);
break;
case MMIO_PROC_32A:
case MMIO_PROC_32W:
if (ioProc->type != type) {
/* map (lParam1, lParam2) into (lp1, lp2) 32 A<=>W */
FIXME("NIY 32 A<=>W mapping\n");
}
result = (ioProc->pIOProc)((LPSTR)mmioinfo, wMsg, lp1, lp2);
#if 0
if (ioProc->type != type) {
/* unmap (lParam1, lParam2) into (lp1, lp2) 32 A<=>W */
}
#endif
break;
default:
FIXME("Internal error\n");
}
return result;
}
/**************************************************************************
* MMIO_ParseExtA [internal]
*
* Parses a filename for the extension.
*
* RETURNS
* The FOURCC code for the extension if found, else 0.
*/
static FOURCC MMIO_ParseExtA(LPCSTR szFileName)
{
/* Filenames are of the form file.ext{+ABC}
For now, we take the last '+' if present */
FOURCC ret = 0;
/* Note that ext{Start,End} point to the . and + respectively */
LPSTR extEnd;
LPSTR extStart;
TRACE("(%s)\n", debugstr_a(szFileName));
if (!szFileName)
return ret;
/* Find the last '.' */
extStart = strrchr(szFileName,'.');
if (!extStart) {
ERR("No . in szFileName: %s\n", debugstr_a(szFileName));
} else {
CHAR ext[5];
/* Find the '+' afterwards */
extEnd = strchr(extStart,'+');
if (extEnd) {
if (extEnd - extStart - 1 > 4)
WARN("Extension length > 4\n");
lstrcpynA(ext, extStart + 1, min(extEnd-extStart,5));
} else {
/* No + so just an extension */
if (strlen(extStart) > 4) {
WARN("Extension length > 4\n");
}
lstrcpynA(ext, extStart + 1, 5);
}
TRACE("Got extension: %s\n", debugstr_a(ext));
/* FOURCC codes identifying file-extensions must be uppercase */
ret = mmioStringToFOURCCA(ext, MMIO_TOUPPER);
}
return ret;
}
/**************************************************************************
* MMIO_Get [internal]
*
* Retrieves the mmio object from current process
*/
LPWINE_MMIO MMIO_Get(HMMIO h)
{
LPWINE_MMIO wm = NULL;
EnterCriticalSection(&WINMM_IData.cs);
for (wm = WINMM_IData.lpMMIO; wm; wm = wm->lpNext) {
if (wm->info.hmmio == h)
break;
}
LeaveCriticalSection(&WINMM_IData.cs);
return wm;
}
/**************************************************************************
* MMIO_Create [internal]
*
* Creates an internal representation for a mmio instance
*/
static LPWINE_MMIO MMIO_Create(void)
{
static WORD MMIO_counter = 0;
LPWINE_MMIO wm;
wm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MMIO));
if (wm) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -