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