winmm: More MIDI boundary tests & fixes.
This commit is contained in:
parent
a311dff763
commit
c89853ebe5
|
@ -207,13 +207,20 @@ static void test_midiOut_device(UINT udev, HWND hwnd)
|
|||
MMRESULT rc;
|
||||
MIDIOUTCAPSA capsA;
|
||||
DWORD ovolume;
|
||||
UINT udevid;
|
||||
MIDIHDR mhdr;
|
||||
|
||||
rc = midiOutGetDevCapsA(udev, &capsA, sizeof(capsA));
|
||||
ok(!rc, "midiOutGetDevCaps(dev=%d) rc=%s\n", udev, mmsys_error(rc));
|
||||
if (!rc) {
|
||||
trace("* %s: manufacturer=%d, product=%d, tech=%d, support=%X: %d voices, %d notes\n",
|
||||
capsA.szPname, capsA.wMid, capsA.wPid, capsA.wTechnology, capsA.dwSupport, capsA.wVoices, capsA.wNotes);
|
||||
trace("* %s: manufacturer=%d, product=%d, tech=%d, support=%X: %d voices, %d notes\n",
|
||||
capsA.szPname, capsA.wMid, capsA.wPid, capsA.wTechnology, capsA.dwSupport, capsA.wVoices, capsA.wNotes);
|
||||
ok(!((MIDIMAPPER==udev) ^ (MOD_MAPPER==capsA.wTechnology)), "technology %d on device %d\n", capsA.wTechnology, udev);
|
||||
if (MOD_MIDIPORT == capsA.wTechnology) {
|
||||
ok(capsA.wVoices == 0 && capsA.wNotes == 0, "external device with notes or voices\n");
|
||||
ok(capsA.wChannelMask == 0xFFFF, "external device channel mask %x\n", capsA.wChannelMask);
|
||||
ok(!(capsA.dwSupport & (MIDICAPS_VOLUME|MIDICAPS_LRVOLUME|MIDICAPS_CACHE)), "external device support=%X\n", capsA.dwSupport);
|
||||
}
|
||||
}
|
||||
|
||||
if (hwnd)
|
||||
|
@ -236,6 +243,9 @@ static void test_midiOut_device(UINT udev, HWND hwnd)
|
|||
rc = midiOutGetVolume(UlongToHandle(udev), &ovolume);
|
||||
ok((capsA.dwSupport & MIDICAPS_VOLUME) ? rc==MMSYSERR_NOERROR || broken(rc==MMSYSERR_NOTENABLED) : rc==MMSYSERR_NOTSUPPORTED, "midiOutGetVolume(dev=%d) rc=%s\n", udev, mmsys_error(rc));
|
||||
|
||||
rc = midiOutGetVolume(hm, NULL);
|
||||
ok(rc==MMSYSERR_INVALPARAM, "midiOutGetVolume NULL rc=%s\n", mmsys_error(rc));
|
||||
|
||||
/* Tests with midiOutSetvolume show that the midi mapper forwards
|
||||
* the value to the real device, but Get initially always reports
|
||||
* FFFFFFFF. Therefore, a Get+SetVolume pair with the mapper is
|
||||
|
@ -294,6 +304,10 @@ static void test_midiOut_device(UINT udev, HWND hwnd)
|
|||
ok(mhdr.dwUser==0x56FA552C, "MIDIHDR.dwUser changed to %lx\n", mhdr.dwUser);
|
||||
ok(mhdr.dwOffset==0xDEADBEEF, "MIDIHDR.dwOffset changed to %x\n", mhdr.dwOffset);
|
||||
|
||||
rc = midiOutGetID(hm, &udevid);
|
||||
ok(!rc, "midiOutGetID rc=%s\n", mmsys_error(rc));
|
||||
if(!rc) ok(udevid==udev, "midiOutGetID gives %d, expect %d\n", udevid, udev);
|
||||
|
||||
rc = midiOutReset(hm); /* Quiet everything */
|
||||
ok(!rc, "midiOutReset rc=%s\n", mmsys_error(rc));
|
||||
|
||||
|
@ -324,19 +338,25 @@ static void test_position(HMIDISTRM hm, UINT typein, UINT typeout)
|
|||
}
|
||||
}
|
||||
|
||||
typedef struct midishortevent_tag { /* ideal size for MEVT_F_SHORT event type */
|
||||
DWORD dwDeltaTime;
|
||||
DWORD dwStreamID;
|
||||
DWORD dwEvent;
|
||||
} MIDISHORTEVENT;
|
||||
|
||||
/* Native crashes on a second run with the const qualifier set on this data! */
|
||||
static BYTE strmEvents[] = { /* A set of variable-sized MIDIEVENT structs */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, /* dwDeltaTime and dwStreamID */
|
||||
0, 0, 0, MEVT_NOP | 0x40, /* with MEVT_F_CALLBACK */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, /* dwDeltaTime and dwStreamID */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0xE0, 0x93, 0x04, MEVT_TEMPO, /* 0493E0 == 300000 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0x93, 0x48, 0x6F, MEVT_SHORTMSG,
|
||||
};
|
||||
|
||||
static BYTE strmNops[] = { /* Test callback + dwOffset */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, MEVT_NOP | 0x40, /* with MEVT_F_CALLBACK */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, MEVT_NOP | 0x40, /* with MEVT_F_CALLBACK */
|
||||
static MIDISHORTEVENT strmNops[] = { /* Test callback + dwOffset */
|
||||
{ 0, 0, (MEVT_NOP <<24)| MEVT_F_CALLBACK },
|
||||
{ 0, 0, (MEVT_NOP <<24)| MEVT_F_CALLBACK },
|
||||
};
|
||||
|
||||
static MMRESULT playStream(HMIDISTRM hm, LPMIDIHDR lpMidiHdr)
|
||||
|
@ -357,8 +377,6 @@ static void test_midiStream(UINT udev, HWND hwnd)
|
|||
MIDIPROPTEMPO tempo;
|
||||
MIDIPROPTIMEDIV tdiv;
|
||||
} midiprop;
|
||||
BYTE * const evt1 = &strmNops[1*offsetof(MIDIEVENT,dwParms)-1];
|
||||
BYTE * const evt2 = &strmNops[2*offsetof(MIDIEVENT,dwParms)-1];
|
||||
|
||||
if (hwnd)
|
||||
rc = midiStreamOpen(&hm, &udev, 1, (DWORD_PTR)hwnd, (DWORD_PTR)MYCBINST, CALLBACK_WINDOW);
|
||||
|
@ -382,7 +400,7 @@ static void test_midiStream(UINT udev, HWND hwnd)
|
|||
mhdr.dwFlags = 0;
|
||||
mhdr.dwUser = 0x56FA552C;
|
||||
mhdr.dwOffset = 1234567890;
|
||||
mhdr.dwBufferLength = sizeof(strmEvents) * sizeof(strmEvents[0]);
|
||||
mhdr.dwBufferLength = sizeof(strmEvents);
|
||||
mhdr.dwBytesRecorded = mhdr.dwBufferLength;
|
||||
mhdr.lpData = (LPSTR)&strmEvents[0];
|
||||
if (mhdr.lpData) {
|
||||
|
@ -410,7 +428,7 @@ static void test_midiStream(UINT udev, HWND hwnd)
|
|||
|
||||
/* MSDN asks to use midiStreamRestart prior to midiStreamOut()
|
||||
* because the starting state is 'pause', but some apps seem to
|
||||
* work with the inverse order.
|
||||
* work with the inverse order: queue everything, then play.
|
||||
*/
|
||||
|
||||
rc = midiStreamRestart(hm);
|
||||
|
@ -452,10 +470,15 @@ static void test_midiStream(UINT udev, HWND hwnd)
|
|||
|
||||
Sleep(400); /* Hear note */
|
||||
|
||||
midiprop.tempo.cbStruct = sizeof(midiprop.tempo);
|
||||
rc = midiStreamProperty(hm, (void*)&midiprop, MIDIPROP_GET|MIDIPROP_TEMPO);
|
||||
ok(!rc, "midiStreamProperty TEMPO rc=%s\n", mmsys_error(rc));
|
||||
ok(0x0493E0==midiprop.tempo.dwTempo, "stream set tempo %u\n", midiprop.tdiv.dwTimeDiv);
|
||||
|
||||
rc = midiStreamRestart(hm);
|
||||
ok(!rc, "midiStreamRestart #2 rc=%s\n", mmsys_error(rc));
|
||||
|
||||
mhdr.dwFlags |= MHDR_ISSTRM; /* just in case */
|
||||
mhdr.dwFlags |= MHDR_ISSTRM;
|
||||
/* Preset flags (e.g. MHDR_ISSTRM) do not disturb. */
|
||||
rc = midiOutPrepareHeader((HMIDIOUT)hm, &mhdr, offsetof(MIDIHDR,dwOffset));
|
||||
ok(!rc, "midiOutPrepare used flags %x rc=%s\n", mhdr.dwFlags, mmsys_error(rc));
|
||||
|
@ -466,16 +489,17 @@ static void test_midiStream(UINT udev, HWND hwnd)
|
|||
ok(!rc, "midiStreamRestart #3 rc=%s\n", mmsys_error(rc));
|
||||
}
|
||||
ok(mhdr.dwUser==0x56FA552C, "MIDIHDR.dwUser changed to %lx\n", mhdr.dwUser);
|
||||
trace("dwStreamID set to %x\n", ((LPMIDIEVENT)&strmEvents[0])->dwStreamID);
|
||||
ok(0==((MIDISHORTEVENT*)&strmEvents)[0].dwStreamID, "dwStreamID set to %x\n", ((LPMIDIEVENT)&strmEvents[0])->dwStreamID);
|
||||
|
||||
/* dwBytesRecorded controls how much is played, not dwBufferLength
|
||||
* allowing to immediately forward packets from midiIn to midiOut */
|
||||
mhdr.dwOffset = 1234123123;
|
||||
mhdr.dwBufferLength = sizeof(strmNops) * sizeof(strmNops[0]);
|
||||
mhdr.dwBufferLength = sizeof(strmNops);
|
||||
trace("buffer: %u\n", mhdr.dwBufferLength);
|
||||
mhdr.dwBytesRecorded = 0;
|
||||
mhdr.lpData = (LPSTR)&strmNops[0];
|
||||
*evt1 |= 0x40; /* MEVT_CALLBACK flag */
|
||||
*evt2 |= 0x40;
|
||||
strmNops[0].dwEvent |= MEVT_F_CALLBACK;
|
||||
strmNops[1].dwEvent |= MEVT_F_CALLBACK;
|
||||
|
||||
rc = midiOutPrepareHeader((HMIDIOUT)hm, &mhdr, sizeof(mhdr));
|
||||
ok(!rc, "midiOutPrepare rc=%s\n", mmsys_error(rc));
|
||||
|
@ -494,7 +518,7 @@ static void test_midiStream(UINT udev, HWND hwnd)
|
|||
* dwOffset slot does not exist in the small size MIDIHDR. */
|
||||
|
||||
mhdr.dwOffset = 1234123123;
|
||||
mhdr.dwBytesRecorded = offsetof(MIDIEVENT,dwParms);
|
||||
mhdr.dwBytesRecorded = 1*sizeof(MIDISHORTEVENT);
|
||||
|
||||
rc = playStream(hm, &mhdr);
|
||||
ok(!rc, "midiStreamOut 1 event out of 2 rc=%s\n", mmsys_error(rc));
|
||||
|
@ -503,10 +527,9 @@ static void test_midiStream(UINT udev, HWND hwnd)
|
|||
test_notification(hwnd, "1 of 2 events", MOM_DONE, (DWORD_PTR)&mhdr);
|
||||
test_notification(hwnd, "1 of 2 events", 0, WHATEVER);
|
||||
ok(0==mhdr.dwOffset, "MIDIHDR.dwOffset 1/2 changed to %u\n", mhdr.dwOffset);
|
||||
trace("MIDIHDR.dwOffset left at %u\n", mhdr.dwOffset);
|
||||
|
||||
mhdr.dwOffset = 1234123123;
|
||||
mhdr.dwBytesRecorded = 2*offsetof(MIDIEVENT,dwParms);
|
||||
mhdr.dwBytesRecorded = 2*sizeof(MIDISHORTEVENT);
|
||||
|
||||
rc = playStream(hm, &mhdr);
|
||||
ok(!rc, "midiStreamOut 1 event out of 2 rc=%s\n", mmsys_error(rc));
|
||||
|
@ -515,11 +538,11 @@ static void test_midiStream(UINT udev, HWND hwnd)
|
|||
test_notification(hwnd, "2 of 2 events", MOM_POSITIONCB, (DWORD_PTR)&mhdr);
|
||||
test_notification(hwnd, "2 of 2 events", MOM_DONE, (DWORD_PTR)&mhdr);
|
||||
test_notification(hwnd, "2 of 2 events", 0, WHATEVER);
|
||||
ok(3*sizeof(DWORD)==mhdr.dwOffset, "MIDIHDR.dwOffset 2/2 changed to %u\n", mhdr.dwOffset);
|
||||
trace("MIDIHDR.dwOffset left at %u\n", mhdr.dwOffset);
|
||||
ok(sizeof(MIDISHORTEVENT)==mhdr.dwOffset, "MIDIHDR.dwOffset 2/2 changed to %u\n", mhdr.dwOffset);
|
||||
ok(mhdr.dwBytesRecorded == 2*sizeof(MIDISHORTEVENT), "dwBytesRecorded changed to %u\n", mhdr.dwBytesRecorded);
|
||||
|
||||
*evt1 &= ~0x40; /* MEVT_CALLBACK flag */
|
||||
*evt2 &= ~0x40;
|
||||
strmNops[0].dwEvent &= ~MEVT_F_CALLBACK;
|
||||
strmNops[1].dwEvent &= ~MEVT_F_CALLBACK;
|
||||
mhdr.dwOffset = 1234123123;
|
||||
rc = playStream(hm, &mhdr);
|
||||
ok(!rc, "midiStreamOut 1 event out of 2 rc=%s\n", mmsys_error(rc));
|
||||
|
@ -527,11 +550,11 @@ static void test_midiStream(UINT udev, HWND hwnd)
|
|||
test_notification(hwnd, "0 CB in 2 events", MOM_DONE, (DWORD_PTR)&mhdr);
|
||||
test_notification(hwnd, "0 CB in 2 events", 0, WHATEVER);
|
||||
/* w9X/me/nt set dwOffset to the position played last */
|
||||
ok(1234123123==mhdr.dwOffset || broken(3*sizeof(DWORD)==mhdr.dwOffset), "MIDIHDR.dwOffset nocb changed to %u\n", mhdr.dwOffset);
|
||||
ok(1234123123==mhdr.dwOffset || broken(sizeof(MIDISHORTEVENT)==mhdr.dwOffset), "MIDIHDR.dwOffset nocb changed to %u\n", mhdr.dwOffset);
|
||||
|
||||
mhdr.dwBytesRecorded = mhdr.dwBufferLength-1;
|
||||
rc = playStream(hm, &mhdr);
|
||||
todo_wine ok(rc==MMSYSERR_INVALPARAM,"midiStreamOut dwBytesRecorded/MIDIEVENT rc=%s\n", mmsys_error(rc));
|
||||
ok(rc==MMSYSERR_INVALPARAM,"midiStreamOut dwBytesRecorded modulo MIDIEVENT rc=%s\n", mmsys_error(rc));
|
||||
if (!rc) {
|
||||
test_notification(hwnd, "2 of 2 events", MOM_DONE, (DWORD_PTR)&mhdr);
|
||||
}
|
||||
|
@ -547,6 +570,8 @@ static void test_midiStream(UINT udev, HWND hwnd)
|
|||
|
||||
rc = midiOutUnprepareHeader((HMIDIOUT)hm, &mhdr, sizeof(mhdr));
|
||||
ok(!rc, "midiOutUnprepare rc=%s\n", mmsys_error(rc));
|
||||
ok(0==strmNops[0].dwStreamID, "dwStreamID[0] set to %x\n", strmNops[0].dwStreamID);
|
||||
ok(0==strmNops[1].dwStreamID, "dwStreamID[1] set to %x\n", strmNops[1].dwStreamID);
|
||||
|
||||
mhdr.dwBufferLength = 70000; /* > 64KB! */
|
||||
mhdr.lpData = HeapAlloc(GetProcessHeap(), 0 , mhdr.dwBufferLength);
|
||||
|
@ -567,6 +592,21 @@ static void test_midiStream(UINT udev, HWND hwnd)
|
|||
ok(!rc, "midiStreamClose rc=%s\n", mmsys_error(rc));
|
||||
test_notification(hwnd, "midiStreamClose", MOM_CLOSE, 0);
|
||||
test_notification(hwnd, "midiStream over", 0, WHATEVER);
|
||||
|
||||
rc = midiStreamOpen(&hm, &udev, 1, 0, (DWORD_PTR)MYCBINST, CALLBACK_FUNCTION);
|
||||
ok(!rc /*w2k*/|| rc==MMSYSERR_INVALPARAM/*w98*/, "midiStreamOpen NULL function rc=%s\n", mmsys_error(rc));
|
||||
if (!rc) {
|
||||
trace("Device %d accepts NULL CALLBACK_FUNCTION\n", udev);
|
||||
rc = midiStreamClose(hm);
|
||||
ok(!rc, "midiStreamClose rc=%s\n", mmsys_error(rc));
|
||||
}
|
||||
|
||||
rc = midiStreamOpen(&hm, &udev, 1, (DWORD_PTR)0xDEADBEEF, (DWORD_PTR)MYCBINST, CALLBACK_WINDOW);
|
||||
ok(rc==MMSYSERR_INVALPARAM, "midiStreamOpen bad window rc=%s\n", mmsys_error(rc));
|
||||
if (!rc) {
|
||||
rc = midiStreamClose(hm);
|
||||
ok(!rc, "midiStreamClose rc=%s\n", mmsys_error(rc));
|
||||
}
|
||||
}
|
||||
|
||||
static void test_midi_outfns(HWND hwnd)
|
||||
|
@ -620,7 +660,7 @@ static void test_midi_outfns(HWND hwnd)
|
|||
|
||||
START_TEST(midi)
|
||||
{
|
||||
HWND hwnd;
|
||||
HWND hwnd = 0;
|
||||
if (1) /* select 1 for CALLBACK_WINDOW or 0 for CALLBACK_FUNCTION */
|
||||
hwnd = CreateWindowExA(0, "static", "winmm midi test", WS_POPUP, 0,0,100,100,
|
||||
0, 0, 0, NULL);
|
||||
|
|
|
@ -911,6 +911,13 @@ UINT WINAPI midiOutOpen(LPHMIDIOUT lphMidiOut, UINT uDeviceID,
|
|||
|
||||
if (lphMidiOut != NULL) *lphMidiOut = 0;
|
||||
|
||||
switch (dwFlags & CALLBACK_TYPEMASK) {
|
||||
case CALLBACK_WINDOW:
|
||||
if (dwCallback && !IsWindow((HWND)dwCallback))
|
||||
return MMSYSERR_INVALPARAM;
|
||||
break;
|
||||
}
|
||||
|
||||
lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &dwFlags, 0, NULL);
|
||||
|
||||
if (lpwm == NULL)
|
||||
|
@ -1754,6 +1761,13 @@ MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID,
|
|||
if (cMidi != 1 || lphMidiStrm == NULL || lpuDeviceID == NULL)
|
||||
return MMSYSERR_INVALPARAM;
|
||||
|
||||
switch (fdwOpen & CALLBACK_TYPEMASK) {
|
||||
case CALLBACK_WINDOW:
|
||||
if (dwCallback && !IsWindow((HWND)dwCallback))
|
||||
return MMSYSERR_INVALPARAM;
|
||||
break;
|
||||
}
|
||||
|
||||
lpMidiStrm = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream));
|
||||
if (!lpMidiStrm)
|
||||
return MMSYSERR_NOMEM;
|
||||
|
@ -1816,7 +1830,8 @@ MMRESULT WINAPI midiStreamOut(HMIDISTRM hMidiStrm, LPMIDIHDR lpMidiHdr,
|
|||
TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMidiHdr, cbMidiHdr);
|
||||
|
||||
if (cbMidiHdr < offsetof(MIDIHDR,dwOffset) || !lpMidiHdr || !lpMidiHdr->lpData
|
||||
|| lpMidiHdr->dwBufferLength < lpMidiHdr->dwBytesRecorded)
|
||||
|| lpMidiHdr->dwBufferLength < lpMidiHdr->dwBytesRecorded
|
||||
|| lpMidiHdr->dwBytesRecorded % 4 /* player expects DWORD padding */)
|
||||
return MMSYSERR_INVALPARAM;
|
||||
/* FIXME: Native additionally checks if the MIDIEVENTs in lpData
|
||||
* exactly fit dwBytesRecorded. */
|
||||
|
|
Loading…
Reference in New Issue