應用程式啟動時播放歡迎音效、操作完成提示音、錯誤警示音。將 .wav 檔內嵌為資源,避免外部檔案遺失、部署麻煩。播放過程不阻塞主執行緒 UI 回應。
notify.wav)。WAVE (大寫) → ID 自動指派 (如 IDR_WAVE1)。IDR_WAVE1 WAVE "notify.wav"。
// 1. 取得模組句柄
HINSTANCE hInst = AfxGetInstanceHandle();
// 2. 尋找資源
HRSRC hRsrc = FindResource(hInst, MAKEINTRESOURCE(IDR_WAVE1), _T("WAVE"));
if (!hRsrc) return; // 找不到
// 3. 載入資源至全域記憶體
HGLOBAL hGlobal = LoadResource(hInst, hRsrc);
if (!hGlobal) return;
// 4. 鎖定記憶體取得指標
LPVOID pSoundData = LockResource(hGlobal);
if (!pSoundData) return;
// 5. 取得資源大小 (可選,sndPlaySound 不需大小)
DWORD dwSize = SizeofResource(hInst, hRsrc);
// 6. 播放 (SND_MEMORY: 從記憶體 | SND_ASYNC: 非同步 | SND_NODEFAULT: 找不到不播放預設音)
sndPlaySound((LPCSTR)pSoundData, SND_MEMORY | SND_ASYNC | SND_NODEFAULT);
// 7. 釋放資源 (非同步播放時需確保資源存活到播放結束,通常配合回呼或延遲釋放)
// 簡單做法:同步播放 (SND_SYNC) 直接 FreeResource
// 非同步做法:另開執行緒播放完再釋放
#pragma once
#include
class CAsyncSoundPlayer
{
public:
static void PlayResource(UINT nResourceID, LPCTSTR lpszType = _T("WAVE"));
static void PlayFile(LPCTSTR lpszFilePath);
private:
static UINT __cdecl PlayThread(LPVOID pParam);
struct ThreadParam
{
HINSTANCE hInst;
UINT nResID;
LPCTSTR lpszType;
CString strFile; // 檔案播放用
bool bIsFile;
};
};
#include "stdafx.h"
#include "AsyncSoundPlayer.h"
#include
#pragma comment(lib, "winmm.lib")
UINT __cdecl CAsyncSoundPlayer::PlayThread(LPVOID pParam)
{
ThreadParam* p = (ThreadParam*)pParam;
if (!p) return 1;
if (p->bIsFile)
{
// 檔案播放
sndPlaySound(p->strFile, SND_FILENAME | SND_ASYNC | SND_NODEFAULT);
// 檔案播放不需鎖定資源,但需確保字串存活
// 簡單做法:Sleep 估算播放時間,或使用波形音訊 API 精確控制
Sleep(2000); // 粗略等待
}
else
{
// 資源播放
HRSRC hRsrc = FindResource(p->hInst, MAKEINTRESOURCE(p->nResID), p->lpszType);
if (hRsrc)
{
HGLOBAL hGlobal = LoadResource(p->hInst, hRsrc);
if (hGlobal)
{
LPVOID pData = LockResource(hGlobal);
if (pData)
{
sndPlaySound((LPCSTR)pData, SND_MEMORY | SND_SYNC | SND_NODEFAULT);
// SND_SYNC 會阻塞到播放結束,安全釋放
}
FreeResource(hGlobal);
}
}
}
delete p; // 釋放參數結構
return 0;
}
void CAsyncSoundPlayer::PlayResource(UINT nResourceID, LPCTSTR lpszType)
{
ThreadParam* p = new ThreadParam;
p->hInst = AfxGetInstanceHandle();
p->nResID = nResourceID;
p->lpszType = lpszType;
p->bIsFile = false;
AfxBeginThread(PlayThread, p, THREAD_PRIORITY_NORMAL);
}
void CAsyncSoundPlayer::PlayFile(LPCTSTR lpszFilePath)
{
ThreadParam* p = new ThreadParam;
p->strFile = lpszFilePath;
p->bIsFile = true;
AfxBeginThread(PlayThread, p, THREAD_PRIORITY_NORMAL);
}
// View 左鍵點擊播放資源音效
void CMyView::OnLButtonDown(UINT nFlags, CPoint point)
{
CAsyncSoundPlayer::PlayResource(IDR_WAVE1); // 播放嵌入資源
CView::OnLButtonDown(nFlags, point);
}
// 工具列按鈕播放外部檔案
void CMainFrame::OnPlayExternalSound()
{
CAsyncSoundPlayer::PlayFile(_T("C:\\Sounds\\alert.wav"));
}
sndPlaySound 功能有限 (無音量控制、無播放完成通知、無混音)。專業音訊應用建議使用 waveOutOpen/waveOutWrite/waveOutClose 系列 API,或更高層的 DirectSound / XAudio2 / WASAPI。
| 特性 | sndPlaySound | waveOut API | DirectSound/XAudio2 |
|---|---|---|---|
| API 層級 | 高層封裝 | 底層波形音訊 | 現代音訊引擎 |
| 非同步支援 | SND_ASYNC (簡易) | 回呼函式/事件 | 完整非同步管線 |
| 音量控制 | 無 | waveOutSetVolume | 完整混音器 |
| 多聲道混音 | 無 (互相打斷) | 手動混音 | 硬體加速混音 |
| 格式支援 | 僅 PCM WAV | PCM WAV | WAV, MP3, ADPCM, xWMA... |
| 適用場景 | 簡單提示音 | 語音錄製/播放、簡單混音 | 遊戲、多媒體、專業音訊 |
WAVE (大寫)、ID 正確、.wav 格式為 PCM (非 ADPCM/MP3)。waveOut 串流播放。sndPlaySound 單一執行個體,同時呼叫會互相打斷。需自行管理混音佇列或升級 API。sndPlaySound 參數為 LPCSTR (32 位元指標),64 位元編譯需確保指標截斷正確,建議改用 PlaySound (支援 LPCVOID)。內嵌聲音資源 + 非同步執行緒播放,是 MFC 應用程式加入音效回饋的輕量級方案。掌握 FindResource → LoadResource → LockResource → sndPlaySound(SND_MEMORY) 流程,即可輕鬆實現。對於音量控制、混音、格式支援有更高需求時,請果斷遷移至 XAudio2 或 WASAPI 現代音訊架構。