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 * + IO buffering is limited to 64k
14 * + optimization of internal buffers (seg / lin)
15 * + even in 32 bit only, a seg ptr IO buffer is allocated (after this is
16 * fixed, we'll have a proper 32/16 separation)
18 * + rename operation is broken
27 #include "wine/winbase16.h"
29 #include "selectors.h"
32 #include "debugtools.h"
35 DEFAULT_DEBUG_CHANNEL(mmio
);
37 /**************************************************************************
38 * mmioDosIOProc [internal]
40 static LRESULT
mmioDosIOProc(LPMMIOINFO lpmmioinfo
, UINT uMessage
,
41 LPARAM lParam1
, LPARAM lParam2
)
43 LRESULT ret
= MMSYSERR_NOERROR
;
45 TRACE("(%p, %X, %ld, %ld);\n", lpmmioinfo
, uMessage
, lParam1
, lParam2
);
51 * lParam1 = szFileName parameter from mmioOpen
52 * lParam2 = reserved (we use it for 16-bitness)
53 * Returns: zero on success, error code on error
54 * NOTE: lDiskOffset automatically set to zero
57 LPCSTR szFileName
= (LPCSTR
)lParam1
;
59 if (lpmmioinfo
->dwFlags
& MMIO_GETTEMP
) {
60 FIXME("MMIO_GETTEMP not implemented\n");
61 return MMIOERR_CANNOTOPEN
;
64 /* if filename NULL, assume open file handle in adwInfo[0] */
67 lpmmioinfo
->adwInfo
[0] = FILE_GetHandle(lpmmioinfo
->adwInfo
[0]);
71 lpmmioinfo
->adwInfo
[0] = (DWORD
)OpenFile(szFileName
, &ofs
,
73 if (lpmmioinfo
->adwInfo
[0] == -1)
74 ret
= MMIOERR_CANNOTOPEN
;
80 * lParam1 = wFlags parameter from mmioClose
82 * Returns: zero on success, error code on error
84 if (!(lParam1
& MMIO_FHOPEN
))
85 _lclose((HFILE
)lpmmioinfo
->adwInfo
[0]);
90 * lParam1 = huge pointer to read buffer
91 * lParam2 = number of bytes to read
92 * Returns: number of bytes read, 0 for EOF, -1 for error (error code
95 ret
= _lread((HFILE
)lpmmioinfo
->adwInfo
[0], (HPSTR
)lParam1
, (LONG
)lParam2
);
97 lpmmioinfo
->lDiskOffset
+= ret
;
102 case MMIOM_WRITEFLUSH
:
103 /* no internal buffering, so WRITEFLUSH handled same as WRITE */
106 * lParam1 = huge pointer to write buffer
107 * lParam2 = number of bytes to write
108 * Returns: number of bytes written, -1 for error (error code in
111 ret
= _hwrite((HFILE
)lpmmioinfo
->adwInfo
[0], (HPSTR
)lParam1
, (LONG
)lParam2
);
113 lpmmioinfo
->lDiskOffset
+= ret
;
118 * lParam1 = new position
119 * lParam2 = from whence to seek (SEEK_SET, SEEK_CUR, SEEK_END)
120 * Returns: new file postion, -1 on error
122 ret
= _llseek((HFILE
)lpmmioinfo
->adwInfo
[0], (LONG
)lParam1
, (LONG
)lParam2
);
124 lpmmioinfo
->lDiskOffset
= ret
;
131 * Returns: zero on success, non-zero on failure
133 FIXME("MMIOM_RENAME unimplemented\n");
134 return MMIOERR_FILENOTFOUND
;
137 FIXME("unexpected message %u\n", uMessage
);
144 /**************************************************************************
145 * mmioMemIOProc [internal]
147 static LRESULT
mmioMemIOProc(LPMMIOINFO lpmmioinfo
, UINT uMessage
,
148 LPARAM lParam1
, LPARAM lParam2
)
150 TRACE("(%p,0x%04x,0x%08lx,0x%08lx)\n", lpmmioinfo
, uMessage
, lParam1
, lParam2
);
156 * lParam1 = filename (must be NULL)
157 * lParam2 = reserved (we use it for 16-bitness)
158 * Returns: zero on success, error code on error
159 * NOTE: lDiskOffset automatically set to zero
161 /* FIXME: io proc shouldn't change it */
162 if (!(lpmmioinfo
->dwFlags
& MMIO_CREATE
))
163 lpmmioinfo
->pchEndRead
= lpmmioinfo
->pchEndWrite
;
168 * lParam1 = wFlags parameter from mmioClose
170 * Returns: zero on success, error code on error
176 * lParam1 = huge pointer to read buffer
177 * lParam2 = number of bytes to read
178 * Returns: number of bytes read, 0 for EOF, -1 for error (error code
180 * NOTE: lDiskOffset should be updated
182 FIXME("MMIOM_READ on memory files should not occur, buffer may be lost!\n");
186 case MMIOM_WRITEFLUSH
:
187 /* no internal buffering, so WRITEFLUSH handled same as WRITE */
190 * lParam1 = huge pointer to write buffer
191 * lParam2 = number of bytes to write
192 * Returns: number of bytes written, -1 for error (error code in
194 * NOTE: lDiskOffset should be updated
196 FIXME("MMIOM_WRITE on memory files should not occur, buffer may be lost!\n");
201 * lParam1 = new position
202 * lParam2 = from whence to seek (SEEK_SET, SEEK_CUR, SEEK_END)
203 * Returns: new file postion, -1 on error
204 * NOTE: lDiskOffset should be updated
206 FIXME("MMIOM_SEEK on memory files should not occur, buffer may be lost!\n");
210 FIXME("unexpected message %u\n", uMessage
);
218 enum mmioProcType
{MMIO_PROC_16
,MMIO_PROC_32A
,MMIO_PROC_32W
};
222 struct IOProcList
*pNext
; /* Next item in linked list */
223 FOURCC fourCC
; /* four-character code identifying IOProc */
224 LPMMIOPROC pIOProc
; /* pointer to IProc */
225 enum mmioProcType type
; /* 16, 32A or 32W */
226 int count
; /* number of objects linked to it */
229 /* This array will be the entire list for most apps */
231 static struct IOProcList defaultProcs
[] = {
232 {&defaultProcs
[1], FOURCC_DOS
, (LPMMIOPROC
)mmioDosIOProc
, MMIO_PROC_32A
, 0},
233 {NULL
, FOURCC_MEM
, (LPMMIOPROC
)mmioMemIOProc
, MMIO_PROC_32A
, 0},
236 static struct IOProcList
* pIOProcListAnchor
= &defaultProcs
[0];
238 /****************************************************************
239 * MMIO_FindProcNode [INTERNAL]
241 * Finds the ProcList node associated with a given FOURCC code.
243 static struct IOProcList
* MMIO_FindProcNode(FOURCC fccIOProc
)
245 struct IOProcList
* pListNode
;
247 for (pListNode
= pIOProcListAnchor
; pListNode
; pListNode
= pListNode
->pNext
) {
248 if (pListNode
->fourCC
== fccIOProc
) {
255 /****************************************************************
256 * MMIO_InstallIOProc [INTERNAL]
258 static LPMMIOPROC
MMIO_InstallIOProc(FOURCC fccIOProc
, LPMMIOPROC pIOProc
,
259 DWORD dwFlags
, enum mmioProcType type
)
261 LPMMIOPROC lpProc
= NULL
;
262 struct IOProcList
* pListNode
;
263 struct IOProcList
** ppListNode
;
265 TRACE("(%ld, %p, %08lX, %i)\n", fccIOProc
, pIOProc
, dwFlags
, type
);
267 if (dwFlags
& MMIO_GLOBALPROC
)
268 FIXME("Global procedures not implemented\n");
270 /* just handle the known procedures for now */
271 switch (dwFlags
& (MMIO_INSTALLPROC
|MMIO_REMOVEPROC
|MMIO_FINDPROC
)) {
272 case MMIO_INSTALLPROC
:
273 /* Create new entry for the IOProc list */
274 pListNode
= HeapAlloc(GetProcessHeap(), 0, sizeof(*pListNode
));
276 /* Fill in this node */
277 pListNode
->fourCC
= fccIOProc
;
278 pListNode
->pIOProc
= pIOProc
;
279 pListNode
->type
= type
;
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 lpProc
= (*ppListNode
)->pIOProc
;
316 HeapFree(GetProcessHeap(), 0, *ppListNode
);
317 *ppListNode
= (*ppListNode
)->pNext
;
323 if ((pListNode
= MMIO_FindProcNode(fccIOProc
))) {
324 lpProc
= pListNode
->pIOProc
;
332 /****************************************************************
333 * MMIO_Map32To16 [INTERNAL]
335 static LRESULT
MMIO_Map32To16(DWORD wMsg
, LPARAM
* lp1
, LPARAM
* lp2
)
340 void* lp
= SEGPTR_ALLOC(strlen((LPSTR
)*lp1
) + 1);
341 if (!lp
) return MMSYSERR_NOMEM
;
343 strcpy((void*)SEGPTR_GET(lp
), (LPSTR
)*lp1
);
353 case MMIOM_WRITEFLUSH
:
355 void* lp
= SEGPTR_ALLOC(*lp2
);
356 if (!lp
) return MMSYSERR_NOMEM
;
358 if (wMsg
!= MMIOM_READ
)
359 memcpy((void*)SEGPTR_GET(lp
), (void*)*lp1
, *lp2
);
364 TRACE("Not a mappable message (%ld)\n", wMsg
);
366 return MMSYSERR_NOERROR
;
369 /****************************************************************
370 * MMIO_UnMap32To16 [INTERNAL]
372 static LRESULT
MMIO_UnMap32To16(DWORD wMsg
, LPARAM lParam1
, LPARAM lParam2
,
373 LPARAM lp1
, LPARAM lp2
)
377 if (!SEGPTR_FREE((void*)lp1
)) {
378 FIXME("bad free line=%d\n", __LINE__
);
386 memcpy((void*)lParam1
, (void*)SEGPTR_GET((void*)lp1
), lp2
);
389 case MMIOM_WRITEFLUSH
:
390 if (!SEGPTR_FREE((void*)lp1
)) {
391 FIXME("bad free line=%d\n", __LINE__
);
395 TRACE("Not a mappable message (%ld)\n", wMsg
);
397 return MMSYSERR_NOERROR
;
400 /****************************************************************
401 * MMIO_GenerateInfoForIOProc [INTERNAL]
403 static SEGPTR
MMIO_GenerateInfoForIOProc(const WINE_MMIO
* wm
)
405 SEGPTR lp
= (SEGPTR
)SEGPTR_ALLOC(sizeof(MMIOINFO16
));
406 LPMMIOINFO16 mmioInfo16
= (LPMMIOINFO16
)SEGPTR_GET((void*)lp
);
408 memset(mmioInfo16
, 0, sizeof(MMIOINFO16
));
410 mmioInfo16
->lDiskOffset
= wm
->info
.lDiskOffset
;
411 mmioInfo16
->adwInfo
[0] = wm
->info
.adwInfo
[0];
412 mmioInfo16
->adwInfo
[1] = wm
->info
.adwInfo
[1];
413 mmioInfo16
->adwInfo
[2] = wm
->info
.adwInfo
[2];
414 mmioInfo16
->adwInfo
[3] = wm
->info
.adwInfo
[3];
419 /****************************************************************
420 * MMIO_UpdateInfoForIOProc [INTERNAL]
422 static LRESULT
MMIO_UpdateInfoForIOProc(WINE_MMIO
* wm
, SEGPTR segmmioInfo16
)
424 const MMIOINFO16
* mmioInfo16
;
426 mmioInfo16
= (const MMIOINFO16
*)SEGPTR_GET((void*)segmmioInfo16
);
428 wm
->info
.lDiskOffset
= mmioInfo16
->lDiskOffset
;
429 wm
->info
.adwInfo
[0] = mmioInfo16
->adwInfo
[0];
430 wm
->info
.adwInfo
[1] = mmioInfo16
->adwInfo
[1];
431 wm
->info
.adwInfo
[2] = mmioInfo16
->adwInfo
[2];
432 wm
->info
.adwInfo
[3] = mmioInfo16
->adwInfo
[3];
434 if (!SEGPTR_FREE((void*)segmmioInfo16
)) {
435 FIXME("bad free line=%d\n", __LINE__
);
438 return MMSYSERR_NOERROR
;
441 /****************************************************************
442 * MMIO_SendMessage [INTERNAL]
444 static LRESULT
MMIO_SendMessage(LPWINE_MMIO wm
, DWORD wMsg
, LPARAM lParam1
,
445 LPARAM lParam2
, enum mmioProcType type
)
448 SEGPTR segmmioInfo16
;
449 LPARAM lp1
= lParam1
, lp2
= lParam2
;
451 if (!wm
->ioProc
|| !wm
->info
.pIOProc
) {
453 result
= MMSYSERR_INVALPARAM
;
456 switch (wm
->ioProc
->type
) {
458 segmmioInfo16
= MMIO_GenerateInfoForIOProc(wm
);
459 if (wm
->ioProc
->type
!= type
) {
460 /* map (lParam1, lParam2) into (lp1, lp2) 32=>16 */
461 if ((result
= MMIO_Map32To16(wMsg
, &lp1
, &lp2
)) != MMSYSERR_NOERROR
)
464 /* FIXME: is wm->info.pIOProc a segmented or a linear address ?
465 * sounds to me it's a segmented one, should use a thunk somewhere
467 result
= ((LPMMIOPROC16
)wm
->info
.pIOProc
)((LPSTR
)segmmioInfo16
,
470 if (wm
->ioProc
->type
!= type
) {
471 MMIO_UnMap32To16(wMsg
, lParam1
, lParam2
, lp1
, lp2
);
473 MMIO_UpdateInfoForIOProc(wm
, segmmioInfo16
);
477 if (wm
->ioProc
->type
!= type
) {
478 /* map (lParam1, lParam2) into (lp1, lp2) 16=>32 */
481 result
= (wm
->info
.pIOProc
)((LPSTR
)&wm
->info
, wMsg
, lp1
, lp2
);
484 if (wm
->ioProc
->type
!= type
) {
485 /* unmap (lParam1, lParam2) into (lp1, lp2) 16=>32 */
490 FIXME("Internal error\n");
491 result
= MMSYSERR_ERROR
;
497 /**************************************************************************
498 * MMIO_ParseExt [internal]
500 * Parses a filename for the extension.
503 * The FOURCC code for the extension if found, else 0.
505 static FOURCC
MMIO_ParseExt(LPCSTR szFileName
)
507 /* Filenames are of the form file.ext+ABC
508 FIXME: What if a '+' is part of the file name?
509 For now, we take the last '+' present */
513 /* Note that ext{Start,End} point to the . and + respectively */
516 TRACE("(%s)\n",debugstr_a(szFileName
));
518 extEnd
= strrchr(szFileName
,'+');
520 /* Need to parse to find the extension */
524 while (extStart
> szFileName
&& extStart
[0] != '.') {
528 if (extStart
== szFileName
) {
529 ERR("+ but no . in szFileName: %s\n", debugstr_a(szFileName
));
533 if (extEnd
- extStart
- 1 > 4)
534 WARN("Extension length > 4\n");
535 lstrcpynA(ext
,extStart
+ 1,min(extEnd
-extStart
,5));
536 TRACE("Got extension: %s\n", debugstr_a(ext
));
537 /* FOURCC codes identifying file-extentions must be uppercase */
538 ret
= mmioStringToFOURCCA(ext
, MMIO_TOUPPER
);
544 /**************************************************************************
545 * MMIO_Get [internal]
547 * Retirieves from current process the mmio object
549 static LPWINE_MMIO
MMIO_Get(LPWINE_MM_IDATA iData
, HMMIO h
)
551 LPWINE_MMIO wm
= NULL
;
553 if (!iData
) iData
= MULTIMEDIA_GetIData();
555 EnterCriticalSection(&iData
->cs
);
556 for (wm
= iData
->lpMMIO
; wm
; wm
= wm
->lpNext
) {
557 if (wm
->info
.hmmio
== h
)
560 LeaveCriticalSection(&iData
->cs
);
564 /**************************************************************************
565 * MMIO_Create [internal]
567 * Creates an internal representation for a mmio instance
569 static LPWINE_MMIO
MMIO_Create(void)
571 static WORD MMIO_counter
= 0;
573 LPWINE_MM_IDATA iData
= MULTIMEDIA_GetIData();
575 wm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WINE_MMIO
));
577 EnterCriticalSection(&iData
->cs
);
578 while (MMIO_Get(iData
, ++MMIO_counter
));
579 wm
->info
.hmmio
= MMIO_counter
;
580 wm
->lpNext
= iData
->lpMMIO
;
582 LeaveCriticalSection(&iData
->cs
);
587 /**************************************************************************
588 * MMIO_Destroy [internal]
590 * Destroys an internal representation for a mmio instance
592 static BOOL
MMIO_Destroy(LPWINE_MMIO wm
)
594 LPWINE_MM_IDATA iData
= MULTIMEDIA_GetIData();
597 EnterCriticalSection(&iData
->cs
);
598 for (m
= &(iData
->lpMMIO
); *m
&& *m
!= wm
; m
= &(*m
)->lpNext
);
601 HeapFree(GetProcessHeap(), 0, *m
);
604 LeaveCriticalSection(&iData
->cs
);
605 return wm
? FALSE
: TRUE
;
608 /****************************************************************
609 * MMIO_Flush [INTERNAL]
611 static LRESULT
MMIO_Flush(WINE_MMIO
* wm
, UINT uFlags
)
613 if ((!wm
->info
.cchBuffer
) || (wm
->info
.fccIOProc
== FOURCC_MEM
)) {
617 /* not quite sure what to do here, but I'll guess */
618 if (wm
->info
.dwFlags
& MMIO_DIRTY
) {
619 MMIO_SendMessage(wm
, MMIOM_SEEK
, wm
->info
.lBufOffset
,
620 SEEK_SET
, MMIO_PROC_32A
);
621 MMIO_SendMessage(wm
, MMIOM_WRITE
, (LPARAM
)wm
->info
.pchBuffer
,
622 wm
->info
.pchNext
- wm
->info
.pchBuffer
, MMIO_PROC_32A
);
623 wm
->info
.dwFlags
&= ~MMIO_DIRTY
;
625 if (uFlags
& MMIO_EMPTYBUF
) {
626 wm
->info
.pchNext
= wm
->info
.pchBuffer
;
627 wm
->info
.pchEndRead
= wm
->info
.pchBuffer
;
628 wm
->info
.pchEndWrite
= wm
->info
.pchBuffer
;
634 /***************************************************************************
635 * MMIO_GrabNextBuffer [INTERNAL]
637 static LONG
MMIO_GrabNextBuffer(LPWINE_MMIO wm
, int for_read
)
639 LONG size
= wm
->info
.cchBuffer
;
641 TRACE("bo=%lx do=%lx of=%lx\n",
642 wm
->info
.lBufOffset
, wm
->info
.lDiskOffset
,
643 MMIO_SendMessage(wm
, MMIOM_SEEK
, 0, SEEK_CUR
, MMIO_PROC_32A
));
645 wm
->info
.lBufOffset
= wm
->info
.lDiskOffset
;
646 wm
->info
.pchNext
= wm
->info
.pchBuffer
;
647 wm
->info
.pchEndRead
= wm
->info
.pchBuffer
;
648 wm
->info
.pchEndWrite
= wm
->info
.pchBuffer
;
651 size
= MMIO_SendMessage(wm
, MMIOM_READ
, (LPARAM
)wm
->info
.pchBuffer
,
652 size
, MMIO_PROC_32A
);
654 wm
->info
.pchEndRead
+= size
;
659 /***************************************************************************
660 * MMIO_SetBuffer [INTERNAL]
662 static UINT
MMIO_SetBuffer(WINE_MMIO
* wm
, void* pchBuffer
, LONG cchBuffer
,
663 UINT uFlags
, BOOL bFrom32
)
665 TRACE("(%p %p %ld %u %d)\n", wm
, pchBuffer
, cchBuffer
, uFlags
, bFrom32
);
667 if (uFlags
) return MMSYSERR_INVALPARAM
;
668 if (cchBuffer
> 0xFFFF) {
669 FIXME("Not handling huge mmio buffers yet (%ld >= 64k)\n", cchBuffer
);
670 return MMSYSERR_INVALPARAM
;
673 if (MMIO_Flush(wm
, MMIO_EMPTYBUF
) != 0)
674 return MMIOERR_CANNOTWRITE
;
676 if ((!cchBuffer
|| pchBuffer
) && (wm
->info
.dwFlags
& MMIO_ALLOCBUF
)) {
677 GlobalUnlock16(wm
->hMem
);
678 GlobalFree16(wm
->hMem
);
679 wm
->info
.dwFlags
&= ~MMIO_ALLOCBUF
;
683 wm
->info
.pchBuffer
= pchBuffer
;
686 wm
->info
.pchBuffer
= PTR_SEG_TO_LIN(pchBuffer
);
687 wm
->buffer16
= (SEGPTR
)pchBuffer
;
690 } else if (cchBuffer
&& (wm
->info
.dwFlags
& MMIO_ALLOCBUF
)) {
692 GlobalUnlock16(wm
->hMem
);
693 hNewBuf
= GlobalReAlloc16(wm
->hMem
, cchBuffer
, 0);
695 /* FIXME: this assumes the memory block didn't move */
696 GlobalLock16(wm
->hMem
);
697 return MMIOERR_OUTOFMEMORY
;
700 } else if (cchBuffer
) {
701 if (!(wm
->hMem
= GlobalAlloc16(GMEM_MOVEABLE
, cchBuffer
)))
702 return MMIOERR_OUTOFMEMORY
;
703 wm
->info
.dwFlags
|= MMIO_ALLOCBUF
;
705 wm
->info
.pchBuffer
= NULL
;
711 wm
->buffer16
= WIN16_GlobalLock16(wm
->hMem
);
712 wm
->info
.pchBuffer
= (void*)PTR_SEG_TO_LIN((void*)wm
->buffer16
);
715 wm
->info
.cchBuffer
= cchBuffer
;
716 wm
->info
.pchNext
= wm
->info
.pchBuffer
;
717 wm
->info
.pchEndRead
= wm
->info
.pchBuffer
;
718 wm
->info
.pchEndWrite
= wm
->info
.pchBuffer
+ cchBuffer
;
719 wm
->info
.lBufOffset
= 0;
724 /**************************************************************************
725 * MMIO_Open [internal]
727 static HMMIO
MMIO_Open(LPSTR szFileName
, MMIOINFO
* refmminfo
,
728 DWORD dwOpenFlags
, enum mmioProcType type
)
732 TRACE("('%s', %p, %08lX, %d);\n", szFileName
, refmminfo
, dwOpenFlags
, type
);
734 if (dwOpenFlags
& (MMIO_PARSE
|MMIO_EXIST
)) {
735 char buffer
[MAX_PATH
];
737 if (GetFullPathNameA(szFileName
, sizeof(buffer
), buffer
, NULL
) >= sizeof(buffer
))
738 return (HMMIO16
)FALSE
;
739 if ((dwOpenFlags
& MMIO_EXIST
) && (GetFileAttributesA(buffer
) == -1))
741 strcpy(szFileName
, buffer
);
745 if ((wm
= MMIO_Create()) == NULL
)
748 /* If both params are NULL, then parse the file name */
749 if (refmminfo
->fccIOProc
== 0 && refmminfo
->pIOProc
== NULL
) {
750 wm
->info
.fccIOProc
= MMIO_ParseExt(szFileName
);
751 /* Handle any unhandled/error case. Assume DOS file */
752 if (wm
->info
.fccIOProc
== 0)
753 wm
->info
.fccIOProc
= FOURCC_DOS
;
754 if (!(wm
->ioProc
= MMIO_FindProcNode(wm
->info
.fccIOProc
))) goto error2
;
755 wm
->info
.pIOProc
= wm
->ioProc
->pIOProc
;
756 wm
->bTmpIOProc
= FALSE
;
758 /* if just the four character code is present, look up IO proc */
759 else if (refmminfo
->pIOProc
== NULL
) {
760 wm
->info
.fccIOProc
= refmminfo
->fccIOProc
;
761 if (!(wm
->ioProc
= MMIO_FindProcNode(wm
->info
.fccIOProc
))) goto error2
;
762 wm
->info
.pIOProc
= wm
->ioProc
->pIOProc
;
763 wm
->bTmpIOProc
= FALSE
;
765 /* if IO proc specified, use it and specified four character code */
767 wm
->info
.fccIOProc
= refmminfo
->fccIOProc
;
768 wm
->info
.pIOProc
= refmminfo
->pIOProc
;
769 MMIO_InstallIOProc(wm
->info
.fccIOProc
, wm
->info
.pIOProc
,
770 MMIO_INSTALLPROC
, type
);
771 if (!(wm
->ioProc
= MMIO_FindProcNode(wm
->info
.fccIOProc
))) goto error2
;
772 assert(wm
->ioProc
->pIOProc
== refmminfo
->pIOProc
);
773 wm
->info
.pIOProc
= wm
->ioProc
->pIOProc
;
774 wm
->bTmpIOProc
= TRUE
;
778 if (dwOpenFlags
& MMIO_ALLOCBUF
) {
779 if ((refmminfo
->wErrorRet
= mmioSetBuffer(wm
->info
.hmmio
, NULL
,
780 MMIO_DEFAULTBUFFER
, 0)))
782 } else if (wm
->info
.fccIOProc
== FOURCC_MEM
) {
783 refmminfo
->wErrorRet
= MMIO_SetBuffer(wm
, refmminfo
->pchBuffer
,
784 refmminfo
->cchBuffer
, 0,
785 type
!= MMIO_PROC_16
);
786 if (refmminfo
->wErrorRet
!= MMSYSERR_NOERROR
)
788 } /* else => unbuffered, wm->info.pchBuffer == NULL */
790 /* see mmioDosIOProc for that one */
791 wm
->info
.adwInfo
[0] = refmminfo
->adwInfo
[0];
792 wm
->info
.dwFlags
= dwOpenFlags
;
794 /* call IO proc to actually open file */
795 refmminfo
->wErrorRet
= MMIO_SendMessage(wm
, MMIOM_OPEN
, (LPARAM
)szFileName
,
796 type
== MMIO_PROC_16
, MMIO_PROC_32A
);
798 if (refmminfo
->wErrorRet
== 0)
799 return wm
->info
.hmmio
;
801 if (wm
->ioProc
) wm
->ioProc
->count
--;
807 /**************************************************************************
808 * mmioOpenW [WINMM.123]
810 HMMIO WINAPI
mmioOpenW(LPWSTR szFileName
, MMIOINFO
* lpmmioinfo
,
814 LPSTR szFn
= HEAP_strdupWtoA(GetProcessHeap(), 0, szFileName
);
817 ret
= MMIO_Open(szFn
, lpmmioinfo
, dwOpenFlags
, MMIO_PROC_32W
);
821 mmioinfo
.fccIOProc
= 0;
822 mmioinfo
.pIOProc
= NULL
;
823 mmioinfo
.pchBuffer
= NULL
;
824 mmioinfo
.cchBuffer
= 0;
826 ret
= MMIO_Open(szFn
, &mmioinfo
, dwOpenFlags
, MMIO_PROC_32W
);
829 HeapFree(GetProcessHeap(), 0, szFn
);
833 /**************************************************************************
834 * mmioOpenA [WINMM.122]
836 HMMIO WINAPI
mmioOpenA(LPSTR szFileName
, MMIOINFO
* lpmmioinfo
,
842 ret
= MMIO_Open(szFileName
, lpmmioinfo
, dwOpenFlags
, MMIO_PROC_32A
);
846 mmioinfo
.fccIOProc
= 0;
847 mmioinfo
.pIOProc
= NULL
;
848 mmioinfo
.pchBuffer
= NULL
;
849 mmioinfo
.cchBuffer
= 0;
851 ret
= MMIO_Open(szFileName
, &mmioinfo
, dwOpenFlags
, MMIO_PROC_32A
);
856 /**************************************************************************
857 * mmioOpen [MMSYSTEM.1210]
859 HMMIO16 WINAPI
mmioOpen16(LPSTR szFileName
, MMIOINFO16
* lpmmioinfo16
,
868 memset(&mmioinfo
, 0, sizeof(mmioinfo
));
870 mmioinfo
.dwFlags
= lpmmioinfo16
->dwFlags
;
871 mmioinfo
.fccIOProc
= lpmmioinfo16
->fccIOProc
;
872 mmioinfo
.pIOProc
= (LPMMIOPROC
)lpmmioinfo16
->pIOProc
;
873 mmioinfo
.cchBuffer
= lpmmioinfo16
->cchBuffer
;
874 mmioinfo
.pchBuffer
= lpmmioinfo16
->pchBuffer
;
875 mmioinfo
.adwInfo
[0] = lpmmioinfo16
->adwInfo
[0];
876 mmioinfo
.adwInfo
[1] = lpmmioinfo16
->adwInfo
[1];
877 mmioinfo
.adwInfo
[2] = lpmmioinfo16
->adwInfo
[2];
878 mmioinfo
.adwInfo
[3] = lpmmioinfo16
->adwInfo
[3];
880 ret
= MMIO_Open(szFileName
, &mmioinfo
, dwOpenFlags
, MMIO_PROC_16
);
882 mmioGetInfo16(mmioinfo
.hmmio
, lpmmioinfo16
, 0);
883 lpmmioinfo16
->wErrorRet
= ret
;
887 mmio
.pchBuffer
= NULL
;
889 ret
= MMIO_Open(szFileName
, &mmio
, dwOpenFlags
, FALSE
);
895 /**************************************************************************
896 * mmioClose [WINMM.114]
898 MMRESULT WINAPI
mmioClose(HMMIO hmmio
, UINT uFlags
)
903 TRACE("(%04X, %04X);\n", hmmio
, uFlags
);
905 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
906 return MMSYSERR_INVALHANDLE
;
908 if ((result
= MMIO_Flush(wm
, MMIO_EMPTYBUF
)) != 0)
911 result
= MMIO_SendMessage(wm
, MMIOM_CLOSE
, uFlags
, 0, MMIO_PROC_32A
);
913 mmioSetBuffer(hmmio
, NULL
, 0, 0);
918 MMIO_InstallIOProc(wm
->info
.fccIOProc
, NULL
,
919 MMIO_REMOVEPROC
, wm
->ioProc
->type
);
926 /**************************************************************************
927 * mmioClose [MMSYSTEM.1211]
929 MMRESULT16 WINAPI
mmioClose16(HMMIO16 hmmio
, UINT16 uFlags
)
931 return mmioClose(hmmio
, uFlags
);
934 /**************************************************************************
935 * mmioRead [WINMM.124]
937 LONG WINAPI
mmioRead(HMMIO hmmio
, HPSTR pch
, LONG cch
)
942 TRACE("(%04X, %p, %ld);\n", hmmio
, pch
, cch
);
944 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
947 /* unbuffered case first */
948 if (!wm
->info
.pchBuffer
)
949 return MMIO_SendMessage(wm
, MMIOM_READ
, (LPARAM
)pch
, cch
, MMIO_PROC_32A
);
951 /* first try from current buffer */
952 if (wm
->info
.pchNext
!= wm
->info
.pchEndRead
) {
953 count
= wm
->info
.pchEndRead
- wm
->info
.pchNext
;
954 if (count
> cch
|| count
< 0) count
= cch
;
955 memcpy(pch
, wm
->info
.pchNext
, count
);
956 wm
->info
.pchNext
+= count
;
962 if (cch
&& (wm
->info
.fccIOProc
!= FOURCC_MEM
)) {
963 assert(wm
->info
.cchBuffer
);
968 size
= MMIO_GrabNextBuffer(wm
, TRUE
);
969 if (size
<= 0) break;
970 if (size
> cch
) size
= cch
;
971 memcpy(pch
, wm
->info
.pchBuffer
, size
);
972 wm
->info
.pchNext
+= size
;
979 TRACE("count=%ld\n", count
);
983 /**************************************************************************
984 * mmioRead [MMSYSTEM.1212]
986 LONG WINAPI
mmioRead16(HMMIO16 hmmio
, HPSTR pch
, LONG cch
)
988 return mmioRead(hmmio
, pch
, cch
);
991 /**************************************************************************
992 * mmioWrite [WINMM.133]
994 LONG WINAPI
mmioWrite(HMMIO hmmio
, HPCSTR pch
, LONG cch
)
999 TRACE("(%04X, %p, %ld);\n", hmmio
, pch
, cch
);
1001 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
1004 if (wm
->info
.cchBuffer
) {
1007 if (wm
->info
.pchNext
!= wm
->info
.pchEndWrite
) {
1008 count
= wm
->info
.pchEndWrite
- wm
->info
.pchNext
;
1009 if (count
> cch
|| count
< 0) count
= cch
;
1010 memcpy(wm
->info
.pchNext
, pch
, count
);
1011 wm
->info
.pchNext
+= count
;
1014 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");
1023 if (wm
->info
.pchNext
== wm
->info
.pchEndWrite
&&
1024 MMIO_Flush(wm
, MMIO_EMPTYBUF
)) break;
1027 count
= MMIO_SendMessage(wm
, MMIOM_WRITE
, (LPARAM
)pch
, cch
, MMIO_PROC_32A
);
1028 wm
->info
.lBufOffset
= wm
->info
.lDiskOffset
;
1031 TRACE("count=%ld\n", count
);
1035 /**************************************************************************
1036 * mmioWrite [MMSYSTEM.1213]
1038 LONG WINAPI
mmioWrite16(HMMIO16 hmmio
, HPCSTR pch
, LONG cch
)
1040 return mmioWrite(hmmio
,pch
,cch
);
1043 /**************************************************************************
1044 * mmioSeek [MMSYSTEM.1214]
1046 LONG WINAPI
mmioSeek(HMMIO hmmio
, LONG lOffset
, INT iOrigin
)
1051 TRACE("(%04X, %08lX, %d);\n", hmmio
, lOffset
, iOrigin
);
1053 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
1054 return MMSYSERR_INVALHANDLE
;
1056 if (!wm
->info
.pchBuffer
)
1057 return MMIO_SendMessage(wm
, MMIOM_SEEK
, lOffset
, iOrigin
, MMIO_PROC_32A
);
1064 offset
= wm
->info
.lBufOffset
+ (wm
->info
.pchNext
- wm
->info
.pchBuffer
) + lOffset
;
1067 if (wm
->info
.fccIOProc
== FOURCC_MEM
) {
1068 offset
= wm
->info
.cchBuffer
;
1070 assert(MMIO_SendMessage(wm
, MMIOM_SEEK
, 0, SEEK_CUR
, MMIO_PROC_32A
) == wm
->info
.lDiskOffset
);
1071 offset
= MMIO_SendMessage(wm
, MMIOM_SEEK
, 0, SEEK_END
, MMIO_PROC_32A
);
1072 MMIO_SendMessage(wm
, MMIOM_SEEK
, wm
->info
.lDiskOffset
, SEEK_SET
, MMIO_PROC_32A
);
1080 /* stay in same buffer ? */
1081 /* some memory mapped buffers are defined with -1 as a size */
1082 if ((wm
->info
.cchBuffer
> 0) &&
1083 ((offset
< wm
->info
.lBufOffset
) ||
1084 (offset
>= wm
->info
.lBufOffset
+ wm
->info
.cchBuffer
))) {
1086 /* condition to change buffer */
1087 if ((wm
->info
.fccIOProc
== FOURCC_MEM
) ||
1088 MMIO_Flush(wm
, MMIO_EMPTYBUF
) ||
1089 /* this also sets the wm->info.lDiskOffset field */
1090 MMIO_SendMessage(wm
, MMIOM_SEEK
,
1091 (offset
/ wm
->info
.cchBuffer
) * wm
->info
.cchBuffer
,
1092 SEEK_SET
, MMIO_PROC_32A
) == -1)
1094 MMIO_GrabNextBuffer(wm
, TRUE
);
1097 wm
->info
.pchNext
= wm
->info
.pchBuffer
+ (offset
- wm
->info
.lBufOffset
);
1099 TRACE("=> %ld\n", offset
);
1103 /**************************************************************************
1104 * mmioSeek [MMSYSTEM.1214]
1106 LONG WINAPI
mmioSeek16(HMMIO16 hmmio
, LONG lOffset
, INT16 iOrigin
)
1108 return mmioSeek(hmmio
, lOffset
, iOrigin
);
1111 /**************************************************************************
1112 * mmioGetInfo [MMSYSTEM.1215]
1114 UINT16 WINAPI
mmioGetInfo16(HMMIO16 hmmio
, MMIOINFO16
* lpmmioinfo
, UINT16 uFlags
)
1118 TRACE("mmioGetInfo\n");
1120 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
1121 return MMSYSERR_INVALHANDLE
;
1124 return MMSYSERR_ERROR
;
1126 lpmmioinfo
->dwFlags
= wm
->info
.dwFlags
;
1127 lpmmioinfo
->fccIOProc
= wm
->info
.fccIOProc
;
1128 lpmmioinfo
->pIOProc
= (LPMMIOPROC16
)wm
->info
.pIOProc
;
1129 lpmmioinfo
->wErrorRet
= wm
->info
.wErrorRet
;
1130 lpmmioinfo
->hTask
= wm
->info
.hTask
;
1131 lpmmioinfo
->cchBuffer
= wm
->info
.cchBuffer
;
1132 lpmmioinfo
->pchBuffer
= (void*)wm
->buffer16
;
1133 lpmmioinfo
->pchNext
= (void*)(wm
->buffer16
+ (wm
->info
.pchNext
- wm
->info
.pchBuffer
));
1134 lpmmioinfo
->pchEndRead
= (void*)(wm
->buffer16
+ (wm
->info
.pchEndRead
- wm
->info
.pchBuffer
));
1135 lpmmioinfo
->pchEndWrite
= (void*)(wm
->buffer16
+ (wm
->info
.pchEndWrite
- wm
->info
.pchBuffer
));
1136 lpmmioinfo
->lBufOffset
= wm
->info
.lBufOffset
;
1137 lpmmioinfo
->lDiskOffset
= wm
->info
.lDiskOffset
;
1138 lpmmioinfo
->adwInfo
[0] = wm
->info
.adwInfo
[0];
1139 lpmmioinfo
->adwInfo
[1] = wm
->info
.adwInfo
[1];
1140 lpmmioinfo
->adwInfo
[2] = wm
->info
.adwInfo
[2];
1141 lpmmioinfo
->adwInfo
[3] = wm
->info
.adwInfo
[3];
1142 lpmmioinfo
->dwReserved1
= 0;
1143 lpmmioinfo
->dwReserved2
= 0;
1144 lpmmioinfo
->hmmio
= wm
->info
.hmmio
;
1149 /**************************************************************************
1150 * mmioGetInfo [WINMM.118]
1152 UINT WINAPI
mmioGetInfo(HMMIO hmmio
, MMIOINFO
* lpmmioinfo
, UINT uFlags
)
1156 TRACE("(0x%04x,%p,0x%08x)\n",hmmio
,lpmmioinfo
,uFlags
);
1158 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
1159 return MMSYSERR_INVALHANDLE
;
1161 memcpy(lpmmioinfo
, &wm
->info
, sizeof(MMIOINFO
));
1166 /**************************************************************************
1167 * mmioSetInfo16 [MMSYSTEM.1216]
1169 UINT16 WINAPI
mmioSetInfo16(HMMIO16 hmmio
, const MMIOINFO16
* lpmmioinfo
, UINT16 uFlags
)
1173 TRACE("mmioSetInfo\n");
1175 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
1176 return MMSYSERR_INVALHANDLE
;
1178 /* check if seg and lin buffers are the same */
1179 if (wm
->info
.cchBuffer
!= lpmmioinfo
->cchBuffer
||
1180 wm
->info
.pchBuffer
!= PTR_SEG_TO_LIN((void*)wm
->buffer16
))
1181 return MMSYSERR_INVALPARAM
;
1183 /* check pointers coherence */
1184 if (lpmmioinfo
->pchNext
< lpmmioinfo
->pchBuffer
||
1185 lpmmioinfo
->pchNext
> lpmmioinfo
->pchBuffer
+ lpmmioinfo
->cchBuffer
||
1186 lpmmioinfo
->pchEndRead
< lpmmioinfo
->pchBuffer
||
1187 lpmmioinfo
->pchEndRead
> lpmmioinfo
->pchBuffer
+ lpmmioinfo
->cchBuffer
||
1188 lpmmioinfo
->pchEndWrite
< lpmmioinfo
->pchBuffer
||
1189 lpmmioinfo
->pchEndWrite
> lpmmioinfo
->pchBuffer
+ lpmmioinfo
->cchBuffer
)
1190 return MMSYSERR_INVALPARAM
;
1192 wm
->info
.pchNext
= wm
->info
.pchBuffer
+ (lpmmioinfo
->pchNext
- lpmmioinfo
->pchBuffer
);
1193 wm
->info
.pchEndRead
= wm
->info
.pchBuffer
+ (lpmmioinfo
->pchEndRead
- lpmmioinfo
->pchBuffer
);
1194 wm
->info
.pchEndWrite
= wm
->info
.pchBuffer
+ (lpmmioinfo
->pchEndWrite
- lpmmioinfo
->pchBuffer
);
1199 /**************************************************************************
1200 * mmioSetInfo [WINMM.130]
1202 UINT WINAPI
mmioSetInfo(HMMIO hmmio
, const MMIOINFO
* lpmmioinfo
, UINT uFlags
)
1206 TRACE("mmioSetInfo\n");
1208 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
1209 return MMSYSERR_INVALHANDLE
;
1211 /* check pointers coherence */
1212 if (lpmmioinfo
->pchNext
< wm
->info
.pchBuffer
||
1213 lpmmioinfo
->pchNext
> wm
->info
.pchBuffer
+ wm
->info
.cchBuffer
||
1214 lpmmioinfo
->pchEndRead
< wm
->info
.pchBuffer
||
1215 lpmmioinfo
->pchEndRead
> wm
->info
.pchBuffer
+ wm
->info
.cchBuffer
||
1216 lpmmioinfo
->pchEndWrite
< wm
->info
.pchBuffer
||
1217 lpmmioinfo
->pchEndWrite
> wm
->info
.pchBuffer
+ wm
->info
.cchBuffer
)
1218 return MMSYSERR_INVALPARAM
;
1220 wm
->info
.pchNext
= lpmmioinfo
->pchNext
;
1221 wm
->info
.pchEndRead
= lpmmioinfo
->pchEndRead
;
1226 /**************************************************************************
1227 * mmioSetBuffer [WINMM.129]
1229 UINT WINAPI
mmioSetBuffer(HMMIO hmmio
, LPSTR pchBuffer
, LONG cchBuffer
, UINT uFlags
)
1233 TRACE("(hmmio=%04x, pchBuf=%p, cchBuf=%ld, uFlags=%#08x)\n",
1234 hmmio
, pchBuffer
, cchBuffer
, uFlags
);
1236 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
1237 return MMSYSERR_INVALHANDLE
;
1239 return MMIO_SetBuffer(wm
, pchBuffer
, cchBuffer
, uFlags
, TRUE
);
1242 /**************************************************************************
1243 * mmioSetBuffer [MMSYSTEM.1217]
1245 UINT16 WINAPI
mmioSetBuffer16(HMMIO16 hmmio
, LPSTR segpchBuffer
,
1246 LONG cchBuffer
, UINT16 uFlags
)
1250 TRACE("(hmmio=%04x, segpchBuf=%p, cchBuf=%ld, uFlags=%#08x)\n",
1251 hmmio
, segpchBuffer
, cchBuffer
, uFlags
);
1253 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
1254 return MMSYSERR_INVALHANDLE
;
1256 return MMIO_SetBuffer(wm
, segpchBuffer
, cchBuffer
, uFlags
, FALSE
);
1259 /**************************************************************************
1260 * mmioFlush [WINMM.117]
1262 UINT WINAPI
mmioFlush(HMMIO hmmio
, UINT uFlags
)
1266 TRACE("(%04X, %04X)\n", hmmio
, uFlags
);
1268 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
1269 return MMSYSERR_INVALHANDLE
;
1271 return MMIO_Flush(wm
, uFlags
);
1274 /**************************************************************************
1275 * mmioFlush [MMSYSTEM.1218]
1277 UINT16 WINAPI
mmioFlush16(HMMIO16 hmmio
, UINT16 uFlags
)
1279 return mmioFlush(hmmio
, uFlags
);
1282 /**************************************************************************
1283 * mmioAdvance [MMSYSTEM.1219]
1285 UINT WINAPI
mmioAdvance(HMMIO hmmio
, MMIOINFO
* lpmmioinfo
, UINT uFlags
)
1289 TRACE("hmmio=%04X, lpmmioinfo=%p, uFlags=%04X\n", hmmio
, lpmmioinfo
, uFlags
);
1291 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
1292 return MMSYSERR_INVALHANDLE
;
1294 if (!wm
->info
.cchBuffer
)
1295 return MMIOERR_UNBUFFERED
;
1297 if (uFlags
!= MMIO_READ
&& uFlags
!= MMIO_WRITE
)
1298 return MMSYSERR_INVALPARAM
;
1300 if (MMIO_Flush(wm
, MMIO_EMPTYBUF
))
1301 return MMIOERR_CANNOTWRITE
;
1303 MMIO_GrabNextBuffer(wm
, uFlags
== MMIO_READ
);
1305 lpmmioinfo
->pchNext
= lpmmioinfo
->pchBuffer
;
1306 lpmmioinfo
->pchEndRead
= lpmmioinfo
->pchBuffer
+
1307 (wm
->info
.pchEndRead
- wm
->info
.pchBuffer
);
1308 lpmmioinfo
->pchEndWrite
= lpmmioinfo
->pchBuffer
+
1309 (wm
->info
.pchEndWrite
- wm
->info
.pchBuffer
);
1310 lpmmioinfo
->lDiskOffset
= wm
->info
.lDiskOffset
;
1311 lpmmioinfo
->lBufOffset
= wm
->info
.lBufOffset
;
1315 /**********************************************************m****************
1316 * mmioAdvance [MMSYSTEM.1219]
1318 UINT16 WINAPI
mmioAdvance16(HMMIO16 hmmio
, MMIOINFO16
* lpmmioinfo
, UINT16 uFlags
)
1322 TRACE("mmioAdvance\n");
1324 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
1325 return MMSYSERR_INVALHANDLE
;
1327 if (!wm
->info
.cchBuffer
)
1328 return MMIOERR_UNBUFFERED
;
1330 if (uFlags
!= MMIO_READ
&& uFlags
!= MMIO_WRITE
)
1331 return MMSYSERR_INVALPARAM
;
1333 if (MMIO_Flush(wm
, MMIO_EMPTYBUF
))
1334 return MMIOERR_CANNOTWRITE
;
1336 MMIO_GrabNextBuffer(wm
, uFlags
== MMIO_READ
);
1338 lpmmioinfo
->pchNext
= lpmmioinfo
->pchBuffer
;
1339 lpmmioinfo
->pchEndRead
= lpmmioinfo
->pchBuffer
+
1340 (wm
->info
.pchEndRead
- wm
->info
.pchBuffer
);
1341 lpmmioinfo
->pchEndWrite
= lpmmioinfo
->pchBuffer
+
1342 (wm
->info
.pchEndWrite
- wm
->info
.pchBuffer
);
1343 lpmmioinfo
->lDiskOffset
= wm
->info
.lDiskOffset
;
1344 lpmmioinfo
->lBufOffset
= wm
->info
.lBufOffset
;
1349 /**************************************************************************
1350 * mmioStringToFOURCCA [WINMM.131]
1352 FOURCC WINAPI
mmioStringToFOURCCA(LPCSTR sz
, UINT uFlags
)
1357 for (i
= 0; i
< 4 && sz
[i
]; i
++) {
1358 if (uFlags
& MMIO_TOUPPER
) {
1359 cc
[i
] = toupper(sz
[i
]);
1365 /* Pad with spaces */
1371 TRACE("Got %c%c%c%c\n",cc
[0],cc
[1],cc
[2],cc
[3]);
1372 return mmioFOURCC(cc
[0],cc
[1],cc
[2],cc
[3]);
1375 /**************************************************************************
1376 * mmioStringToFOURCCW [WINMM.132]
1378 FOURCC WINAPI
mmioStringToFOURCCW(LPCWSTR sz
, UINT uFlags
)
1380 LPSTR szA
= HEAP_strdupWtoA(GetProcessHeap(),0,sz
);
1381 FOURCC ret
= mmioStringToFOURCCA(szA
,uFlags
);
1383 HeapFree(GetProcessHeap(),0,szA
);
1387 /**************************************************************************
1388 * mmioStringToFOURCC [MMSYSTEM.1220]
1390 FOURCC WINAPI
mmioStringToFOURCC16(LPCSTR sz
, UINT16 uFlags
)
1392 return mmioStringToFOURCCA(sz
, uFlags
);
1395 /**************************************************************************
1396 * mmioInstallIOProc16 [MMSYSTEM.1221]
1398 LPMMIOPROC16 WINAPI
mmioInstallIOProc16(FOURCC fccIOProc
, LPMMIOPROC16 pIOProc
,
1401 return (LPMMIOPROC16
)MMIO_InstallIOProc(fccIOProc
, (LPMMIOPROC
)pIOProc
,
1402 dwFlags
, MMIO_PROC_16
);
1405 /**************************************************************************
1406 * mmioInstallIOProcA [WINMM.120]
1408 LPMMIOPROC WINAPI
mmioInstallIOProcA(FOURCC fccIOProc
,
1409 LPMMIOPROC pIOProc
, DWORD dwFlags
)
1411 return MMIO_InstallIOProc(fccIOProc
, pIOProc
, dwFlags
, MMIO_PROC_32A
);
1414 /**************************************************************************
1415 * mmioInstallIOProcW [WINMM.]
1417 LPMMIOPROC WINAPI
mmioInstallIOProcW(FOURCC fccIOProc
,
1418 LPMMIOPROC pIOProc
, DWORD dwFlags
)
1420 return MMIO_InstallIOProc(fccIOProc
, pIOProc
, dwFlags
, MMIO_PROC_32W
);
1423 /**************************************************************************
1424 * mmioSendMessage16 [MMSYSTEM.1222]
1426 LRESULT WINAPI
mmioSendMessage16(HMMIO16 hmmio
, UINT16 uMessage
,
1427 LPARAM lParam1
, LPARAM lParam2
)
1431 TRACE("(%04X, %u, %ld, %ld)\n", hmmio
, uMessage
, lParam1
, lParam2
);
1433 if (uMessage
< MMIOM_USER
)
1434 return MMSYSERR_INVALPARAM
;
1436 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
1437 return MMSYSERR_INVALHANDLE
;
1439 return MMIO_SendMessage(wm
, uMessage
, lParam1
, lParam2
, MMIO_PROC_16
);
1442 /**************************************************************************
1443 * mmioSendMessage [WINMM.]
1445 LRESULT WINAPI
mmioSendMessage(HMMIO hmmio
, UINT uMessage
,
1446 LPARAM lParam1
, LPARAM lParam2
)
1450 TRACE("(%04X, %u, %ld, %ld)\n", hmmio
, uMessage
, lParam1
, lParam2
);
1452 if (uMessage
< MMIOM_USER
)
1453 return MMSYSERR_INVALPARAM
;
1455 if ((wm
= MMIO_Get(NULL
, hmmio
)) == NULL
)
1456 return MMSYSERR_INVALHANDLE
;
1458 return MMIO_SendMessage(wm
, uMessage
, lParam1
, lParam2
, MMIO_PROC_32A
);
1461 /**************************************************************************
1462 * mmioDescend [MMSYSTEM.1223]
1464 UINT WINAPI
mmioDescend(HMMIO hmmio
, LPMMCKINFO lpck
,
1465 const MMCKINFO
* lpckParent
, UINT uFlags
)
1472 TRACE("(%04X, %p, %p, %04X);\n", hmmio
, lpck
, lpckParent
, uFlags
);
1475 return MMSYSERR_INVALPARAM
;
1477 dwOldPos
= mmioSeek(hmmio
, 0, SEEK_CUR
);
1478 TRACE("dwOldPos=%ld\n", dwOldPos
);
1480 if (lpckParent
!= NULL
) {
1481 TRACE("seek inside parent at %ld !\n", lpckParent
->dwDataOffset
);
1482 /* EPP: was dwOldPos = mmioSeek(hmmio,lpckParent->dwDataOffset,SEEK_SET); */
1483 if (dwOldPos
< lpckParent
->dwDataOffset
||
1484 dwOldPos
>= lpckParent
->dwDataOffset
+ lpckParent
->cksize
) {
1485 WARN("outside parent chunk\n");
1486 return MMIOERR_CHUNKNOTFOUND
;
1490 /* The SDK docu says 'ckid' is used for all cases. Real World
1491 * examples disagree -Marcus,990216.
1495 /* find_chunk looks for 'ckid' */
1496 if (uFlags
& MMIO_FINDCHUNK
)
1497 srchCkId
= lpck
->ckid
;
1498 /* find_riff and find_list look for 'fccType' */
1499 if (uFlags
& MMIO_FINDLIST
) {
1500 srchCkId
= FOURCC_LIST
;
1501 srchType
= lpck
->fccType
;
1503 if (uFlags
& MMIO_FINDRIFF
) {
1504 srchCkId
= FOURCC_RIFF
;
1505 srchType
= lpck
->fccType
;
1508 if (uFlags
& (MMIO_FINDCHUNK
|MMIO_FINDLIST
|MMIO_FINDRIFF
)) {
1509 TRACE("searching for %.4s.%.4s\n",
1511 srchType
?(LPSTR
)&srchType
:"any ");
1516 ix
= mmioRead(hmmio
, (LPSTR
)lpck
, 3 * sizeof(DWORD
));
1517 if (ix
< 2*sizeof(DWORD
)) {
1518 mmioSeek(hmmio
, dwOldPos
, SEEK_SET
);
1519 WARN("return ChunkNotFound\n");
1520 return MMIOERR_CHUNKNOTFOUND
;
1522 lpck
->dwDataOffset
= dwOldPos
+ 2 * sizeof(DWORD
);
1523 if (ix
< lpck
->dwDataOffset
- dwOldPos
) {
1524 mmioSeek(hmmio
, dwOldPos
, SEEK_SET
);
1525 WARN("return ChunkNotFound\n");
1526 return MMIOERR_CHUNKNOTFOUND
;
1528 TRACE("ckid=%.4s fcc=%.4s cksize=%08lX !\n",
1530 srchType
?(LPSTR
)&lpck
->fccType
:"<na>",
1532 if ((srchCkId
== lpck
->ckid
) &&
1533 (!srchType
|| (srchType
== lpck
->fccType
))
1537 dwOldPos
= lpck
->dwDataOffset
+ ((lpck
->cksize
+ 1) & ~1);
1538 mmioSeek(hmmio
, dwOldPos
, SEEK_SET
);
1541 /* FIXME: unverified, does it do this? */
1542 /* NB: This part is used by WAVE_mciOpen, among others */
1543 if (mmioRead(hmmio
, (LPSTR
)lpck
, 3 * sizeof(DWORD
)) < 3 * sizeof(DWORD
)) {
1544 mmioSeek(hmmio
, dwOldPos
, SEEK_SET
);
1545 WARN("return ChunkNotFound 2nd\n");
1546 return MMIOERR_CHUNKNOTFOUND
;
1548 lpck
->dwDataOffset
= dwOldPos
+ 2 * sizeof(DWORD
);
1551 /* If we were looking for RIFF/LIST chunks, the final file position
1552 * is after the chunkid. If we were just looking for the chunk
1553 * it is after the cksize. So add 4 in RIFF/LIST case.
1555 if (lpck
->ckid
== FOURCC_RIFF
|| lpck
->ckid
== FOURCC_LIST
)
1556 mmioSeek(hmmio
, lpck
->dwDataOffset
+ sizeof(DWORD
), SEEK_SET
);
1558 mmioSeek(hmmio
, lpck
->dwDataOffset
, SEEK_SET
);
1559 TRACE("lpck: ckid=%.4s, cksize=%ld, dwDataOffset=%ld fccType=%08lX (%.4s)!\n",
1560 (LPSTR
)&lpck
->ckid
, lpck
->cksize
, lpck
->dwDataOffset
,
1561 lpck
->fccType
, srchType
?(LPSTR
)&lpck
->fccType
:"");
1565 /**************************************************************************
1566 * mmioDescend16 [MMSYSTEM.1223]
1568 UINT16 WINAPI
mmioDescend16(HMMIO16 hmmio
, LPMMCKINFO lpck
,
1569 const MMCKINFO
* lpckParent
, UINT16 uFlags
)
1571 return mmioDescend(hmmio
, lpck
, lpckParent
, uFlags
);
1574 /**************************************************************************
1575 * mmioAscend [WINMM.113]
1577 UINT WINAPI
mmioAscend(HMMIO hmmio
, LPMMCKINFO lpck
, UINT uFlags
)
1579 TRACE("(%04X, %p, %04X);\n", hmmio
, lpck
, uFlags
);
1581 if (lpck
->dwFlags
& MMIO_DIRTY
) {
1582 DWORD dwOldPos
, dwNewSize
, dwSizePos
;
1584 TRACE("chunk is marked MMIO_DIRTY, correcting chunk size\n");
1585 dwOldPos
= mmioSeek(hmmio
, 0, SEEK_CUR
);
1586 TRACE("dwOldPos=%ld\n", dwOldPos
);
1587 dwNewSize
= dwOldPos
- lpck
->dwDataOffset
;
1588 if (dwNewSize
!= lpck
->cksize
) {
1589 TRACE("dwNewSize=%ld\n", dwNewSize
);
1590 lpck
->cksize
= dwNewSize
;
1592 dwSizePos
= lpck
->dwDataOffset
- sizeof(DWORD
);
1593 TRACE("dwSizePos=%ld\n", dwSizePos
);
1595 mmioSeek(hmmio
, dwSizePos
, SEEK_SET
);
1596 mmioWrite(hmmio
, (LPSTR
)&dwNewSize
, sizeof(DWORD
));
1600 mmioSeek(hmmio
, lpck
->dwDataOffset
+ ((lpck
->cksize
+ 1) & ~1), SEEK_SET
);
1605 /**************************************************************************
1606 * mmioAscend [MMSYSTEM.1224]
1608 UINT16 WINAPI
mmioAscend16(HMMIO16 hmmio
, MMCKINFO
* lpck
, UINT16 uFlags
)
1610 return mmioAscend(hmmio
,lpck
,uFlags
);
1613 /**************************************************************************
1614 * mmioCreateChunk [MMSYSTEM.1225]
1616 UINT16 WINAPI
mmioCreateChunk16(HMMIO16 hmmio
, MMCKINFO
* lpck
, UINT16 uFlags
)
1622 TRACE("(%04X, %p, %04X);\n", hmmio
, lpck
, uFlags
);
1624 dwOldPos
= mmioSeek(hmmio
, 0, SEEK_CUR
);
1625 TRACE("dwOldPos=%ld\n", dwOldPos
);
1627 if (uFlags
== MMIO_CREATELIST
)
1628 lpck
->ckid
= FOURCC_LIST
;
1629 else if (uFlags
== MMIO_CREATERIFF
)
1630 lpck
->ckid
= FOURCC_RIFF
;
1632 TRACE("ckid=%08lX\n", lpck
->ckid
);
1634 size
= 2 * sizeof(DWORD
);
1635 lpck
->dwDataOffset
= dwOldPos
+ size
;
1637 if (lpck
->ckid
== FOURCC_RIFF
|| lpck
->ckid
== FOURCC_LIST
)
1638 size
+= sizeof(DWORD
);
1639 lpck
->dwFlags
= MMIO_DIRTY
;
1641 ix
= mmioWrite(hmmio
, (LPSTR
)lpck
, size
);
1642 TRACE("after mmioWrite ix = %ld req = %ld, errno = %d\n",ix
, size
, errno
);
1644 mmioSeek(hmmio
, dwOldPos
, SEEK_SET
);
1645 WARN("return CannotWrite\n");
1646 return MMIOERR_CANNOTWRITE
;
1652 /**************************************************************************
1653 * mmioCreateChunk [WINMM.115]
1655 UINT WINAPI
mmioCreateChunk(HMMIO hmmio
, MMCKINFO
* lpck
, UINT uFlags
)
1657 return mmioCreateChunk16(hmmio
, lpck
, uFlags
);
1660 /**************************************************************************
1661 * mmioRename [MMSYSTEM.1226]
1663 UINT16 WINAPI
mmioRename16(LPCSTR szFileName
, LPCSTR szNewFileName
,
1664 MMIOINFO16
* lpmmioinfo
, DWORD dwRenameFlags
)
1666 UINT16 result
= MMSYSERR_ERROR
;
1667 LPMMIOPROC16 ioProc
;
1669 TRACE("('%s', '%s', %p, %08lX);\n",
1670 szFileName
, szNewFileName
, lpmmioinfo
, dwRenameFlags
);
1672 /* If both params are NULL, then parse the file name */
1673 if (lpmmioinfo
->fccIOProc
== 0 && lpmmioinfo
->pIOProc
== NULL
)
1674 lpmmioinfo
->fccIOProc
= MMIO_ParseExt(szFileName
);
1676 /* Handle any unhandled/error case from above. Assume DOS file */
1677 if (lpmmioinfo
->fccIOProc
== 0 && lpmmioinfo
->pIOProc
== NULL
)
1678 ioProc
= (LPMMIOPROC16
)mmioDosIOProc
;
1679 /* if just the four character code is present, look up IO proc */
1680 else if (lpmmioinfo
->pIOProc
== NULL
)
1681 ioProc
= mmioInstallIOProc16(lpmmioinfo
->fccIOProc
, NULL
, MMIO_FINDPROC
);
1683 ioProc
= lpmmioinfo
->pIOProc
;
1685 /* FIXME: ioProc is likely a segmented address, thus needing a
1686 * thunk somewhere. The main issue is that Wine's current thunking
1687 * 32 to 16 only supports pascal calling convention
1690 result
= (ioProc
)(0, MMIOM_RENAME
,
1691 (LPARAM
)szFileName
, (LPARAM
)szNewFileName
);
1696 /**************************************************************************
1697 * mmioRenameA [WINMM.125]
1699 UINT WINAPI
mmioRenameA(LPCSTR szFileName
, LPCSTR szNewFileName
,
1700 MMIOINFO
* lpmmioinfo
, DWORD dwRenameFlags
)
1702 UINT result
= MMSYSERR_ERROR
;
1705 TRACE("('%s', '%s', %p, %08lX);\n",
1706 szFileName
, szNewFileName
, lpmmioinfo
, dwRenameFlags
);
1708 /* If both params are NULL, then parse the file name */
1709 if (lpmmioinfo
->fccIOProc
== 0 && lpmmioinfo
->pIOProc
== NULL
)
1710 lpmmioinfo
->fccIOProc
= MMIO_ParseExt(szFileName
);
1712 /* Handle any unhandled/error case from above. Assume DOS file */
1713 if (lpmmioinfo
->fccIOProc
== 0 && lpmmioinfo
->pIOProc
== NULL
)
1714 ioProc
= (LPMMIOPROC
)mmioDosIOProc
;
1715 /* if just the four character code is present, look up IO proc */
1716 else if (lpmmioinfo
->pIOProc
== NULL
)
1717 ioProc
= MMIO_InstallIOProc(lpmmioinfo
->fccIOProc
, NULL
,
1718 MMIO_FINDPROC
, MMIO_PROC_32A
);
1720 ioProc
= lpmmioinfo
->pIOProc
;
1723 result
= (ioProc
)(0, MMIOM_RENAME
,
1724 (LPARAM
)szFileName
, (LPARAM
)szNewFileName
);
1729 /**************************************************************************
1730 * mmioRenameW [WINMM.126]
1732 UINT WINAPI
mmioRenameW(LPCWSTR szFileName
, LPCWSTR szNewFileName
,
1733 MMIOINFO
* lpmmioinfo
, DWORD dwRenameFlags
)
1735 LPSTR szFn
= HEAP_strdupWtoA(GetProcessHeap(), 0, szFileName
);
1736 LPSTR sznFn
= HEAP_strdupWtoA(GetProcessHeap(), 0, szNewFileName
);
1737 UINT ret
= mmioRenameA(szFn
, sznFn
, lpmmioinfo
, dwRenameFlags
);
1739 HeapFree(GetProcessHeap(),0,szFn
);
1740 HeapFree(GetProcessHeap(),0,sznFn
);