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