Menu hides when clicked for a second time.
[wine.git] / multimedia / mmio.c
blob5759b99bab349c412d15a236ab671afafb742b29
1 /*
2 * MMIO functions
4 * Copyright 1998 Andrew Taylor
5 * Copyright 1998 Ove Kåven
7 */
10 #include <stdlib.h>
11 #include <string.h>
12 #include <errno.h>
13 #include "windef.h"
14 #include "wine/winbase16.h"
15 #include "heap.h"
16 #include "selectors.h"
17 #include "file.h"
18 #include "mmsystem.h"
19 #include "debugtools.h"
21 DEFAULT_DEBUG_CHANNEL(mmio)
23 /**************************************************************************
24 * mmioDosIOProc [internal]
26 static LRESULT mmioDosIOProc(LPMMIOINFO16 lpmmioinfo, UINT16 uMessage, LPARAM lParam1, LPARAM lParam2) {
27 TRACE("(%p, %X, %ld, %ld);\n", lpmmioinfo, uMessage, lParam1, lParam2);
29 switch (uMessage) {
31 case MMIOM_OPEN: {
32 /* Parameters:
33 * lParam1 = szFileName parameter from mmioOpen
34 * lParam2 = reserved (we use it for 16-bitness)
35 * Returns: zero on success, error code on error
36 * NOTE: lDiskOffset automatically set to zero
39 OFSTRUCT ofs;
40 LPSTR szFileName = (LPSTR) lParam1;
42 if (lpmmioinfo->dwFlags & MMIO_GETTEMP) {
43 FIXME("MMIO_GETTEMP not implemented\n");
44 return MMIOERR_CANNOTOPEN;
47 /* if filename NULL, assume open file handle in adwInfo[0] */
48 if (!szFileName) {
49 if (lParam2) lpmmioinfo->adwInfo[0] =
50 FILE_GetHandle(lpmmioinfo->adwInfo[0]);
51 return 0;
54 lpmmioinfo->adwInfo[0] =
55 (DWORD) OpenFile(szFileName, &ofs, lpmmioinfo->dwFlags);
56 if (lpmmioinfo->adwInfo[0] == -1)
57 return MMIOERR_CANNOTOPEN;
59 return 0;
62 case MMIOM_CLOSE: {
63 /* Parameters:
64 * lParam1 = wFlags parameter from mmioClose
65 * lParam2 = unused
66 * Returns: zero on success, error code on error
69 UINT16 uFlags = (UINT16) lParam1;
71 if (uFlags & MMIO_FHOPEN)
72 return 0;
74 _lclose((HFILE)lpmmioinfo->adwInfo[0]);
75 return 0;
79 case MMIOM_READ: {
80 /* Parameters:
81 * lParam1 = huge pointer to read buffer
82 * lParam2 = number of bytes to read
83 * Returns: number of bytes read, 0 for EOF, -1 for error (error code
84 * in wErrorRet)
85 * NOTE: lDiskOffset should be updated
88 HPSTR pch = (HPSTR) lParam1;
89 LONG cch = (LONG) lParam2;
90 LONG count;
92 count = _lread((HFILE)lpmmioinfo->adwInfo[0], pch, cch);
93 if (count != -1)
94 lpmmioinfo->lDiskOffset += count;
96 return count;
99 case MMIOM_WRITE:
100 case MMIOM_WRITEFLUSH: {
101 /* no internal buffering, so WRITEFLUSH handled same as WRITE */
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 * NOTE: lDiskOffset should be updated
111 HPSTR pch = (HPSTR) lParam1;
112 LONG cch = (LONG) lParam2;
113 LONG count;
115 count = _hwrite((HFILE)lpmmioinfo->adwInfo[0], pch, cch);
116 if (count != -1)
117 lpmmioinfo->lDiskOffset += count;
119 return count;
122 case MMIOM_SEEK: {
123 /* Parameters:
124 * lParam1 = new position
125 * lParam2 = from whence to seek (SEEK_SET, SEEK_CUR, SEEK_END)
126 * Returns: new file postion, -1 on error
127 * NOTE: lDiskOffset should be updated
130 LONG Offset = (LONG) lParam1;
131 LONG Whence = (LONG) lParam2;
132 LONG pos;
134 pos = _llseek((HFILE)lpmmioinfo->adwInfo[0], Offset, Whence);
135 if (pos != -1)
136 lpmmioinfo->lDiskOffset = pos;
138 return pos;
141 case MMIOM_RENAME: {
142 /* Parameters:
143 * lParam1 = old name
144 * lParam2 = new name
145 * Returns: zero on success, non-zero on failure
148 FIXME("MMIOM_RENAME unimplemented\n");
149 return MMIOERR_FILENOTFOUND;
152 default:
153 FIXME("unexpected message %u\n", uMessage);
154 return 0;
157 return 0;
160 /**************************************************************************
161 * mmioMemIOProc [internal]
163 static LRESULT mmioMemIOProc(LPMMIOINFO16 lpmmioinfo, UINT16 uMessage, LPARAM lParam1, LPARAM lParam2) {
164 TRACE("(%p,0x%04x,0x%08lx,0x%08lx)\n",lpmmioinfo,uMessage,lParam1,lParam2);
165 switch (uMessage) {
167 case MMIOM_OPEN: {
168 /* Parameters:
169 * lParam1 = filename (must be NULL)
170 * lParam2 = reserved (we use it for 16-bitness)
171 * Returns: zero on success, error code on error
172 * NOTE: lDiskOffset automatically set to zero
175 if (!(lpmmioinfo->dwFlags & MMIO_CREATE))
176 lpmmioinfo->pchEndRead = lpmmioinfo->pchEndWrite;
178 return 0;
181 case MMIOM_CLOSE: {
182 /* Parameters:
183 * lParam1 = wFlags parameter from mmioClose
184 * lParam2 = unused
185 * Returns: zero on success, error code on error
188 return 0;
192 case MMIOM_READ: {
193 /* Parameters:
194 * lParam1 = huge pointer to read buffer
195 * lParam2 = number of bytes to read
196 * Returns: number of bytes read, 0 for EOF, -1 for error (error code
197 * in wErrorRet)
198 * NOTE: lDiskOffset should be updated
201 /* HPSTR pch = (HPSTR) lParam1; */
202 /* LONG cch = (LONG) lParam2; */
204 FIXME("MMIOM_READ on memory files should not occur, buffer may be lost!\n");
205 return 0;
208 case MMIOM_WRITE:
209 case MMIOM_WRITEFLUSH: {
210 /* no internal buffering, so WRITEFLUSH handled same as WRITE */
212 /* Parameters:
213 * lParam1 = huge pointer to write buffer
214 * lParam2 = number of bytes to write
215 * Returns: number of bytes written, -1 for error (error code in
216 * wErrorRet)
217 * NOTE: lDiskOffset should be updated
220 /* HPSTR pch = (HPSTR) lParam1; */
221 /* LONG cch = (LONG) lParam2; */
223 FIXME("MMIOM_WRITE on memory files should not occur, buffer may be lost!\n");
224 return 0;
227 case MMIOM_SEEK: {
228 /* Parameters:
229 * lParam1 = new position
230 * lParam2 = from whence to seek (SEEK_SET, SEEK_CUR, SEEK_END)
231 * Returns: new file postion, -1 on error
232 * NOTE: lDiskOffset should be updated
235 /* LONG Offset = (LONG) lParam1; */
236 /* LONG Whence = (LONG) lParam2; */
238 FIXME("MMIOM_SEEK on memory files should not occur, buffer may be lost!\n");
239 return -1;
242 default:
243 FIXME("unexpected message %u\n", uMessage);
244 return 0;
247 return 0;
250 /**************************************************************************
251 * MMIO_Open [internal]
253 static HMMIO16 MMIO_Open(LPSTR szFileName, MMIOINFO16 * lpmmioinfo,
254 DWORD dwOpenFlags, int use16)
256 LPMMIOINFO16 lpmminfo;
257 HMMIO16 hmmio;
258 UINT16 result;
260 TRACE("('%s', %p, %08lX);\n", szFileName, lpmmioinfo, dwOpenFlags);
262 if (dwOpenFlags & MMIO_PARSE) {
263 char buffer[MAX_PATH];
265 if (GetFullPathNameA(szFileName, sizeof(buffer), buffer, NULL) >= sizeof(buffer))
266 return (HMMIO16)FALSE;
267 strcpy(szFileName, buffer);
268 return (HMMIO16)TRUE;
271 hmmio = GlobalAlloc16(GHND, sizeof(MMIOINFO16));
272 lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
273 if (lpmminfo == NULL)
274 return 0;
275 memset(lpmminfo, 0, sizeof(MMIOINFO16));
277 /* assume DOS file if not otherwise specified */
278 if (!lpmmioinfo ||
279 (lpmmioinfo->fccIOProc == 0 && lpmmioinfo->pIOProc == NULL)) {
281 lpmminfo->fccIOProc = FOURCC_DOS;
282 lpmminfo->pIOProc = (LPMMIOPROC16) mmioDosIOProc;
284 /* if just the four character code is present, look up IO proc */
285 else if (lpmmioinfo->pIOProc == NULL) {
287 lpmminfo->fccIOProc = lpmmioinfo->fccIOProc;
288 lpmminfo->pIOProc = mmioInstallIOProc16(lpmmioinfo->fccIOProc, NULL, MMIO_FINDPROC);
291 /* if IO proc specified, use it and specified four character code */
292 else {
294 lpmminfo->fccIOProc = lpmmioinfo->fccIOProc;
295 lpmminfo->pIOProc = lpmmioinfo->pIOProc;
298 if (dwOpenFlags & MMIO_ALLOCBUF) {
299 if ((result = mmioSetBuffer16(hmmio, NULL, MMIO_DEFAULTBUFFER, 0))) {
300 if (lpmmioinfo)
301 lpmmioinfo->wErrorRet = result;
302 return 0;
304 } else
305 if (lpmminfo->fccIOProc == FOURCC_MEM) {
306 if ((result = mmioSetBuffer16(hmmio,
307 (use16) ?
308 PTR_SEG_TO_LIN(lpmmioinfo->pchBuffer) :
309 lpmmioinfo->pchBuffer,
310 lpmmioinfo->cchBuffer, 0))) {
311 if (lpmmioinfo)
312 lpmmioinfo->wErrorRet = result;
313 return 0;
317 lpmminfo->dwFlags = dwOpenFlags;
318 lpmminfo->hmmio = hmmio;
320 /* call IO proc to actually open file */
321 result = (UINT16) mmioSendMessage(hmmio, MMIOM_OPEN, (LPARAM) szFileName, (LPARAM) use16);
323 GlobalUnlock16(hmmio);
325 if (result != 0) {
326 GlobalFree16(hmmio);
327 return 0;
330 return hmmio;
333 /**************************************************************************
334 * mmioOpenW [WINMM.123]
336 HMMIO WINAPI mmioOpenW(LPWSTR szFileName, MMIOINFO * lpmmioinfo,
337 DWORD dwOpenFlags)
339 LPSTR szFn = HEAP_strdupWtoA(GetProcessHeap(),0,szFileName);
340 HMMIO ret = MMIO_Open(szFn,(LPMMIOINFO16)lpmmioinfo,dwOpenFlags,FALSE);
342 HeapFree(GetProcessHeap(),0,szFn);
343 return ret;
346 /**************************************************************************
347 * mmioOpenA [WINMM.122]
349 HMMIO WINAPI mmioOpenA(LPSTR szFileName, MMIOINFO * lpmmioinfo,
350 DWORD dwOpenFlags)
352 return MMIO_Open(szFileName,(LPMMIOINFO16)lpmmioinfo,dwOpenFlags,FALSE);
355 /**************************************************************************
356 * mmioOpen [MMSYSTEM.1210]
358 HMMIO16 WINAPI mmioOpen16(LPSTR szFileName, MMIOINFO16 * lpmmioinfo,
359 DWORD dwOpenFlags)
361 return MMIO_Open(szFileName,(LPMMIOINFO16)lpmmioinfo,dwOpenFlags,TRUE);
365 /**************************************************************************
366 * mmioClose [WINMM.114]
368 MMRESULT WINAPI mmioClose(HMMIO hmmio, UINT uFlags)
370 LPMMIOINFO16 lpmminfo;
371 MMRESULT result;
373 TRACE("(%04X, %04X);\n", hmmio, uFlags);
375 lpmminfo = (LPMMIOINFO16) GlobalLock16(hmmio);
376 if (lpmminfo == NULL)
377 return 0;
379 /* flush the file - if error reported, ignore */
380 if (mmioFlush(hmmio, MMIO_EMPTYBUF) != 0)
381 lpmminfo->dwFlags &= ~MMIO_DIRTY;
383 result = mmioSendMessage(hmmio,MMIOM_CLOSE,(LPARAM)uFlags,(LPARAM)0);
385 mmioSetBuffer16(hmmio, NULL, 0, 0);
387 GlobalUnlock16(hmmio);
388 GlobalFree16(hmmio);
390 return result;
394 /**************************************************************************
395 * mmioClose [MMSYSTEM.1211]
397 MMRESULT16 WINAPI mmioClose16(HMMIO16 hmmio, UINT16 uFlags)
399 return mmioClose(hmmio,uFlags);
404 /**************************************************************************
405 * mmioRead [WINMM.124]
407 LONG WINAPI mmioRead(HMMIO hmmio, HPSTR pch, LONG cch)
409 LONG count;
410 LPMMIOINFO16 lpmminfo;
412 TRACE("(%04X, %p, %ld);\n", hmmio, pch, cch);
414 lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
415 if (lpmminfo == NULL)
416 return -1;
418 if (lpmminfo->pchNext != lpmminfo->pchEndRead) {
419 count = lpmminfo->pchEndRead - lpmminfo->pchNext;
420 if (count > cch || count < 0) count = cch;
421 memcpy(pch, lpmminfo->pchNext, count);
422 lpmminfo->pchNext += count;
423 pch += count;
424 cch -= count;
425 } else
426 count = 0;
428 if (cch&&(lpmminfo->fccIOProc!=FOURCC_MEM)) {
429 if (lpmminfo->cchBuffer) {
430 mmioFlush(hmmio, MMIO_EMPTYBUF);
432 while (cch) {
433 LONG size;
434 lpmminfo->lBufOffset = lpmminfo->lDiskOffset;
435 lpmminfo->pchNext = lpmminfo->pchBuffer;
436 lpmminfo->pchEndRead = lpmminfo->pchBuffer;
437 size = mmioSendMessage(hmmio, MMIOM_READ,
438 (LPARAM) lpmminfo->pchBuffer,
439 (LPARAM) lpmminfo->cchBuffer);
440 if (size<=0) break;
441 lpmminfo->pchEndRead = lpmminfo->pchBuffer + size;
442 if (size > cch) size = cch;
443 memcpy(pch, lpmminfo->pchNext, size);
444 lpmminfo->pchNext += size;
445 pch += size;
446 cch -= size;
447 count += size;
449 } else {
450 count += mmioSendMessage(hmmio, MMIOM_READ, (LPARAM) pch, (LPARAM) cch);
451 if (count>0) lpmminfo->lBufOffset += count;
455 GlobalUnlock16(hmmio);
456 TRACE("count=%ld\n", count);
457 return count;
460 /**************************************************************************
461 * mmioRead [MMSYSTEM.1212]
463 LONG WINAPI mmioRead16(HMMIO16 hmmio, HPSTR pch, LONG cch)
465 return mmioRead(hmmio,pch,cch);
468 /**************************************************************************
469 * mmioWrite [WINMM.133]
471 LONG WINAPI mmioWrite(HMMIO hmmio, HPCSTR pch, LONG cch)
473 LONG count;
474 LPMMIOINFO16 lpmminfo;
476 TRACE("(%04X, %p, %ld);\n", hmmio, pch, cch);
478 lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
479 if (lpmminfo == NULL)
480 return -1;
482 if (lpmminfo->cchBuffer) {
483 count = 0;
484 while (cch) {
485 if (lpmminfo->pchNext != lpmminfo->pchEndWrite) {
486 count = lpmminfo->pchEndWrite - lpmminfo->pchNext;
487 if (count > cch || count < 0) count = cch;
488 memcpy(lpmminfo->pchNext, pch, count);
489 lpmminfo->pchNext += count;
490 pch += count;
491 cch -= count;
492 lpmminfo->dwFlags |= MMIO_DIRTY;
493 } else
494 if (lpmminfo->fccIOProc==FOURCC_MEM) {
495 if (lpmminfo->adwInfo[0]) {
496 /* from where would we get the memory handle? */
497 FIXME("memory file expansion not implemented!\n");
498 } else break;
501 if (lpmminfo->pchNext == lpmminfo->pchEndWrite
502 && mmioFlush(hmmio, MMIO_EMPTYBUF)) break;
504 } else {
505 count = mmioSendMessage(hmmio, MMIOM_WRITE, (LPARAM) pch, (LPARAM) cch);
506 lpmminfo->lBufOffset = lpmminfo->lDiskOffset;
509 GlobalUnlock16(hmmio);
510 TRACE("count=%ld\n", count);
511 return count;
514 /**************************************************************************
515 * mmioWrite [MMSYSTEM.1213]
517 LONG WINAPI mmioWrite16(HMMIO16 hmmio, HPCSTR pch, LONG cch)
519 return mmioWrite(hmmio,pch,cch);
522 /**************************************************************************
523 * mmioSeek [MMSYSTEM.1214]
525 LONG WINAPI mmioSeek(HMMIO hmmio, LONG lOffset, INT iOrigin)
527 int offset;
528 LPMMIOINFO16 lpmminfo;
530 TRACE("(%04X, %08lX, %d);\n", hmmio, lOffset, iOrigin);
532 lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
533 if (lpmminfo == NULL)
534 return -1;
536 offset = (iOrigin==SEEK_SET)?(lOffset - lpmminfo->lBufOffset):
537 (iOrigin==SEEK_CUR)?(lOffset +
538 (lpmminfo->pchNext - lpmminfo->pchBuffer)):-1;
540 if ((lpmminfo->cchBuffer<0)||
541 ((offset>=0)&&(offset<=(lpmminfo->pchEndRead-lpmminfo->pchBuffer)))) {
542 lpmminfo->pchNext = lpmminfo->pchBuffer + offset;
543 GlobalUnlock16(hmmio);
544 return lpmminfo->lBufOffset + offset;
547 if ((lpmminfo->fccIOProc==FOURCC_MEM)||mmioFlush(hmmio, MMIO_EMPTYBUF)) {
548 GlobalUnlock16(hmmio);
549 return -1;
552 offset = mmioSendMessage(hmmio, MMIOM_SEEK, (LPARAM) lOffset, (LPARAM) iOrigin);
553 lpmminfo->lBufOffset = lpmminfo->lDiskOffset;
555 GlobalUnlock16(hmmio);
556 return offset;
559 /**************************************************************************
560 * mmioSeek [MMSYSTEM.1214]
562 LONG WINAPI mmioSeek16(HMMIO16 hmmio, LONG lOffset, INT16 iOrigin)
564 return mmioSeek(hmmio,lOffset,iOrigin);
567 /**************************************************************************
568 * mmioGetInfo [MMSYSTEM.1215]
570 UINT16 WINAPI mmioGetInfo16(HMMIO16 hmmio, MMIOINFO16 * lpmmioinfo, UINT16 uFlags)
572 LPMMIOINFO16 lpmminfo;
573 TRACE("mmioGetInfo\n");
574 lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
575 if (lpmminfo == NULL) return 0;
576 memcpy(lpmmioinfo, lpmminfo, sizeof(MMIOINFO16));
577 GlobalUnlock16(hmmio);
578 return 0;
581 /**************************************************************************
582 * mmioGetInfo [WINMM.118]
584 UINT WINAPI mmioGetInfo(HMMIO hmmio, MMIOINFO*lpmmioinfo, UINT uFlags)
586 MMIOINFO16 mmioinfo;
587 LPMMIOINFO16 lpmminfo=&mmioinfo;
588 UINT16 ret;
590 TRACE("(0x%04x,%p,0x%08x)\n",hmmio,lpmmioinfo,uFlags);
591 ret = mmioGetInfo16(hmmio,&mmioinfo,uFlags);
592 if (!ret)
593 return 0;
594 lpmmioinfo->dwFlags = lpmminfo->dwFlags;
595 lpmmioinfo->fccIOProc = lpmminfo->fccIOProc;
596 lpmmioinfo->pIOProc = (LPMMIOPROC)lpmminfo->pIOProc;
597 lpmmioinfo->wErrorRet = lpmminfo->wErrorRet;
598 lpmmioinfo->htask = lpmminfo->htask;
599 lpmmioinfo->cchBuffer = lpmminfo->cchBuffer;
600 lpmmioinfo->pchBuffer = lpmminfo->pchBuffer;
601 lpmmioinfo->pchNext = lpmminfo->pchNext;
602 lpmmioinfo->pchEndRead = lpmminfo->pchEndRead;
603 lpmmioinfo->pchEndWrite = lpmminfo->pchEndWrite;
604 lpmmioinfo->lBufOffset = lpmminfo->lBufOffset;
605 lpmmioinfo->lDiskOffset = lpmminfo->lDiskOffset;
606 memcpy(lpmmioinfo->adwInfo,lpmminfo->adwInfo,sizeof(lpmminfo->adwInfo));
607 lpmmioinfo->dwReserved1 = lpmminfo->dwReserved1;
608 lpmmioinfo->dwReserved2 = lpmminfo->dwReserved2;
609 lpmmioinfo->hmmio = lpmminfo->hmmio;
610 return 0;
613 /**************************************************************************
614 * mmioSetInfo [MMSYSTEM.1216]
616 UINT16 WINAPI mmioSetInfo16(HMMIO16 hmmio, const MMIOINFO16 * lpmmioinfo, UINT16 uFlags)
618 LPMMIOINFO16 lpmminfo;
619 TRACE("mmioSetInfo\n");
620 lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
621 if (lpmminfo == NULL) return 0;
622 lpmminfo->pchNext = lpmmioinfo->pchNext;
623 lpmminfo->pchEndRead = lpmmioinfo->pchEndRead;
624 GlobalUnlock16(hmmio);
625 return 0;
628 /**************************************************************************
629 * mmioSetInfo [WINMM.130]
631 UINT WINAPI mmioSetInfo(HMMIO hmmio, const MMIOINFO * lpmmioinfo, UINT uFlags)
633 LPMMIOINFO16 lpmminfo;
634 TRACE("mmioSetInfo\n");
635 lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
636 if (lpmminfo == NULL) return 0;
637 lpmminfo->pchNext = lpmmioinfo->pchNext;
638 lpmminfo->pchEndRead = lpmmioinfo->pchEndRead;
639 GlobalUnlock16(hmmio);
640 return 0;
643 /**************************************************************************
644 * mmioSetBuffer [WINMM.129]
646 UINT WINAPI mmioSetBuffer(HMMIO hmmio, LPSTR pchBuffer,
647 LONG cchBuffer, UINT uFlags)
649 LPMMIOINFO16 lpmminfo;
651 if (mmioFlush(hmmio, MMIO_EMPTYBUF) != 0)
652 return MMIOERR_CANNOTWRITE;
654 TRACE("(hmmio=%04x, pchBuf=%p, cchBuf=%ld, uFlags=%#08x)\n",
655 hmmio, pchBuffer, cchBuffer, uFlags);
657 lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
658 if (lpmminfo == NULL) return 0;
659 if ((!cchBuffer || pchBuffer) && lpmminfo->dwFlags&MMIO_ALLOCBUF) {
660 GlobalUnlock16(lpmminfo->dwReserved1);
661 GlobalFree16(lpmminfo->dwReserved1);
662 lpmminfo->dwFlags &= ~MMIO_ALLOCBUF;
664 if (pchBuffer) {
665 lpmminfo->pchBuffer = pchBuffer;
666 } else if (lpmminfo->dwFlags&MMIO_ALLOCBUF) {
667 HGLOBAL16 hNewBuf;
668 GlobalUnlock16(lpmminfo->dwReserved1);
669 hNewBuf = GlobalReAlloc16(lpmminfo->dwReserved1, cchBuffer, 0);
670 if (!hNewBuf) {
671 /* FIXME: this assumes the memory block didn't move */
672 GlobalLock16(lpmminfo->dwReserved1);
673 GlobalUnlock16(hmmio);
674 return MMIOERR_OUTOFMEMORY;
676 lpmminfo->dwReserved1 = hNewBuf;
677 lpmminfo->pchBuffer = GlobalLock16(hNewBuf);
678 } else if (cchBuffer) {
679 HGLOBAL16 hNewBuf = GlobalAlloc16(GMEM_MOVEABLE, cchBuffer);
680 if (!hNewBuf) {
681 GlobalUnlock16(hmmio);
682 return MMIOERR_OUTOFMEMORY;
684 lpmminfo->dwReserved1 = hNewBuf;
685 lpmminfo->pchBuffer = GlobalLock16(hNewBuf);
686 lpmminfo->dwFlags |= MMIO_ALLOCBUF;
687 } else
688 lpmminfo->pchBuffer = NULL;
689 lpmminfo->cchBuffer = cchBuffer;
690 lpmminfo->pchNext = lpmminfo->pchBuffer;
691 lpmminfo->pchEndRead = lpmminfo->pchBuffer;
692 lpmminfo->pchEndWrite = lpmminfo->pchBuffer + cchBuffer;
693 lpmminfo->lBufOffset = 0;
695 GlobalUnlock16(hmmio);
696 return (UINT16) 0;
699 /**************************************************************************
700 * mmioSetBuffer [MMSYSTEM.1217]
702 UINT16 WINAPI mmioSetBuffer16(HMMIO16 hmmio, LPSTR pchBuffer,
703 LONG cchBuffer, UINT16 uFlags)
705 return mmioSetBuffer(hmmio, pchBuffer, cchBuffer, uFlags);
708 /**************************************************************************
709 * mmioFlush [WINMM.117]
711 UINT WINAPI mmioFlush(HMMIO hmmio, UINT uFlags)
713 LPMMIOINFO16 lpmminfo;
714 TRACE("(%04X, %04X)\n", hmmio, uFlags);
715 lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
716 if (lpmminfo == NULL) return 0;
718 if ((!lpmminfo->cchBuffer)||(lpmminfo->fccIOProc==FOURCC_MEM)) {
719 GlobalUnlock16(hmmio);
720 return 0;
722 /* not quite sure what to do here, but I'll guess */
723 if (lpmminfo->dwFlags & MMIO_DIRTY) {
724 mmioSendMessage(hmmio, MMIOM_SEEK,
725 (LPARAM) lpmminfo->lBufOffset,
726 (LPARAM) SEEK_SET);
727 mmioSendMessage(hmmio, MMIOM_WRITE,
728 (LPARAM) lpmminfo->pchBuffer,
729 (LPARAM) (lpmminfo->pchNext - lpmminfo->pchBuffer) );
730 lpmminfo->dwFlags &= ~MMIO_DIRTY;
732 if (uFlags & MMIO_EMPTYBUF) {
733 /* seems Windows doesn't do any seeking here, hopefully this
734 won't matter, otherwise a slight rewrite is necessary */
735 mmioSendMessage(hmmio, MMIOM_SEEK,
736 (LPARAM) (lpmminfo->lBufOffset +
737 (lpmminfo->pchNext - lpmminfo->pchBuffer)),
738 (LPARAM) SEEK_SET);
739 lpmminfo->pchNext = lpmminfo->pchBuffer;
740 lpmminfo->pchEndRead = lpmminfo->pchBuffer;
741 lpmminfo->lBufOffset = lpmminfo->lDiskOffset;
744 GlobalUnlock16(hmmio);
745 return 0;
748 /**************************************************************************
749 * mmioFlush [MMSYSTEM.1218]
751 UINT16 WINAPI mmioFlush16(HMMIO16 hmmio, UINT16 uFlags)
753 return mmioFlush(hmmio,uFlags);
756 /**************************************************************************
757 * mmioAdvance [MMSYSTEM.1219]
759 UINT WINAPI mmioAdvance(HMMIO hmmio,MMIOINFO*lpmmioinfo,UINT uFlags)
761 LPMMIOINFO16 lpmminfo;
762 TRACE("mmioAdvance\n");
763 lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
764 if (lpmminfo == NULL) return 0;
765 if (!lpmminfo->cchBuffer) {
766 GlobalUnlock16(hmmio);
767 return MMIOERR_UNBUFFERED;
769 lpmminfo->pchNext = lpmmioinfo->pchNext;
770 if (mmioFlush(hmmio, MMIO_EMPTYBUF)) {
771 GlobalUnlock16(hmmio);
772 return MMIOERR_CANNOTWRITE;
774 if (uFlags == MMIO_READ)
775 lpmmioinfo->pchEndRead = lpmmioinfo->pchBuffer +
776 mmioSendMessage(hmmio, MMIOM_READ,
777 (LPARAM) lpmmioinfo->pchBuffer,
778 (LPARAM) lpmmioinfo->cchBuffer);
779 #if 0 /* mmioFlush already did the writing */
780 if (uFlags == MMIO_WRITE)
781 mmioSendMessage(hmmio, MMIOM_WRITE,
782 (LPARAM) lpmmioinfo->pchBuffer,
783 (LPARAM) lpmmioinfo->cchBuffer);
784 #endif
785 lpmmioinfo->pchNext = lpmmioinfo->pchBuffer;
786 GlobalUnlock16(hmmio);
787 return 0;
790 /**************************************************************************
791 * mmioAdvance [MMSYSTEM.1219]
793 UINT16 WINAPI mmioAdvance16(HMMIO16 hmmio,MMIOINFO16*lpmmioinfo,UINT16 uFlags)
795 LPMMIOINFO16 lpmminfo;
796 TRACE("mmioAdvance\n");
797 lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
798 if (lpmminfo == NULL) return 0;
799 if (!lpmminfo->cchBuffer) {
800 GlobalUnlock16(hmmio);
801 return MMIOERR_UNBUFFERED;
803 lpmminfo->pchNext = lpmmioinfo->pchNext;
804 if (mmioFlush(hmmio, MMIO_EMPTYBUF)) {
805 GlobalUnlock16(hmmio);
806 return MMIOERR_CANNOTWRITE;
808 if (uFlags == MMIO_READ)
809 lpmmioinfo->pchEndRead = lpmmioinfo->pchBuffer +
810 mmioSendMessage(hmmio, MMIOM_READ,
811 (LPARAM) lpmmioinfo->pchBuffer,
812 (LPARAM) lpmmioinfo->cchBuffer);
813 #if 0 /* mmioFlush already did the writing */
814 if (uFlags == MMIO_WRITE)
815 mmioSendMessage(hmmio, MMIOM_WRITE,
816 (LPARAM) lpmmioinfo->pchBuffer,
817 (LPARAM) lpmmioinfo->cchBuffer);
818 #endif
819 lpmmioinfo->pchNext = lpmmioinfo->pchBuffer;
820 GlobalUnlock16(hmmio);
821 return 0;
824 /**************************************************************************
825 * mmioStringToFOURCCA [WINMM.131]
827 FOURCC WINAPI mmioStringToFOURCCA(LPCSTR sz, UINT uFlags)
829 return mmioStringToFOURCC16(sz,uFlags);
832 /**************************************************************************
833 * mmioStringToFOURCCW [WINMM.132]
835 FOURCC WINAPI mmioStringToFOURCCW(LPCWSTR sz, UINT uFlags)
837 LPSTR szA = HEAP_strdupWtoA(GetProcessHeap(),0,sz);
838 FOURCC ret = mmioStringToFOURCCA(szA,uFlags);
840 HeapFree(GetProcessHeap(),0,szA);
841 return ret;
844 /**************************************************************************
845 * mmioStringToFOURCC [MMSYSTEM.1220]
847 FOURCC WINAPI mmioStringToFOURCC16(LPCSTR sz, UINT16 uFlags)
849 return mmioFOURCC(sz[0],sz[1],sz[2],sz[3]);
852 /**************************************************************************
853 * mmioInstallIOProc16 [MMSYSTEM.1221]
855 LPMMIOPROC16 WINAPI mmioInstallIOProc16(FOURCC fccIOProc,
856 LPMMIOPROC16 pIOProc, DWORD dwFlags)
858 TRACE("(%ld, %p, %08lX)\n",
859 fccIOProc, pIOProc, dwFlags);
861 if (dwFlags & MMIO_GLOBALPROC) {
862 FIXME(" global procedures not implemented\n");
865 /* just handle the known procedures for now */
866 switch(dwFlags & (MMIO_INSTALLPROC|MMIO_REMOVEPROC|MMIO_FINDPROC)) {
867 case MMIO_INSTALLPROC:
868 return NULL;
869 case MMIO_REMOVEPROC:
870 return NULL;
871 case MMIO_FINDPROC:
872 if (fccIOProc == FOURCC_DOS)
873 return (LPMMIOPROC16) mmioDosIOProc;
874 else if (fccIOProc == FOURCC_MEM)
875 return (LPMMIOPROC16) mmioMemIOProc;
876 else
877 return NULL;
878 default:
879 return NULL;
883 /**************************************************************************
884 * mmioInstallIOProcA [WINMM.120]
886 LPMMIOPROC WINAPI mmioInstallIOProcA(FOURCC fccIOProc,
887 LPMMIOPROC pIOProc, DWORD dwFlags)
889 FIXME("(%c%c%c%c,%p,0x%08lx) -- empty stub \n",
890 (char)((fccIOProc&0xff000000)>>24),
891 (char)((fccIOProc&0x00ff0000)>>16),
892 (char)((fccIOProc&0x0000ff00)>> 8),
893 (char)(fccIOProc&0x000000ff),
894 pIOProc, dwFlags );
895 return 0;
898 /**************************************************************************
899 * mmioSendMessage [MMSYSTEM.1222]
901 LRESULT WINAPI mmioSendMessage(HMMIO16 hmmio, UINT16 uMessage,
902 LPARAM lParam1, LPARAM lParam2)
904 LPMMIOINFO16 lpmminfo;
905 LRESULT result;
906 const char *msg = NULL;
908 #ifdef DEBUG_RUNTIME
909 switch (uMessage) {
910 #define msgname(x) case x: msg = #x; break;
911 msgname(MMIOM_OPEN);
912 msgname(MMIOM_CLOSE);
913 msgname(MMIOM_READ);
914 msgname(MMIOM_WRITE);
915 msgname(MMIOM_WRITEFLUSH);
916 msgname(MMIOM_SEEK);
917 msgname(MMIOM_RENAME);
918 #undef msgname
920 #endif
922 if (msg)
923 TRACE("(%04X, %s, %ld, %ld)\n",
924 hmmio, msg, lParam1, lParam2);
925 else
926 TRACE("(%04X, %u, %ld, %ld)\n",
927 hmmio, uMessage, lParam1, lParam2);
929 lpmminfo = (LPMMIOINFO16)GlobalLock16(hmmio);
931 if (lpmminfo && lpmminfo->pIOProc)
932 result = (*lpmminfo->pIOProc)((LPSTR)lpmminfo, uMessage, lParam1, lParam2);
933 else
934 result = MMSYSERR_INVALPARAM;
936 GlobalUnlock16(hmmio);
938 return result;
941 /**************************************************************************
942 * mmioDescend [MMSYSTEM.1223]
944 UINT16 WINAPI mmioDescend(HMMIO16 hmmio, LPMMCKINFO lpck,
945 const MMCKINFO * lpckParent, UINT16 uFlags)
947 DWORD dwOldPos;
948 MMCKINFO searchcki;
949 char ckid[5],fcc[5];
951 TRACE("(%04X, %p, %p, %04X);\n",hmmio,lpck,lpckParent,uFlags);
953 if (lpck == NULL)
954 return MMSYSERR_INVALPARAM;
956 dwOldPos = mmioSeek(hmmio, 0, SEEK_CUR);
957 TRACE("dwOldPos=%ld\n", dwOldPos);
959 if (lpckParent != NULL) {
960 TRACE("seek inside parent at %ld !\n", lpckParent->dwDataOffset);
961 /* EPP: was dwOldPos = mmioSeek(hmmio,lpckParent->dwDataOffset,SEEK_SET); */
962 if (dwOldPos < lpckParent->dwDataOffset || dwOldPos >= lpckParent->dwDataOffset + lpckParent->cksize) {
963 ERR("outside parent chunk\n");
964 return MMIOERR_CHUNKNOTFOUND;
968 /* The SDK docu says 'ckid' is used for all cases. Real World
969 * examples disagree -Marcus,990216.
972 searchcki.fccType = 0;
973 /* find_chunk looks for 'ckid' */
974 if (uFlags & MMIO_FINDCHUNK)
975 searchcki.ckid = lpck->ckid;
976 /* find_riff and find_list look for 'fccType' */
977 if (uFlags & MMIO_FINDLIST) {
978 searchcki.ckid = FOURCC_LIST;
979 searchcki.fccType = lpck->fccType;
981 if (uFlags & MMIO_FINDRIFF) {
982 searchcki.ckid = FOURCC_RIFF;
983 searchcki.fccType = lpck->fccType;
985 memcpy(&fcc,&(searchcki.fccType),4);fcc[4]=0;
986 memcpy(&ckid,&(searchcki.ckid),4);ckid[4]=0;
987 TRACE("searching for %s.%s\n",ckid,searchcki.fccType?fcc:"<any>");
989 if (uFlags & (MMIO_FINDCHUNK|MMIO_FINDLIST|MMIO_FINDRIFF)) {
990 while (TRUE) {
991 LONG ix;
993 ix = mmioRead(hmmio, (LPSTR)lpck, 3 * sizeof(DWORD));
994 if (ix < 2*sizeof(DWORD)) {
995 mmioSeek(hmmio, dwOldPos, SEEK_SET);
996 WARN("return ChunkNotFound\n");
997 return MMIOERR_CHUNKNOTFOUND;
999 lpck->dwDataOffset = dwOldPos + 2 * sizeof(DWORD);
1000 if (ix < lpck->dwDataOffset - dwOldPos) {
1001 mmioSeek(hmmio, dwOldPos, SEEK_SET);
1002 WARN("return ChunkNotFound\n");
1003 return MMIOERR_CHUNKNOTFOUND;
1005 memcpy(ckid,&lpck->ckid,4);
1006 memcpy(fcc,&lpck->fccType,4);
1007 TRACE("ckid=%s fcc=%s cksize=%08lX !\n",
1008 ckid, searchcki.fccType?fcc:"<unused>",
1009 lpck->cksize);
1010 if ((searchcki.ckid == lpck->ckid) &&
1011 (!searchcki.fccType ||
1012 (searchcki.fccType == lpck->fccType)
1015 break;
1017 dwOldPos = lpck->dwDataOffset + ((lpck->cksize + 1) & ~1);
1018 mmioSeek(hmmio, dwOldPos, SEEK_SET);
1020 /* If we were looking for RIFF/LIST chunks, the final dataptr
1021 * is after the chunkid. If we were just looking for the chunk
1022 * it is after the cksize. So add 4 in RIFF/LIST case.
1024 if (uFlags & (MMIO_FINDLIST|MMIO_FINDRIFF))
1025 lpck->dwDataOffset+=sizeof(DWORD);
1026 } else {
1027 /* FIXME: unverified, does it do this? */
1028 if (mmioRead(hmmio, (LPSTR)lpck, 3 * sizeof(DWORD)) < 3 * sizeof(DWORD)) {
1029 mmioSeek(hmmio, dwOldPos, SEEK_SET);
1030 WARN("return ChunkNotFound 2nd\n");
1031 return MMIOERR_CHUNKNOTFOUND;
1033 lpck->dwDataOffset = dwOldPos + 2 * sizeof(DWORD);
1034 lpck->dwFlags = 0;
1035 if (lpck->ckid == FOURCC_RIFF || lpck->ckid == FOURCC_LIST)
1036 lpck->dwDataOffset += sizeof(DWORD);
1038 mmioSeek(hmmio, lpck->dwDataOffset, SEEK_SET);
1039 memcpy(ckid,&(lpck->ckid),4);
1040 TRACE("lpck->ckid=%s lpck->cksize=%ld !\n", ckid, lpck->cksize);
1041 memcpy(fcc,&(lpck->fccType),4);
1042 TRACE("lpck->fccType=%08lX (%s)!\n", lpck->fccType,searchcki.fccType?fcc:"");
1043 return 0;
1046 /**************************************************************************
1047 * mmioAscend [WINMM.113]
1049 UINT WINAPI mmioAscend(HMMIO hmmio, MMCKINFO * lpck, UINT uFlags)
1051 TRACE("(%04X, %p, %04X);\n",
1052 hmmio, lpck, uFlags);
1053 if (lpck->dwFlags&MMIO_DIRTY) {
1054 DWORD dwOldPos, dwNewSize, dwSizePos;
1056 TRACE("chunk is marked MMIO_DIRTY, correcting chunk size\n");
1057 dwOldPos = mmioSeek(hmmio, 0, SEEK_CUR);
1058 TRACE("dwOldPos=%ld\n", dwOldPos);
1059 dwNewSize = dwOldPos - lpck->dwDataOffset;
1060 if (dwNewSize != lpck->cksize) {
1061 TRACE("dwNewSize=%ld\n", dwNewSize);
1062 lpck->cksize = dwNewSize;
1064 dwSizePos = lpck->dwDataOffset - sizeof(DWORD);
1065 if (lpck->ckid == FOURCC_RIFF || lpck->ckid == FOURCC_LIST)
1066 dwSizePos -= sizeof(DWORD);
1067 TRACE("dwSizePos=%ld\n", dwSizePos);
1069 mmioSeek(hmmio, dwSizePos, SEEK_SET);
1070 mmioWrite(hmmio, (LPSTR)&dwNewSize, sizeof(DWORD));
1073 mmioSeek(hmmio,lpck->dwDataOffset+lpck->cksize,SEEK_SET);
1075 return 0;
1078 /**************************************************************************
1079 * mmioAscend [MMSYSTEM.1224]
1081 UINT16 WINAPI mmioAscend16(HMMIO16 hmmio, MMCKINFO * lpck, UINT16 uFlags)
1083 return mmioAscend(hmmio,lpck,uFlags);
1086 /**************************************************************************
1087 * mmioCreateChunk [MMSYSTEM.1225]
1089 UINT16 WINAPI mmioCreateChunk16(HMMIO16 hmmio, MMCKINFO * lpck, UINT16 uFlags)
1091 DWORD dwOldPos;
1092 LONG ix;
1094 TRACE("(%04X, %p, %04X);\n",
1095 hmmio, lpck, uFlags);
1097 dwOldPos = mmioSeek(hmmio, 0, SEEK_CUR);
1098 TRACE("dwOldPos=%ld\n", dwOldPos);
1100 if (uFlags == MMIO_CREATELIST)
1101 lpck->ckid = FOURCC_LIST;
1102 else if (uFlags == MMIO_CREATERIFF)
1103 lpck->ckid = FOURCC_RIFF;
1105 TRACE("ckid=%08lX\n", lpck->ckid);
1107 lpck->dwDataOffset = dwOldPos + 2 * sizeof(DWORD);
1108 if (lpck->ckid == FOURCC_RIFF || lpck->ckid == FOURCC_LIST)
1109 lpck->dwDataOffset += sizeof(DWORD);
1110 lpck->dwFlags = MMIO_DIRTY;
1112 ix = mmioWrite(hmmio, (LPSTR)lpck, lpck->dwDataOffset - dwOldPos);
1113 TRACE("after mmioWrite ix = %ld req = %ld, errno = %d\n",ix,lpck->dwDataOffset - dwOldPos,errno);
1114 if (ix < lpck->dwDataOffset - dwOldPos) {
1116 mmioSeek(hmmio, dwOldPos, SEEK_SET);
1117 WARN("return CannotWrite\n");
1118 return MMIOERR_CANNOTWRITE;
1121 return 0;
1124 /**************************************************************************
1125 * mmioCreateChunk [WINMM.115]
1127 UINT WINAPI mmioCreateChunk(HMMIO hmmio, MMCKINFO * lpck, UINT uFlags)
1129 return mmioCreateChunk16(hmmio, lpck, uFlags);
1132 /**************************************************************************
1133 * mmioRename [MMSYSTEM.1226]
1135 UINT16 WINAPI mmioRename16(LPCSTR szFileName, LPCSTR szNewFileName,
1136 MMIOINFO16 * lpmmioinfo, DWORD dwRenameFlags)
1138 UINT16 result;
1139 LPMMIOINFO16 lpmminfo;
1140 HMMIO16 hmmio;
1142 TRACE("('%s', '%s', %p, %08lX);\n",
1143 szFileName, szNewFileName, lpmmioinfo, dwRenameFlags);
1145 hmmio = GlobalAlloc16(GHND, sizeof(MMIOINFO16));
1146 lpmminfo = (LPMMIOINFO16) GlobalLock16(hmmio);
1148 if (lpmmioinfo)
1149 memcpy(lpmminfo, lpmmioinfo, sizeof(MMIOINFO16));
1151 /* assume DOS file if not otherwise specified */
1152 if (lpmminfo->fccIOProc == 0 && lpmminfo->pIOProc == NULL) {
1154 lpmminfo->fccIOProc = mmioFOURCC('D', 'O', 'S', ' ');
1155 lpmminfo->pIOProc = (LPMMIOPROC16) mmioDosIOProc;
1158 /* if just the four character code is present, look up IO proc */
1159 else if (lpmminfo->pIOProc == NULL) {
1161 lpmminfo->pIOProc = mmioInstallIOProc16(lpmminfo->fccIOProc, NULL, MMIO_FINDPROC);
1164 /* (if IO proc specified, use it and specified four character code) */
1166 result = (UINT16) mmioSendMessage(hmmio, MMIOM_RENAME, (LPARAM) szFileName, (LPARAM) szNewFileName);
1168 GlobalUnlock16(hmmio);
1169 GlobalFree16(hmmio);
1171 return result;
1174 /**************************************************************************
1175 * mmioRenameA [WINMM.125]
1177 UINT WINAPI mmioRenameA(LPCSTR szFileName, LPCSTR szNewFileName,
1178 MMIOINFO* lpmmioinfo, DWORD dwRenameFlags)
1180 FIXME("This may fail\n");
1181 return mmioRename16(szFileName, szNewFileName, (MMIOINFO16*)lpmmioinfo, dwRenameFlags);
1184 /**************************************************************************
1185 * mmioRenameW [WINMM.126]
1187 UINT WINAPI mmioRenameW(LPCWSTR szFileName, LPCWSTR szNewFileName,
1188 MMIOINFO* lpmmioinfo, DWORD dwRenameFlags)
1190 LPSTR szFn = HEAP_strdupWtoA(GetProcessHeap(), 0, szFileName);
1191 LPSTR sznFn = HEAP_strdupWtoA(GetProcessHeap(), 0, szNewFileName);
1192 UINT ret = mmioRenameA(szFn, sznFn, lpmmioinfo, dwRenameFlags);
1194 HeapFree(GetProcessHeap(),0,szFn);
1195 HeapFree(GetProcessHeap(),0,sznFn);
1196 return ret;