【问题标题】:How can you perform other functions simultaneously with PlaySound?如何使用 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 返回的线程句柄。

标签: c++ windows


【解决方案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 中所说的泄漏线程句柄;这很重要。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-01
相关资源
最近更新 更多