如何使用 PlaySound 同时执行其他功能?

Posted

技术标签:

【中文标题】如何使用 PlaySound 同时执行其他功能?【英文标题】:How can you perform other functions simultaneously with PlaySound? 【发布时间】:2019-06-13 11:05:39 【问题描述】:

我正在编写一个 C++ Windows 应用程序,它需要从一个数组中播放一首随机选择的歌曲,并且用户需要能够通过单击一个按钮来播放列表中的另一首歌曲。你会如何停止第一首歌曲的声音以播放第二首歌曲?

通过按下播放第一首歌曲的按钮,播放音频资源,但是我的程序不再响应任何点击,并且代码在歌曲完成之前不会继续。我曾尝试使用 CreateThread(),但无济于事,因为我的程序仍处于无响应状态。

包含 PlaySound 的函数:

LPTHREAD_START_ROUTINE WINAPI PlayWavFile(int resource) 
    PlaySound(MAKEINTRESOURCE(resource), hInst, SND_RESOURCE | SND_SYNC);
    return 0;

WndProc 函数中判断按钮按下结果的情况:

case WM_COMMAND:
        if (LOWORD(wParam) == 1) 
            HANDLE hThread = CreateThread(
                NULL,
                0,
                PlayWavFile(i),
                NULL,
                NULL,
                NULL
            );
        
        else if (LOWORD(wParam) == 2) 
            HANDLE hPlaySecond = CreateThread(
                NULL,
                0,
                PlayWavFile(j),
                NULL,
                NULL,
                NULL
            );
        
        else if (LOWORD(wParam) == 3) 
            HANDLE hStop = CreateThread(
                NULL,
                0,
                PlayWavFile(NULL),
                NULL,
                NULL,
                NULL
            );
        
        break;

此外,如果我尝试单击应将 wParam 值设为 3 的按钮,则程序会遇到异常,该异常指出:

Audio Player.exe 在 0x00000000 处引发异常:0xC0000005:执行位置 0x00000000 的访问冲突。发生了。

最终目标是程序在后台播放音乐时做出响应。

【问题讨论】:

与基本问题无关,但绝对与您的解决方案尝试有关,您在创建每个线程时都会泄漏线程句柄。如果您不打算通过 waitforsingleobject 或类似方法等待线程,则应关闭从 CreateThread 返回的线程句柄。 【参考方案1】:

只需使用SND_ASYNC 而不是SND_SYNC 直接调用PlaySound。这将导致PlaySound 立即返回并在后台播放声音。

没有必要为此纠结线程。

【讨论】:

谢谢,这立即奏效了。不敢相信我没有想到这一点。【参考方案2】:

当你这样做时

HANDLE hThread = CreateThread(
    NULL,
    0,
    PlayWavFile(i),
    NULL,
    NULL,
    NULL
);

您正在调用函数PlayWavFile,并使用它返回的值作为要调用的线程函数。而且由于函数总是返回0,它是一个空指针,它相当于

HANDLE hThread = CreateThread(
    NULL,
    0,
    nullptr,
    NULL,
    NULL,
    NULL
);

线程函数参数的类型为LPTHREAD_START_ROUTINE,它是一个指向函数的指针,该函数接受LPVOID 参数并返回DWORD

你需要相应地改变你的线程函数,然后调用CreateThread as

HANDLE hThread = CreateThread(
    NULL,
    0,
    &PlayWavFile,  // Pass a pointer to the function
    reinterpret_cast<LPVOID>(i),    // The argument to pass
    NULL,
    NULL
);

有了这个PlayWavFile 可能看起来像

DWORD PlayWavFile(LPVOID argument) 
    int resource = reinterpret_cast<int>(argument);
    PlaySound(MAKEINTRESOURCE(resource), hInst, SND_RESOURCE | SND_SYNC);
    return 0;

【讨论】:

我完全按照你说的做了,收到了这个错误:“DWORD (*)(LPVOID arg)”类型的参数与“LPTHREAD_START_ROUTINE”类型的参数不兼容 @Siggers LPTHREAD_START_ROUTINE 是线程过程的函数指针类型。它 not 是线程过程的正确返回值类型,因为您似乎正在使用它。您的函数应该 (a) 返回一个 DWORD,(b) 使用 WINAPI 调用约定,以及 (c) 采用单个 LPVOID 参数。并注意我在您的问题下方的一般 cmets 中所说的泄漏线程句柄;这很重要。

以上是关于如何使用 PlaySound 同时执行其他功能?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Python 中的 playsound 模块同时播放两种声音?

如何使用 PlaySound() 或任何基本函数/方法在 C++ 中同时播放 1 个以上的 .wav 声音?

在做其他事情的同时在 C++ 中播放声音

C++ 中的 Playsound:.wav 文件的文件错误

如何使用winsound同时播放多个声音?

如何异步使用playsound?