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