Fixed bugs in output functions (write).
[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] == (DWORD)HFILE_ERROR)
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  MMRESULT 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             /* FIXME: error handling */
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         }
624         if (uFlags & MMIO_EMPTYBUF) 
625             wm->info.pchNext = wm->info.pchEndRead = wm->info.pchBuffer;
626     }
627     wm->info.dwFlags &= ~MMIO_DIRTY;
628
629     return MMSYSERR_NOERROR;
630 }
631
632 /***************************************************************************
633  *                      MMIO_GrabNextBuffer                     [INTERNAL]
634  */
635 static LONG     MMIO_GrabNextBuffer(LPWINE_MMIO wm, int for_read)
636 {
637     LONG        size = wm->info.cchBuffer;
638
639     TRACE("bo=%lx do=%lx of=%lx\n", 
640           wm->info.lBufOffset, wm->info.lDiskOffset, 
641           MMIO_SendMessage(wm, MMIOM_SEEK, 0, SEEK_CUR, MMIO_PROC_32A));
642           
643     wm->info.lBufOffset = wm->info.lDiskOffset;
644     wm->info.pchNext = wm->info.pchBuffer;
645     wm->info.pchEndRead = wm->info.pchBuffer;
646     wm->info.pchEndWrite = wm->info.pchBuffer + wm->info.cchBuffer;
647
648     if (for_read) {
649         size = MMIO_SendMessage(wm, MMIOM_READ, (LPARAM)wm->info.pchBuffer,
650                                 size, MMIO_PROC_32A);
651         if (size > 0)
652             wm->info.pchEndRead += size;
653     }
654
655     wm->bBufferLoaded = TRUE;
656     return size;
657 }
658
659 /***************************************************************************
660  *                      MMIO_SetBuffer                          [INTERNAL]
661  */
662 static MMRESULT MMIO_SetBuffer(WINE_MMIO* wm, void* pchBuffer, LONG cchBuffer, 
663                                UINT uFlags, BOOL bFrom32)
664 {
665     TRACE("(%p %p %ld %u %d)\n", wm, pchBuffer, cchBuffer, uFlags, bFrom32);
666
667     if (uFlags)                 return MMSYSERR_INVALPARAM;
668     if (cchBuffer > 0xFFFF)
669         WARN("Untested handling of huge mmio buffers (%ld >= 64k)\n", cchBuffer);
670         
671     if (MMIO_Flush(wm, 0) != MMSYSERR_NOERROR)
672         return MMIOERR_CANNOTWRITE;
673     
674     if (wm->hMem && (wm->info.dwFlags & MMIO_ALLOCBUF)) {
675         GlobalUnlock16(wm->hMem);
676         GlobalFree16(wm->hMem);
677         wm->hMem = 0;
678         wm->info.dwFlags &= ~MMIO_ALLOCBUF;
679     }
680
681     if (pchBuffer) {
682         if (bFrom32) {
683             wm->info.pchBuffer = pchBuffer;
684             wm->buffer16 = 0;
685         } else {
686             wm->info.pchBuffer = MapSL((SEGPTR)pchBuffer);
687             wm->buffer16 = (SEGPTR)pchBuffer;
688         }
689         wm->hMem = 0;
690     } else if (cchBuffer) {
691         if (!(wm->hMem = GlobalAlloc16(GMEM_MOVEABLE, cchBuffer)))
692             return MMIOERR_OUTOFMEMORY;
693         wm->info.dwFlags |= MMIO_ALLOCBUF;
694     } else {
695         wm->info.pchBuffer = NULL;
696         wm->hMem = 0;
697         wm->buffer16 = 0;
698     }
699
700     if (wm->hMem) {
701         wm->buffer16 = K32WOWGlobalLock16(wm->hMem);
702         wm->info.pchBuffer = MapSL(wm->buffer16);
703     }
704
705     wm->info.cchBuffer = cchBuffer;
706     wm->info.pchNext = wm->info.pchBuffer;
707     wm->info.pchEndRead = wm->info.pchBuffer;
708     wm->info.pchEndWrite = wm->info.pchBuffer + cchBuffer;
709     wm->info.lBufOffset = 0;
710     wm->bBufferLoaded = FALSE;
711
712     return MMSYSERR_NOERROR;
713 }
714
715 /**************************************************************************
716  *                      MMIO_Open                               [internal]
717  */
718 static HMMIO MMIO_Open(LPSTR szFileName, MMIOINFO* refmminfo, 
719                        DWORD dwOpenFlags, enum mmioProcType type)
720 {
721     LPWINE_MMIO         wm;
722
723     TRACE("('%s', %p, %08lX, %d);\n", szFileName, refmminfo, dwOpenFlags, type);
724
725     if (dwOpenFlags & (MMIO_PARSE|MMIO_EXIST)) {
726         char    buffer[MAX_PATH];
727         
728         if (GetFullPathNameA(szFileName, sizeof(buffer), buffer, NULL) >= sizeof(buffer))
729             return (HMMIO16)FALSE;
730         if ((dwOpenFlags & MMIO_EXIST) && (GetFileAttributesA(buffer) == -1))
731             return (HMMIO)FALSE;
732         strcpy(szFileName, buffer);
733         return (HMMIO)TRUE;
734     }
735     
736     if ((wm = MMIO_Create()) == NULL)
737         return 0;
738
739     /* If both params are NULL, then parse the file name if available */
740     if (refmminfo->fccIOProc == 0 && refmminfo->pIOProc == NULL) {
741         wm->info.fccIOProc = MMIO_ParseExt(szFileName);
742         /* Handle any unhandled/error case. Assume DOS file */
743         if (wm->info.fccIOProc == 0)
744             wm->info.fccIOProc = FOURCC_DOS;
745         if (!(wm->ioProc = MMIO_FindProcNode(wm->info.fccIOProc))) goto error2;
746         wm->info.pIOProc = wm->ioProc->pIOProc;
747         wm->bTmpIOProc = FALSE;
748     }
749     /* if just the four character code is present, look up IO proc */
750     else if (refmminfo->pIOProc == NULL) {      
751         wm->info.fccIOProc = refmminfo->fccIOProc;
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 IO proc specified, use it and specified four character code */
757     else {
758         wm->info.fccIOProc = refmminfo->fccIOProc;
759         wm->info.pIOProc = refmminfo->pIOProc;
760         MMIO_InstallIOProc(wm->info.fccIOProc, wm->info.pIOProc, 
761                            MMIO_INSTALLPROC, type);
762         if (!(wm->ioProc = MMIO_FindProcNode(wm->info.fccIOProc))) goto error2;
763         assert(wm->ioProc->pIOProc == refmminfo->pIOProc);
764         wm->info.pIOProc = wm->ioProc->pIOProc;
765         wm->bTmpIOProc = TRUE;
766     }
767     
768     wm->bBufferLoaded = FALSE;
769     wm->ioProc->count++;
770
771     if (dwOpenFlags & MMIO_ALLOCBUF) {
772         if ((refmminfo->wErrorRet = mmioSetBuffer(wm->info.hmmio, NULL, 
773                                                   MMIO_DEFAULTBUFFER, 0)))
774             goto error1;
775     } else if (wm->info.fccIOProc == FOURCC_MEM) {
776         refmminfo->wErrorRet = MMIO_SetBuffer(wm, refmminfo->pchBuffer, 
777                                               refmminfo->cchBuffer, 0, 
778                                               type != MMIO_PROC_16);
779         if (refmminfo->wErrorRet != MMSYSERR_NOERROR)
780             goto error1;
781         wm->bBufferLoaded = TRUE;
782     } /* else => unbuffered, wm->info.pchBuffer == NULL */
783     
784     /* see mmioDosIOProc for that one */
785     wm->info.adwInfo[0] = refmminfo->adwInfo[0];
786     wm->info.dwFlags = dwOpenFlags;
787     
788     /* call IO proc to actually open file */
789     refmminfo->wErrorRet = MMIO_SendMessage(wm, MMIOM_OPEN, (LPARAM)szFileName, 
790                                         type == MMIO_PROC_16, MMIO_PROC_32A);
791
792     if (refmminfo->wErrorRet == 0)
793         return wm->info.hmmio;
794  error1:
795     if (wm->ioProc) wm->ioProc->count--;
796  error2:
797     MMIO_Destroy(wm);
798     return 0;
799 }
800
801 /**************************************************************************
802  *                              mmioOpenW                       [WINMM.@]
803  */
804 HMMIO WINAPI mmioOpenW(LPWSTR szFileName, MMIOINFO* lpmmioinfo,
805                        DWORD dwOpenFlags)
806 {
807     HMMIO       ret;
808     LPSTR       szFn = HEAP_strdupWtoA(GetProcessHeap(), 0, szFileName);
809
810     if (lpmmioinfo) {
811         ret = MMIO_Open(szFn, lpmmioinfo, dwOpenFlags, MMIO_PROC_32W);
812     } else {
813         MMIOINFO        mmioinfo;
814         
815         mmioinfo.fccIOProc = 0;
816         mmioinfo.pIOProc = NULL;
817         mmioinfo.pchBuffer = NULL;
818         mmioinfo.cchBuffer = 0;
819         
820         ret = MMIO_Open(szFn, &mmioinfo, dwOpenFlags, MMIO_PROC_32W);
821     }
822
823     HeapFree(GetProcessHeap(), 0, szFn);
824     return ret;
825 }
826
827 /**************************************************************************
828  *                              mmioOpenA                       [WINMM.@]
829  */
830 HMMIO WINAPI mmioOpenA(LPSTR szFileName, MMIOINFO* lpmmioinfo, 
831                        DWORD dwOpenFlags)
832 {
833     HMMIO       ret;
834     
835     if (lpmmioinfo) {
836         ret = MMIO_Open(szFileName, lpmmioinfo, dwOpenFlags, MMIO_PROC_32A);
837     } else {
838         MMIOINFO        mmioinfo;
839         
840         mmioinfo.fccIOProc = 0;
841         mmioinfo.pIOProc = NULL;
842         mmioinfo.pchBuffer = NULL;
843         mmioinfo.cchBuffer = 0;
844         
845         ret = MMIO_Open(szFileName, &mmioinfo, dwOpenFlags, MMIO_PROC_32A);
846     }
847     return ret;
848 }
849
850 /**************************************************************************
851  *                              mmioOpen                [MMSYSTEM.1210]
852  */
853 HMMIO16 WINAPI mmioOpen16(LPSTR szFileName, MMIOINFO16* lpmmioinfo16, 
854                           DWORD dwOpenFlags)
855 {
856     HMMIO       ret;
857     MMIOINFO    mmio;
858     
859     if (lpmmioinfo16) {
860         MMIOINFO        mmioinfo;
861        
862         memset(&mmioinfo, 0, sizeof(mmioinfo));
863
864         mmioinfo.dwFlags     = lpmmioinfo16->dwFlags; 
865         mmioinfo.fccIOProc   = lpmmioinfo16->fccIOProc; 
866         mmioinfo.pIOProc     = (LPMMIOPROC)lpmmioinfo16->pIOProc; 
867         mmioinfo.cchBuffer   = lpmmioinfo16->cchBuffer; 
868         mmioinfo.pchBuffer   = lpmmioinfo16->pchBuffer;
869         mmioinfo.adwInfo[0]  = lpmmioinfo16->adwInfo[0]; 
870         mmioinfo.adwInfo[1]  = lpmmioinfo16->adwInfo[1]; 
871         mmioinfo.adwInfo[2]  = lpmmioinfo16->adwInfo[2]; 
872         mmioinfo.adwInfo[3]  = lpmmioinfo16->adwInfo[3]; 
873         
874         ret = MMIO_Open(szFileName, &mmioinfo, dwOpenFlags, MMIO_PROC_16);
875
876         mmioGetInfo16(mmioinfo.hmmio, lpmmioinfo16, 0);
877         lpmmioinfo16->wErrorRet = ret;
878     } else {
879         mmio.fccIOProc = 0;
880         mmio.pIOProc = NULL;
881         mmio.pchBuffer = NULL;
882         mmio.cchBuffer = 0;
883         ret = MMIO_Open(szFileName, &mmio, dwOpenFlags, FALSE);
884     }
885     return ret;
886 }
887
888     
889 /**************************************************************************
890  *                              mmioClose               [WINMM.@]
891  */
892 MMRESULT WINAPI mmioClose(HMMIO hmmio, UINT uFlags)
893 {
894     LPWINE_MMIO wm;
895     MMRESULT    result;
896     
897     TRACE("(%04X, %04X);\n", hmmio, uFlags);
898     
899     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
900         return MMSYSERR_INVALHANDLE;
901     
902     if ((result = MMIO_Flush(wm, 0)) != MMSYSERR_NOERROR)
903         return result;
904     
905     result = MMIO_SendMessage(wm, MMIOM_CLOSE, uFlags, 0, MMIO_PROC_32A);
906     
907     mmioSetBuffer(hmmio, NULL, 0, 0);
908     
909     wm->ioProc->count--;
910
911     if (wm->bTmpIOProc)
912         MMIO_InstallIOProc(wm->info.fccIOProc, NULL, 
913                            MMIO_REMOVEPROC, wm->ioProc->type);
914
915     MMIO_Destroy(wm);
916
917     return result;
918 }
919
920 /**************************************************************************
921  *                              mmioClose               [MMSYSTEM.1211]
922  */
923 MMRESULT16 WINAPI mmioClose16(HMMIO16 hmmio, UINT16 uFlags)
924 {
925     return mmioClose(hmmio, uFlags);
926 }
927
928 /**************************************************************************
929  *                              mmioRead                [WINMM.@]
930  */
931 LONG WINAPI mmioRead(HMMIO hmmio, HPSTR pch, LONG cch)
932 {
933     LPWINE_MMIO wm;
934     LONG        count;
935     
936     TRACE("(%04X, %p, %ld);\n", hmmio, pch, cch);
937     
938     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
939         return -1;
940
941     /* unbuffered case first */
942     if (!wm->info.pchBuffer)
943         return MMIO_SendMessage(wm, MMIOM_READ, (LPARAM)pch, cch, MMIO_PROC_32A);
944
945     /* first try from current buffer */
946     if (wm->info.pchNext != wm->info.pchEndRead) {
947         count = wm->info.pchEndRead - wm->info.pchNext;
948         if (count > cch || count < 0) count = cch;
949         memcpy(pch, wm->info.pchNext, count);
950         wm->info.pchNext += count;
951         pch += count;
952         cch -= count;
953     } else
954         count = 0;
955     
956     if (cch && (wm->info.fccIOProc != FOURCC_MEM)) {
957         assert(wm->info.cchBuffer);
958
959         while (cch) {
960             LONG size;
961
962             size = MMIO_GrabNextBuffer(wm, TRUE);
963             if (size <= 0) break;
964             if (size > cch) size = cch;
965             memcpy(pch, wm->info.pchBuffer, size);
966             wm->info.pchNext += size;
967             pch += size;
968             cch -= size;
969             count += size;
970         }
971     }
972     
973     TRACE("count=%ld\n", count);
974     return count;
975 }
976
977 /**************************************************************************
978  *                              mmioRead                [MMSYSTEM.1212]
979  */
980 LONG WINAPI mmioRead16(HMMIO16 hmmio, HPSTR pch, LONG cch)
981 {
982     return mmioRead(hmmio, pch, cch);
983 }
984
985 /**************************************************************************
986  *                              mmioWrite               [WINMM.@]
987  */
988 LONG WINAPI mmioWrite(HMMIO hmmio, HPCSTR pch, LONG cch)
989 {
990     LPWINE_MMIO wm;
991     LONG        count;
992     
993     TRACE("(%04X, %p, %ld);\n", hmmio, pch, cch);
994
995     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
996         return -1;
997     
998     if (wm->info.cchBuffer) {
999         LONG    bytesW = 0;
1000
1001         count = 0;
1002         while (cch) {
1003             if (wm->info.pchNext != wm->info.pchEndWrite) {
1004                 count = wm->info.pchEndWrite - wm->info.pchNext;
1005                 if (count > cch || count < 0) count = cch;
1006                 memcpy(wm->info.pchNext, pch, count);
1007                 wm->info.pchNext += count;
1008                 pch += count;
1009                 cch -= count;
1010                 bytesW += count;
1011                 wm->info.dwFlags |= MMIO_DIRTY;                                             
1012             } else {
1013                 if (wm->info.fccIOProc == FOURCC_MEM) {
1014                     if (wm->info.adwInfo[0]) {
1015                         /* from where would we get the memory handle? */
1016                         FIXME("memory file expansion not implemented!\n");
1017                         break;                                                                      
1018                     } else break;
1019                 }
1020             }
1021
1022             if (wm->info.pchNext == wm->info.pchEndWrite)
1023             {
1024                 MMIO_Flush(wm, MMIO_EMPTYBUF);
1025                 MMIO_GrabNextBuffer(wm, FALSE);
1026             }
1027             else break;
1028         }
1029         count = bytesW;
1030     } else {
1031         count = MMIO_SendMessage(wm, MMIOM_WRITE, (LPARAM)pch, cch, MMIO_PROC_32A);
1032         wm->info.lBufOffset = wm->info.lDiskOffset;
1033     }
1034     
1035     TRACE("bytes written=%ld\n", count);
1036     return count;
1037 }
1038
1039 /**************************************************************************
1040  *                              mmioWrite               [MMSYSTEM.1213]
1041  */
1042 LONG WINAPI mmioWrite16(HMMIO16 hmmio, HPCSTR pch, LONG cch)
1043 {
1044     return mmioWrite(hmmio,pch,cch);
1045 }
1046
1047 /**************************************************************************
1048  *                              mmioSeek                [WINMM.@]
1049  */
1050 LONG WINAPI mmioSeek(HMMIO hmmio, LONG lOffset, INT iOrigin)
1051 {
1052     LPWINE_MMIO wm;
1053     LONG        offset;
1054
1055     TRACE("(%04X, %08lX, %d);\n", hmmio, lOffset, iOrigin);
1056     
1057     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
1058         return MMSYSERR_INVALHANDLE;
1059
1060     /* not buffered, direct seek on file */
1061     if (!wm->info.pchBuffer)
1062         return MMIO_SendMessage(wm, MMIOM_SEEK, lOffset, iOrigin, MMIO_PROC_32A);
1063
1064     switch (iOrigin) {
1065     case SEEK_SET: 
1066         offset = lOffset;
1067         break;
1068     case SEEK_CUR: 
1069         offset = wm->info.lBufOffset + (wm->info.pchNext - wm->info.pchBuffer) + lOffset;
1070         break;
1071     case SEEK_END: 
1072         if (wm->info.fccIOProc == FOURCC_MEM) {
1073             offset = wm->info.cchBuffer;
1074         } else {
1075             assert(MMIO_SendMessage(wm, MMIOM_SEEK, 0, SEEK_CUR, MMIO_PROC_32A) == wm->info.lDiskOffset);
1076             offset = MMIO_SendMessage(wm, MMIOM_SEEK, 0, SEEK_END, MMIO_PROC_32A);
1077             MMIO_SendMessage(wm, MMIOM_SEEK, wm->info.lDiskOffset, SEEK_SET, MMIO_PROC_32A);
1078         }
1079         offset -= lOffset;
1080         break;
1081     default:
1082         return -1;
1083     }
1084
1085     /* stay in same buffer ? */
1086     /* some memory mapped buffers are defined with -1 as a size */
1087     if ((wm->info.cchBuffer > 0) &&
1088         ((offset < wm->info.lBufOffset) ||
1089          (offset >= wm->info.lBufOffset + wm->info.cchBuffer) ||
1090          !wm->bBufferLoaded)) {
1091
1092         /* condition to change buffer */
1093         if ((wm->info.fccIOProc == FOURCC_MEM) || 
1094             MMIO_Flush(wm, 0) != MMSYSERR_NOERROR ||
1095             /* this also sets the wm->info.lDiskOffset field */
1096             MMIO_SendMessage(wm, MMIOM_SEEK, 
1097                              (offset / wm->info.cchBuffer) * wm->info.cchBuffer,
1098                              SEEK_SET, MMIO_PROC_32A) == -1)
1099             return -1;
1100         MMIO_GrabNextBuffer(wm, TRUE);
1101     }
1102
1103     wm->info.pchNext = wm->info.pchBuffer + (offset - wm->info.lBufOffset);
1104
1105     TRACE("=> %ld\n", offset);
1106     return offset;
1107 }
1108
1109 /**************************************************************************
1110  *                              mmioSeek                [MMSYSTEM.1214]
1111  */
1112 LONG WINAPI mmioSeek16(HMMIO16 hmmio, LONG lOffset, INT16 iOrigin)
1113 {
1114     return mmioSeek(hmmio, lOffset, iOrigin);
1115 }
1116
1117 /**************************************************************************
1118  *                              mmioGetInfo             [MMSYSTEM.1215]
1119  */
1120 MMRESULT16 WINAPI mmioGetInfo16(HMMIO16 hmmio, MMIOINFO16* lpmmioinfo, UINT16 uFlags)
1121 {
1122     LPWINE_MMIO wm;
1123
1124     TRACE("(0x%04x,%p,0x%08x)\n",hmmio,lpmmioinfo,uFlags);
1125
1126     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
1127         return MMSYSERR_INVALHANDLE;
1128
1129     if (!wm->buffer16)
1130         return MMSYSERR_ERROR;
1131
1132     lpmmioinfo->dwFlags     = wm->info.dwFlags; 
1133     lpmmioinfo->fccIOProc   = wm->info.fccIOProc; 
1134     lpmmioinfo->pIOProc     = (LPMMIOPROC16)wm->info.pIOProc; 
1135     lpmmioinfo->wErrorRet   = wm->info.wErrorRet; 
1136     lpmmioinfo->hTask       = wm->info.hTask; 
1137     lpmmioinfo->cchBuffer   = wm->info.cchBuffer; 
1138     lpmmioinfo->pchBuffer   = (void*)wm->buffer16;
1139     lpmmioinfo->pchNext     = (void*)(wm->buffer16 + (wm->info.pchNext - wm->info.pchBuffer));
1140     lpmmioinfo->pchEndRead  = (void*)(wm->buffer16 + (wm->info.pchEndRead - wm->info.pchBuffer));
1141     lpmmioinfo->pchEndWrite = (void*)(wm->buffer16 + (wm->info.pchEndWrite - wm->info.pchBuffer)); 
1142     lpmmioinfo->lBufOffset  = wm->info.lBufOffset; 
1143     lpmmioinfo->lDiskOffset = wm->info.lDiskOffset; 
1144     lpmmioinfo->adwInfo[0]  = wm->info.adwInfo[0]; 
1145     lpmmioinfo->adwInfo[1]  = wm->info.adwInfo[1]; 
1146     lpmmioinfo->adwInfo[2]  = wm->info.adwInfo[2]; 
1147     lpmmioinfo->adwInfo[3]  = wm->info.adwInfo[3]; 
1148     lpmmioinfo->dwReserved1 = 0;
1149     lpmmioinfo->dwReserved2 = 0;
1150     lpmmioinfo->hmmio = wm->info.hmmio; 
1151
1152     return MMSYSERR_NOERROR;
1153 }
1154
1155 /**************************************************************************
1156  *                              mmioGetInfo             [WINMM.@]
1157  */
1158 MMRESULT WINAPI mmioGetInfo(HMMIO hmmio, MMIOINFO* lpmmioinfo, UINT uFlags)
1159 {
1160     LPWINE_MMIO         wm;
1161     
1162     TRACE("(0x%04x,%p,0x%08x)\n",hmmio,lpmmioinfo,uFlags);
1163
1164     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
1165         return MMSYSERR_INVALHANDLE;
1166
1167     memcpy(lpmmioinfo, &wm->info, sizeof(MMIOINFO));
1168
1169     return MMSYSERR_NOERROR;
1170 }
1171
1172 /**************************************************************************
1173  *                              mmioSetInfo             [MMSYSTEM.1216]
1174  */
1175 MMRESULT16 WINAPI mmioSetInfo16(HMMIO16 hmmio, const MMIOINFO16* lpmmioinfo, UINT16 uFlags)
1176 {
1177     LPWINE_MMIO         wm;
1178
1179     TRACE("(0x%04x,%p,0x%08x)\n",hmmio,lpmmioinfo,uFlags);
1180
1181     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
1182         return MMSYSERR_INVALHANDLE;
1183
1184     /* check if seg and lin buffers are the same */
1185     if (wm->info.cchBuffer != lpmmioinfo->cchBuffer ||
1186         wm->info.pchBuffer != MapSL(wm->buffer16))
1187         return MMSYSERR_INVALPARAM;
1188         
1189     /* check pointers coherence */
1190     if (lpmmioinfo->pchNext < lpmmioinfo->pchBuffer || 
1191         lpmmioinfo->pchNext > lpmmioinfo->pchBuffer + lpmmioinfo->cchBuffer ||
1192         lpmmioinfo->pchEndRead < lpmmioinfo->pchBuffer || 
1193         lpmmioinfo->pchEndRead > lpmmioinfo->pchBuffer + lpmmioinfo->cchBuffer ||
1194         lpmmioinfo->pchEndWrite < lpmmioinfo->pchBuffer || 
1195         lpmmioinfo->pchEndWrite > lpmmioinfo->pchBuffer + lpmmioinfo->cchBuffer)
1196         return MMSYSERR_INVALPARAM;
1197
1198     wm->info.pchNext     = wm->info.pchBuffer + (lpmmioinfo->pchNext     - lpmmioinfo->pchBuffer);
1199     wm->info.pchEndRead  = wm->info.pchBuffer + (lpmmioinfo->pchEndRead  - lpmmioinfo->pchBuffer);
1200     wm->info.pchEndWrite = wm->info.pchBuffer + (lpmmioinfo->pchEndWrite - lpmmioinfo->pchBuffer);
1201
1202     return MMSYSERR_NOERROR;
1203 }
1204
1205 /**************************************************************************
1206  *                              mmioSetInfo             [WINMM.@]
1207  */
1208 MMRESULT WINAPI mmioSetInfo(HMMIO hmmio, const MMIOINFO* lpmmioinfo, UINT uFlags)
1209 {
1210     LPWINE_MMIO         wm;
1211
1212     TRACE("(0x%04x,%p,0x%08x)\n",hmmio,lpmmioinfo,uFlags);
1213
1214     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
1215         return MMSYSERR_INVALHANDLE;
1216     
1217     /* check pointers coherence */
1218     if (lpmmioinfo->pchNext < wm->info.pchBuffer || 
1219         lpmmioinfo->pchNext > wm->info.pchBuffer + wm->info.cchBuffer ||
1220         lpmmioinfo->pchEndRead < wm->info.pchBuffer || 
1221         lpmmioinfo->pchEndRead > wm->info.pchBuffer + wm->info.cchBuffer ||
1222         lpmmioinfo->pchEndWrite < wm->info.pchBuffer || 
1223         lpmmioinfo->pchEndWrite > wm->info.pchBuffer + wm->info.cchBuffer)
1224         return MMSYSERR_INVALPARAM;
1225
1226     wm->info.pchNext = lpmmioinfo->pchNext;
1227     wm->info.pchEndRead = lpmmioinfo->pchEndRead;
1228
1229     return MMSYSERR_NOERROR;
1230 }
1231
1232 /**************************************************************************
1233 *                               mmioSetBuffer           [WINMM.@]
1234 */
1235 MMRESULT WINAPI mmioSetBuffer(HMMIO hmmio, LPSTR pchBuffer, LONG cchBuffer, UINT uFlags)
1236 {
1237     LPWINE_MMIO         wm;
1238
1239     TRACE("(hmmio=%04x, pchBuf=%p, cchBuf=%ld, uFlags=%#08x)\n",
1240           hmmio, pchBuffer, cchBuffer, uFlags);
1241     
1242     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
1243         return MMSYSERR_INVALHANDLE;
1244
1245     return MMIO_SetBuffer(wm, pchBuffer, cchBuffer, uFlags, TRUE);
1246 }
1247
1248 /**************************************************************************
1249  *                              mmioSetBuffer           [MMSYSTEM.1217]
1250  */
1251 MMRESULT16 WINAPI mmioSetBuffer16(HMMIO16 hmmio, LPSTR segpchBuffer, 
1252                                   LONG cchBuffer, UINT16 uFlags)
1253 {
1254     LPWINE_MMIO         wm;
1255
1256     TRACE("(hmmio=%04x, segpchBuf=%p, cchBuf=%ld, uFlags=%#08x)\n",
1257           hmmio, segpchBuffer, cchBuffer, uFlags);
1258     
1259     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
1260         return MMSYSERR_INVALHANDLE;
1261
1262     return MMIO_SetBuffer(wm, segpchBuffer, cchBuffer, uFlags, FALSE);
1263 }
1264
1265 /**************************************************************************
1266  *                              mmioFlush               [WINMM.@]
1267  */
1268 MMRESULT WINAPI mmioFlush(HMMIO hmmio, UINT uFlags)
1269 {
1270     LPWINE_MMIO         wm;
1271
1272     TRACE("(%04X, %04X)\n", hmmio, uFlags);
1273
1274     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
1275         return MMSYSERR_INVALHANDLE;
1276        
1277     return MMIO_Flush(wm, uFlags);
1278 }
1279
1280 /**************************************************************************
1281  *                              mmioFlush               [MMSYSTEM.1218]
1282  */
1283 MMRESULT16 WINAPI mmioFlush16(HMMIO16 hmmio, UINT16 uFlags)
1284 {
1285     return mmioFlush(hmmio, uFlags);
1286 }
1287
1288 /**************************************************************************
1289  *                              mmioAdvance             [WINMM.@]
1290  */
1291 MMRESULT WINAPI mmioAdvance(HMMIO hmmio, MMIOINFO* lpmmioinfo, UINT uFlags)
1292 {
1293     LPWINE_MMIO         wm;
1294     
1295     TRACE("hmmio=%04X, lpmmioinfo=%p, uFlags=%04X\n", hmmio, lpmmioinfo, uFlags);
1296
1297     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
1298         return MMSYSERR_INVALHANDLE;
1299
1300     if (!wm->info.cchBuffer)
1301         return MMIOERR_UNBUFFERED;
1302
1303     if (uFlags != MMIO_READ && uFlags != MMIO_WRITE)
1304         return MMSYSERR_INVALPARAM;
1305
1306     if (uFlags == MMIO_WRITE && (lpmmioinfo->dwFlags & MMIO_DIRTY))
1307     {
1308         FIXME("writing data to disk\n");
1309         MMIO_SendMessage(wm, MMIOM_SEEK, lpmmioinfo->lBufOffset, SEEK_SET, MMIO_PROC_32A);
1310         MMIO_SendMessage(wm, MMIOM_WRITE, (LPARAM)lpmmioinfo->pchBuffer,
1311                          lpmmioinfo->pchNext - lpmmioinfo->pchBuffer, MMIO_PROC_32A);
1312         lpmmioinfo->dwFlags &= ~MMIO_DIRTY;
1313     }
1314     if (MMIO_Flush(wm, 0) != MMSYSERR_NOERROR)
1315         return MMIOERR_CANNOTWRITE;
1316
1317     MMIO_GrabNextBuffer(wm, uFlags == MMIO_READ);
1318
1319     lpmmioinfo->pchNext = lpmmioinfo->pchBuffer;
1320     lpmmioinfo->pchEndRead  = lpmmioinfo->pchBuffer + 
1321         (wm->info.pchEndRead - wm->info.pchBuffer);
1322     lpmmioinfo->pchEndWrite = lpmmioinfo->pchBuffer + 
1323         (wm->info.pchEndWrite - wm->info.pchBuffer);
1324     lpmmioinfo->lDiskOffset = wm->info.lDiskOffset;
1325     lpmmioinfo->lBufOffset = wm->info.lBufOffset;
1326     return MMSYSERR_NOERROR;
1327 }
1328
1329 /***********************************************************************
1330  *                              mmioAdvance             [MMSYSTEM.1219]
1331  */
1332 MMRESULT16 WINAPI mmioAdvance16(HMMIO16 hmmio, MMIOINFO16* lpmmioinfo, UINT16 uFlags)
1333 {
1334     LPWINE_MMIO         wm;
1335
1336     TRACE("hmmio=%04X, lpmmioinfo=%p, uFlags=%04X\n", hmmio, lpmmioinfo, uFlags);
1337
1338     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
1339         return MMSYSERR_INVALHANDLE;
1340
1341     if (!wm->info.cchBuffer)
1342         return MMIOERR_UNBUFFERED;
1343
1344     if (uFlags != MMIO_READ && uFlags != MMIO_WRITE)
1345         return MMSYSERR_INVALPARAM;
1346
1347     if (MMIO_Flush(wm, 0) != MMSYSERR_NOERROR)
1348         return MMIOERR_CANNOTWRITE;
1349
1350     MMIO_GrabNextBuffer(wm, uFlags == MMIO_READ);
1351         
1352     lpmmioinfo->pchNext = lpmmioinfo->pchBuffer;
1353     lpmmioinfo->pchEndRead  = lpmmioinfo->pchBuffer + 
1354         (wm->info.pchEndRead - wm->info.pchBuffer);
1355     lpmmioinfo->pchEndWrite = lpmmioinfo->pchBuffer + 
1356         (wm->info.pchEndWrite - wm->info.pchBuffer);
1357     lpmmioinfo->lDiskOffset = wm->info.lDiskOffset;
1358     lpmmioinfo->lBufOffset = wm->info.lBufOffset;
1359
1360     return MMSYSERR_NOERROR;
1361 }
1362
1363 /**************************************************************************
1364  *                              mmioStringToFOURCCA     [WINMM.@]
1365  */
1366 FOURCC WINAPI mmioStringToFOURCCA(LPCSTR sz, UINT uFlags)
1367 {
1368     CHAR cc[4];
1369     int i = 0;
1370     
1371     for (i = 0; i < 4 && sz[i]; i++) {
1372         if (uFlags & MMIO_TOUPPER) {
1373             cc[i] = toupper(sz[i]);
1374         } else {
1375             cc[i] = sz[i];
1376         }
1377     }
1378     
1379     /* Pad with spaces */
1380     while (i < 4) cc[i++] = ' ';
1381     
1382     TRACE("Got '%.4s'\n",cc);
1383     return mmioFOURCC(cc[0],cc[1],cc[2],cc[3]);
1384 }
1385
1386 /**************************************************************************
1387  *                              mmioStringToFOURCCW     [WINMM.@]
1388  */
1389 FOURCC WINAPI mmioStringToFOURCCW(LPCWSTR sz, UINT uFlags)
1390 {
1391     LPSTR       szA = HEAP_strdupWtoA(GetProcessHeap(),0,sz);
1392     FOURCC      ret = mmioStringToFOURCCA(szA,uFlags);
1393     
1394     HeapFree(GetProcessHeap(), 0, szA);
1395     return ret;
1396 }
1397
1398 /**************************************************************************
1399  *                              mmioStringToFOURCC      [MMSYSTEM.1220]
1400  */
1401 FOURCC WINAPI mmioStringToFOURCC16(LPCSTR sz, UINT16 uFlags)
1402 {
1403     return mmioStringToFOURCCA(sz, uFlags);
1404 }
1405
1406 /**************************************************************************
1407  *              mmioInstallIOProc    [MMSYSTEM.1221]
1408  */
1409 LPMMIOPROC16 WINAPI mmioInstallIOProc16(FOURCC fccIOProc, LPMMIOPROC16 pIOProc,
1410                                         DWORD dwFlags)
1411 {
1412     return (LPMMIOPROC16)MMIO_InstallIOProc(fccIOProc, (LPMMIOPROC)pIOProc, 
1413                                             dwFlags, MMIO_PROC_16); 
1414 }
1415
1416 /**************************************************************************
1417  *                              mmioInstallIOProcA         [WINMM.@]
1418  */
1419 LPMMIOPROC WINAPI mmioInstallIOProcA(FOURCC fccIOProc, 
1420                                      LPMMIOPROC pIOProc, DWORD dwFlags)
1421 {
1422     return MMIO_InstallIOProc(fccIOProc, pIOProc, dwFlags, MMIO_PROC_32A);
1423 }
1424
1425 /**************************************************************************
1426  *                              mmioInstallIOProcW         [WINMM.@]
1427  */
1428 LPMMIOPROC WINAPI mmioInstallIOProcW(FOURCC fccIOProc, 
1429                                      LPMMIOPROC pIOProc, DWORD dwFlags)
1430 {
1431     return MMIO_InstallIOProc(fccIOProc, pIOProc, dwFlags, MMIO_PROC_32W);
1432 }
1433
1434 /**************************************************************************
1435  *                              mmioSendMessage [MMSYSTEM.1222]
1436  */
1437 LRESULT WINAPI mmioSendMessage16(HMMIO16 hmmio, UINT16 uMessage,
1438                                  LPARAM lParam1, LPARAM lParam2)
1439 {
1440     LPWINE_MMIO         wm;
1441     
1442     TRACE("(%04X, %u, %ld, %ld)\n", hmmio, uMessage, lParam1, lParam2);
1443
1444     if (uMessage < MMIOM_USER)
1445         return MMSYSERR_INVALPARAM;
1446     
1447     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
1448         return MMSYSERR_INVALHANDLE;
1449     
1450     return MMIO_SendMessage(wm, uMessage, lParam1, lParam2, MMIO_PROC_16);
1451 }
1452
1453 /**************************************************************************
1454  *                              mmioSendMessage         [WINMM.@]
1455  */
1456 LRESULT WINAPI mmioSendMessage(HMMIO hmmio, UINT uMessage,
1457                                LPARAM lParam1, LPARAM lParam2)
1458 {
1459     LPWINE_MMIO         wm;
1460     
1461     TRACE("(%04X, %u, %ld, %ld)\n", hmmio, uMessage, lParam1, lParam2);
1462
1463     if (uMessage < MMIOM_USER)
1464         return MMSYSERR_INVALPARAM;
1465     
1466     if ((wm = MMIO_Get(NULL, hmmio)) == NULL)
1467         return MMSYSERR_INVALHANDLE;
1468     
1469     return MMIO_SendMessage(wm, uMessage, lParam1, lParam2, MMIO_PROC_32A);
1470 }
1471
1472 /**************************************************************************
1473  *                              mmioDescend             [WINMM.@]
1474  */
1475 MMRESULT WINAPI mmioDescend(HMMIO hmmio, LPMMCKINFO lpck,
1476                             const MMCKINFO* lpckParent, UINT uFlags)
1477 {
1478     DWORD               dwOldPos;
1479     FOURCC              srchCkId;
1480     FOURCC              srchType;
1481     
1482     
1483     TRACE("(%04X, %p, %p, %04X);\n", hmmio, lpck, lpckParent, uFlags);
1484     
1485     if (lpck == NULL)
1486         return MMSYSERR_INVALPARAM;
1487     
1488     dwOldPos = mmioSeek(hmmio, 0, SEEK_CUR);
1489     TRACE("dwOldPos=%ld\n", dwOldPos);
1490     
1491     if (lpckParent != NULL) {
1492         TRACE("seek inside parent at %ld !\n", lpckParent->dwDataOffset);
1493         /* EPP: was dwOldPos = mmioSeek(hmmio,lpckParent->dwDataOffset,SEEK_SET); */
1494         if (dwOldPos < lpckParent->dwDataOffset || 
1495             dwOldPos >= lpckParent->dwDataOffset + lpckParent->cksize) {
1496             WARN("outside parent chunk\n");
1497             return MMIOERR_CHUNKNOTFOUND;
1498         }
1499     }
1500     
1501     /* The SDK docu says 'ckid' is used for all cases. Real World
1502      * examples disagree -Marcus,990216. 
1503      */
1504     
1505     srchType = 0;
1506     /* find_chunk looks for 'ckid' */
1507     if (uFlags & MMIO_FINDCHUNK)
1508         srchCkId = lpck->ckid;
1509     /* find_riff and find_list look for 'fccType' */
1510     if (uFlags & MMIO_FINDLIST) {
1511         srchCkId = FOURCC_LIST;
1512         srchType = lpck->fccType;
1513     }
1514     if (uFlags & MMIO_FINDRIFF) {
1515         srchCkId = FOURCC_RIFF;
1516         srchType = lpck->fccType;
1517     }
1518     
1519     if (uFlags & (MMIO_FINDCHUNK|MMIO_FINDLIST|MMIO_FINDRIFF)) {
1520         TRACE("searching for %.4s.%.4s\n", 
1521               (LPSTR)&srchCkId,
1522               srchType?(LPSTR)&srchType:"any ");
1523         
1524         while (TRUE) {
1525             LONG ix;
1526             
1527             ix = mmioRead(hmmio, (LPSTR)lpck, 3 * sizeof(DWORD));
1528             if (ix < 2*sizeof(DWORD)) {
1529                 mmioSeek(hmmio, dwOldPos, SEEK_SET);
1530                 WARN("return ChunkNotFound\n");
1531                 return MMIOERR_CHUNKNOTFOUND;
1532             }
1533             lpck->dwDataOffset = dwOldPos + 2 * sizeof(DWORD);
1534             if (ix < lpck->dwDataOffset - dwOldPos) {
1535                 mmioSeek(hmmio, dwOldPos, SEEK_SET);
1536                 WARN("return ChunkNotFound\n");
1537                 return MMIOERR_CHUNKNOTFOUND;
1538             }
1539             TRACE("ckid=%.4s fcc=%.4s cksize=%08lX !\n",
1540                   (LPSTR)&lpck->ckid, 
1541                   srchType?(LPSTR)&lpck->fccType:"<na>",
1542                   lpck->cksize);
1543             if ((srchCkId == lpck->ckid) &&
1544                 (!srchType || (srchType == lpck->fccType))
1545                 )
1546                 break;
1547             
1548             dwOldPos = lpck->dwDataOffset + ((lpck->cksize + 1) & ~1);
1549             mmioSeek(hmmio, dwOldPos, SEEK_SET);
1550         }
1551     } else {
1552         /* FIXME: unverified, does it do this? */
1553         /* NB: This part is used by WAVE_mciOpen, among others */
1554         if (mmioRead(hmmio, (LPSTR)lpck, 3 * sizeof(DWORD)) < 3 * sizeof(DWORD)) {
1555             mmioSeek(hmmio, dwOldPos, SEEK_SET);
1556             WARN("return ChunkNotFound 2nd\n");
1557             return MMIOERR_CHUNKNOTFOUND;
1558         }
1559         lpck->dwDataOffset = dwOldPos + 2 * sizeof(DWORD);
1560     }
1561     lpck->dwFlags = 0;
1562     /* If we were looking for RIFF/LIST chunks, the final file position
1563      * is after the chunkid. If we were just looking for the chunk
1564      * it is after the cksize. So add 4 in RIFF/LIST case.
1565      */
1566     if (lpck->ckid == FOURCC_RIFF || lpck->ckid == FOURCC_LIST)
1567         mmioSeek(hmmio, lpck->dwDataOffset + sizeof(DWORD), SEEK_SET);
1568     else
1569         mmioSeek(hmmio, lpck->dwDataOffset, SEEK_SET);
1570     TRACE("lpck: ckid=%.4s, cksize=%ld, dwDataOffset=%ld fccType=%08lX (%.4s)!\n", 
1571           (LPSTR)&lpck->ckid, lpck->cksize, lpck->dwDataOffset, 
1572           lpck->fccType, srchType?(LPSTR)&lpck->fccType:"");
1573     return MMSYSERR_NOERROR;
1574 }
1575
1576 /**************************************************************************
1577  *                              mmioDescend             [MMSYSTEM.1223]
1578  */
1579 MMRESULT16 WINAPI mmioDescend16(HMMIO16 hmmio, LPMMCKINFO lpck,
1580                                 const MMCKINFO* lpckParent, UINT16 uFlags)
1581 {
1582     return mmioDescend(hmmio, lpck, lpckParent, uFlags);
1583 }
1584
1585 /**************************************************************************
1586  *                              mmioAscend              [WINMM.@]
1587  */
1588 MMRESULT WINAPI mmioAscend(HMMIO hmmio, LPMMCKINFO lpck, UINT uFlags)
1589 {
1590     TRACE("(%04X, %p, %04X);\n", hmmio, lpck, uFlags);
1591     
1592     if (lpck->dwFlags & MMIO_DIRTY) {
1593         DWORD   dwOldPos, dwNewSize;
1594         
1595         TRACE("Chunk is dirty, checking if chunk's size is correct\n");
1596         dwOldPos = mmioSeek(hmmio, 0, SEEK_CUR);
1597         TRACE("dwOldPos=%ld lpck->dwDataOffset = %ld\n", dwOldPos, lpck->dwDataOffset);
1598         dwNewSize = dwOldPos - lpck->dwDataOffset;
1599         if (dwNewSize != lpck->cksize) {
1600             TRACE("Nope: lpck->cksize=%ld dwNewSize=%ld\n", lpck->cksize, dwNewSize);
1601             lpck->cksize = dwNewSize;
1602             
1603             /* pad odd size with 0 */
1604             if (dwNewSize & 1) {
1605                 char ch = 0;
1606                 mmioWrite(hmmio, &ch, 1);
1607             }
1608             mmioSeek(hmmio, lpck->dwDataOffset - sizeof(DWORD), SEEK_SET);
1609             mmioWrite(hmmio, (LPSTR)&dwNewSize, sizeof(DWORD));
1610         }
1611         lpck->dwFlags = 0;
1612     }
1613     
1614     mmioSeek(hmmio, lpck->dwDataOffset + ((lpck->cksize + 1) & ~1), SEEK_SET);
1615     
1616     return MMSYSERR_NOERROR;
1617 }
1618
1619 /**************************************************************************
1620  *                              mmioAscend              [MMSYSTEM.1224]
1621  */
1622 MMRESULT16 WINAPI mmioAscend16(HMMIO16 hmmio, MMCKINFO* lpck, UINT16 uFlags)
1623 {
1624     return mmioAscend(hmmio,lpck,uFlags);
1625 }
1626
1627 /**************************************************************************
1628  *                      mmioCreateChunk                         [WINMM.@]
1629  */
1630 MMRESULT WINAPI mmioCreateChunk(HMMIO hmmio, MMCKINFO* lpck, UINT uFlags)
1631 {
1632     DWORD       dwOldPos;
1633     LONG        size;
1634     LONG        ix;
1635     
1636     TRACE("(%04X, %p, %04X);\n", hmmio, lpck, uFlags);
1637     
1638     dwOldPos = mmioSeek(hmmio, 0, SEEK_CUR);
1639     TRACE("dwOldPos=%ld\n", dwOldPos);
1640     
1641     if (uFlags == MMIO_CREATELIST)
1642         lpck->ckid = FOURCC_LIST;
1643     else if (uFlags == MMIO_CREATERIFF)
1644         lpck->ckid = FOURCC_RIFF;
1645     
1646     TRACE("ckid=%.4s\n", (LPSTR)&lpck->ckid);
1647     
1648     size = 2 * sizeof(DWORD);
1649     lpck->dwDataOffset = dwOldPos + size;
1650     
1651     if (lpck->ckid == FOURCC_RIFF || lpck->ckid == FOURCC_LIST) 
1652         size += sizeof(DWORD);
1653     lpck->dwFlags = MMIO_DIRTY;
1654     
1655     ix = mmioWrite(hmmio, (LPSTR)lpck, size);
1656     TRACE("after mmioWrite ix = %ld req = %ld, errno = %d\n",ix, size, errno);
1657     if (ix < size) {
1658         mmioSeek(hmmio, dwOldPos, SEEK_SET);
1659         WARN("return CannotWrite\n");
1660         return MMIOERR_CANNOTWRITE;
1661     }
1662
1663     return MMSYSERR_NOERROR;
1664 }
1665
1666 /**************************************************************************
1667  *                              mmioCreateChunk         [MMSYSTEM.1225]
1668  */
1669 MMRESULT16 WINAPI mmioCreateChunk16(HMMIO16 hmmio, MMCKINFO* lpck, UINT16 uFlags)
1670 {
1671     return mmioCreateChunk(hmmio, lpck, uFlags);
1672 }
1673
1674 /**************************************************************************
1675  *                              mmioRename              [MMSYSTEM.1226]
1676  */
1677 MMRESULT16 WINAPI mmioRename16(LPCSTR szFileName, LPCSTR szNewFileName,
1678                                MMIOINFO16* lpmmioinfo, DWORD dwRenameFlags)
1679 {
1680     UINT16              result = MMSYSERR_ERROR;
1681     LPMMIOPROC16        ioProc;
1682
1683     TRACE("('%s', '%s', %p, %08lX);\n",
1684           szFileName, szNewFileName, lpmmioinfo, dwRenameFlags);
1685     
1686     /* If both params are NULL, then parse the file name */
1687     if (lpmmioinfo && lpmmioinfo->fccIOProc == 0 && lpmmioinfo->pIOProc == NULL)
1688         lpmmioinfo->fccIOProc = MMIO_ParseExt(szFileName);
1689
1690     /* Handle any unhandled/error case from above. Assume DOS file */
1691     if (!lpmmioinfo || (lpmmioinfo->fccIOProc == 0 && lpmmioinfo->pIOProc == NULL))
1692         ioProc = (LPMMIOPROC16)mmioDosIOProc;
1693     /* if just the four character code is present, look up IO proc */
1694     else if (lpmmioinfo->pIOProc == NULL)
1695         ioProc = mmioInstallIOProc16(lpmmioinfo->fccIOProc, NULL, MMIO_FINDPROC);
1696     else
1697         ioProc = lpmmioinfo->pIOProc;
1698
1699     /* FIXME: ioProc is likely a segmented address, thus needing a
1700      * thunk somewhere. The main issue is that Wine's current thunking
1701      * 32 to 16 only supports pascal calling convention
1702      */
1703     if (ioProc) 
1704         result = (ioProc)(0, MMIOM_RENAME, 
1705                           (LPARAM)szFileName, (LPARAM)szNewFileName);
1706     
1707     return result;
1708 }
1709
1710 /**************************************************************************
1711  *                              mmioRenameA                     [WINMM.@]
1712  */
1713 MMRESULT WINAPI mmioRenameA(LPCSTR szFileName, LPCSTR szNewFileName,
1714                             MMIOINFO* lpmmioinfo, DWORD dwRenameFlags)
1715 {
1716     UINT        result = MMSYSERR_ERROR;
1717     LPMMIOPROC  ioProc;
1718
1719     TRACE("('%s', '%s', %p, %08lX);\n",
1720           szFileName, szNewFileName, lpmmioinfo, dwRenameFlags);
1721
1722     /* If both params are NULL, then parse the file name */
1723     if (lpmmioinfo && lpmmioinfo->fccIOProc == 0 && lpmmioinfo->pIOProc == NULL)
1724         lpmmioinfo->fccIOProc = MMIO_ParseExt(szFileName);
1725
1726     /* Handle any unhandled/error case from above. Assume DOS file */
1727     if (!lpmmioinfo || (lpmmioinfo->fccIOProc == 0 && lpmmioinfo->pIOProc == NULL))
1728         ioProc = (LPMMIOPROC)mmioDosIOProc;
1729     /* if just the four character code is present, look up IO proc */
1730     else if (lpmmioinfo->pIOProc == NULL)
1731         ioProc = MMIO_InstallIOProc(lpmmioinfo->fccIOProc, NULL, 
1732                                     MMIO_FINDPROC, MMIO_PROC_32A);
1733     else /* use relevant ioProc */
1734         ioProc = lpmmioinfo->pIOProc;
1735
1736     if (ioProc) 
1737         result = (ioProc)(0, MMIOM_RENAME, 
1738                           (LPARAM)szFileName, (LPARAM)szNewFileName);
1739     
1740     return result;
1741 }
1742
1743 /**************************************************************************
1744  *                              mmioRenameW                     [WINMM.@]
1745  */
1746 MMRESULT WINAPI mmioRenameW(LPCWSTR szFileName, LPCWSTR szNewFileName,
1747                             MMIOINFO* lpmmioinfo, DWORD dwRenameFlags)
1748 {
1749     LPSTR       szFn = HEAP_strdupWtoA(GetProcessHeap(), 0, szFileName);
1750     LPSTR       sznFn = HEAP_strdupWtoA(GetProcessHeap(), 0, szNewFileName);
1751     UINT        ret = mmioRenameA(szFn, sznFn, lpmmioinfo, dwRenameFlags);
1752     
1753     HeapFree(GetProcessHeap(),0,szFn);
1754     HeapFree(GetProcessHeap(),0,sznFn);
1755     return ret;
1756 }