WINMM `PlaySound` does not allow passing byte arrays.
colejohnson66 opened this issue · 1 comments
Actual behavior
WINMD's PlaySound
is documented as taking an LPCTSTR
of the filename to play. However, if fdwSound
is SND_MEMORY
, the filename is interpreted as a WAVE file blob. CsWin32 does not allow this usage, but this is how System.Media.SoundPlayer
works:
[LibraryImport(Libraries.WinMM, EntryPoint = "PlaySoundW", StringMarshalling = StringMarshalling.Utf16)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool PlaySound(string soundName, IntPtr hmod, int soundFlags);
[LibraryImport(Libraries.WinMM, EntryPoint = "PlaySoundW")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool PlaySound(byte[]? soundName, IntPtr hmod, int soundFlags);
internal static unsafe winmdroot.Foundation.BOOL PlaySound(string pszSound, SafeHandle hmod, winmdroot.Media.Audio.SND_FLAGS fdwSound)
{
bool hmodAddRef = false;
try
{
fixed (char* pszSoundLocal = pszSound)
{
winmdroot.Foundation.HMODULE hmodLocal;
if (hmod is object)
{
hmod.DangerousAddRef(ref hmodAddRef);
hmodLocal = (winmdroot.Foundation.HMODULE)hmod.DangerousGetHandle();
}
else
hmodLocal = (winmdroot.Foundation.HMODULE )new IntPtr(0L);
winmdroot.Foundation.BOOL __result = PInvoke.PlaySound(pszSoundLocal, hmodLocal, fdwSound);
return __result;
}
}
finally
{
if (hmodAddRef)
hmod.DangerousRelease();
}
}
[DllImport("WINMM.dll", ExactSpelling = true, EntryPoint = "PlaySoundW")]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
internal static extern winmdroot.Foundation.BOOL PlaySound(winmdroot.Foundation.PCWSTR pszSound, winmdroot.Foundation.HMODULE hmod, winmdroot.Media.Audio.SND_FLAGS fdwSound);
Expected behavior
Two overloads are generated: one taking a string
, and one taking a Span<byte>
. Both would ideally lower to the same P/Invoke around a void*
.
Repro steps
NativeMethods.txt
content:
PlaySound
Context
- CsWin32 version: 0.3.106
- Target Framework:
net8.0
LangVersion
:Latest
CsWin32 generates overloads based on the metadata, which is based on the header files. Since the original function takes a string pointer, so does our PCWSTR extern method. The string
overload is just a friendly version of that.
And just as the native function will let you point at a string or a byte array, you can do the same with PCWSTR
. Just create it with a pointer to a byte array instead of a string, as per the documentation. You'll have to cast the pointer (as I expect you would have to do in C).