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