C言語（Windows API）でWindowsで指定した音を鳴らす方法

C言語（Windows API）を使ってWindowsで指定した音を鳴らす方法を紹介します。

# MessageBeep関数
一般の警告音、システム エラー、メッセージ (問い合わせ)、メッセージ (警告)、メッセージ (情報)の音を鳴らすのに一番簡単な方法は、MessageBeep関数です。
Windows.hをインクルードすれば使えます。

```c
BOOL MessageBeep(
	UINT uType	//サウンドタイプ
);
```
## 引数
### uType

|値|音|
|:--|:--|
|-1|標準的なビープ音※1|
|MB_OK|一般の警告音|
|MB_ICONHAND|システム エラー|
|MB_ICONERROR|システム エラー|
|MB_ICONSTOP|システム エラー|
|MB_ICONQUESTION|メッセージ (問い合わせ)|
|MB_ICONEXCLAMATION|メッセージ (警告)|
|MB_ICONWARNING|メッセージ (警告)|
|MB_ICONASTERISK|メッセージ (情報)|
|MB_ICONINFORMATION|メッセージ (情報)|

※1:標準的なビープ音と書いてありますが、僕が使ってみたら鳴ったのは一般の警告音でした。

## 例
標準的なビープ音、一般の警告音、システム エラー、メッセージ (問い合わせ)、メッセージ (警告)、メッセージ (情報)の音を1秒ごとに鳴らします。

```c++:Sound.cpp
#include <Windows.h>

int main() {
	MessageBeep(-1);	//標準的なビープ音
	Sleep(1000);		//1秒待つ

	MessageBeep(MB_OK);	//一般の警告音
	Sleep(1000);

	MessageBeep(MB_ICONHAND);	//システム エラー
	Sleep(1000);

	MessageBeep(MB_ICONQUESTION);	//メッセージ (問い合わせ)
	Sleep(1000);

	MessageBeep(MB_ICONEXCLAMATION);	//メッセージ (警告)
	Sleep(1000);

	MessageBeep(MB_ICONASTERISK);	//メッセージ (情報)
	Sleep(1000);

	return 0;
}
```

# PlaySound関数
上の5つ以外の音を鳴らすには、PlaySound関数を使います。
Windows.h、mmsystem.hをインクルードしてwinmm.libをリンクすれば使えます。

```c
BOOL PlaySound(
	LPCSTR pszSound,	//再生対象のサウンド
	HMODULE hmod,		//インスタンスハンドル
	DWORD fdwSound		//再生フラグ
);
```

## 引数
### PszSound
値を文字列で指定します。

