1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
5 * Copyright 1998 Andrew Taylor
6 * Copyright 1998 Ove Kåven
7 * Copyright 2000 Eric Pouech
11 * + correct handling of global/local IOProcs
12 * + mode of mmio objects is not used (read vs write vs readwrite)
13 * + optimization of internal buffers (seg / lin)
14 * + even in 32 bit only, a seg ptr IO buffer is allocated (after this is
15 * fixed, we'll have a proper 32/16 separation)
17 * + rename operation is broken
26 #include "wine/winbase16.h"
29 #include "debugtools.h"
32 DEFAULT_DEBUG_CHANNEL(mmio
);
34 /**************************************************************************
35 * mmioDosIOProc [internal]
37 static LRESULT CALLBACK
mmioDosIOProc(LPMMIOINFO lpmmioinfo
, UINT uMessage
,
38 LPARAM lParam1
, LPARAM lParam2
)
40 LRESULT ret
= MMSYSERR_NOERROR
;
42 TRACE("(%p, %X, %ld, %ld);\n", lpmmioinfo
, uMessage
, lParam1
, lParam2
);
48 * lParam1 = szFileName parameter from mmioOpen
49 * lParam2 = reserved (we use it for 16-bitness)
50 * Returns: zero on success, error code on error
51 * NOTE: lDiskOffset automatically set to zero
54 LPCSTR szFileName
= (LPCSTR
)lParam1
;
56 if (lpmmioinfo
->dwFlags
& MMIO_GETTEMP
) {
57 FIXME("MMIO_GETTEMP not implemented\n");
58 return MMIOERR_CANNOTOPEN
;
61 /* if filename NULL, assume open file handle in adwInfo[0] */
64 lpmmioinfo
->adwInfo
[0] = DosFileHandleToWin32Handle(lpmmioinfo
->adwInfo
[0]);
68 lpmmioinfo
->adwInfo
[0] = (DWORD
)OpenFile(szFileName
, &ofs
,
70 if (lpmmioinfo
->adwInfo
[0] == -1)
71 ret
= MMIOERR_CANNOTOPEN
;
77 * lParam1 = wFlags parameter from mmioClose
79 * Returns: zero on success, error code on error
81 if (!(lParam1
& MMIO_FHOPEN
))
82 _lclose((HFILE
)lpmmioinfo
->adwInfo
[0]);
87 * lParam1 = huge pointer to read buffer
88 * lParam2 = number of bytes to read
89 * Returns: number of bytes read, 0 for EOF, -1 for error (error code
92 ret
= _lread((HFILE
)lpmmioinfo
->adwInfo
[0], (HPSTR
)lParam1
, (LONG
)lParam2
);
94 lpmmioinfo
->lDiskOffset
+= ret
;
99 case MMIOM_WRITEFLUSH
:
100 /* no internal buffering, so WRITEFLUSH handled same as WRITE */
103 * lParam1 = huge pointer to write buffer
104 * lParam2 = number of bytes to write
105 * Returns: number of bytes written, -1 for error (error code in
108 ret
= _hwrite((HFILE
)lpmmioinfo
->adwInfo
[0], (HPSTR
)lParam1
, (LONG
)lParam2
);
110 lpmmioinfo
->lDiskOffset
+= ret
;
115 * lParam1 = new position
116 * lParam2 = from whence to seek (SEEK_SET, SEEK_CUR, SEEK_END)
117 * Returns: new file postion, -1 on error
119 ret
= _llseek((HFILE
)lpmmioinfo
->adwInfo
[0], (LONG
)lParam1
, (LONG
)lParam2
);
121 lpmmioinfo
->lDiskOffset
= ret
;
128 * Returns: zero on success, non-zero on failure
130 FIXME("MMIOM_RENAME incomplete\n");
131 if (!MoveFileA((const char*)lParam1
, (const char*)lParam2
))
132 ret
= MMIOERR_FILENOTFOUND
;
136 FIXME("unexpected message %u\n", uMessage
);
143 /**************************************************************************
144 * mmioMemIOProc [internal]
146 static LRESULT CALLBACK
mmioMemIOProc(LPMMIOINFO lpmmioinfo
, UINT uMessage
,
147 LPARAM lParam1
, LPARAM lParam2
)
149 TRACE("(%p,0x%04x,0x%08lx,0x%08lx)\n", lpmmioinfo
, uMessage
, lParam1
, lParam2
);
155 * lParam1 = filename (must be NULL)
156 * lParam2 = reserved (we use it for 16-bitness)
157 * Returns: zero on success, error code on error
158 * NOTE: lDiskOffset automatically set to zero
160 /* FIXME: io proc shouldn't change it */
161 if (!(lpmmioinfo
->dwFlags
& MMIO_CREATE
))
162 lpmmioinfo
->pchEndRead
= lpmmioinfo
->pchEndWrite
;
167 * lParam1 = wFlags parameter from mmioClose
169 * Returns: zero on success, error code on error
175 * lParam1 = huge pointer to read buffer
176 * lParam2 = number of bytes to read
177 * Returns: number of bytes read, 0 for EOF, -1 for error (error code
179 * NOTE: lDiskOffset should be updated
181 FIXME("MMIOM_READ on memory files should not occur, buffer may be lost!\n");
185 case MMIOM_WRITEFLUSH
:
186 /* no internal buffering, so WRITEFLUSH handled same as WRITE */
189 * lParam1 = huge pointer to write buffer
190 * lParam2 = number of bytes to write
191 * Returns: number of bytes written, -1 for error (error code in
193 * NOTE: lDiskOffset should be updated
195 FIXME("MMIOM_WRITE on memory files should not occur, buffer may be lost!\n");
200 * lParam1 = new position
201 * lParam2 = from whence to seek (SEEK_SET, SEEK_CUR, SEEK_END)
202 * Returns: new file postion, -1 on error
203 * NOTE: lDiskOffset should be updated
205 FIXME("MMIOM_SEEK on memory files should not occur, buffer may be lost!\n");
209 FIXME("unexpected message %u\n", uMessage
);
217 enum mmioProcType
{MMIO_PROC_16
,MMIO_PROC_32A
,MMIO_PROC_32W
};
221 struct IOProcList
*pNext
; /* Next item in linked list */
222 FOURCC fourCC
; /* four-character code identifying IOProc */
223 LPMMIOPROC pIOProc
; /* pointer to IProc */
224 enum mmioProcType type
; /* 16, 32A or 32W */
225 int count
; /* number of objects linked to it */
228 /* This array will be the entire list for most apps */
230 static struct IOProcList defaultProcs
[] = {
231 {&defaultProcs
[1], FOURCC_DOS
, (LPMMIOPROC
)mmioDosIOProc
, MMIO_PROC_32A
, 0},
232 {NULL
, FOURCC_MEM
, (LPMMIOPROC
)mmioMemIOProc
, MMIO_PROC_32A
, 0},
235 static struct IOProcList
* pIOProcListAnchor
= &defaultProcs
[0];
237 /****************************************************************
238 * MMIO_FindProcNode [INTERNAL]
240 * Finds the ProcList node associated with a given FOURCC code.
242 static struct IOProcList
* MMIO_FindProcNode(FOURCC fccIOProc
)
244 struct IOProcList
* pListNode
;
246 for (pListNode
= pIOProcListAnchor
; pListNode
; pListNode
= pListNode
->pNext
) {
247 if (pListNode
->fourCC
== fccIOProc
) {
254 /****************************************************************
255 * MMIO_InstallIOProc [INTERNAL]
257 static LPMMIOPROC
MMIO_InstallIOProc(FOURCC fccIOProc
, LPMMIOPROC pIOProc
,
258 DWORD dwFlags
, enum mmioProcType type
)
260 LPMMIOPROC lpProc
= NULL
;
261 struct IOProcList
* pListNode
;
262 struct IOProcList
** ppListNode
;
264 TRACE("(%ld, %p, %08lX, %i)\n", fccIOProc
, pIOProc
, dwFlags
, type
);
266 if (dwFlags
& MMIO_GLOBALPROC
)
267 FIXME("Global procedures not implemented\n");
269 /* just handle the known procedures for now */
270 switch (dwFlags
& (MMIO_INSTALLPROC
|MMIO_REMOVEPROC
|MMIO_FINDPROC
)) {
271 case MMIO_INSTALLPROC
:
272 /* Create new entry for the IOProc list */
273 pListNode
= HeapAlloc(GetProcessHeap(), 0, sizeof(*pListNode
));
275 /* Fill in this node */
276 pListNode
->fourCC
= fccIOProc
;
277 pListNode
->pIOProc
= pIOProc
;
278 pListNode
->type
= type
;
279 pListNode
->count
= 0;
281 /* Stick it on the end of the list */
282 pListNode
->pNext
= pIOProcListAnchor
;
283 pIOProcListAnchor
= pListNode
;
285 /* Return this IOProc - that's how the caller knows we succeeded */
290 case MMIO_REMOVEPROC
:
292 * Search for the node that we're trying to remove - note
293 * that this method won't find the first item on the list, but
294 * since the first two items on this list are ones we won't
295 * let the user delete anyway, that's okay
297 ppListNode
= &pIOProcListAnchor
;
298 while ((*ppListNode
) && (*ppListNode
)->fourCC
!= fccIOProc
)
299 ppListNode
= &((*ppListNode
)->pNext
);
301 if (*ppListNode
) { /* found it */
302 /* FIXME: what should be done if an open mmio object uses this proc ?
303 * shall we return an error, nuke the mmio object ?
305 if ((*ppListNode
)->count
) {
306 ERR("Cannot remove a mmIOProc while in use\n");
309 /* remove it, but only if it isn't builtin */
310 if ((*ppListNode
) >= defaultProcs
&&
311 (*ppListNode
) < defaultProcs
+ sizeof(defaultProcs
)) {
312 WARN("Tried to remove built-in mmio proc. Skipping\n");
315 struct IOProcList
* ptmpNode
= *ppListNode
;
316 lpProc
= (*ppListNode
)->pIOProc
;
317 *ppListNode
= (*ppListNode
)->pNext
;
318 HeapFree(GetProcessHeap(), 0, ptmpNode
);
324 if ((pListNode
= MMIO_FindProcNode(fccIOProc
))) {
325 lpProc
= pListNode
->pIOProc
;
333 /****************************************************************
334 * MMIO_Map32To16 [INTERNAL]
336 static LRESULT
MMIO_Map32To16(DWORD wMsg
, LPARAM
* lp1
, LPARAM
* lp2
)
341 char *lp
= SEGPTR_STRDUP( (LPSTR
)*lp1
);
342 if (!lp
) return MMSYSERR_NOMEM
;
343 *lp1
= SEGPTR_GET(lp
);
352 case MMIOM_WRITEFLUSH
:
354 void* lp
= SEGPTR_ALLOC(*lp2
);
355 if (!lp
) return MMSYSERR_NOMEM
;
357 if (wMsg
!= MMIOM_READ
)
358 memcpy(lp
, (void*)*lp1
, *lp2
);
359 *lp1
= SEGPTR_GET(lp
);
363 TRACE("Not a mappable message (%ld)\n", wMsg
);
365 return MMSYSERR_NOERROR
;
368 /****************************************************************
369 * MMIO_UnMap32To16 [INTERNAL]
371 static LRESULT
MMIO_UnMap32To16(DWORD wMsg
, LPARAM lParam1
, LPARAM lParam2
,
372 LPARAM lp1
, LPARAM lp2
)
376 if (!SEGPTR_FREE((void*)lp1
)) {
377 FIXME("bad free line=%d\n", __LINE__
);
385 memcpy((void*)lParam1
, MapSL(lp1
), lp2
);
388 case MMIOM_WRITEFLUSH
:
389 if (!SEGPTR_FREE(MapSL(lp1
))) {
390 FIXME("bad free line=%d\n", __LINE__
);
394 TRACE("Not a mappable message (%ld)\n", wMsg
);
396 return MMSYSERR_NOERROR
;
399 /****************************************************************
400 * MMIO_GenerateInfoForIOProc [INTERNAL]
402 static SEGPTR
MMIO_GenerateInfoForIOProc(const WINE_MMIO
* wm
)
404 LPMMIOINFO16 mmioInfo16
= SEGPTR_ALLOC(sizeof(MMIOINFO16
));
406 memset(mmioInfo16
, 0, sizeof(MMIOINFO16
));
408 mmioInfo16
->lDiskOffset
= wm
->info
.lDiskOffset
;
409 mmioInfo16
->adwInfo
[0] = wm
->info
.adwInfo
[0];
410 mmioInfo16
->adwInfo
[1] = wm
->info
.adwInfo
[1];
411 mmioInfo16
->adwInfo
[2] = wm
->info
.adwInfo
[2];
412 mmioInfo16
->adwInfo
[3] = wm
->info
.adwInfo
[3];
414 return SEGPTR_GET(mmioInfo16
);
417 /****************************************************************
418 * MMIO_UpdateInfoForIOProc [INTERNAL]
420 static LRESULT
MMIO_UpdateInfoForIOProc(WINE_MMIO
* wm
, SEGPTR segmmioInfo16
)
422 MMIOINFO16
* mmioInfo16
= MapSL(segmmioInfo16
);
424 wm
->info
.lDiskOffset
= mmioInfo16
->lDiskOffset
;
425 wm
->info
.adwInfo
[0] = mmioInfo16
->adwInfo
[0];
426 wm
->info
.adwInfo
[1] = mmioInfo16
->adwInfo
[1];
427 wm
->info
.adwInfo
[2] = mmioInfo16
->adwInfo
[2];
428 wm
->info
.adwInfo
[3] = mmioInfo16
->adwInfo
[3];
430 if (!SEGPTR_FREE(mmioInfo16
)) FIXME("bad free\n");
432 return MMSYSERR_NOERROR
;
435 /****************************************************************
436 * MMIO_SendMessage [INTERNAL]
438 static LRESULT
MMIO_SendMessage(LPWINE_MMIO wm
, DWORD wMsg
, LPARAM lParam1
,
439 LPARAM lParam2
, enum mmioProcType type
)
442 SEGPTR segmmioInfo16
;
443 LPARAM lp1
= lParam1
, lp2
= lParam2
;
445 if (!wm
->ioProc
|| !wm
->info
.pIOProc
) {
447 result
= MMSYSERR_INVALPARAM
;
450 switch (wm
->ioProc
->type
) {
452 segmmioInfo16
= MMIO_GenerateInfoForIOProc(wm
);
453 if (wm
->ioProc
->type
!= type
) {
454 /* map (lParam1, lParam2) into (lp1, lp2) 32=>16 */
455 if ((result
= MMIO_Map32To16(wMsg
, &lp1
, &lp2
)) != MMSYSERR_NOERROR
)
458 /* FIXME: is wm->info.pIOProc a segmented or a linear address ?
459 * sounds to me it's a segmented one, should use a thunk somewhere
461 result
= ((LPMMIOPROC16
)wm
->info
.pIOProc
)((LPSTR
)segmmioInfo16
,
464 if (wm
->ioProc
->type
!= type
) {
465 MMIO_UnMap32To16(wMsg
, lParam1
, lParam2
, lp1
, lp2
);
467 MMIO_UpdateInfoForIOProc(wm
, segmmioInfo16
);
471 if (wm
->ioProc
->type
!= type
) {
472 /* map (lParam1, lParam2) into (lp1, lp2) 16=>32 */
475 result
= (wm
->info
.pIOProc
)((LPSTR
)&wm
->info
, wMsg
, lp1
, lp2
);
478 if (wm
->ioProc
->type
!= type
) {
479 /* unmap (lParam1, lParam2) into (lp1, lp2) 16=>32 */
484 FIXME("Internal error\n");
485 result
= MMSYSERR_ERROR
;
491 /**************************************************************************
492 * MMIO_ParseExt [internal]
494 * Parses a filename for the extension.
497 * The FOURCC code for the extension if found, else 0.
499 static FOURCC
MMIO_ParseExt(LPCSTR szFileName
)
501 /* Filenames are of the form file.ext+ABC
502 FIXME: What if a '+' is part of the file name?
503 For now, we take the last '+' present */
507 /* Note that ext{Start,End} point to the . and + respectively */
510 TRACE("(%s)\n",debugstr_a(szFileName
));
514 extEnd
= strrchr(szFileName
,'+');
516 /* Need to parse to find the extension */
520 while (extStart
> szFileName
&& extStart
[0] != '.') {
524 if (extStart
== szFileName
) {
525 ERR("+ but no . in szFileName: %s\n", debugstr_a(szFileName
));
529 if (extEnd
- extStart
- 1 > 4)
530 WARN("Extension length > 4\n");
531 lstrcpynA(ext
,extStart
+ 1,min(extEnd
-extStart
,5));
532 TRACE("Got extension: %s\n", debugstr_a(ext
));
533 /* FOURCC codes identifying file-extensions must be uppercase */
534 ret
= mmioStringToFOURCCA(ext
, MMIO_TOUPPER
);
540 /**************************************************************************
541 * MMIO_Get [internal]
543 * Retirieves from current process the mmio object
545 static LPWINE_MMIO
MMIO_Get(LPWINE_MM_IDATA iData
, HMMIO h
)
547 LPWINE_MMIO wm
= NULL
;
549 if (!iData
) iData
= MULTIMEDIA_GetIData();
551 EnterCriticalSection(&iData
->cs
);
552 for (wm
= iData
->lpMMIO
; wm
; wm
= wm
->lpNext
) {
553 if (wm
->info
.hmmio
== h
)
556 LeaveCriticalSection(&iData
->cs
);
560 /**************************************************************************
561 * MMIO_Create [internal]
563 * Creates an internal representation for a mmio instance
565 static LPWINE_MMIO
MMIO_Create(void)
567 static WORD MMIO_counter
= 0;
569 LPWINE_MM_IDATA iData
= MULTIMEDIA_GetIData();
571 wm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WINE_MMIO
));
573 EnterCriticalSection(&iData
->cs
);
574 while (MMIO_Get(iData
, ++MMIO_counter
));
575 wm
->info
.hmmio
= MMIO_counter
;
576 wm
->lpNext
= iData
->lpMMIO
;
578 LeaveCriticalSection(&iData
->cs
);
583 /**************************************************************************
584 * MMIO_Destroy [internal]
586 * Destroys an internal representation for a mmio instance
588 static BOOL
MMIO_Destroy(LPWINE_MMIO wm
)
590 LPWINE_MM_IDATA iData
= MULTIMEDIA_GetIData();
593 EnterCriticalSection(&iData
->cs
);
594 /* search for the matching one... */
595 m
= &(iData
->lpMMIO
);
596 while (*m
&& *m
!= wm
) m
= &(*m
)->lpNext
;
600 HeapFree(GetProcessHeap(), 0, wm
);
603 LeaveCriticalSection(&iData
->cs
);
604 return wm
? FALSE
: TRUE
;
607 /****************************************************************
608 * MMIO_Flush [INTERNAL]
610 static LRESULT
MMIO_Flush(WINE_MMIO
* wm
, UINT uFlags
)
612 if (wm
->info
.cchBuffer
&& (wm
->info
.fccIOProc
!= FOURCC_MEM
)) {
613 /* not quite sure what to do here, but I'll guess */
614 if (wm
->info
.dwFlags
& MMIO_DIRTY
) {
615 MMIO_SendMessage(wm
, MMIOM_SEEK
, wm
->info
.lBufOffset
,
616 SEEK_SET
, MMIO_PROC_32A
);
617 MMIO_SendMessage(wm
, MMIOM_WRITE
, (LPARAM
)wm
->info
.pchBuffer
,
618 wm
->info
.pchNext
- wm
->info
.pchBuffer
, MMIO_PROC_32A
);
620 if (uFlags
& MMIO_EMPTYBUF
)
621 wm
->info
.pchNext
= wm
->info
.pchBuffer
;
623 wm
->info
.dwFlags
&= ~MMIO_DIRTY
;
628 /***************************************************************************
629 * MMIO_GrabNextBuffer [INTERNAL]
631 static LONG
MMIO_GrabNextBuffer(LPWINE_MMIO wm
, int for_read
)
633 LONG size
= wm
->info
.cchBuffer
;
635 TRACE("bo=%lx do=%lx of=%lx\n",
636 wm
->info
.lBufOffset
, wm
->info
.lDiskOffset
,
637 MMIO_SendMessage(wm
, MMIOM_SEEK
, 0, SEEK_CUR
, MMIO_PROC_32A
));
639 wm
->info
.lBufOffset
= wm
->info
.lDiskOffset
;
640 wm
->info
.pchNext
= wm
->info
.pchBuffer
;
641 wm
->info
.pchEndRead
= wm
->info
.pchBuffer
;
642 wm
->info
.pchEndWrite
= wm
->info
.pchBuffer
+ wm
->info
.cchBuffer
;
645 size
= MMIO_SendMessage(wm
, MMIOM_READ
, (LPARAM
)wm
->info
.pchBuffer
,
646 size
, MMIO_PROC_32A
);
648 wm
->info
.pchEndRead
+= size
;
650 wm
->bBufferLoaded
= TRUE
;
654 /***************************************************************************
655 * MMIO_SetBuffer [INTERNAL]
657 static UINT
MMIO_SetBuffer(WINE_MMIO
* wm
, void* pchBuffer
, LONG cchBuffer
,
658 UINT uFlags
, BOOL bFrom32
)
660 TRACE("(%p %p %ld %u %d)\n", wm
, pchBuffer
, cchBuffer
, uFlags
, bFrom32
);
662 if (uFlags
) return MMSYSERR_INVALPARAM
;
663 if (cchBuffer
> 0xFFFF)
664 WARN("Untested handling of huge mmio buffers (%ld >= 64k)\n", cchBuffer
);
666 if (MMIO_Flush(wm
, MMIO_EMPTYBUF
) != 0)
667 return MMIOERR_CANNOTWRITE
;
669 if ((!cchBuffer
|| pchBuffer
) && (wm
->info
.dwFlags
& MMIO_ALLOCBUF
)) {
670 GlobalUnlock16(wm
->hMem
);
671 GlobalFree16(wm
->hMem
);
672 wm
->info
.dwFlags
&= ~MMIO_ALLOCBUF
;
676 wm
->info
.pchBuffer
= pchBuffer
;
679 wm
->info
.pchBuffer
= MapSL((SEGPTR
)pchBuffer
);
680 wm
->buffer16
= (SEGPTR
)pchBuffer
;
683 } else if (cchBuffer
&& (wm
->info
.dwFlags
& MMIO_ALLOCBUF
)) {
685 GlobalUnlock16(wm
->hMem
);
686 hNewBuf
= GlobalReAlloc16(wm
->hMem
, cchBuffer
, 0);
688 /* FIXME: this assumes the memory block didn't move */
689 GlobalLock16(wm
->hMem
);
690 return MMIOERR_OUTOFMEMORY
;
693 } else if (cchBuffer
) {
694 if (!(wm
->hMem
= GlobalAlloc16(GMEM_MOVEABLE
, cchBuffer
)))
695 return MMIOERR_OUTOFMEMORY
;
696 wm
->info
.dwFlags
|= MMIO_ALLOCBUF
;
698 wm
->info
.pchBuffer
= NULL
;
704 wm
->buffer16
= K32WOWGlobalLock16(wm
->hMem
);
705 wm
->info
.pchBuffer
= MapSL(wm
->buffer16
);
708 wm
->info
.cchBuffer
= cchBuffer
;
709 wm
->info
.pchNext
= wm
->info
.pchBuffer
;
710 wm
->info
.pchEndRead
= wm
->info
.pchBuffer
;
711 wm
->info
.pchEndWrite
= wm
->info
.pchBuffer
+ cchBuffer
;
712 wm
->info
.lBufOffset
= 0;
713 wm
->bBufferLoaded
= FALSE
;
718 /**************************************************************************
719 * MMIO_Open [internal]
721 static HMMIO
MMIO_Open(LPSTR szFileName
, MMIOINFO
* refmminfo
,
722 DWORD dwOpenFlags
, enum mmioProcType type
)
726 TRACE("('%s', %p, %08lX, %d);\n", szFileName
, refmminfo
, dwOpenFlags
, type
);
728 if (dwOpenFlags
& (MMIO_PARSE
|MMIO_EXIST
)) {
729 char buffer
[MAX_PATH
];
731 if (GetFullPathNameA(szFileName
, sizeof(buffer
), buffer
, NULL
) >= sizeof(buffer
))
732 return (HMMIO16
)FALSE
;
733 if ((dwOpenFlags
& MMIO_EXIST
) && (GetFileAttributesA(buffer
) == -1))
735 strcpy(szFileName
, buffer
);
739 if ((wm
= MMIO_Create()) == NULL
)
742 /* If both params are NULL, then parse the file name if available */
743 if (refmminfo
->fccIOProc
== 0 && refmminfo
->pIOProc
== NULL
) {
744 wm
->info
.fccIOProc
= MMIO_ParseExt(szFileName
);
745 /* Handle any unhandled/error case. Assume DOS file */
746 if (wm
->info
.fccIOProc
== 0)
747 wm
->info
.fccIOProc
= FOURCC_DOS
;
748 if (!(wm
->ioProc
= MMIO_FindProcNode(wm
->info
.fccIOProc
))) goto error2
;
749 wm
->info
.pIOProc
= wm
->ioProc
->pIOProc
;
750 wm
->bTmpIOProc
= FALSE
;
752 /* if just the four character code is present, look up IO proc */
753 else if (refmminfo
->pIOProc
== NULL
) {
754 wm
->info
.fccIOProc
= refmminfo
->fccIOProc
;
755 if (!(wm
->ioProc
= MMIO_FindProcNode(wm
->info
.fccIOProc
))) goto error2
;
756 wm
->info
.pIOProc
= wm
->ioProc
->pIOProc
;
757 wm
->bTmpIOProc
= FALSE
;
759 /* if IO proc specified, use it and specified four character code */
761 wm
->info
.fccIOProc
= refmminfo
->fccIOProc
;
762 wm
->info
.pIOProc
= refmminfo
->pIOProc
;
763 MMIO_InstallIOProc(wm
->info
.fccIOProc
, wm
->info
.pIOProc
,
764 MMIO_INSTALLPROC
, type
);
765 if (!(wm
->ioProc
= MMIO_FindProcNode(wm
->info
.fccIOProc
))) goto error2
;
766 assert(wm
->ioProc
->pIOProc
== refmminfo
->pIOProc
);
767 wm
->info
.pIOProc
= wm
->ioProc
->pIOProc
;
768 wm
->bTmpIOProc
= TRUE
;
771 wm
->bBufferLoaded
= FALSE
;
774 if (dwOpenFlags
& MMIO_ALLOCBUF
) {
775 if ((refmminfo
->wErrorRet
= mmioSetBuffer(wm
->info
.hmmio
, NULL
,
776 MMIO_DEFAULTBUFFER
, 0)))
778 } else if (wm
->info
.fccIOProc
== FOURCC_MEM
) {
779 refmminfo
->wErrorRet
= MMIO_SetBuffer(wm
, refmminfo
->pchBuffer
,
780 refmminfo
->cchBuffer
, 0,
781 type
!= MMIO_PROC_16
);
782 if (refmminfo
->wErrorRet
!= MMSYSERR_NOERROR
)
784 wm
->bBufferLoaded
= TRUE
;
785 } /* else => unbuffered, wm->info.pchBuffer == NULL */
787 /* see mmioDosIOProc for that one */
788 wm
->info
.adwInfo
[0] = refmminfo
->adwInfo
[0];
789 wm
->info
.dwFlags
= dwOpenFlags
;
791 /* call IO proc to actually open file */
792 refmminfo
->wErrorRet
= MMIO_SendMessage(wm
, MMIOM_OPEN
, (LPARAM
)szFileName
,
793 type
== MMIO_PROC_16
, MMIO_PROC_32A
);
795 if (refmminfo
->wErrorRet
== 0)
796 return wm
->info
.hmmio
;
798 if (wm
->ioProc
) wm
->ioProc
->count
--;
804 /**************************************************************************
805 * mmioOpenW [WINMM.123]
807 HMMIO WINAPI
mmioOpenW(LPWSTR szFileName
, MMIOINFO
* lpmmioinfo
,
811 LPSTR szFn
= HEAP_strdupWtoA(GetProcessHeap(), 0, szFileName
);
814 ret
= MMIO_Open(szFn
, lpmmioinfo
, dwOpenFlags
, MMIO_PROC_32W
);
818 mmioinfo
.fccIOProc
= 0;
819 mmioinfo
.pIOProc
= NULL
;
820 mmioinfo
.pchBuffer
= NULL
;
821 mmioinfo
.cchBuffer
= 0;
823 ret
= MMIO_Open(szFn
, &mmioinfo
, dwOpenFlags
, MMIO_PROC_32W
);
826 HeapFree(GetProcessHeap(), 0, szFn
);
830 /**************************************************************************
831 * mmioOpenA [WINMM.122]
833 HMMIO WINAPI
mmioOpenA(LPSTR szFileName
, MMIOINFO
* lpmmioinfo
,
839 ret
= MMIO_Open(szFileName
, lpmmioinfo
, dwOpenFlags
, MMIO_PROC_32A
);
843 mmioinfo
.fccIOProc
= 0;
844 mmioinfo
.pIOProc
= NULL
;
845 mmioinfo
.pchBuffer
= NULL
;
846 mmioinfo
.cchBuffer
= 0;
848 ret
= MMIO_Open(szFileName
, &mmioinfo
, dwOpenFlags
, MMIO_PROC_32A
);
853 /**************************************************************************
854 * mmioOpen [MMSYSTEM.1210]
856 HMMIO16 WINAPI
mmioOpen16(LPSTR szFileName
, MMIOINFO16
* lpmmioinfo16
,
865 memset(&mmioinfo
, 0, sizeof(mmioinfo
));
867 mmioinfo
.dwFlags
= lpmmioinfo16
->dwFlags
;
868 mmioinfo
.fccIOProc
= lpmmioinfo16
->fccIOProc
;
869 mmioinfo
.pIOProc
= (LPMMIOPROC
)lpmmioinfo16
->pIOProc
;
870 mmioinfo
.cchBuffer
= lpmmioinfo16
->cchBuffer
;
871 mmioinfo
.pchBuffer
= lpmmioinfo16
->pchBuffer
;
872 mmioinfo
.adwInfo
[0] = lpmmioinfo16
->adwInfo
[0];
873 mmioinfo
.adwInfo
[1] = lpmmioinfo16
->adwInfo
[1];
874 mmioinfo
.adwInfo
[2] = lpmmioinfo16
->adwInfo
[2];
875 mmioinfo
.adwInfo
[3] = lpmmioinfo16
->adwInfo
[3];
877 ret
= MMIO_Open(szFileName
, &mmioinfo
, dwOpenFlags
, MMIO_PROC_16
);
879 mmioGetInfo16(mmioinfo
.hmmio
, lpmmioinfo16
, 0);
880 lpmmioinfo16
->wErrorRet
= ret
;
884 mmio
.pchBuffer
= NULL
;
886 ret
= MMIO_Open(szFileName
, &mmio
, dwOpenFlags
, FALSE
);
892 /**************************************************************************
893 * mmioClose [WINMM.114]
895 MMRESULT WINAPI
mmioClose(HMMIO hmmio
, UINT uFlags
)
900 TRACE("(%04X, %04X);\n", hmmio
, uFlags
);
902 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
903 return MMSYSERR_INVALHANDLE
;
905 if ((result
= MMIO_Flush(wm
, MMIO_EMPTYBUF
)) != 0)
908 result
= MMIO_SendMessage(wm
, MMIOM_CLOSE
, uFlags
, 0, MMIO_PROC_32A
);
910 mmioSetBuffer(hmmio
, NULL
, 0, 0);
915 MMIO_InstallIOProc(wm
->info
.fccIOProc
, NULL
,
916 MMIO_REMOVEPROC
, wm
->ioProc
->type
);
923 /**************************************************************************
924 * mmioClose [MMSYSTEM.1211]
926 MMRESULT16 WINAPI
mmioClose16(HMMIO16 hmmio
, UINT16 uFlags
)
928 return mmioClose(hmmio
, uFlags
);
931 /**************************************************************************
932 * mmioRead [WINMM.124]
934 LONG WINAPI
mmioRead(HMMIO hmmio
, HPSTR pch
, LONG cch
)
939 TRACE("(%04X, %p, %ld);\n", hmmio
, pch
, cch
);
941 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
944 /* unbuffered case first */
945 if (!wm
->info
.pchBuffer
)
946 return MMIO_SendMessage(wm
, MMIOM_READ
, (LPARAM
)pch
, cch
, MMIO_PROC_32A
);
948 /* first try from current buffer */
949 if (wm
->info
.pchNext
!= wm
->info
.pchEndRead
) {
950 count
= wm
->info
.pchEndRead
- wm
->info
.pchNext
;
951 if (count
> cch
|| count
< 0) count
= cch
;
952 memcpy(pch
, wm
->info
.pchNext
, count
);
953 wm
->info
.pchNext
+= count
;
959 if (cch
&& (wm
->info
.fccIOProc
!= FOURCC_MEM
)) {
960 assert(wm
->info
.cchBuffer
);
965 size
= MMIO_GrabNextBuffer(wm
, TRUE
);
966 if (size
<= 0) break;
967 if (size
> cch
) size
= cch
;
968 memcpy(pch
, wm
->info
.pchBuffer
, size
);
969 wm
->info
.pchNext
+= size
;
976 TRACE("count=%ld\n", count
);
980 /**************************************************************************
981 * mmioRead [MMSYSTEM.1212]
983 LONG WINAPI
mmioRead16(HMMIO16 hmmio
, HPSTR pch
, LONG cch
)
985 return mmioRead(hmmio
, pch
, cch
);
988 /**************************************************************************
989 * mmioWrite [WINMM.133]
991 LONG WINAPI
mmioWrite(HMMIO hmmio
, HPCSTR pch
, LONG cch
)
996 TRACE("(%04X, %p, %ld);\n", hmmio
, pch
, cch
);
998 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
1001 if (wm
->info
.cchBuffer
) {
1004 if (wm
->info
.pchNext
!= wm
->info
.pchEndWrite
) {
1005 count
= wm
->info
.pchEndWrite
- wm
->info
.pchNext
;
1006 if (count
> cch
|| count
< 0) count
= cch
;
1007 memcpy(wm
->info
.pchNext
, pch
, count
);
1008 wm
->info
.pchNext
+= count
;
1012 wm
->info
.dwFlags
|= MMIO_DIRTY
;
1016 if (wm
->info
.fccIOProc
== FOURCC_MEM
) {
1017 if (wm
->info
.adwInfo
[0]) {
1018 /* from where would we get the memory handle? */
1019 FIXME("memory file expansion not implemented!\n");
1025 if (wm
->info
.pchNext
== wm
->info
.pchEndWrite
)
1027 MMIO_Flush(wm
, MMIO_EMPTYBUF
);
1028 MMIO_GrabNextBuffer(wm
, FALSE
);
1033 bytesW
= MMIO_SendMessage(wm
, MMIOM_WRITE
, (LPARAM
)pch
, cch
, MMIO_PROC_32A
);
1034 wm
->info
.lBufOffset
= wm
->info
.lDiskOffset
;
1037 TRACE("bytes written=%ld\n", bytesW
);
1041 /**************************************************************************
1042 * mmioWrite [MMSYSTEM.1213]
1044 LONG WINAPI
mmioWrite16(HMMIO16 hmmio
, HPCSTR pch
, LONG cch
)
1046 return mmioWrite(hmmio
,pch
,cch
);
1049 /**************************************************************************
1050 * mmioSeek [MMSYSTEM.1214]
1052 LONG WINAPI
mmioSeek(HMMIO hmmio
, LONG lOffset
, INT iOrigin
)
1057 TRACE("(%04X, %08lX, %d);\n", hmmio
, lOffset
, iOrigin
);
1059 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
1060 return MMSYSERR_INVALHANDLE
;
1062 /* not buffered, direct seek on file */
1063 if (!wm
->info
.pchBuffer
)
1064 return MMIO_SendMessage(wm
, MMIOM_SEEK
, lOffset
, iOrigin
, MMIO_PROC_32A
);
1071 offset
= wm
->info
.lBufOffset
+ (wm
->info
.pchNext
- wm
->info
.pchBuffer
) + lOffset
;
1074 if (wm
->info
.fccIOProc
== FOURCC_MEM
) {
1075 offset
= wm
->info
.cchBuffer
;
1077 assert(MMIO_SendMessage(wm
, MMIOM_SEEK
, 0, SEEK_CUR
, MMIO_PROC_32A
) == wm
->info
.lDiskOffset
);
1078 offset
= MMIO_SendMessage(wm
, MMIOM_SEEK
, 0, SEEK_END
, MMIO_PROC_32A
);
1079 MMIO_SendMessage(wm
, MMIOM_SEEK
, wm
->info
.lDiskOffset
, SEEK_SET
, MMIO_PROC_32A
);
1087 /* stay in same buffer ? */
1088 /* some memory mapped buffers are defined with -1 as a size */
1089 if ((wm
->info
.cchBuffer
> 0) &&
1090 ((offset
< wm
->info
.lBufOffset
) ||
1091 (offset
>= wm
->info
.lBufOffset
+ wm
->info
.cchBuffer
) ||
1092 !wm
->bBufferLoaded
)) {
1094 /* condition to change buffer */
1095 if ((wm
->info
.fccIOProc
== FOURCC_MEM
) ||
1096 MMIO_Flush(wm
, MMIO_EMPTYBUF
) ||
1097 /* this also sets the wm->info.lDiskOffset field */
1098 MMIO_SendMessage(wm
, MMIOM_SEEK
,
1099 (offset
/ wm
->info
.cchBuffer
) * wm
->info
.cchBuffer
,
1100 SEEK_SET
, MMIO_PROC_32A
) == -1)
1102 MMIO_GrabNextBuffer(wm
, TRUE
);
1105 wm
->info
.pchNext
= wm
->info
.pchBuffer
+ (offset
- wm
->info
.lBufOffset
);
1107 TRACE("=> %ld\n", offset
);
1111 /**************************************************************************
1112 * mmioSeek [MMSYSTEM.1214]
1114 LONG WINAPI
mmioSeek16(HMMIO16 hmmio
, LONG lOffset
, INT16 iOrigin
)
1116 return mmioSeek(hmmio
, lOffset
, iOrigin
);
1119 /**************************************************************************
1120 * mmioGetInfo [MMSYSTEM.1215]
1122 UINT16 WINAPI
mmioGetInfo16(HMMIO16 hmmio
, MMIOINFO16
* lpmmioinfo
, UINT16 uFlags
)
1126 TRACE("mmioGetInfo\n");
1128 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
1129 return MMSYSERR_INVALHANDLE
;
1132 return MMSYSERR_ERROR
;
1134 lpmmioinfo
->dwFlags
= wm
->info
.dwFlags
;
1135 lpmmioinfo
->fccIOProc
= wm
->info
.fccIOProc
;
1136 lpmmioinfo
->pIOProc
= (LPMMIOPROC16
)wm
->info
.pIOProc
;
1137 lpmmioinfo
->wErrorRet
= wm
->info
.wErrorRet
;
1138 lpmmioinfo
->hTask
= wm
->info
.hTask
;
1139 lpmmioinfo
->cchBuffer
= wm
->info
.cchBuffer
;
1140 lpmmioinfo
->pchBuffer
= (void*)wm
->buffer16
;
1141 lpmmioinfo
->pchNext
= (void*)(wm
->buffer16
+ (wm
->info
.pchNext
- wm
->info
.pchBuffer
));
1142 lpmmioinfo
->pchEndRead
= (void*)(wm
->buffer16
+ (wm
->info
.pchEndRead
- wm
->info
.pchBuffer
));
1143 lpmmioinfo
->pchEndWrite
= (void*)(wm
->buffer16
+ (wm
->info
.pchEndWrite
- wm
->info
.pchBuffer
));
1144 lpmmioinfo
->lBufOffset
= wm
->info
.lBufOffset
;
1145 lpmmioinfo
->lDiskOffset
= wm
->info
.lDiskOffset
;
1146 lpmmioinfo
->adwInfo
[0] = wm
->info
.adwInfo
[0];
1147 lpmmioinfo
->adwInfo
[1] = wm
->info
.adwInfo
[1];
1148 lpmmioinfo
->adwInfo
[2] = wm
->info
.adwInfo
[2];
1149 lpmmioinfo
->adwInfo
[3] = wm
->info
.adwInfo
[3];
1150 lpmmioinfo
->dwReserved1
= 0;
1151 lpmmioinfo
->dwReserved2
= 0;
1152 lpmmioinfo
->hmmio
= wm
->info
.hmmio
;
1157 /**************************************************************************
1158 * mmioGetInfo [WINMM.118]
1160 UINT WINAPI
mmioGetInfo(HMMIO hmmio
, MMIOINFO
* lpmmioinfo
, UINT uFlags
)
1164 TRACE("(0x%04x,%p,0x%08x)\n",hmmio
,lpmmioinfo
,uFlags
);
1166 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
1167 return MMSYSERR_INVALHANDLE
;
1169 memcpy(lpmmioinfo
, &wm
->info
, sizeof(MMIOINFO
));
1174 /**************************************************************************
1175 * mmioSetInfo16 [MMSYSTEM.1216]
1177 UINT16 WINAPI
mmioSetInfo16(HMMIO16 hmmio
, const MMIOINFO16
* lpmmioinfo
, UINT16 uFlags
)
1181 TRACE("mmioSetInfo\n");
1183 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
1184 return MMSYSERR_INVALHANDLE
;
1186 /* check if seg and lin buffers are the same */
1187 if (wm
->info
.cchBuffer
!= lpmmioinfo
->cchBuffer
||
1188 wm
->info
.pchBuffer
!= MapSL(wm
->buffer16
))
1189 return MMSYSERR_INVALPARAM
;
1191 /* check pointers coherence */
1192 if (lpmmioinfo
->pchNext
< lpmmioinfo
->pchBuffer
||
1193 lpmmioinfo
->pchNext
> lpmmioinfo
->pchBuffer
+ lpmmioinfo
->cchBuffer
||
1194 lpmmioinfo
->pchEndRead
< lpmmioinfo
->pchBuffer
||
1195 lpmmioinfo
->pchEndRead
> lpmmioinfo
->pchBuffer
+ lpmmioinfo
->cchBuffer
||
1196 lpmmioinfo
->pchEndWrite
< lpmmioinfo
->pchBuffer
||
1197 lpmmioinfo
->pchEndWrite
> lpmmioinfo
->pchBuffer
+ lpmmioinfo
->cchBuffer
)
1198 return MMSYSERR_INVALPARAM
;
1200 wm
->info
.pchNext
= wm
->info
.pchBuffer
+ (lpmmioinfo
->pchNext
- lpmmioinfo
->pchBuffer
);
1201 wm
->info
.pchEndRead
= wm
->info
.pchBuffer
+ (lpmmioinfo
->pchEndRead
- lpmmioinfo
->pchBuffer
);
1202 wm
->info
.pchEndWrite
= wm
->info
.pchBuffer
+ (lpmmioinfo
->pchEndWrite
- lpmmioinfo
->pchBuffer
);
1207 /**************************************************************************
1208 * mmioSetInfo [WINMM.130]
1210 UINT WINAPI
mmioSetInfo(HMMIO hmmio
, const MMIOINFO
* lpmmioinfo
, UINT uFlags
)
1214 TRACE("mmioSetInfo\n");
1216 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
1217 return MMSYSERR_INVALHANDLE
;
1219 /* check pointers coherence */
1220 if (lpmmioinfo
->pchNext
< wm
->info
.pchBuffer
||
1221 lpmmioinfo
->pchNext
> wm
->info
.pchBuffer
+ wm
->info
.cchBuffer
||
1222 lpmmioinfo
->pchEndRead
< wm
->info
.pchBuffer
||
1223 lpmmioinfo
->pchEndRead
> wm
->info
.pchBuffer
+ wm
->info
.cchBuffer
||
1224 lpmmioinfo
->pchEndWrite
< wm
->info
.pchBuffer
||
1225 lpmmioinfo
->pchEndWrite
> wm
->info
.pchBuffer
+ wm
->info
.cchBuffer
)
1226 return MMSYSERR_INVALPARAM
;
1228 wm
->info
.pchNext
= lpmmioinfo
->pchNext
;
1229 wm
->info
.pchEndRead
= lpmmioinfo
->pchEndRead
;
1234 /**************************************************************************
1235 * mmioSetBuffer [WINMM.129]
1237 UINT WINAPI
mmioSetBuffer(HMMIO hmmio
, LPSTR pchBuffer
, LONG cchBuffer
, UINT uFlags
)
1241 TRACE("(hmmio=%04x, pchBuf=%p, cchBuf=%ld, uFlags=%#08x)\n",
1242 hmmio
, pchBuffer
, cchBuffer
, uFlags
);
1244 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
1245 return MMSYSERR_INVALHANDLE
;
1247 return MMIO_SetBuffer(wm
, pchBuffer
, cchBuffer
, uFlags
, TRUE
);
1250 /**************************************************************************
1251 * mmioSetBuffer [MMSYSTEM.1217]
1253 UINT16 WINAPI
mmioSetBuffer16(HMMIO16 hmmio
, LPSTR segpchBuffer
,
1254 LONG cchBuffer
, UINT16 uFlags
)
1258 TRACE("(hmmio=%04x, segpchBuf=%p, cchBuf=%ld, uFlags=%#08x)\n",
1259 hmmio
, segpchBuffer
, cchBuffer
, uFlags
);
1261 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
1262 return MMSYSERR_INVALHANDLE
;
1264 return MMIO_SetBuffer(wm
, segpchBuffer
, cchBuffer
, uFlags
, FALSE
);
1267 /**************************************************************************
1268 * mmioFlush [WINMM.117]
1270 UINT WINAPI
mmioFlush(HMMIO hmmio
, UINT uFlags
)
1274 TRACE("(%04X, %04X)\n", hmmio
, uFlags
);
1276 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
1277 return MMSYSERR_INVALHANDLE
;
1279 return MMIO_Flush(wm
, uFlags
);
1282 /**************************************************************************
1283 * mmioFlush [MMSYSTEM.1218]
1285 UINT16 WINAPI
mmioFlush16(HMMIO16 hmmio
, UINT16 uFlags
)
1287 return mmioFlush(hmmio
, uFlags
);
1290 /**************************************************************************
1291 * mmioAdvance [MMSYSTEM.1219]
1293 UINT WINAPI
mmioAdvance(HMMIO hmmio
, MMIOINFO
* lpmmioinfo
, UINT uFlags
)
1297 TRACE("hmmio=%04X, lpmmioinfo=%p, uFlags=%04X\n", hmmio
, lpmmioinfo
, uFlags
);
1299 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
1300 return MMSYSERR_INVALHANDLE
;
1302 if (!wm
->info
.cchBuffer
)
1303 return MMIOERR_UNBUFFERED
;
1305 if (uFlags
!= MMIO_READ
&& uFlags
!= MMIO_WRITE
)
1306 return MMSYSERR_INVALPARAM
;
1308 if (MMIO_Flush(wm
, MMIO_EMPTYBUF
))
1309 return MMIOERR_CANNOTWRITE
;
1311 MMIO_GrabNextBuffer(wm
, uFlags
== MMIO_READ
);
1313 lpmmioinfo
->pchNext
= lpmmioinfo
->pchBuffer
;
1314 lpmmioinfo
->pchEndRead
= lpmmioinfo
->pchBuffer
+
1315 (wm
->info
.pchEndRead
- wm
->info
.pchBuffer
);
1316 lpmmioinfo
->pchEndWrite
= lpmmioinfo
->pchBuffer
+
1317 (wm
->info
.pchEndWrite
- wm
->info
.pchBuffer
);
1318 lpmmioinfo
->lDiskOffset
= wm
->info
.lDiskOffset
;
1319 lpmmioinfo
->lBufOffset
= wm
->info
.lBufOffset
;
1323 /***********************************************************************
1324 * mmioAdvance [MMSYSTEM.1219]
1326 UINT16 WINAPI
mmioAdvance16(HMMIO16 hmmio
, MMIOINFO16
* lpmmioinfo
, UINT16 uFlags
)
1330 TRACE("mmioAdvance\n");
1332 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
1333 return MMSYSERR_INVALHANDLE
;
1335 if (!wm
->info
.cchBuffer
)
1336 return MMIOERR_UNBUFFERED
;
1338 if (uFlags
!= MMIO_READ
&& uFlags
!= MMIO_WRITE
)
1339 return MMSYSERR_INVALPARAM
;
1341 if (MMIO_Flush(wm
, MMIO_EMPTYBUF
))
1342 return MMIOERR_CANNOTWRITE
;
1344 MMIO_GrabNextBuffer(wm
, uFlags
== MMIO_READ
);
1346 lpmmioinfo
->pchNext
= lpmmioinfo
->pchBuffer
;
1347 lpmmioinfo
->pchEndRead
= lpmmioinfo
->pchBuffer
+
1348 (wm
->info
.pchEndRead
- wm
->info
.pchBuffer
);
1349 lpmmioinfo
->pchEndWrite
= lpmmioinfo
->pchBuffer
+
1350 (wm
->info
.pchEndWrite
- wm
->info
.pchBuffer
);
1351 lpmmioinfo
->lDiskOffset
= wm
->info
.lDiskOffset
;
1352 lpmmioinfo
->lBufOffset
= wm
->info
.lBufOffset
;
1357 /**************************************************************************
1358 * mmioStringToFOURCCA [WINMM.131]
1360 FOURCC WINAPI
mmioStringToFOURCCA(LPCSTR sz
, UINT uFlags
)
1365 for (i
= 0; i
< 4 && sz
[i
]; i
++) {
1366 if (uFlags
& MMIO_TOUPPER
) {
1367 cc
[i
] = toupper(sz
[i
]);
1373 /* Pad with spaces */
1379 TRACE("Got %c%c%c%c\n",cc
[0],cc
[1],cc
[2],cc
[3]);
1380 return mmioFOURCC(cc
[0],cc
[1],cc
[2],cc
[3]);
1383 /**************************************************************************
1384 * mmioStringToFOURCCW [WINMM.132]
1386 FOURCC WINAPI
mmioStringToFOURCCW(LPCWSTR sz
, UINT uFlags
)
1388 LPSTR szA
= HEAP_strdupWtoA(GetProcessHeap(),0,sz
);
1389 FOURCC ret
= mmioStringToFOURCCA(szA
,uFlags
);
1391 HeapFree(GetProcessHeap(),0,szA
);
1395 /**************************************************************************
1396 * mmioStringToFOURCC [MMSYSTEM.1220]
1398 FOURCC WINAPI
mmioStringToFOURCC16(LPCSTR sz
, UINT16 uFlags
)
1400 return mmioStringToFOURCCA(sz
, uFlags
);
1403 /**************************************************************************
1404 * mmioInstallIOProc16 [MMSYSTEM.1221]
1406 LPMMIOPROC16 WINAPI
mmioInstallIOProc16(FOURCC fccIOProc
, LPMMIOPROC16 pIOProc
,
1409 return (LPMMIOPROC16
)MMIO_InstallIOProc(fccIOProc
, (LPMMIOPROC
)pIOProc
,
1410 dwFlags
, MMIO_PROC_16
);
1413 /**************************************************************************
1414 * mmioInstallIOProcA [WINMM.120]
1416 LPMMIOPROC WINAPI
mmioInstallIOProcA(FOURCC fccIOProc
,
1417 LPMMIOPROC pIOProc
, DWORD dwFlags
)
1419 return MMIO_InstallIOProc(fccIOProc
, pIOProc
, dwFlags
, MMIO_PROC_32A
);
1422 /**************************************************************************
1423 * mmioInstallIOProcW [WINMM.]
1425 LPMMIOPROC WINAPI
mmioInstallIOProcW(FOURCC fccIOProc
,
1426 LPMMIOPROC pIOProc
, DWORD dwFlags
)
1428 return MMIO_InstallIOProc(fccIOProc
, pIOProc
, dwFlags
, MMIO_PROC_32W
);
1431 /**************************************************************************
1432 * mmioSendMessage16 [MMSYSTEM.1222]
1434 LRESULT WINAPI
mmioSendMessage16(HMMIO16 hmmio
, UINT16 uMessage
,
1435 LPARAM lParam1
, LPARAM lParam2
)
1439 TRACE("(%04X, %u, %ld, %ld)\n", hmmio
, uMessage
, lParam1
, lParam2
);
1441 if (uMessage
< MMIOM_USER
)
1442 return MMSYSERR_INVALPARAM
;
1444 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
1445 return MMSYSERR_INVALHANDLE
;
1447 return MMIO_SendMessage(wm
, uMessage
, lParam1
, lParam2
, MMIO_PROC_16
);
1450 /**************************************************************************
1451 * mmioSendMessage [WINMM.]
1453 LRESULT WINAPI
mmioSendMessage(HMMIO hmmio
, UINT uMessage
,
1454 LPARAM lParam1
, LPARAM lParam2
)
1458 TRACE("(%04X, %u, %ld, %ld)\n", hmmio
, uMessage
, lParam1
, lParam2
);
1460 if (uMessage
< MMIOM_USER
)
1461 return MMSYSERR_INVALPARAM
;
1463 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
1464 return MMSYSERR_INVALHANDLE
;
1466 return MMIO_SendMessage(wm
, uMessage
, lParam1
, lParam2
, MMIO_PROC_32A
);
1469 /**************************************************************************
1470 * mmioDescend [MMSYSTEM.1223]
1472 UINT WINAPI
mmioDescend(HMMIO hmmio
, LPMMCKINFO lpck
,
1473 const MMCKINFO
* lpckParent
, UINT uFlags
)
1480 TRACE("(%04X, %p, %p, %04X);\n", hmmio
, lpck
, lpckParent
, uFlags
);
1483 return MMSYSERR_INVALPARAM
;
1485 dwOldPos
= mmioSeek(hmmio
, 0, SEEK_CUR
);
1486 TRACE("dwOldPos=%ld\n", dwOldPos
);
1488 if (lpckParent
!= NULL
) {
1489 TRACE("seek inside parent at %ld !\n", lpckParent
->dwDataOffset
);
1490 /* EPP: was dwOldPos = mmioSeek(hmmio,lpckParent->dwDataOffset,SEEK_SET); */
1491 if (dwOldPos
< lpckParent
->dwDataOffset
||
1492 dwOldPos
>= lpckParent
->dwDataOffset
+ lpckParent
->cksize
) {
1493 WARN("outside parent chunk\n");
1494 return MMIOERR_CHUNKNOTFOUND
;
1498 /* The SDK docu says 'ckid' is used for all cases. Real World
1499 * examples disagree -Marcus,990216.
1503 /* find_chunk looks for 'ckid' */
1504 if (uFlags
& MMIO_FINDCHUNK
)
1505 srchCkId
= lpck
->ckid
;
1506 /* find_riff and find_list look for 'fccType' */
1507 if (uFlags
& MMIO_FINDLIST
) {
1508 srchCkId
= FOURCC_LIST
;
1509 srchType
= lpck
->fccType
;
1511 if (uFlags
& MMIO_FINDRIFF
) {
1512 srchCkId
= FOURCC_RIFF
;
1513 srchType
= lpck
->fccType
;
1516 if (uFlags
& (MMIO_FINDCHUNK
|MMIO_FINDLIST
|MMIO_FINDRIFF
)) {
1517 TRACE("searching for %.4s.%.4s\n",
1519 srchType
?(LPSTR
)&srchType
:"any ");
1524 ix
= mmioRead(hmmio
, (LPSTR
)lpck
, 3 * sizeof(DWORD
));
1525 if (ix
< 2*sizeof(DWORD
)) {
1526 mmioSeek(hmmio
, dwOldPos
, SEEK_SET
);
1527 WARN("return ChunkNotFound\n");
1528 return MMIOERR_CHUNKNOTFOUND
;
1530 lpck
->dwDataOffset
= dwOldPos
+ 2 * sizeof(DWORD
);
1531 if (ix
< lpck
->dwDataOffset
- dwOldPos
) {
1532 mmioSeek(hmmio
, dwOldPos
, SEEK_SET
);
1533 WARN("return ChunkNotFound\n");
1534 return MMIOERR_CHUNKNOTFOUND
;
1536 TRACE("ckid=%.4s fcc=%.4s cksize=%08lX !\n",
1538 srchType
?(LPSTR
)&lpck
->fccType
:"<na>",
1540 if ((srchCkId
== lpck
->ckid
) &&
1541 (!srchType
|| (srchType
== lpck
->fccType
))
1545 dwOldPos
= lpck
->dwDataOffset
+ ((lpck
->cksize
+ 1) & ~1);
1546 mmioSeek(hmmio
, dwOldPos
, SEEK_SET
);
1549 /* FIXME: unverified, does it do this? */
1550 /* NB: This part is used by WAVE_mciOpen, among others */
1551 if (mmioRead(hmmio
, (LPSTR
)lpck
, 3 * sizeof(DWORD
)) < 3 * sizeof(DWORD
)) {
1552 mmioSeek(hmmio
, dwOldPos
, SEEK_SET
);
1553 WARN("return ChunkNotFound 2nd\n");
1554 return MMIOERR_CHUNKNOTFOUND
;
1556 lpck
->dwDataOffset
= dwOldPos
+ 2 * sizeof(DWORD
);
1559 /* If we were looking for RIFF/LIST chunks, the final file position
1560 * is after the chunkid. If we were just looking for the chunk
1561 * it is after the cksize. So add 4 in RIFF/LIST case.
1563 if (lpck
->ckid
== FOURCC_RIFF
|| lpck
->ckid
== FOURCC_LIST
)
1564 mmioSeek(hmmio
, lpck
->dwDataOffset
+ sizeof(DWORD
), SEEK_SET
);
1566 mmioSeek(hmmio
, lpck
->dwDataOffset
, SEEK_SET
);
1567 TRACE("lpck: ckid=%.4s, cksize=%ld, dwDataOffset=%ld fccType=%08lX (%.4s)!\n",
1568 (LPSTR
)&lpck
->ckid
, lpck
->cksize
, lpck
->dwDataOffset
,
1569 lpck
->fccType
, srchType
?(LPSTR
)&lpck
->fccType
:"");
1573 /**************************************************************************
1574 * mmioDescend16 [MMSYSTEM.1223]
1576 UINT16 WINAPI
mmioDescend16(HMMIO16 hmmio
, LPMMCKINFO lpck
,
1577 const MMCKINFO
* lpckParent
, UINT16 uFlags
)
1579 return mmioDescend(hmmio
, lpck
, lpckParent
, uFlags
);
1582 /**************************************************************************
1583 * mmioAscend [WINMM.113]
1585 UINT WINAPI
mmioAscend(HMMIO hmmio
, LPMMCKINFO lpck
, UINT uFlags
)
1587 TRACE("(%04X, %p, %04X);\n", hmmio
, lpck
, uFlags
);
1589 if (lpck
->dwFlags
& MMIO_DIRTY
) {
1590 DWORD dwOldPos
, dwNewSize
, dwSizePos
;
1592 TRACE("chunk is marked MMIO_DIRTY, correcting chunk size\n");
1593 dwOldPos
= mmioSeek(hmmio
, 0, SEEK_CUR
);
1594 TRACE("dwOldPos=%ld lpck->dwDataOffset = %ld\n", dwOldPos
, lpck
->dwDataOffset
);
1595 dwNewSize
= dwOldPos
- lpck
->dwDataOffset
;
1596 if (dwNewSize
!= lpck
->cksize
) {
1597 TRACE("dwNewSize=%ld\n", dwNewSize
);
1598 lpck
->cksize
= dwNewSize
;
1600 dwSizePos
= lpck
->dwDataOffset
- sizeof(DWORD
);
1601 TRACE("dwSizePos=%ld\n", dwSizePos
);
1603 mmioSeek(hmmio
, dwSizePos
, SEEK_SET
);
1604 mmioWrite(hmmio
, (LPSTR
)&dwNewSize
, sizeof(DWORD
));
1608 mmioSeek(hmmio
, lpck
->dwDataOffset
+ ((lpck
->cksize
+ 1) & ~1), SEEK_SET
);
1613 /**************************************************************************
1614 * mmioAscend [MMSYSTEM.1224]
1616 UINT16 WINAPI
mmioAscend16(HMMIO16 hmmio
, MMCKINFO
* lpck
, UINT16 uFlags
)
1618 return mmioAscend(hmmio
,lpck
,uFlags
);
1621 /**************************************************************************
1622 * mmioCreateChunk [MMSYSTEM.1225]
1624 UINT16 WINAPI
mmioCreateChunk16(HMMIO16 hmmio
, MMCKINFO
* lpck
, UINT16 uFlags
)
1630 TRACE("(%04X, %p, %04X);\n", hmmio
, lpck
, uFlags
);
1632 dwOldPos
= mmioSeek(hmmio
, 0, SEEK_CUR
);
1633 TRACE("dwOldPos=%ld\n", dwOldPos
);
1635 if (uFlags
== MMIO_CREATELIST
)
1636 lpck
->ckid
= FOURCC_LIST
;
1637 else if (uFlags
== MMIO_CREATERIFF
)
1638 lpck
->ckid
= FOURCC_RIFF
;
1640 TRACE("ckid=%08lX\n", lpck
->ckid
);
1642 size
= 2 * sizeof(DWORD
);
1643 lpck
->dwDataOffset
= dwOldPos
+ size
;
1645 if (lpck
->ckid
== FOURCC_RIFF
|| lpck
->ckid
== FOURCC_LIST
)
1646 size
+= sizeof(DWORD
);
1647 lpck
->dwFlags
= MMIO_DIRTY
;
1649 ix
= mmioWrite(hmmio
, (LPSTR
)lpck
, size
);
1650 TRACE("after mmioWrite ix = %ld req = %ld, errno = %d\n",ix
, size
, errno
);
1652 mmioSeek(hmmio
, dwOldPos
, SEEK_SET
);
1653 WARN("return CannotWrite\n");
1654 return MMIOERR_CANNOTWRITE
;
1660 /**************************************************************************
1661 * mmioCreateChunk [WINMM.115]
1663 UINT WINAPI
mmioCreateChunk(HMMIO hmmio
, MMCKINFO
* lpck
, UINT uFlags
)
1665 return mmioCreateChunk16(hmmio
, lpck
, uFlags
);
1668 /**************************************************************************
1669 * mmioRename [MMSYSTEM.1226]
1671 UINT16 WINAPI
mmioRename16(LPCSTR szFileName
, LPCSTR szNewFileName
,
1672 MMIOINFO16
* lpmmioinfo
, DWORD dwRenameFlags
)
1674 UINT16 result
= MMSYSERR_ERROR
;
1675 LPMMIOPROC16 ioProc
;
1677 TRACE("('%s', '%s', %p, %08lX);\n",
1678 szFileName
, szNewFileName
, lpmmioinfo
, dwRenameFlags
);
1680 /* If both params are NULL, then parse the file name */
1681 if (lpmmioinfo
&& lpmmioinfo
->fccIOProc
== 0 && lpmmioinfo
->pIOProc
== NULL
)
1682 lpmmioinfo
->fccIOProc
= MMIO_ParseExt(szFileName
);
1684 /* Handle any unhandled/error case from above. Assume DOS file */
1685 if (!lpmmioinfo
|| (lpmmioinfo
->fccIOProc
== 0 && lpmmioinfo
->pIOProc
== NULL
))
1686 ioProc
= (LPMMIOPROC16
)mmioDosIOProc
;
1687 /* if just the four character code is present, look up IO proc */
1688 else if (lpmmioinfo
->pIOProc
== NULL
)
1689 ioProc
= mmioInstallIOProc16(lpmmioinfo
->fccIOProc
, NULL
, MMIO_FINDPROC
);
1691 ioProc
= lpmmioinfo
->pIOProc
;
1693 /* FIXME: ioProc is likely a segmented address, thus needing a
1694 * thunk somewhere. The main issue is that Wine's current thunking
1695 * 32 to 16 only supports pascal calling convention
1698 result
= (ioProc
)(0, MMIOM_RENAME
,
1699 (LPARAM
)szFileName
, (LPARAM
)szNewFileName
);
1704 /**************************************************************************
1705 * mmioRenameA [WINMM.125]
1707 UINT WINAPI
mmioRenameA(LPCSTR szFileName
, LPCSTR szNewFileName
,
1708 MMIOINFO
* lpmmioinfo
, DWORD dwRenameFlags
)
1710 UINT result
= MMSYSERR_ERROR
;
1713 TRACE("('%s', '%s', %p, %08lX);\n",
1714 szFileName
, szNewFileName
, lpmmioinfo
, dwRenameFlags
);
1716 /* If both params are NULL, then parse the file name */
1717 if (lpmmioinfo
&& lpmmioinfo
->fccIOProc
== 0 && lpmmioinfo
->pIOProc
== NULL
)
1718 lpmmioinfo
->fccIOProc
= MMIO_ParseExt(szFileName
);
1720 /* Handle any unhandled/error case from above. Assume DOS file */
1721 if (!lpmmioinfo
|| (lpmmioinfo
->fccIOProc
== 0 && lpmmioinfo
->pIOProc
== NULL
))
1722 ioProc
= (LPMMIOPROC
)mmioDosIOProc
;
1723 /* if just the four character code is present, look up IO proc */
1724 else if (lpmmioinfo
->pIOProc
== NULL
)
1725 ioProc
= MMIO_InstallIOProc(lpmmioinfo
->fccIOProc
, NULL
,
1726 MMIO_FINDPROC
, MMIO_PROC_32A
);
1727 else /* use relevant ioProc */
1728 ioProc
= lpmmioinfo
->pIOProc
;
1731 result
= (ioProc
)(0, MMIOM_RENAME
,
1732 (LPARAM
)szFileName
, (LPARAM
)szNewFileName
);
1737 /**************************************************************************
1738 * mmioRenameW [WINMM.126]
1740 UINT WINAPI
mmioRenameW(LPCWSTR szFileName
, LPCWSTR szNewFileName
,
1741 MMIOINFO
* lpmmioinfo
, DWORD dwRenameFlags
)
1743 LPSTR szFn
= HEAP_strdupWtoA(GetProcessHeap(), 0, szFileName
);
1744 LPSTR sznFn
= HEAP_strdupWtoA(GetProcessHeap(), 0, szNewFileName
);
1745 UINT ret
= mmioRenameA(szFn
, sznFn
, lpmmioinfo
, dwRenameFlags
);
1747 HeapFree(GetProcessHeap(),0,szFn
);
1748 HeapFree(GetProcessHeap(),0,sznFn
);