[PATCH V2 2/3] mmsystem.dll16: Refcount midihdr to work around buggy application which unprepares buffer during a callback.
Vijay Kiran Kamuju
infyquest at gmail.com
Wed Apr 17 08:33:26 CDT 2019
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=40024
From: Michael Müller <michael at fds-team.de>
Signed-off-by: Vijay Kiran Kamuju <infyquest at gmail.com>
---
dlls/mmsystem.dll16/message16.c | 73 +++++++++++++++++++++------------
1 file changed, 46 insertions(+), 27 deletions(-)
diff --git a/dlls/mmsystem.dll16/message16.c b/dlls/mmsystem.dll16/message16.c
index 28f20ba0b29..c2ffa0d3ab1 100644
--- a/dlls/mmsystem.dll16/message16.c
+++ b/dlls/mmsystem.dll16/message16.c
@@ -33,6 +33,13 @@
WINE_DEFAULT_DEBUG_CHANNEL(winmm);
+struct mihdrWrap
+{
+ int ref;
+ SEGPTR mh16;
+ MIDIHDR hdr;
+};
+
/* =================================
* A U X M A P P E R S
* ================================= */
@@ -117,13 +124,13 @@ static void MMSYSTDRV_MidiIn_MapCB(UINT uMsg, DWORD_PTR* dwUser, DWORD_PTR* dwPa
case MIM_LONGDATA:
case MIM_LONGERROR:
{
- LPMIDIHDR mh32 = (LPMIDIHDR)(*dwParam1);
- SEGPTR segmh16 = *(SEGPTR*)((LPSTR)mh32 - sizeof(LPMIDIHDR));
+ struct mihdrWrap *mh32 = CONTAINING_RECORD((MIDIHDR *)*dwParam1, struct mihdrWrap, hdr);
+ SEGPTR segmh16 = mh32->mh16;
LPMIDIHDR16 mh16 = MapSL(segmh16);
*dwParam1 = (DWORD)segmh16;
- mh16->dwFlags = mh32->dwFlags;
- mh16->dwBytesRecorded = mh32->dwBytesRecorded;
+ mh16->dwFlags = mh32->hdr.dwFlags;
+ mh16->dwBytesRecorded = mh32->hdr.dwBytesRecorded;
}
break;
default:
@@ -175,17 +182,17 @@ static MMSYSTEM_MapType MMSYSTDRV_MidiOut_Map16To32W (UINT wMsg, DWORD_PTR* lpP
break;
case MODM_PREPARE:
{
- LPMIDIHDR mh32 = HeapAlloc(GetProcessHeap(), 0, sizeof(LPMIDIHDR) + sizeof(MIDIHDR));
+ struct mihdrWrap *mh32 = HeapAlloc(GetProcessHeap(), 0, sizeof(struct mihdrWrap));
LPMIDIHDR16 mh16 = MapSL(*lpParam1);
if (mh32) {
- *(LPMIDIHDR*)mh32 = (LPMIDIHDR)*lpParam1;
- mh32 = (LPMIDIHDR)((LPSTR)mh32 + sizeof(LPMIDIHDR));
- mh32->lpData = MapSL((SEGPTR)mh16->lpData);
- mh32->dwBufferLength = mh16->dwBufferLength;
- mh32->dwBytesRecorded = mh16->dwBytesRecorded;
- mh32->dwUser = mh16->dwUser;
- mh32->dwFlags = mh16->dwFlags;
+ mh32->ref = 2;
+ mh32->mh16 = (SEGPTR)*lpParam1;
+ mh32->hdr.lpData = MapSL((SEGPTR)mh16->lpData);
+ mh32->hdr.dwBufferLength = mh16->dwBufferLength;
+ mh32->hdr.dwBytesRecorded = mh16->dwBytesRecorded;
+ mh32->hdr.dwUser = mh16->dwUser;
+ mh32->hdr.dwFlags = mh16->dwFlags;
mh16->lpNext = (MIDIHDR16*)mh32; /* for reuse in unprepare and write */
*lpParam1 = (DWORD)mh32;
*lpParam2 = offsetof(MIDIHDR,dwOffset); /* old size, without dwOffset */
@@ -200,16 +207,17 @@ static MMSYSTEM_MapType MMSYSTDRV_MidiOut_Map16To32W (UINT wMsg, DWORD_PTR* lpP
case MODM_LONGDATA:
{
LPMIDIHDR16 mh16 = MapSL(*lpParam1);
- LPMIDIHDR mh32 = (MIDIHDR*)mh16->lpNext;
+ struct mihdrWrap *mh32 = (struct mihdrWrap*)mh16->lpNext;
- *lpParam1 = (DWORD)mh32;
+ mh32->ref++;
+ *lpParam1 = (DWORD)&mh32->hdr;
*lpParam2 = offsetof(MIDIHDR,dwOffset);
/* dwBufferLength can be reduced between prepare & write */
- if (wMsg == MODM_LONGDATA && mh32->dwBufferLength < mh16->dwBufferLength) {
+ if (wMsg == MODM_LONGDATA && mh32->hdr.dwBufferLength < mh16->dwBufferLength) {
ERR("Size of buffer has been increased from %d to %d, keeping initial value\n",
- mh32->dwBufferLength, mh16->dwBufferLength);
+ mh32->hdr.dwBufferLength, mh16->dwBufferLength);
} else
- mh32->dwBufferLength = mh16->dwBufferLength;
+ mh32->hdr.dwBufferLength = mh16->dwBufferLength;
ret = MMSYSTEM_MAP_OKMEM;
}
break;
@@ -267,16 +275,27 @@ static MMSYSTEM_MapType MMSYSTDRV_MidiOut_UnMap16To32W(UINT wMsg, DWORD_PTR* lpP
case MODM_UNPREPARE:
case MODM_LONGDATA:
{
- LPMIDIHDR mh32 = (LPMIDIHDR)(*lpParam1);
- LPMIDIHDR16 mh16 = MapSL(*(SEGPTR*)((LPSTR)mh32 - sizeof(LPMIDIHDR)));
+ struct mihdrWrap *mh32 = CONTAINING_RECORD((MIDIHDR *)*lpParam1, struct mihdrWrap, hdr);
+ LPMIDIHDR16 mh16;
- assert((MIDIHDR*)mh16->lpNext == mh32);
- mh16->dwFlags = mh32->dwFlags;
+ /* Prosound unprepares the buffer during a callback */
+ if (mh32->mh16)
+ {
+ mh16 = MapSL(mh32->mh16);
+ assert((struct mihdrWrap *)mh16->lpNext == mh32);
+ mh16->dwFlags = mh32->hdr.dwFlags;
- if (wMsg == MODM_UNPREPARE && fn_ret == MMSYSERR_NOERROR) {
- HeapFree(GetProcessHeap(), 0, (LPSTR)mh32 - sizeof(LPMIDIHDR));
- mh16->lpNext = 0;
+ if (wMsg == MODM_UNPREPARE && fn_ret == MMSYSERR_NOERROR)
+ {
+ mh32->mh16 = 0;
+ mh32->ref--;
+ mh16->lpNext = 0;
+ }
}
+
+ if (!--mh32->ref)
+ HeapFree(GetProcessHeap(), 0, mh32);
+
ret = MMSYSTEM_MAP_OK;
}
break;
@@ -307,12 +326,12 @@ static void MMSYSTDRV_MidiOut_MapCB(UINT uMsg, DWORD_PTR* dwUser, DWORD_PTR* dwP
case MOM_DONE:
{
/* initial map is: 16 => 32 */
- LPMIDIHDR mh32 = (LPMIDIHDR)(*dwParam1);
- SEGPTR segmh16 = *(SEGPTR*)((LPSTR)mh32 - sizeof(LPMIDIHDR));
+ struct mihdrWrap *mh32 = CONTAINING_RECORD((MIDIHDR *)*dwParam1, struct mihdrWrap, hdr);
+ SEGPTR segmh16 = mh32->mh16;
LPMIDIHDR16 mh16 = MapSL(segmh16);
*dwParam1 = (DWORD)segmh16;
- mh16->dwFlags = mh32->dwFlags;
+ mh16->dwFlags = mh32->hdr.dwFlags;
}
break;
default:
--
2.17.0
More information about the wine-devel
mailing list