この表は、Windows 10の場合です。
もともとどこで鳴る音なのかは、[こちら](http://toracatman.livedoor.blog/archives/7016587.html)を参照してください。

|値|音|
|:--|:--|
|Notification.Proximity|NFP 完了|
|ProximityConnection|NFP 接続|
|WindowsUnlock|Windows のロック解除|
|SystemExit|Windows の終了|
|SystemStart|Windows の起動|
|ChangeTheme|Windows テーマの変更|
|WindowsUAC|Windows ユーザー アカウント制御|
|WindowsLogoff|Windows ログオフ|
|WindowsLogon|Windows ログオン|
|Notification.Looping.Alarm|アラーム 1|
|Notification.Looping.Alarm10|アラーム 10|
|Notification.Looping.Alarm2|アラーム 2|
|Notification.Looping.Alarm3|アラーム 3|
|Notification.Looping.Alarm4|アラーム 4|
|Notification.Looping.Alarm5|アラーム 5|
|Notification.Looping.Alarm6|アラーム 6|
|Notification.Looping.Alarm7|アラーム 7|
|Notification.Looping.Alarm8|アラーム 8|
|Notification.Looping.Alarm9|アラーム 9|
|Notification.IM|インスタント メッセージの通知|
|SystemHand|システム エラー|
|SystemNotification|システム通知|
|ShowBand|ツール バー バンドの表示|
|MailBeep|デスクトップ メールの通知|
|DeviceDisconnect|デバイスの切断|
|DeviceConnect|デバイスの接続|
|DeviceFail|デバイスの接続の失敗|
|LowBatteryAlarm|バッテリ低下アラーム|
|CriticalBatteryAlarm|バッテリ切れアラーム|
|AppGPFault|プログラム エラー|
|Close|プログラムの終了|
|Open|プログラムの起動|
|SystemQuestion|メッセージ (問い合わせ)|
|SystemAsterisk|メッセージ (情報)|
|SystemExclamation|メッセージ (警告)|
|MessageNudge|メッセージのシェイク|
|MenuCommand|メニュー コマンド|
|MenuPopup|メニュー ポップアップ|
|.Default|一般の警告音|
|Notification.Reminder|予定表のアラーム|
|RestoreUp|元に戻す (拡大)|
|RestoreDown|元に戻す (縮小)|
|PrintComplete|印刷完了|
|Notification.SMS|新着テキスト メッセージの通知|
|FaxBeep|新着ファックスの通知|
|Notification.Mail|新着メールの通知|
|Maximize|最大化|
|Minimize|最小化|
|Notification.Looping.Call|着信呼の通知 1|
|Notification.Looping.Call10|着信呼の通知 10|
|Notification.Looping.Call2|着信呼の通知 2|
|Notification.Looping.Call3|着信呼の通知 3|
|Notification.Looping.Call4|着信呼の通知 4|
|Notification.Looping.Call5|着信呼の通知 5|
|Notification.Looping.Call6|着信呼の通知 6|
|Notification.Looping.Call7|着信呼の通知 7|
|Notification.Looping.Call8|着信呼の通知 8|
|Notification.Looping.Call9|着信呼の通知 9|
|Notification.Default|通知|
|CCSelect|選択|

### hmod
Windowsの音を鳴らすときは`NULL`を指定します。

### fdwSound
Windowsの音を鳴らすときは、基本的に、
鳴っている間はプログラムを止めるには、`SND_ALIAS | SND_SYNC | SND_NODEFAULT`を指定します。
鳴っている間もプログラムを動かすには、`SND_ALIAS | SND_ASYNC | SND_NODEFAULT`を指定します。

## 例
### 例1
次の例は、Windows テーマの変更の音を鳴らします。

```c++:ChangeThemeSound.cpp
#include <Windows.h>
#include <mmsystem.h>

#pragma comment(lib, "winmm.lib")

int main() {
	PlaySound("ChangeTheme", NULL, SND_ALIAS | SND_SYNC | SND_NODEFAULT); //Windows テーマの変更

	return 0;
}
```

### 例2
次の例は、Windowsに指定された音を、音の名前を表示しながら順番に鳴らします。
この例には、Windows のロック解除、アラーム 1～10、着信呼の通知 1～10はありません。

```c++:SoundCheck.cpp
#include <stdio.h>
#include <Windows.h>
#include <mmsystem.h>
#include <stdlib.h>

#pragma comment(lib, "winmm.lib")

//Windowsの音
char sound[39][2][256] = {
    { "NFP 完了",                           "Notification.Proximity" },
    { "NFP 接続",                           "ProximityConnection" },
    { "Windows の終了",                     "SystemExit" },
    { "Windows の起動",                     "SystemStart" },
    { "Windows テーマの変更",               "ChangeTheme" },
    { "Windows ユーザー アカウント制御",    "WindowsUAC" },
    { "Windows ログオフ",                   "WindowsLogoff" },
    { "Windows ログオン",                   "WindowsLogon" },
    { "インスタント メッセージの通知",      "Notification.IM" },
    { "システム エラー",                    "SystemHand" },
    { "システム通知",                       "SystemNotification" },
    { "ツール バー バンドの表示",           "ShowBand" },
    { "デスクトップ メールの通知",          "MailBeep" },
    { "デバイスの切断",                     "DeviceDisconnect" },
    { "デバイスの接続",                     "DeviceConnect" },
    { "デバイスの接続の失敗",               "DeviceFail" },
    { "バッテリ低下アラーム",               "LowBatteryAlarm" },
    { "バッテリ切れアラーム",               "CriticalBatteryAlarm" },
    { "プログラム エラー",                  "AppGPFault" },
    { "プログラムの終了",                   "Close" },
    { "プログラムの起動",                   "Open" },
    { "メッセージ (問い合わせ)",            "SystemQuestion" },
    { "メッセージ (情報)",                  "SystemAsterisk" },
    { "メッセージ (警告)",                  "SystemExclamation" },
    { "メッセージのシェイク",               "MessageNudge" },
    { "メニュー コマンド",                  "MenuCommand" },
    { "メニュー ポップアップ",              "MenuPopup" },
    { "一般の警告音",                       ".Default" },
    { "予定表のアラーム",                   "Notification.Reminder" },
    { "元に戻す (拡大)",                    "RestoreUp" },
    { "元に戻す (縮小)",                    "RestoreDown" },
    { "印刷完了",                           "PrintComplete" },
    { "新着テキスト メッセージの通知",      "Notification.SMS" },
    { "新着ファックスの通知",               "FaxBeep" },
    { "新着メールの通知",                   "Notification.Mail" },
    { "最大化",                             "Maximize" },
    { "最小化",                             "Minimize" },
    { "通知",                               "Notification.Default" },
    { "選択",                               "CCSelect" }
};

int main() {
    int l = sizeof(sound) / sizeof(sound[0]);   //Windowsの音の数を取得
    for (int i = 0; i < l; i++) {
        printf("%s", sound[i][0]);  //Windowsの音の名前を表示
        PlaySound(sound[i][1], NULL, SND_ALIAS | SND_SYNC | SND_NODEFAULT); //鳴らす
        system("cls");  //画面のクリア
    }

    return 0;
}
```

# エクスプローラーの音を鳴らす方法
サウンド設定のWindows以外の音を鳴らすには、fdwSoundにSND_APPLICATIONフラグを立てればいいという情報を得たので、
試しにナビゲーションの開始を鳴らそうとしてみたところ、鳴りませんでした。

```c
PlaySound("Navigating", NULL, SND_ALIAS | SND_APPLICATION | SND_SYNC | SND_NODEFAULT); //ナビゲーションの開始（失敗）
```

なので、ほかに方法がないか調べたところ、次の方法が見つかりました。
ごみ箱を空にする、ナビゲーションの開始など、サウンド設定のエクスプローラーの音を鳴らすには、次のようにします。

```c
char path[256];
HKEY hKey;
DWORD Size;
RegOpenKeyEx(HKEY_CURRENT_USER, "AppEvents\\Schemes\\Apps\\Explorer\\（値）\\.Current", 0, KEY_ALL_ACCESS, &hKey);    //レジストリを開く
Size = sizeof(path);    //パスのサイズを取得
RegQueryValueEx(hKey, "", NULL, NULL, (LPBYTE)&path, &Size);    //レジストリを取得
RegCloseKey(hKey);  //レジストリを閉じる
PlaySound(path, NULL, SND_FILENAME | SND_SYNC | SND_NODEFAULT); //鳴らす
```

レジストリから直接エクスプローラーの音に指定されている音のパスを取得します。
fdwSoundにSND_FILENAMEフラグを立てたときはpszSoundが音のパスになるので、レジストリから取得したパスを指定し、鳴らします。
（値）のところに指定できるのは次の7つです。

|値|音|
|:--|:--|
|EmptyRecycleBin|ごみ箱を空にする|
|ActivatingDocument|ナビゲーションの完了|
|Navigating|ナビゲーションの開始|
|FeedDiscovered|フィードの発見|
|BlockedPopup|ポップアップ ウィンドウのブロック|
|MoveMenuItem|メニュー項目の移動|
|SecurityBand|通知バー|

## 例
### 例1
次の例は、ナビゲーションの開始の音を鳴らします。

```c++:NavigatingSound.cpp
#include <Windows.h>
#include <mmsystem.h>

#pragma comment(lib, "winmm.lib")

int main() {
    char path[256];
    HKEY hKey;
    DWORD Size;
    RegOpenKeyEx(HKEY_CURRENT_USER, "AppEvents\\Schemes\\Apps\\Explorer\\Navigating\\.Current", 0, KEY_ALL_ACCESS, &hKey);
    Size = sizeof(path);
    RegQueryValueEx(hKey, "", NULL, NULL, (LPBYTE)&path, &Size);
    RegCloseKey(hKey);
    PlaySound(path, NULL, SND_FILENAME | SND_SYNC | SND_NODEFAULT);

    return 0;
}
```

### 例2
次の例は、エクスプローラーの音を、音の名前を表示しながら順番に鳴らします。

```c++:ExplorerSound.cpp
#include <stdio.h>
#include <Windows.h>
#include <mmsystem.h>
#include <stdlib.h>

#pragma comment(lib, "winmm.lib")

//エクスプローラーの音
char explorer_sound[7][2][256] = {
    { "ごみ箱を空にする",                   "EmptyRecycleBin" },
    { "ナビゲーションの完了",               "ActivatingDocument" },
    { "ナビゲーションの開始",               "Navigating" },
    { "フィードの発見",                     "FeedDiscovered" },
    { "ポップアップ ウィンドウのブロック",  "BlockedPopup" },
    { "メニュー項目の移動",                 "MoveMenuItem" },
    { "通知バー",                           "SecurityBand" }
};

int main() {
    char path[256];
    HKEY hKey;
    DWORD Size;

    int l = sizeof(explorer_sound) / sizeof(explorer_sound[0]); //エクスプローラーの音の数を取得
    for (int i = 0; i < l; i++) {
        printf("%s", explorer_sound[i][0]); //エクスプローラーの音の名前を表示

        //エクスプローラーの音のレジストリのパスを取得
        sprintf_s(path, sizeof(path), "AppEvents\\Schemes\\Apps\\Explorer\\%s\\.Current", explorer_sound[i][1]);

        RegOpenKeyEx(HKEY_CURRENT_USER, path, 0, KEY_ALL_ACCESS, &hKey);    //レジストリを開く
        path[0] = '\0'; //パスのクリア
        Size = sizeof(path);    //パスのサイズを取得
        RegQueryValueEx(hKey, "", NULL, NULL, (LPBYTE)&path, &Size);    //レジストリを取得
        RegCloseKey(hKey);  //レジストリを閉じる
        PlaySound(path, NULL, SND_FILENAME | SND_SYNC | SND_NODEFAULT); //鳴らす

        system("cls");  //画面のクリア
    }

    return 0;
}
```

# Windows 音声認識の音を鳴らす方法
エクスプローラーの音を鳴らすのと同様に、レジストリから直接音のパスを取得します。
エクスプローラーの音との違いは、レジストリのパスのExplorerがsapisvrになります。

```c
char path[256];
HKEY hKey;
DWORD Size;
RegOpenKeyEx(HKEY_CURRENT_USER, "AppEvents\\Schemes\\Apps\\sapisvr\\（値）\\.Current", 0, KEY_ALL_ACCESS, &hKey);
Size = sizeof(path);
RegQueryValueEx(hKey, "", NULL, NULL, (LPBYTE)&path, &Size);
RegCloseKey(hKey);
PlaySound(path, NULL, SND_FILENAME | SND_SYNC | SND_NODEFAULT);
```

|値|音|
|:--|:--|
|HubOffSound|オフ|
|HubOnSound|オン|
|HubSleepSound|スリープ状態|
|PanelSound|不明瞭解消パネル|
|DisNumbersSound|不明瞭解消数字|
|MisrecoSound|誤認識|