Fix compilation errors on FreeBSD.
[wine] / dlls / winmm / mmio.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
3  * MMIO functions
4  *
5  * Copyright 1998 Andrew Taylor
6  * Copyright 1998 Ove Kåven
7  * Copyright 2000 Eric Pouech
8  */
9
10 /* Still to be done:
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)
16  *      + thread safeness
17  *      + rename operation is broken
18  */
19
20 #include <ctype.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <assert.h>
25
26 #include "mmsystem.h"
27 #include "windef.h"
28
29 #include "wine/mmsystem16.h"
30 #include "wine/winbase16.h"
31 #include "heap.h"
32 #include "winemm.h"
33
34 #include "debugtools.h"
35
36 DEFAULT_DEBUG_CHANNEL(mmio);
37
38 /**************************************************************************
39  *                      mmioDosIOProc                           [internal]
40  */
41 static LRESULT CALLBACK mmioDosIOProc(LPMMIOINFO lpmmioinfo, UINT uMessage, 
42                                       LPARAM lParam1, LPARAM lParam2) 
43 {
44     LRESULT     ret = MMSYSERR_NOERROR;
45
46     TRACE("(%p, %X, %ld, %ld);\n", lpmmioinfo, uMessage, lParam1, lParam2);
47     
48     switch (uMessage) {
49     case MMIOM_OPEN: 
50         {
51             /* Parameters:
52              * lParam1 = szFileName parameter from mmioOpen
53              * lParam2 = reserved (we use it for 16-bitness)
54              * Returns: zero on success, error code on error
55              * NOTE: lDiskOffset automatically set to zero
56              */
57             OFSTRUCT ofs;
58             LPCSTR szFileName = (LPCSTR)lParam1;
59             
60             if (lpmmioinfo->dwFlags & MMIO_GETTEMP) {
61                 FIXME("MMIO_GETTEMP not implemented\n");
62                 return MMIOERR_CANNOTOPEN;
63             }
64             
65             /* if filename NULL, assume open file handle in adwInfo[0] */
66             if (!szFileName) {
67                 if (lParam2) 
68                     lpmmioinfo->adwInfo[0] = DosFileHandleToWin32Handle(lpmmioinfo->adwInfo[0]);
69                 break;
70             }
71             
72             lpmmioinfo->adwInfo[0] = (DWORD)OpenFile(szFileName, &ofs, 
73                                                      lpmmioinfo->dwFlags);
74             if (lpmmioinfo->adwInfo[0] == -1)
75                 ret = MMIOERR_CANNOTOPEN;
76         }
77         break;
78     
79     case MMIOM_CLOSE: 
80         /* Parameters:
81          * lParam1 = wFlags parameter from mmioClose
82          * lParam2 = unused
83          * Returns: zero on success, error code on error
84          */
85         if (!(lParam1 & MMIO_FHOPEN))
86             _lclose((HFILE)lpmmioinfo->adwInfo[0]);
87         break;
88             
89     case MMIOM_READ: 
90         /* Parameters:
91          * lParam1 = huge pointer to read buffer
92          * lParam2 = number of bytes to read
93          * Returns: number of bytes read, 0 for EOF, -1 for error (error code
94          *         in wErrorRet)
95          */
96         ret = _lread((HFILE)lpmmioinfo->adwInfo[0], (HPSTR)lParam1, (LONG)lParam2);
97         if (ret != -1)
98             lpmmioinfo->lDiskOffset += ret;
99         
100         break;
101     
102     case MMIOM_WRITE:
103     case MMIOM_WRITEFLUSH: 
104         /* no internal buffering, so WRITEFLUSH handled same as WRITE */
105         
106         /* Parameters:
107          * lParam1 = huge pointer to write buffer
108          * lParam2 = number of bytes to write
109          * Returns: number of bytes written, -1 for error (error code in
110          *              wErrorRet)
111          */
112         ret = _hwrite((HFILE)lpmmioinfo->adwInfo[0], (HPSTR)lParam1, (LONG)lParam2);
113         if (ret != -1)
114             lpmmioinfo->lDiskOffset += ret;
115         break;
116     
117     case MMIOM_SEEK: 
118         /* Parameters:
119          * lParam1 = new position
120          * lParam2 = from whence to seek (SEEK_SET, SEEK_CUR, SEEK_END)
121          * Returns: new file postion, -1 on error
122          */
123         ret = _llseek((HFILE)lpmmioinfo->adwInfo[0], (LONG)lParam1, (LONG)lParam2);
124         if (ret != -1)
125             lpmmioinfo->lDiskOffset = ret;
126         return ret;
127     
128     case MMIOM_RENAME: 
129         /* Parameters:
130          * lParam1 = old name
131          * lParam2 = new name
132          * Returns: zero on success, non-zero on failure
133          */
134          if (!MoveFileA((const char*)lParam1, (const char*)lParam2))
135              ret = MMIOERR_FILENOTFOUND;
136          break;
137
138     default:
139         FIXME("unexpected message %u\n", uMessage);
140         return 0;
141     }
142     
143     return ret;
144 }
145
146 /**************************************************************************
147  *                      mmioMemIOProc                           [internal]
148  */
149 static LRESULT CALLBACK mmioMemIOProc(LPMMIOINFO lpmmioinfo, UINT uMessage, 
150                                       LPARAM lParam1, LPARAM lParam2) 
151 {
152     TRACE("(%p,0x%04x,0x%08lx,0x%08lx)\n", lpmmioinfo, uMessage, lParam1, lParam2);
153
154     switch (uMessage) {
155         
156     case MMIOM_OPEN: 
157         /* Parameters:
158          * lParam1 = filename (must be NULL)
159          * lParam2 = reserved (we use it for 16-bitness)
160          * Returns: zero on success, error code on error
161          * NOTE: lDiskOffset automatically set to zero
162          */
163         /* FIXME: io proc shouldn't change it */
164         if (!(lpmmioinfo->dwFlags & MMIO_CREATE))
165             lpmmioinfo->pchEndRead = lpmmioinfo->pchEndWrite;
166         return 0;
167         
168     case MMIOM_CLOSE: 
169         /* Parameters:
170          * lParam1 = wFlags parameter from mmioClose
171          * lParam2 = unused
172          * Returns: zero on success, error code on error
173          */
174         return 0;
175         
176     case MMIOM_READ: 
177         /* Parameters:
178          * lParam1 = huge pointer to read buffer
179          * lParam2 = number of bytes to read
180          * Returns: number of bytes read, 0 for EOF, -1 for error (error code
181          *         in wErrorRet)
182          * NOTE: lDiskOffset should be updated
183          */
184         FIXME("MMIOM_READ on memory files should not occur, buffer may be lost!\n");
185         return 0;
186     
187     case MMIOM_WRITE:
188     case MMIOM_WRITEFLUSH: 
189         /* no internal buffering, so WRITEFLUSH handled same as WRITE */
190         
191         /* Parameters:
192          * lParam1 = huge pointer to write buffer
193          * lParam2 = number of bytes to write
194          * Returns: number of bytes written, -1 for error (error code in
195          *              wErrorRet)
196          * NOTE: lDiskOffset should be updated
197          */
198         FIXME("MMIOM_WRITE on memory files should not occur, buffer may be lost!\n");
199         return 0;
200     
201     case MMIOM_SEEK: 
202         /* Parameters:
203          * lParam1 = new position
204          * lParam2 = from whence to seek (SEEK_SET, SEEK_CUR, SEEK_END)
205          * Returns: new file postion, -1 on error
206          * NOTE: lDiskOffset should be updated
207          */
208         FIXME("MMIOM_SEEK on memory files should not occur, buffer may be lost!\n");
209         return -1;
210     
211     default:
212         FIXME("unexpected message %u\n", uMessage);
213         return 0;
214     }
215     
216     return 0;
217 }
218
219
220 enum mmioProcType {MMIO_PROC_16,MMIO_PROC_32A,MMIO_PROC_32W};
221
222 struct IOProcList
223 {
224     struct IOProcList*pNext;       /* Next item in linked list */
225     FOURCC            fourCC;      /* four-character code identifying IOProc */
226     LPMMIOPROC        pIOProc;     /* pointer to IProc */
227     enum mmioProcType type;        /* 16, 32A or 32W */
228     int               count;       /* number of objects linked to it */
229 };
230
231 /* This array will be the entire list for most apps */
232
233 static struct IOProcList defaultProcs[] = {
234     {&defaultProcs[1], FOURCC_DOS, (LPMMIOPROC)mmioDosIOProc, MMIO_PROC_32A, 0},
235     {NULL,             FOURCC_MEM, (LPMMIOPROC)mmioMemIOProc, MMIO_PROC_32A, 0},
236 };
237
238 static struct IOProcList*       pIOProcListAnchor = &defaultProcs[0];
239
240 /****************************************************************
241  *              MMIO_FindProcNode                       [INTERNAL]
242  *
243  * Finds the ProcList node associated with a given FOURCC code.
244  */
245 static struct IOProcList*       MMIO_FindProcNode(FOURCC fccIOProc) 
246 {
247     struct IOProcList*  pListNode;
248
249     for (pListNode = pIOProcListAnchor; pListNode; pListNode = pListNode->pNext) {
250         if (pListNode->fourCC == fccIOProc) {
251             return pListNode;
252         }
253     }
254     return NULL;
255 }
256
257 /****************************************************************
258  *              MMIO_InstallIOProc                      [INTERNAL]
259  */
260 static LPMMIOPROC MMIO_InstallIOProc(FOURCC fccIOProc, LPMMIOPROC pIOProc,
261                                      DWORD dwFlags, enum mmioProcType type)
262 {
263     LPMMIOPROC          lpProc = NULL;
264     struct IOProcList*  pListNode;
265     struct IOProcList** ppListNode;
266
267     TRACE("(%ld, %p, %08lX, %i)\n", fccIOProc, pIOProc, dwFlags, type);
268
269     if (dwFlags & MMIO_GLOBALPROC)
270         FIXME("Global procedures not implemented\n");
271
272     /* just handle the known procedures for now */
273     switch (dwFlags & (MMIO_INSTALLPROC|MMIO_REMOVEPROC|MMIO_FINDPROC)) {
274     case MMIO_INSTALLPROC:
275         /* Create new entry for the IOProc list */
276         pListNode = HeapAlloc(GetProcessHeap(), 0, sizeof(*pListNode));
277         if (pListNode) {
278             /* Fill in this node */
279             pListNode->fourCC = fccIOProc;
280             pListNode->pIOProc = pIOProc;
281             pListNode->type = type;
282             pListNode->count = 0;
283
284             /* Stick it on the end of the list */
285             pListNode->pNext = pIOProcListAnchor;
286             pIOProcListAnchor = pListNode;
287             
288             /* Return this IOProc - that's how the caller knows we succeeded */
289             lpProc = pIOProc;
290         } 
291         break;
292                   
293     case MMIO_REMOVEPROC:
294         /* 
295          * Search for the node that we're trying to remove - note
296          * that this method won't find the first item on the list, but
297          * since the first two items on this list are ones we won't
298          * let the user delete anyway, that's okay
299          */         
300         ppListNode = &pIOProcListAnchor;
301         while ((*ppListNode) && (*ppListNode)->fourCC != fccIOProc)
302             ppListNode = &((*ppListNode)->pNext);
303
304         if (*ppListNode) { /* found it */
305             /* FIXME: what should be done if an open mmio object uses this proc ?
306              * shall we return an error, nuke the mmio object ?
307              */
308             if ((*ppListNode)->count) {
309                 ERR("Cannot remove a mmIOProc while in use\n");
310                 break;
311             }
312             /* remove it, but only if it isn't builtin */
313             if ((*ppListNode) >= defaultProcs && 
314                 (*ppListNode) < defaultProcs + sizeof(defaultProcs)) {
315                 WARN("Tried to remove built-in mmio proc. Skipping\n");
316             } else {
317                 /* Okay, nuke it */
318                 struct IOProcList*  ptmpNode = *ppListNode;
319                 lpProc = (*ppListNode)->pIOProc;
320                 *ppListNode = (*ppListNode)->pNext;
321                 HeapFree(GetProcessHeap(), 0, ptmpNode);
322             }
323         }
324         break;
325             
326     case MMIO_FINDPROC:
327         if ((pListNode = MMIO_FindProcNode(fccIOProc))) {
328             lpProc = pListNode->pIOProc;
329         }
330         break;
331     }
332     
333     return lpProc;
334 }
335
336 /****************************************************************
337  *                      MMIO_Map32To16                  [INTERNAL]
338  */
339 static LRESULT  MMIO_Map32To16(DWORD wMsg, LPARAM* lp1, LPARAM* lp2)
340 {
341     switch (wMsg) {
342     case MMIOM_OPEN:
343         {
344             char *lp = SEGPTR_STRDUP( (LPSTR)*lp1 );
345             if (!lp) return MMSYSERR_NOMEM;
346             *lp1 = SEGPTR_GET(lp);
347         }
348         break;
349     case MMIOM_CLOSE:
350     case MMIOM_SEEK:
351         /* nothing to do */
352         break;
353     case MMIOM_READ:
354     case MMIOM_WRITE:
355     case MMIOM_WRITEFLUSH:
356         {
357             void*       lp = SEGPTR_ALLOC(*lp2);
358             if (!lp) return MMSYSERR_NOMEM;
359            
360             if (wMsg != MMIOM_READ)
361                 memcpy(lp, (void*)*lp1, *lp2);
362             *lp1 = SEGPTR_GET(lp);
363         }
364         break;
365     default:
366         TRACE("Not a mappable message (%ld)\n", wMsg);
367     }
368     return MMSYSERR_NOERROR;
369 }
370
371 /****************************************************************
372  *              MMIO_UnMap32To16                        [INTERNAL]
373  */
374 static LRESULT  MMIO_UnMap32To16(DWORD wMsg, LPARAM lParam1, LPARAM lParam2,
375                                  LPARAM lp1, LPARAM lp2)
376 {
377     switch (wMsg) {
378     case MMIOM_OPEN:
379         if (!SEGPTR_FREE((void*)lp1)) {
380             FIXME("bad free line=%d\n", __LINE__);
381         } 
382         break;
383     case MMIOM_CLOSE:
384     case MMIOM_SEEK:
385         /* nothing to do */
386         break;
387     case MMIOM_READ:
388         memcpy((void*)lParam1, MapSL(lp1), lp2);
389         /* fall through */
390     case MMIOM_WRITE:
391     case MMIOM_WRITEFLUSH:
392         if (!SEGPTR_FREE(MapSL(lp1))) {
393             FIXME("bad free line=%d\n", __LINE__);
394         } 
395         break;
396     default:
397         TRACE("Not a mappable message (%ld)\n", wMsg);
398     }
399     return MMSYSERR_NOERROR;
400 }
401
402 /****************************************************************
403  *              MMIO_GenerateInfoForIOProc              [INTERNAL]
404  */
405 static  SEGPTR  MMIO_GenerateInfoForIOProc(const WINE_MMIO* wm)
406 {
407     LPMMIOINFO16 mmioInfo16 = SEGPTR_ALLOC(sizeof(MMIOINFO16));
408
409     memset(mmioInfo16, 0, sizeof(MMIOINFO16));
410
411     mmioInfo16->lDiskOffset = wm->info.lDiskOffset;
412     mmioInfo16->adwInfo[0]  = wm->info.adwInfo[0];
413     mmioInfo16->adwInfo[1]  = wm->info.adwInfo[1];
414     mmioInfo16->adwInfo[2]  = wm->info.adwInfo[2];
415     mmioInfo16->adwInfo[3]  = wm->info.adwInfo[3];
416
417     return SEGPTR_GET(mmioInfo16);
418 }
419
420 /****************************************************************
421  *              MMIO_UpdateInfoForIOProc                [INTERNAL]
422  */
423 static  LRESULT MMIO_UpdateInfoForIOProc(WINE_MMIO* wm, SEGPTR segmmioInfo16)
424 {
425     MMIOINFO16* mmioInfo16 = MapSL(segmmioInfo16);
426
427     wm->info.lDiskOffset = mmioInfo16->lDiskOffset;
428     wm->info.adwInfo[0]  = mmioInfo16->adwInfo[0];
429     wm->info.adwInfo[1]  = mmioInfo16->adwInfo[1];
430     wm->info.adwInfo[2]  = mmioInfo16->adwInfo[2];
431     wm->info.adwInfo[3]  = mmioInfo16->adwInfo[3];
432
433     if (!SEGPTR_FREE(mmioInfo16)) FIXME("bad free\n");
434
435     return MMSYSERR_NOERROR;
436 }
437
438 /****************************************************************
439  *              MMIO_SendMessage                        [INTERNAL]
440  */
441 static LRESULT  MMIO_SendMessage(LPWINE_MMIO wm, DWORD wMsg, LPARAM lParam1, 
442                                  LPARAM lParam2, enum mmioProcType type)
443 {
444     LRESULT             result;
445     SEGPTR              segmmioInfo16;
446     LPARAM              lp1 = lParam1, lp2 = lParam2;
447
448     if (!wm->ioProc || !wm->info.pIOProc) {
449         ERR("brrr\n");
450         result = MMSYSERR_INVALPARAM;
451     }
452
453     switch (wm->ioProc->type) {
454     case MMIO_PROC_16:
455         segmmioInfo16 = MMIO_GenerateInfoForIOProc(wm);
456         if (wm->ioProc->type != type) {
457             /* map (lParam1, lParam2) into (lp1, lp2) 32=>16 */
458             if ((result = MMIO_Map32To16(wMsg, &lp1, &lp2)) != MMSYSERR_NOERROR)
459                 return result;
460         }
461         /* FIXME: is wm->info.pIOProc a segmented or a linear address ?
462          * sounds to me it's a segmented one, should use a thunk somewhere
463          */
464         result = ((LPMMIOPROC16)wm->info.pIOProc)((LPSTR)segmmioInfo16, 
465                                                   wMsg, lp1, lp2);
466         
467         if (wm->ioProc->type != type) {
468             MMIO_UnMap32To16(wMsg, lParam1, lParam2, lp1, lp2);
469         }
470         MMIO_UpdateInfoForIOProc(wm, segmmioInfo16);
471         break;
472     case MMIO_PROC_32A:
473     case MMIO_PROC_32W:
474         if (wm->ioProc->type != type) {
475             /* map (lParam1, lParam2) into (lp1, lp2) 16=>32 */
476             WARN("NIY\n");
477         }
478         result = (wm->info.pIOProc)((LPSTR)&wm->info, wMsg, lp1, lp2);
479         
480 #if 0
481         if (wm->ioProc->type != type) {
482             /* unmap (lParam1, lParam2) into (lp1, lp2) 16=>32 */
483         }
484 #endif
485         break;
486     default:  
487         FIXME("Internal error\n");
488         result = MMSYSERR_ERROR;
489     }
490
491     return result;
492 }
493
494 /**************************************************************************
495  *                              MMIO_ParseExt                   [internal]
496  *
497  * Parses a filename for the extension.
498  *
499  * RETURNS
500  *  The FOURCC code for the extension if found, else 0.
501  */
502 static FOURCC MMIO_ParseExt(LPCSTR szFileName)
503 {
504     /* Filenames are of the form file.ext+ABC
505        FIXME: What if a '+' is part of the file name?
506        For now, we take the last '+' present */
507     
508     FOURCC ret = 0;
509     
510     /* Note that ext{Start,End} point to the . and + respectively */
511     LPSTR extEnd;
512     
513     TRACE("(%s)\n",debugstr_a(szFileName));
514     
515     if (!szFileName)
516         return ret;
517     extEnd = strrchr(szFileName,'+');
518     if (extEnd) {
519         /* Need to parse to find the extension */
520         LPSTR extStart;
521         
522         extStart = extEnd;
523         while (extStart >= szFileName && extStart[0] != '.') {
524             extStart--;
525         }
526         
527         if (extStart < szFileName) {
528             ERR("+ but no . in szFileName: %s\n", debugstr_a(szFileName));
529         } else {
530             CHAR ext[5];
531             
532             if (extEnd - extStart - 1 > 4)
533                 WARN("Extension length > 4\n");
534             lstrcpynA(ext,extStart + 1,min(extEnd-extStart,5));
535             TRACE("Got extension: %s\n", debugstr_a(ext));
536             /* FOURCC codes identifying file-extensions must be uppercase */
537             ret = mmioStringToFOURCCA(ext, MMIO_TOUPPER);
538         }
539     }
540     return ret;
541 }
542
543 /**************************************************************************
544  *                              MMIO_Get                        [internal]
545  *
546  * Retrieves the mmio object from current process
547  */
548 static  LPWINE_MMIO     MMIO_Get(LPWINE_MM_IDATA iData, HMMIO h)
549 {
550     LPWINE_MMIO         wm = NULL;
551
552     if (!iData) iData = MULTIMEDIA_GetIData();
553
554     EnterCriticalSection(&iData->cs);
555     for (wm = iData->lpMMIO; wm; wm = wm->lpNext) {
556         if (wm->info.hmmio == h)
557             break;
558     }
559     LeaveCriticalSection(&iData->cs);
560     return wm;
561 }
562
563 /**************************************************************************
564  *                              MMIO_Create                     [internal]
565  *
566  * Creates an internal representation for a mmio instance
567  */
568 static  LPWINE_MMIO             MMIO_Create(void)
569 {
570     static      WORD    MMIO_counter = 0;
571     LPWINE_MMIO         wm;
572     LPWINE_MM_IDATA     iData = MULTIMEDIA_GetIData();
573
574     wm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MMIO));
575     if (wm) {
576         EnterCriticalSection(&iData->cs);
577         while (MMIO_Get(iData, ++MMIO_counter));
578         wm->info.hmmio = MMIO_counter;
579         wm->lpNext = iData->lpMMIO;
580         iData->lpMMIO = wm;
581         LeaveCriticalSection(&iData->cs);
582     }
583     return wm;
584 }
585
586 /**************************************************************************
587  *                              MMIO_Destroy                    [internal]
588  *-
589  * Destroys an internal representation for a mmio instance
590  */
591 static  BOOL            MMIO_Destroy(LPWINE_MMIO wm)
592 {
593     LPWINE_MM_IDATA     iData = MULTIMEDIA_GetIData();
594     LPWINE_MMIO*        m;
595
596     EnterCriticalSection(&iData->cs);
597     /* search for the matching one... */
598     m = &(iData->lpMMIO);
599     while (*m && *m != wm) m = &(*m)->lpNext;
600     /* ...and destroy */
601     if (*m) {
602         *m = (*m)->lpNext;
603         HeapFree(GetProcessHeap(), 0, wm);
604         wm = NULL;
605     }
606     LeaveCriticalSection(&iData->cs);
607     return wm ? FALSE : TRUE;
608 }
609
610 /****************************************************************
611  *                      MMIO_Flush                      [INTERNAL]
612  */
613 static  LRESULT MMIO_Flush(WINE_MMIO* wm, UINT uFlags)
614 {
615     if (wm->info.cchBuffer && (wm->info.fccIOProc != FOURCC_MEM)) {
616         /* not quite sure what to do here, but I'll guess */
617         if (wm->info.dwFlags & MMIO_DIRTY) {
618             MMIO_SendMessage(wm, MMIOM_SEEK, wm->info.lBufOffset,
619                              SEEK_SET, MMIO_PROC_32A);
620             MMIO_SendMessage(wm, MMIOM_WRITE, (LPARAM)wm->info.pchBuffer,
621                              wm->info.pchNext - wm->info.pchBuffer, MMIO_PROC_32A);
622         }
623         if (uFlags & MMIO_EMPTYBUF) 
624             wm->info.pchNext = wm->info.pchEndRead = wm->info.pchBuffer;
625     }
626     wm->info.dwFlags &= ~MMIO_DIRTY;
627
628     return 0;
629 }
630
631 /***************************************************************************
632  *                      MMIO_GrabNextBuffer                     [INTERNAL]
633  */
634 static LONG     MMIO_GrabNextBuffer(LPWINE_MMIO wm, int for_read)
635 {
636     LONG        size = wm->info.cchBuffer;
637
638     TRACE("bo=%lx do=%lx of=%lx\n", 
639           wm->info.lBufOffset, wm->info.lDiskOffset, 
640           MMIO_SendMessage(wm, MMIOM_SEEK, 0, SEEK_CUR, MMIO_PROC_32A));
641           
642     wm->info.lBufOffset = wm->info.lDiskOffset;
643     wm->info.pchNext = wm->info.pchBuffer;
644     wm->info.pchEndRead = wm->info.pchBuffer;
645     wm->info.pchEndWrite = wm->info.pchBuffer + wm->info.cchBuffer;
646
647     if (for_read) {
648         size = MMIO_SendMessage(wm, MMIOM_READ, (LPARAM)wm->info.pchBuffer,
649                                 size, MMIO_PROC_32A);
650         if (size > 0)
651             wm->info.pchEndRead += size;
652     }
653
654     wm->bBufferLoaded = TRUE;
655     return size;
656 }
657
658 /***************************************************************************
659  *                      MMIO_SetBuffer                          [INTERNAL]
660  */
661 static  UINT    MMIO_SetBuffer(WINE_MMIO* wm, void* pchBuffer, LONG cchBuffer, 
662                                UINT uFlags, BOOL bFrom32)
663 {
664     TRACE("(%p %p %ld %u %d)\n", wm, pchBuffer, cchBuffer, uFlags, bFrom32);
665
666     if (uFlags)                 return MMSYSERR_INVALPARAM;
667     if (cchBuffer > 0xFFFF)
668         WARN("Untested handling of huge mmio buffers (%ld >= 64k)\n", cchBuffer);
669         
670     if (MMIO_Flush(wm, 0) != 0)
671         return MMIOERR_CANNOTWRITE;
672     
673     if ((!cchBuffer || pchBuffer) && (wm->info.dwFlags & MMIO_ALLOCBUF)) {
674         GlobalUnlock16(wm->hMem);
675         GlobalFree16(wm->hMem);
676         wm->info.dwFlags &= ~MMIO_ALLOCBUF;
677     }
678     if (pchBuffer) {
679         if (bFrom32) {
680             wm->info.pchBuffer = pchBuffer;
681             wm->buffer16 = 0;
682         } else {
683             wm->info.pchBuffer = MapSL((SEGPTR)pchBuffer);
684             wm->buffer16 = (SEGPTR)pchBuffer;
685         }
686         wm->hMem = 0;
687     } else if (cchBuffer && (wm->info.dwFlags & MMIO_ALLOCBUF)) {
688         HGLOBAL16 hNewBuf;
689         GlobalUnlock16(wm->hMem);
690         hNewBuf = GlobalReAlloc16(wm->hMem, cchBuffer, 0);
691         if (!hNewBuf) {
692             /* FIXME: this assumes the memory block didn't move */
693             GlobalLock16(wm->hMem);
694             return MMIOERR_OUTOFMEMORY;
695         }
696         wm->hMem = hNewBuf;
697     } else if (cchBuffer) {
698         if (!(wm->hMem = GlobalAlloc16(GMEM_MOVEABLE, cchBuffer)))
699             return MMIOERR_OUTOFMEMORY;
700         wm->info.dwFlags |= MMIO_ALLOCBUF;
701     } else {
702         wm->info.pchBuffer = NULL;
703         wm->hMem = 0;
704         wm->buffer16 = 0;
705     }
706
707     if (wm->hMem) {
708         wm->buffer16 = K32WOWGlobalLock16(wm->hMem);
709         wm->info.pchBuffer = MapSL(wm->buffer16);
710     }
711
712     wm->info.cchBuffer = cchBuffer;
713     wm->info.pchNext = wm->info.pchBuffer;
714     wm->info.pchEndRead = wm->info.pchBuffer;
715     wm->info.pchEndWrite = wm->info.pchBuffer + cchBuffer;
716     wm->info.lBufOffset = 0;
717     wm->bBufferLoaded = FALSE;
718
719     return 0;
720 }
721
722 /**************************************************************************
723  *                      MMIO_Open                               [internal]
724  */
725 static HMMIO MMIO_Open(LPSTR szFileName, MMIOINFO* refmminfo, 
726                        DWORD dwOpenFlags, enum mmioProcType type)
727 {
728     LPWINE_MMIO         wm;
729
730     TRACE("('%s', %p, %08lX, %d);\n", szFileName, refmminfo, dwOpenFlags, type);
731
732     if (dwOpenFlags & (MMIO_PARSE|MMIO_EXIST)) {
733         char    buffer[MAX_PATH];
734         
735         if (GetFullPathNameA(szFileName, sizeof(buffer), buffer, NULL) >= sizeof(buffer))
736             return (HMMIO16)FALSE;
737         if ((dwOpenFlags & MMIO_EXIST) && (GetFileAttributesA(buffer) == -1))
738             return (HMMIO)FALSE;
739         strcpy(szFileName, buffer);
740         return (HMMIO)TRUE;
741     }
742     
743     if ((wm = MMIO_Create()) == NULL)
744         return 0;
745
746     /* If both params are NULL, then parse the file name if available */
747     if (refmminfo->fccIOProc == 0 && refmminfo->pIOProc == NULL) {
748         wm->info.fccIOProc = MMIO_ParseExt(szFileName);
749         /* Handle any unhandled/error case. Assume DOS file */
750         if (wm->info.fccIOProc == 0)
751             wm->info.fccIOProc = FOURCC_DOS;
752         if (!(wm->ioProc = MMIO_FindProcNode(wm->info.fccIOProc))) goto error2;
753         wm->info.pIOProc = wm->ioProc->pIOProc;
754         wm->bTmpIOProc = FALSE;
755     }
756     /* if just the four character code is present, look up IO proc */
757     else if (refmminfo->pIOProc == NULL) {      
758         wm->info.fccIOProc = refmminfo->fccIOProc;
759         if (!(wm->ioProc = MMIO_FindProcNode(wm->info.fccIOProc))) goto error2;
760         wm->info.pIOProc = wm->ioProc->pIOProc;
761         wm->bTmpIOProc = FALSE;
762     } 
763     /* if IO proc specified, use it and specified four character code */
764     else {
765         wm->info.fccIOProc = refmminfo->fccIOProc;
766         wm->info.pIOProc = refmminfo->pIOProc;
767         MMIO_InstallIOProc(wm->info.fccIOProc, wm->info.pIOProc, 
768                            MMIO_INSTALLPROC, type);
769         if (!(wm->ioProc = MMIO_FindProcNode(wm->info.fccIOProc))) goto error2;
770         assert(wm->ioProc->pIOProc == refmminfo->pIOProc);
771         wm->info.pIOProc = wm->ioProc->pIOProc;
772         wm->bTmpIOProc = TRUE;
773     }
774     
775     wm->bBufferLoaded = FALSE;
776     wm->ioProc->count++;
777
778     if (dwOpenFlags & MMIO_ALLOCBUF) {
779         if ((refmminfo->wErrorRet = mmioSetBuffer(wm->info.hmmio, NULL, 
780                                                   MMIO_DEFAULTBUFFER, 0)))
781             goto error1;
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)
787             goto error1;
788         wm->bBufferLoaded = TRUE;
789     } /* else => unbuffered, wm->info.pchBuffer == NULL */
790     
791     /* see mmioDosIOProc for that one */
792     wm->info.adwInfo[0] = refmminfo->adwInfo[0];
793     wm->info.dwFlags = dwOpenFlags;
794     
795     /* call IO proc to actually open file */
796     refmminfo->wErrorRet = MMIO_SendMessage(wm, MMIOM_OPEN, (LPARAM)szFileName, 
797                                         type == MMIO_PROC_16, MMIO_PROC_32A);
798
799     if (refmminfo->wErrorRet == 0)
800         return wm->info.hmmio;
801  error1:
802     if (wm->ioProc) wm->ioProc->count--;
803  error2:
804     MMIO_Destroy(wm);
805     return 0;
806 }
807
808 /**************************************************************************
809  *                              mmioOpenW                       [WINMM.@]
810  */
811 HMMIO WINAPI mmioOpenW(LPWSTR szFileName, MMIOINFO* lpmmioinfo,
812                        DWORD dwOpenFlags)
813 {
814     HMMIO       ret;
815     LPSTR       szFn = HEAP_strdupWtoA(GetProcessHeap(), 0, szFileName);
816
817     if (lpmmioinfo) {
818         ret = MMIO_Open(szFn, lpmmioinfo, dwOpenFlags, MMIO_PROC_32W);
819     } else {
820         MMIOINFO        mmioinfo;
821         
822         mmioinfo.fccIOProc = 0;
823         mmioinfo.pIOProc = NULL;
824         mmioinfo.pchBuffer = NULL;
825         mmioinfo.cchBuffer = 0;
826         
827         ret = MMIO_Open(szFn, &mmioinfo, dwOpenFlags, MMIO_PROC_32W);
828     }
829
830     HeapFree(GetProcessHeap(), 0, szFn);
831     return ret;
832 }
833
834 /**************************************************************************
835  *                              mmioOpenA                       [WINMM.@]
836  */
837 HMMIO WINAPI mmioOpenA(LPSTR szFileName, MMIOINFO* lpmmioinfo, 
838                        DWORD dwOpenFlags)
839 {
840     HMMIO       ret;
841     
842     if (lpmmioinfo) {
843         ret = MMIO_Open(szFileName, lpmmioinfo, dwOpenFlags, MMIO_PROC_32A);
844     } else {
845         MMIOINFO        mmioinfo;
846         
847         mmioinfo.fccIOProc = 0;
848         mmioinfo.pIOProc = NULL;
849         mmioinfo.pchBuffer = NULL;
850         mmioinfo.cchBuffer = 0;
851         
852         ret = MMIO_Open(szFileName, &mmioinfo, dwOpenFlags, MMIO_PROC_32A);
853     }
854     return ret;
855 }
856
857 /**************************************************************************
858  *                              mmioOpen                [MMSYSTEM.1210]
859  */
860 HMMIO16 WINAPI mmioOpen16(LPSTR szFileName, MMIOINFO16* lpmmioinfo16, 
861                           DWORD dwOpenFlags)
862 {
863     HMMIO       ret;
864     MMIOINFO    mmio;
865     
866     if (lpmmioinfo16) {
867         MMIOINFO        mmioinfo;
868        
869         memset(&mmioinfo, 0, sizeof(mmioinfo));
870
871         mmioinfo.dwFlags     = lpmmioinfo16->dwFlags; 
872         mmioinfo.fccIOProc   = lpmmioinfo16->fccIOProc; 
873         mmioinfo.pIOProc     = (LPMMIOPROC)lpmmioinfo16->pIOProc; 
874         mmioinfo.cchBuffer   = lpmmioinfo16->cchBuffer; 
875         mmioinfo.pchBuffer   = lpmmioinfo16->pchBuffer;
876         mmioinfo.adwInfo[0]  = lpmmioinfo16->adwInfo[0]; 
877         mmioinfo.adwInfo[1]  = lpmmioinfo16->adwInfo[1]; 
878         mmioinfo.adwInfo[2]  = lpmmioinfo16->adwInfo[2]; 
879         mmioinfo.adwInfo[3]  = lpmmioinfo16->adwInfo[3]; 
880         
881         ret = MMIO_Open(szFileName, &mmioinfo, dwOpenFlags, MMIO_PROC_16);
882
883         mmioGetInfo16(mmioinfo.hmmio, lpmmioinfo16, 0);
884         lpmmioinfo16->wErrorRet = ret;
885     } else {
886         mmio.fccIOProc = 0;
887         mmio.pIOProc = NULL;
888         mmio.pchBuffer = NULL;
889         mmio.cchBuffer = 0;
890         ret = MMIO_Open(szFileName, &mmio, dwOpenFlags, FALSE);
891     }
892     return ret;
893 }
894
895     
896 /**************************************************************************
897  *                              mmioClose               [WINMM.@]
898  */
899 MMRESULT WINAPI mmioClose(HMMIO hmmio, UINT uFlags)
900 {
901     LPWINE_MMIO wm;
902     MMRESULT    result;
903     
904     TRACE("(%04X, %04X);\n", hmmio, uFlags);
905     
906     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
907         return MMSYSERR_INVALHANDLE;
908     
909     if ((result = MMIO_Flush(wm, 0)) != 0)
910         return result;
911     
912     result = MMIO_SendMessage(wm, MMIOM_CLOSE, uFlags, 0, MMIO_PROC_32A);
913     
914     mmioSetBuffer(hmmio, NULL, 0, 0);
915     
916     wm->ioProc->count--;
917
918     if (wm->bTmpIOProc)
919         MMIO_InstallIOProc(wm->info.fccIOProc, NULL, 
920                            MMIO_REMOVEPROC, wm->ioProc->type);
921
922     MMIO_Destroy(wm);
923
924     return result;
925 }
926
927 /**************************************************************************
928  *                              mmioClose               [MMSYSTEM.1211]
929  */
930 MMRESULT16 WINAPI mmioClose16(HMMIO16 hmmio, UINT16 uFlags)
931 {
932     return mmioClose(hmmio, uFlags);
933 }
934
935 /**************************************************************************
936  *                              mmioRead                [WINMM.@]
937  */
938 LONG WINAPI mmioRead(HMMIO hmmio, HPSTR pch, LONG cch)
939 {
940     LPWINE_MMIO wm;
941     LONG        count;
942     
943     TRACE("(%04X, %p, %ld);\n", hmmio, pch, cch);
944     
945     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
946         return -1;
947
948     /* unbuffered case first */
949     if (!wm->info.pchBuffer)
950         return MMIO_SendMessage(wm, MMIOM_READ, (LPARAM)pch, cch, MMIO_PROC_32A);
951
952     /* first try from current buffer */
953     if (wm->info.pchNext != wm->info.pchEndRead) {
954         count = wm->info.pchEndRead - wm->info.pchNext;
955         if (count > cch || count < 0) count = cch;
956         memcpy(pch, wm->info.pchNext, count);
957         wm->info.pchNext += count;
958         pch += count;
959         cch -= count;
960     } else
961         count = 0;
962     
963     if (cch && (wm->info.fccIOProc != FOURCC_MEM)) {
964         assert(wm->info.cchBuffer);
965
966         while (cch) {
967             LONG size;
968
969             size = MMIO_GrabNextBuffer(wm, TRUE);
970             if (size <= 0) break;
971             if (size > cch) size = cch;
972             memcpy(pch, wm->info.pchBuffer, size);
973             wm->info.pchNext += size;
974             pch += size;
975             cch -= size;
976             count += size;
977         }
978     }
979     
980     TRACE("count=%ld\n", count);
981     return count;
982 }
983
984 /**************************************************************************
985  *                              mmioRead                [MMSYSTEM.1212]
986  */
987 LONG WINAPI mmioRead16(HMMIO16 hmmio, HPSTR pch, LONG cch)
988 {
989     return mmioRead(hmmio, pch, cch);
990 }
991
992 /**************************************************************************
993  *                              mmioWrite               [WINMM.@]
994  */
995 LONG WINAPI mmioWrite(HMMIO hmmio, HPCSTR pch, LONG cch)
996 {
997     LPWINE_MMIO wm;
998     LONG count,bytesW=0;
999
1000     TRACE("(%04X, %p, %ld);\n", hmmio, pch, cch);
1001
1002     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
1003         return -1;
1004     
1005     if (wm->info.cchBuffer) {
1006         count = 0;
1007         while (cch) {
1008             if (wm->info.pchNext != wm->info.pchEndWrite) {
1009                 count = wm->info.pchEndWrite - wm->info.pchNext;
1010                 if (count > cch || count < 0) count = cch;
1011                 memcpy(wm->info.pchNext, pch, count);
1012                 wm->info.pchNext += count;
1013                 pch += count;
1014                 cch -= count;
1015                 bytesW+=count;                
1016                 wm->info.dwFlags |= MMIO_DIRTY;
1017             }
1018             else
1019             {
1020                 if (wm->info.fccIOProc == FOURCC_MEM) {
1021                     if (wm->info.adwInfo[0]) {
1022                         /* from where would we get the memory handle? */
1023                         FIXME("memory file expansion not implemented!\n");
1024                         break;
1025                     } else break;
1026                 }
1027             }
1028
1029             if (wm->info.pchNext == wm->info.pchEndWrite)
1030             {
1031                 MMIO_Flush(wm, MMIO_EMPTYBUF);
1032                 MMIO_GrabNextBuffer(wm, FALSE);
1033             }
1034             else break;
1035         }
1036     } else {
1037         bytesW = MMIO_SendMessage(wm, MMIOM_WRITE, (LPARAM)pch, cch, MMIO_PROC_32A);
1038         wm->info.lBufOffset = wm->info.lDiskOffset;
1039     }
1040     
1041     TRACE("bytes written=%ld\n", bytesW);
1042     return bytesW;
1043 }
1044
1045 /**************************************************************************
1046  *                              mmioWrite               [MMSYSTEM.1213]
1047  */
1048 LONG WINAPI mmioWrite16(HMMIO16 hmmio, HPCSTR pch, LONG cch)
1049 {
1050     return mmioWrite(hmmio,pch,cch);
1051 }
1052
1053 /**************************************************************************
1054  *                              mmioSeek                [WINMM.@]
1055  */
1056 LONG WINAPI mmioSeek(HMMIO hmmio, LONG lOffset, INT iOrigin)
1057 {
1058     LPWINE_MMIO wm;
1059     LONG        offset;
1060
1061     TRACE("(%04X, %08lX, %d);\n", hmmio, lOffset, iOrigin);
1062     
1063     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
1064         return MMSYSERR_INVALHANDLE;
1065
1066     /* not buffered, direct seek on file */
1067     if (!wm->info.pchBuffer)
1068         return MMIO_SendMessage(wm, MMIOM_SEEK, lOffset, iOrigin, MMIO_PROC_32A);
1069
1070     switch (iOrigin) {
1071     case SEEK_SET: 
1072         offset = lOffset;
1073         break;
1074     case SEEK_CUR: 
1075         offset = wm->info.lBufOffset + (wm->info.pchNext - wm->info.pchBuffer) + lOffset;
1076         break;
1077     case SEEK_END: 
1078         if (wm->info.fccIOProc == FOURCC_MEM) {
1079             offset = wm->info.cchBuffer;
1080         } else {
1081             assert(MMIO_SendMessage(wm, MMIOM_SEEK, 0, SEEK_CUR, MMIO_PROC_32A) == wm->info.lDiskOffset);
1082             offset = MMIO_SendMessage(wm, MMIOM_SEEK, 0, SEEK_END, MMIO_PROC_32A);
1083             MMIO_SendMessage(wm, MMIOM_SEEK, wm->info.lDiskOffset, SEEK_SET, MMIO_PROC_32A);
1084         }
1085         offset -= lOffset;
1086         break;
1087     default:
1088         return -1;
1089     }
1090
1091     /* stay in same buffer ? */
1092     /* some memory mapped buffers are defined with -1 as a size */
1093     if ((wm->info.cchBuffer > 0) &&
1094         ((offset < wm->info.lBufOffset) ||
1095          (offset >= wm->info.lBufOffset + wm->info.cchBuffer) ||
1096          !wm->bBufferLoaded)) {
1097
1098         /* condition to change buffer */
1099         if ((wm->info.fccIOProc == FOURCC_MEM) || 
1100             MMIO_Flush(wm, 0) ||
1101             /* this also sets the wm->info.lDiskOffset field */
1102             MMIO_SendMessage(wm, MMIOM_SEEK, 
1103                              (offset / wm->info.cchBuffer) * wm->info.cchBuffer,
1104                              SEEK_SET, MMIO_PROC_32A) == -1)
1105             return -1;
1106         MMIO_GrabNextBuffer(wm, TRUE);
1107     }
1108
1109     wm->info.pchNext = wm->info.pchBuffer + (offset - wm->info.lBufOffset);
1110
1111     TRACE("=> %ld\n", offset);
1112     return offset;
1113 }
1114
1115 /**************************************************************************
1116  *                              mmioSeek                [MMSYSTEM.1214]
1117  */
1118 LONG WINAPI mmioSeek16(HMMIO16 hmmio, LONG lOffset, INT16 iOrigin)
1119 {
1120     return mmioSeek(hmmio, lOffset, iOrigin);
1121 }
1122
1123 /**************************************************************************
1124  *                              mmioGetInfo             [MMSYSTEM.1215]
1125  */
1126 UINT16 WINAPI mmioGetInfo16(HMMIO16 hmmio, MMIOINFO16* lpmmioinfo, UINT16 uFlags)
1127 {
1128     LPWINE_MMIO wm;
1129
1130     TRACE("(0x%04x,%p,0x%08x)\n",hmmio,lpmmioinfo,uFlags);
1131
1132     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
1133         return MMSYSERR_INVALHANDLE;
1134
1135     if (!wm->buffer16)
1136         return MMSYSERR_ERROR;
1137
1138     lpmmioinfo->dwFlags     = wm->info.dwFlags; 
1139     lpmmioinfo->fccIOProc   = wm->info.fccIOProc; 
1140     lpmmioinfo->pIOProc     = (LPMMIOPROC16)wm->info.pIOProc; 
1141     lpmmioinfo->wErrorRet   = wm->info.wErrorRet; 
1142     lpmmioinfo->hTask       = wm->info.hTask; 
1143     lpmmioinfo->cchBuffer   = wm->info.cchBuffer; 
1144     lpmmioinfo->pchBuffer   = (void*)wm->buffer16;
1145     lpmmioinfo->pchNext     = (void*)(wm->buffer16 + (wm->info.pchNext - wm->info.pchBuffer));
1146     lpmmioinfo->pchEndRead  = (void*)(wm->buffer16 + (wm->info.pchEndRead - wm->info.pchBuffer));
1147     lpmmioinfo->pchEndWrite = (void*)(wm->buffer16 + (wm->info.pchEndWrite - wm->info.pchBuffer)); 
1148     lpmmioinfo->lBufOffset  = wm->info.lBufOffset; 
1149     lpmmioinfo->lDiskOffset = wm->info.lDiskOffset; 
1150     lpmmioinfo->adwInfo[0]  = wm->info.adwInfo[0]; 
1151     lpmmioinfo->adwInfo[1]  = wm->info.adwInfo[1]; 
1152     lpmmioinfo->adwInfo[2]  = wm->info.adwInfo[2]; 
1153     lpmmioinfo->adwInfo[3]  = wm->info.adwInfo[3]; 
1154     lpmmioinfo->dwReserved1 = 0;
1155     lpmmioinfo->dwReserved2 = 0;
1156     lpmmioinfo->hmmio = wm->info.hmmio; 
1157
1158     return 0;
1159 }
1160
1161 /**************************************************************************
1162  *                              mmioGetInfo             [WINMM.@]
1163  */
1164 UINT WINAPI mmioGetInfo(HMMIO hmmio, MMIOINFO* lpmmioinfo, UINT uFlags)
1165 {
1166     LPWINE_MMIO         wm;
1167     
1168     TRACE("(0x%04x,%p,0x%08x)\n",hmmio,lpmmioinfo,uFlags);
1169
1170     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
1171         return MMSYSERR_INVALHANDLE;
1172
1173     memcpy(lpmmioinfo, &wm->info, sizeof(MMIOINFO));
1174
1175     return 0;
1176 }
1177
1178 /**************************************************************************
1179  *                              mmioSetInfo             [MMSYSTEM.1216]
1180  */
1181 UINT16 WINAPI mmioSetInfo16(HMMIO16 hmmio, const MMIOINFO16* lpmmioinfo, UINT16 uFlags)
1182 {
1183     LPWINE_MMIO         wm;
1184
1185     TRACE("(0x%04x,%p,0x%08x)\n",hmmio,lpmmioinfo,uFlags);
1186
1187     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
1188         return MMSYSERR_INVALHANDLE;
1189
1190     /* check if seg and lin buffers are the same */
1191     if (wm->info.cchBuffer != lpmmioinfo->cchBuffer ||
1192         wm->info.pchBuffer != MapSL(wm->buffer16))
1193         return MMSYSERR_INVALPARAM;
1194         
1195     /* check pointers coherence */
1196     if (lpmmioinfo->pchNext < lpmmioinfo->pchBuffer || 
1197         lpmmioinfo->pchNext > lpmmioinfo->pchBuffer + lpmmioinfo->cchBuffer ||
1198         lpmmioinfo->pchEndRead < lpmmioinfo->pchBuffer || 
1199         lpmmioinfo->pchEndRead > lpmmioinfo->pchBuffer + lpmmioinfo->cchBuffer ||
1200         lpmmioinfo->pchEndWrite < lpmmioinfo->pchBuffer || 
1201         lpmmioinfo->pchEndWrite > lpmmioinfo->pchBuffer + lpmmioinfo->cchBuffer)
1202         return MMSYSERR_INVALPARAM;
1203
1204     wm->info.pchNext     = wm->info.pchBuffer + (lpmmioinfo->pchNext     - lpmmioinfo->pchBuffer);
1205     wm->info.pchEndRead  = wm->info.pchBuffer + (lpmmioinfo->pchEndRead  - lpmmioinfo->pchBuffer);
1206     wm->info.pchEndWrite = wm->info.pchBuffer + (lpmmioinfo->pchEndWrite - lpmmioinfo->pchBuffer);
1207
1208     return 0;
1209 }
1210
1211 /**************************************************************************
1212  *                              mmioSetInfo             [WINMM.@]
1213  */
1214 UINT WINAPI mmioSetInfo(HMMIO hmmio, const MMIOINFO* lpmmioinfo, UINT uFlags)
1215 {
1216     LPWINE_MMIO         wm;
1217
1218     TRACE("(0x%04x,%p,0x%08x)\n",hmmio,lpmmioinfo,uFlags);
1219
1220     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
1221         return MMSYSERR_INVALHANDLE;
1222     
1223     /* check pointers coherence */
1224     if (lpmmioinfo->pchNext < wm->info.pchBuffer || 
1225         lpmmioinfo->pchNext > wm->info.pchBuffer + wm->info.cchBuffer ||
1226         lpmmioinfo->pchEndRead < wm->info.pchBuffer || 
1227         lpmmioinfo->pchEndRead > wm->info.pchBuffer + wm->info.cchBuffer ||
1228         lpmmioinfo->pchEndWrite < wm->info.pchBuffer || 
1229         lpmmioinfo->pchEndWrite > wm->info.pchBuffer + wm->info.cchBuffer)
1230         return MMSYSERR_INVALPARAM;
1231
1232     wm->info.pchNext = lpmmioinfo->pchNext;
1233     wm->info.pchEndRead = lpmmioinfo->pchEndRead;
1234
1235     return 0;
1236 }
1237
1238 /**************************************************************************
1239 *                               mmioSetBuffer           [WINMM.@]
1240 */
1241 UINT WINAPI mmioSetBuffer(HMMIO hmmio, LPSTR pchBuffer, LONG cchBuffer, UINT uFlags)
1242 {
1243     LPWINE_MMIO         wm;
1244
1245     TRACE("(hmmio=%04x, pchBuf=%p, cchBuf=%ld, uFlags=%#08x)\n",
1246           hmmio, pchBuffer, cchBuffer, uFlags);
1247     
1248     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
1249         return MMSYSERR_INVALHANDLE;
1250
1251     return MMIO_SetBuffer(wm, pchBuffer, cchBuffer, uFlags, TRUE);
1252 }
1253
1254 /**************************************************************************
1255  *                              mmioSetBuffer           [MMSYSTEM.1217]
1256  */
1257 UINT16 WINAPI mmioSetBuffer16(HMMIO16 hmmio, LPSTR segpchBuffer, 
1258                               LONG cchBuffer, UINT16 uFlags)
1259 {
1260     LPWINE_MMIO         wm;
1261
1262     TRACE("(hmmio=%04x, segpchBuf=%p, cchBuf=%ld, uFlags=%#08x)\n",
1263           hmmio, segpchBuffer, cchBuffer, uFlags);
1264     
1265     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
1266         return MMSYSERR_INVALHANDLE;
1267
1268     return MMIO_SetBuffer(wm, segpchBuffer, cchBuffer, uFlags, FALSE);
1269 }
1270
1271 /**************************************************************************
1272  *                              mmioFlush               [WINMM.@]
1273  */
1274 UINT WINAPI mmioFlush(HMMIO hmmio, UINT uFlags)
1275 {
1276     LPWINE_MMIO         wm;
1277
1278     TRACE("(%04X, %04X)\n", hmmio, uFlags);
1279
1280     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
1281         return MMSYSERR_INVALHANDLE;
1282        
1283     return MMIO_Flush(wm, uFlags);
1284 }
1285
1286 /**************************************************************************
1287  *                              mmioFlush               [MMSYSTEM.1218]
1288  */
1289 UINT16 WINAPI mmioFlush16(HMMIO16 hmmio, UINT16 uFlags)
1290 {
1291     return mmioFlush(hmmio, uFlags);
1292 }
1293
1294 /**************************************************************************
1295  *                              mmioAdvance             [WINMM.@]
1296  */
1297 UINT WINAPI mmioAdvance(HMMIO hmmio, MMIOINFO* lpmmioinfo, UINT uFlags)
1298 {
1299     LPWINE_MMIO         wm;
1300     
1301     TRACE("hmmio=%04X, lpmmioinfo=%p, uFlags=%04X\n", hmmio, lpmmioinfo, uFlags);
1302
1303     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
1304         return MMSYSERR_INVALHANDLE;
1305
1306     if (!wm->info.cchBuffer)
1307         return MMIOERR_UNBUFFERED;
1308
1309     if (uFlags != MMIO_READ && uFlags != MMIO_WRITE)
1310         return MMSYSERR_INVALPARAM;
1311
1312     if (MMIO_Flush(wm, 0))
1313         return MMIOERR_CANNOTWRITE;
1314
1315     MMIO_GrabNextBuffer(wm, uFlags == MMIO_READ);
1316
1317     lpmmioinfo->pchNext = lpmmioinfo->pchBuffer;
1318     lpmmioinfo->pchEndRead  = lpmmioinfo->pchBuffer + 
1319         (wm->info.pchEndRead - wm->info.pchBuffer);
1320     lpmmioinfo->pchEndWrite = lpmmioinfo->pchBuffer + 
1321         (wm->info.pchEndWrite - wm->info.pchBuffer);
1322     lpmmioinfo->lDiskOffset = wm->info.lDiskOffset;
1323     lpmmioinfo->lBufOffset = wm->info.lBufOffset;
1324     return 0;
1325 }
1326
1327 /***********************************************************************
1328  *                              mmioAdvance             [MMSYSTEM.1219]
1329  */
1330 UINT16 WINAPI mmioAdvance16(HMMIO16 hmmio, MMIOINFO16* lpmmioinfo, UINT16 uFlags)
1331 {
1332     LPWINE_MMIO         wm;
1333
1334     TRACE("hmmio=%04X, lpmmioinfo=%p, uFlags=%04X\n", hmmio, lpmmioinfo, uFlags);
1335
1336     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
1337         return MMSYSERR_INVALHANDLE;
1338
1339     if (!wm->info.cchBuffer)
1340         return MMIOERR_UNBUFFERED;
1341
1342     if (uFlags != MMIO_READ && uFlags != MMIO_WRITE)
1343         return MMSYSERR_INVALPARAM;
1344
1345     if (MMIO_Flush(wm, 0))
1346         return MMIOERR_CANNOTWRITE;
1347
1348     MMIO_GrabNextBuffer(wm, uFlags == MMIO_READ);
1349         
1350     lpmmioinfo->pchNext = lpmmioinfo->pchBuffer;
1351     lpmmioinfo->pchEndRead  = lpmmioinfo->pchBuffer + 
1352         (wm->info.pchEndRead - wm->info.pchBuffer);
1353     lpmmioinfo->pchEndWrite = lpmmioinfo->pchBuffer + 
1354         (wm->info.pchEndWrite - wm->info.pchBuffer);
1355     lpmmioinfo->lDiskOffset = wm->info.lDiskOffset;
1356     lpmmioinfo->lBufOffset = wm->info.lBufOffset;
1357
1358     return 0;
1359 }
1360
1361 /**************************************************************************
1362  *                              mmioStringToFOURCCA     [WINMM.@]
1363  */
1364 FOURCC WINAPI mmioStringToFOURCCA(LPCSTR sz, UINT uFlags)
1365 {
1366     CHAR cc[4];
1367     int i = 0;
1368     
1369     for (i = 0; i < 4 && sz[i]; i++) {
1370         if (uFlags & MMIO_TOUPPER) {
1371             cc[i] = toupper(sz[i]);
1372         } else {
1373             cc[i] = sz[i];
1374         }
1375     }
1376     
1377     /* Pad with spaces */
1378     while (i < 4) cc[i++] = ' ';
1379     
1380     TRACE("Got '%.4s'\n",cc);
1381     return mmioFOURCC(cc[0],cc[1],cc[2],cc[3]);
1382 }
1383
1384 /**************************************************************************
1385  *                              mmioStringToFOURCCW     [WINMM.@]
1386  */
1387 FOURCC WINAPI mmioStringToFOURCCW(LPCWSTR sz, UINT uFlags)
1388 {
1389     LPSTR       szA = HEAP_strdupWtoA(GetProcessHeap(),0,sz);
1390     FOURCC      ret = mmioStringToFOURCCA(szA,uFlags);
1391     
1392     HeapFree(GetProcessHeap(),0,szA);
1393     return ret;
1394 }
1395
1396 /**************************************************************************
1397  *                              mmioStringToFOURCC      [MMSYSTEM.1220]
1398  */
1399 FOURCC WINAPI mmioStringToFOURCC16(LPCSTR sz, UINT16 uFlags)
1400 {
1401     return mmioStringToFOURCCA(sz, uFlags);
1402 }
1403
1404 /**************************************************************************
1405  *              mmioInstallIOProc    [MMSYSTEM.1221]
1406  */
1407 LPMMIOPROC16 WINAPI mmioInstallIOProc16(FOURCC fccIOProc, LPMMIOPROC16 pIOProc,
1408                                         DWORD dwFlags)
1409 {
1410     return (LPMMIOPROC16)MMIO_InstallIOProc(fccIOProc, (LPMMIOPROC)pIOProc, 
1411                                             dwFlags, MMIO_PROC_16); 
1412 }
1413
1414 /**************************************************************************
1415  *                              mmioInstallIOProcA         [WINMM.@]
1416  */
1417 LPMMIOPROC WINAPI mmioInstallIOProcA(FOURCC fccIOProc, 
1418                                      LPMMIOPROC pIOProc, DWORD dwFlags)
1419 {
1420     return MMIO_InstallIOProc(fccIOProc, pIOProc, dwFlags, MMIO_PROC_32A);
1421 }
1422
1423 /**************************************************************************
1424  *                              mmioInstallIOProcW         [WINMM.@]
1425  */
1426 LPMMIOPROC WINAPI mmioInstallIOProcW(FOURCC fccIOProc, 
1427                                      LPMMIOPROC pIOProc, DWORD dwFlags)
1428 {
1429     return MMIO_InstallIOProc(fccIOProc, pIOProc, dwFlags, MMIO_PROC_32W);
1430 }
1431
1432 /**************************************************************************
1433  *                              mmioSendMessage [MMSYSTEM.1222]
1434  */
1435 LRESULT WINAPI mmioSendMessage16(HMMIO16 hmmio, UINT16 uMessage,
1436                                  LPARAM lParam1, LPARAM lParam2)
1437 {
1438     LPWINE_MMIO         wm;
1439     
1440     TRACE("(%04X, %u, %ld, %ld)\n", hmmio, uMessage, lParam1, lParam2);
1441
1442     if (uMessage < MMIOM_USER)
1443         return MMSYSERR_INVALPARAM;
1444     
1445     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
1446         return MMSYSERR_INVALHANDLE;
1447     
1448     return MMIO_SendMessage(wm, uMessage, lParam1, lParam2, MMIO_PROC_16);
1449 }
1450
1451 /**************************************************************************
1452  *                              mmioSendMessage         [WINMM.@]
1453  */
1454 LRESULT WINAPI mmioSendMessage(HMMIO hmmio, UINT uMessage,
1455                                LPARAM lParam1, LPARAM lParam2)
1456 {
1457     LPWINE_MMIO         wm;
1458     
1459     TRACE("(%04X, %u, %ld, %ld)\n", hmmio, uMessage, lParam1, lParam2);
1460
1461     if (uMessage < MMIOM_USER)
1462         return MMSYSERR_INVALPARAM;
1463     
1464     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
1465         return MMSYSERR_INVALHANDLE;
1466     
1467     return MMIO_SendMessage(wm, uMessage, lParam1, lParam2, MMIO_PROC_32A);
1468 }
1469
1470 /**************************************************************************
1471  *                              mmioDescend             [WINMM.@]
1472  */
1473 UINT WINAPI mmioDescend(HMMIO hmmio, LPMMCKINFO lpck,
1474                         const MMCKINFO* lpckParent, UINT uFlags)
1475 {
1476     DWORD               dwOldPos;
1477     FOURCC              srchCkId;
1478     FOURCC              srchType;
1479     
1480     
1481     TRACE("(%04X, %p, %p, %04X);\n", hmmio, lpck, lpckParent, uFlags);
1482     
1483     if (lpck == NULL)
1484         return MMSYSERR_INVALPARAM;
1485     
1486     dwOldPos = mmioSeek(hmmio, 0, SEEK_CUR);
1487     TRACE("dwOldPos=%ld\n", dwOldPos);
1488     
1489     if (lpckParent != NULL) {
1490         TRACE("seek inside parent at %ld !\n", lpckParent->dwDataOffset);
1491         /* EPP: was dwOldPos = mmioSeek(hmmio,lpckParent->dwDataOffset,SEEK_SET); */
1492         if (dwOldPos < lpckParent->dwDataOffset || 
1493             dwOldPos >= lpckParent->dwDataOffset + lpckParent->cksize) {
1494             WARN("outside parent chunk\n");
1495             return MMIOERR_CHUNKNOTFOUND;
1496         }
1497     }
1498     
1499     /* The SDK docu says 'ckid' is used for all cases. Real World
1500      * examples disagree -Marcus,990216. 
1501      */
1502     
1503     srchType = 0;
1504     /* find_chunk looks for 'ckid' */
1505     if (uFlags & MMIO_FINDCHUNK)
1506         srchCkId = lpck->ckid;
1507     /* find_riff and find_list look for 'fccType' */
1508     if (uFlags & MMIO_FINDLIST) {
1509         srchCkId = FOURCC_LIST;
1510         srchType = lpck->fccType;
1511     }
1512     if (uFlags & MMIO_FINDRIFF) {
1513         srchCkId = FOURCC_RIFF;
1514         srchType = lpck->fccType;
1515     }
1516     
1517     if (uFlags & (MMIO_FINDCHUNK|MMIO_FINDLIST|MMIO_FINDRIFF)) {
1518         TRACE("searching for %.4s.%.4s\n", 
1519               (LPSTR)&srchCkId,
1520               srchType?(LPSTR)&srchType:"any ");
1521         
1522         while (TRUE) {
1523             LONG ix;
1524             
1525             ix = mmioRead(hmmio, (LPSTR)lpck, 3 * sizeof(DWORD));
1526             if (ix < 2*sizeof(DWORD)) {
1527                 mmioSeek(hmmio, dwOldPos, SEEK_SET);
1528                 WARN("return ChunkNotFound\n");
1529                 return MMIOERR_CHUNKNOTFOUND;
1530             }
1531             lpck->dwDataOffset = dwOldPos + 2 * sizeof(DWORD);
1532             if (ix < lpck->dwDataOffset - dwOldPos) {
1533                 mmioSeek(hmmio, dwOldPos, SEEK_SET);
1534                 WARN("return ChunkNotFound\n");
1535                 return MMIOERR_CHUNKNOTFOUND;
1536             }
1537             TRACE("ckid=%.4s fcc=%.4s cksize=%08lX !\n",
1538                   (LPSTR)&lpck->ckid, 
1539                   srchType?(LPSTR)&lpck->fccType:"<na>",
1540                   lpck->cksize);
1541             if ((srchCkId == lpck->ckid) &&
1542                 (!srchType || (srchType == lpck->fccType))
1543                 )
1544                 break;
1545             
1546             dwOldPos = lpck->dwDataOffset + ((lpck->cksize + 1) & ~1);
1547             mmioSeek(hmmio, dwOldPos, SEEK_SET);
1548         }
1549     } else {
1550         /* FIXME: unverified, does it do this? */
1551         /* NB: This part is used by WAVE_mciOpen, among others */
1552         if (mmioRead(hmmio, (LPSTR)lpck, 3 * sizeof(DWORD)) < 3 * sizeof(DWORD)) {
1553             mmioSeek(hmmio, dwOldPos, SEEK_SET);
1554             WARN("return ChunkNotFound 2nd\n");
1555             return MMIOERR_CHUNKNOTFOUND;
1556         }
1557         lpck->dwDataOffset = dwOldPos + 2 * sizeof(DWORD);
1558     }
1559     lpck->dwFlags = 0;
1560     /* If we were looking for RIFF/LIST chunks, the final file position
1561      * is after the chunkid. If we were just looking for the chunk
1562      * it is after the cksize. So add 4 in RIFF/LIST case.
1563      */
1564     if (lpck->ckid == FOURCC_RIFF || lpck->ckid == FOURCC_LIST)
1565         mmioSeek(hmmio, lpck->dwDataOffset + sizeof(DWORD), SEEK_SET);
1566     else
1567         mmioSeek(hmmio, lpck->dwDataOffset, SEEK_SET);
1568     TRACE("lpck: ckid=%.4s, cksize=%ld, dwDataOffset=%ld fccType=%08lX (%.4s)!\n", 
1569           (LPSTR)&lpck->ckid, lpck->cksize, lpck->dwDataOffset, 
1570           lpck->fccType, srchType?(LPSTR)&lpck->fccType:"");
1571     return 0;
1572 }
1573
1574 /**************************************************************************
1575  *                              mmioDescend             [MMSYSTEM.1223]
1576  */
1577 UINT16 WINAPI mmioDescend16(HMMIO16 hmmio, LPMMCKINFO lpck,
1578                             const MMCKINFO* lpckParent, UINT16 uFlags)
1579 {
1580     return mmioDescend(hmmio, lpck, lpckParent, uFlags);
1581 }
1582
1583 /**************************************************************************
1584  *                              mmioAscend              [WINMM.@]
1585  */
1586 UINT WINAPI mmioAscend(HMMIO hmmio, LPMMCKINFO lpck, UINT uFlags)
1587 {
1588     TRACE("(%04X, %p, %04X);\n", hmmio, lpck, uFlags);
1589     
1590     if (lpck->dwFlags & MMIO_DIRTY) {
1591         DWORD   dwOldPos, dwNewSize;
1592         
1593         TRACE("Chunk is dirty, checking if chunk's size is correct\n");
1594         dwOldPos = mmioSeek(hmmio, 0, SEEK_CUR);
1595         TRACE("dwOldPos=%ld lpck->dwDataOffset = %ld\n", dwOldPos, lpck->dwDataOffset);
1596         dwNewSize = dwOldPos - lpck->dwDataOffset;
1597         if (dwNewSize != lpck->cksize) {
1598             TRACE("Nope: lpck->cksize=%ld dwNewSize=%ld\n", lpck->cksize, dwNewSize);
1599             lpck->cksize = dwNewSize;
1600             
1601             /* pad odd size with 0 */
1602             if (dwNewSize & 1) {
1603                 char ch = 0;
1604                 mmioWrite(hmmio, &ch, 1);
1605             }
1606             mmioSeek(hmmio, lpck->dwDataOffset - sizeof(DWORD), SEEK_SET);
1607             mmioWrite(hmmio, (LPSTR)&dwNewSize, sizeof(DWORD));
1608         }
1609         lpck->dwFlags = 0;
1610     }
1611     
1612     mmioSeek(hmmio, lpck->dwDataOffset + ((lpck->cksize + 1) & ~1), SEEK_SET);
1613     
1614     return 0;
1615 }
1616
1617 /**************************************************************************
1618  *                              mmioAscend              [MMSYSTEM.1224]
1619  */
1620 UINT16 WINAPI mmioAscend16(HMMIO16 hmmio, MMCKINFO* lpck, UINT16 uFlags)
1621 {
1622     return mmioAscend(hmmio,lpck,uFlags);
1623 }
1624
1625 /**************************************************************************
1626  *                      mmioCreateChunk                         [WINMM.@]
1627  */
1628 UINT WINAPI mmioCreateChunk(HMMIO hmmio, MMCKINFO* lpck, UINT uFlags)
1629 {
1630     DWORD       dwOldPos;
1631     LONG        size;
1632     LONG        ix;
1633     
1634     TRACE("(%04X, %p, %04X);\n", hmmio, lpck, uFlags);
1635     
1636     dwOldPos = mmioSeek(hmmio, 0, SEEK_CUR);
1637     TRACE("dwOldPos=%ld\n", dwOldPos);
1638     
1639     if (uFlags == MMIO_CREATELIST)
1640         lpck->ckid = FOURCC_LIST;
1641     else if (uFlags == MMIO_CREATERIFF)
1642         lpck->ckid = FOURCC_RIFF;
1643     
1644     TRACE("ckid=%.4s\n", (LPSTR)&lpck->ckid);
1645     
1646     size = 2 * sizeof(DWORD);
1647     lpck->dwDataOffset = dwOldPos + size;
1648     
1649     if (lpck->ckid == FOURCC_RIFF || lpck->ckid == FOURCC_LIST) 
1650         size += sizeof(DWORD);
1651     lpck->dwFlags = MMIO_DIRTY;
1652     
1653     ix = mmioWrite(hmmio, (LPSTR)lpck, size);
1654     TRACE("after mmioWrite ix = %ld req = %ld, errno = %d\n",ix, size, errno);
1655     if (ix < size) {
1656         mmioSeek(hmmio, dwOldPos, SEEK_SET);
1657         WARN("return CannotWrite\n");
1658         return MMIOERR_CANNOTWRITE;
1659     }
1660
1661     return 0;
1662 }
1663
1664 /**************************************************************************
1665  *                              mmioCreateChunk         [MMSYSTEM.1225]
1666  */
1667 UINT16 WINAPI mmioCreateChunk16(HMMIO16 hmmio, MMCKINFO* lpck, UINT16 uFlags)
1668 {
1669     return mmioCreateChunk(hmmio, lpck, uFlags);
1670 }
1671
1672 /**************************************************************************
1673  *                              mmioRename              [MMSYSTEM.1226]
1674  */
1675 UINT16 WINAPI mmioRename16(LPCSTR szFileName, LPCSTR szNewFileName,
1676                            MMIOINFO16* lpmmioinfo, DWORD dwRenameFlags)
1677 {
1678     UINT16              result = MMSYSERR_ERROR;
1679     LPMMIOPROC16        ioProc;
1680
1681     TRACE("('%s', '%s', %p, %08lX);\n",
1682           szFileName, szNewFileName, lpmmioinfo, dwRenameFlags);
1683     
1684     /* If both params are NULL, then parse the file name */
1685     if (lpmmioinfo && lpmmioinfo->fccIOProc == 0 && lpmmioinfo->pIOProc == NULL)
1686         lpmmioinfo->fccIOProc = MMIO_ParseExt(szFileName);
1687
1688     /* Handle any unhandled/error case from above. Assume DOS file */
1689     if (!lpmmioinfo || (lpmmioinfo->fccIOProc == 0 && lpmmioinfo->pIOProc == NULL))
1690         ioProc = (LPMMIOPROC16)mmioDosIOProc;
1691     /* if just the four character code is present, look up IO proc */
1692     else if (lpmmioinfo->pIOProc == NULL)
1693         ioProc = mmioInstallIOProc16(lpmmioinfo->fccIOProc, NULL, MMIO_FINDPROC);
1694     else
1695         ioProc = lpmmioinfo->pIOProc;
1696
1697     /* FIXME: ioProc is likely a segmented address, thus needing a
1698      * thunk somewhere. The main issue is that Wine's current thunking
1699      * 32 to 16 only supports pascal calling convention
1700      */
1701     if (ioProc) 
1702         result = (ioProc)(0, MMIOM_RENAME, 
1703                           (LPARAM)szFileName, (LPARAM)szNewFileName);
1704     
1705     return result;
1706 }
1707
1708 /**************************************************************************
1709  *                              mmioRenameA                     [WINMM.@]
1710  */
1711 UINT WINAPI mmioRenameA(LPCSTR szFileName, LPCSTR szNewFileName,
1712                         MMIOINFO* lpmmioinfo, DWORD dwRenameFlags)
1713 {
1714     UINT        result = MMSYSERR_ERROR;
1715     LPMMIOPROC  ioProc;
1716
1717     TRACE("('%s', '%s', %p, %08lX);\n",
1718           szFileName, szNewFileName, lpmmioinfo, dwRenameFlags);
1719
1720     /* If both params are NULL, then parse the file name */
1721     if (lpmmioinfo && lpmmioinfo->fccIOProc == 0 && lpmmioinfo->pIOProc == NULL)
1722         lpmmioinfo->fccIOProc = MMIO_ParseExt(szFileName);
1723
1724     /* Handle any unhandled/error case from above. Assume DOS file */
1725     if (!lpmmioinfo || (lpmmioinfo->fccIOProc == 0 && lpmmioinfo->pIOProc == NULL))
1726         ioProc = (LPMMIOPROC)mmioDosIOProc;
1727     /* if just the four character code is present, look up IO proc */
1728     else if (lpmmioinfo->pIOProc == NULL)
1729         ioProc = MMIO_InstallIOProc(lpmmioinfo->fccIOProc, NULL, 
1730                                     MMIO_FINDPROC, MMIO_PROC_32A);
1731     else /* use relevant ioProc */
1732         ioProc = lpmmioinfo->pIOProc;
1733
1734     if (ioProc) 
1735         result = (ioProc)(0, MMIOM_RENAME, 
1736                           (LPARAM)szFileName, (LPARAM)szNewFileName);
1737     
1738     return result;
1739 }
1740
1741 /**************************************************************************
1742  *                              mmioRenameW                     [WINMM.@]
1743  */
1744 UINT WINAPI mmioRenameW(LPCWSTR szFileName, LPCWSTR szNewFileName,
1745                         MMIOINFO* lpmmioinfo, DWORD dwRenameFlags)
1746 {
1747     LPSTR       szFn = HEAP_strdupWtoA(GetProcessHeap(), 0, szFileName);
1748     LPSTR       sznFn = HEAP_strdupWtoA(GetProcessHeap(), 0, szNewFileName);
1749     UINT        ret = mmioRenameA(szFn, sznFn, lpmmioinfo, dwRenameFlags);
1750     
1751     HeapFree(GetProcessHeap(),0,szFn);
1752     HeapFree(GetProcessHeap(),0,sznFn);
1753     return ret;
1754 }