スキップしてメイン コンテンツへ

 none
C++/CLIで PlaySound() でwavファイルを再生できない RRS feed

  • 質問

  • C#, CLI どちらもコンパイルは通るのですが、
    C++/CLI の方だけ、音が再生されずFalseが戻ってしまいます。

    ★音が再生されない原因がどこにあるのかを探す方法
    を教えて下さる方、 いらっしゃいましたら宜しくお願いします m(_ _)m

    以下、部分的ですが、 C#とCLIのそれぞれのコードです。

    // C# こっちは音が出てTrueが戻る
    using System.Runtime.InteropServices;

    public partial class Form1 : Form
    {
      [Flags]
      private enum SoundFlags : int { /* ●2 */ }

      [DllImport("winmm.dll")]
      private static extern bool PlaySound
      (String soundName, IntPtr hmod, SoundFlags sf);

      public Form1() {InitializeComponent();}

      private void button_Click(object sender, EventArgs e)
      {
        MessageBox.Show // ●開けたかどうかも兼ねて。。。
        ( PlaySound("Alarm01.wav", IntPtr.Zero, SoundFlags.SND_FILENAME | SoundFlags.SND_ASYNC).ToString() );
      }
    } // partial class

    ////////////////////////////////////////////////////////////////////

    // CLI こっちは音が出ずFalseが戻る
    using namespace System::Runtime::InteropServices;

    public ref class Form1 : public Form
    {
      [Flags]
      enum class SoundFlags : int { /* ●2 */ }; // ●こっちはクラス?

      private: [DllImport("winmm.dll")] // ●ここに private:
      static bool PlaySound
      (String^ soundName, IntPtr hmod, SoundFlags^ sf);

      public: Form1() {InitializeComponent();}

      private: void button_Click(Object^ sender, EventArgs^ e)
      {
        MessageBox::Show
        ( PlaySound("Alarm01.wav", IntPtr::Zero, SoundFlags::SND_FILENAME | SoundFlags::SND_ASYNC).ToString() );
      }
    }; // ref class

    ////////////////////////////////////////////////////////////////////

    // ●1 [Flags]
    // 列挙型 (C# によるプログラミング入門)
    // http://ufcpp.net/study/csharp/st_enum.html
    // のフラグの部分
    // 論理演算させないようにする? (001|010を011にさせない)

    // ●2 C#もCLIもenum内部は以下の通りです
    // PlaySound 関数
    // http://msdn.microsoft.com/ja-jp/library/cc428768.aspx
    // のfdwSoundの部分
    {
      SND_SYNC  = 0x0000,
      SND_ASYNC  = 0x0001,
      SND_NODEFAULT  = 0x0002,
      SND_MEMORY  = 0x0004,
      SND_LOOP  = 0x0008,
      SND_NOSTOP  = 0x0010,
      SND_NOWAIT  = 0x00002000,
      SND_ALIAS  = 0x00010000,
      SND_ALIAS_ID  = 0x00110000,
      SND_FILENAME  = 0x00020000,
      SND_RESOURCE  = 0x00040004,
      SND_PURGE  = 0x0040,
      SND_APPLICATION = 0x0080
    }

    // ●3 [DllImport("")]
    // ネイティブなコードで作られたdll内の関数を、
    // マーシャリングすることでマネージなコードから扱えるようにする?

    2015年1月16日 14:43

回答

  • P/Invokeの宣言でSoundFlagsに^は要りません。

    private: [DllImport("winmm.dll")] // ●ここに private:
    static  bool PlaySound(String^ soundName, IntPtr hmod, SoundFlags sf);
    SoundFlagsの定義がenum classとなっていて参照型と勘違いしたのだと思いますが、名前空間付きのenumなので値型です。

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 回答としてマーク koujichiu 2015年1月17日 18:26
    2015年1月16日 17:30

すべての返信

  • P/Invokeの宣言でSoundFlagsに^は要りません。

    private: [DllImport("winmm.dll")] // ●ここに private:
    static  bool PlaySound(String^ soundName, IntPtr hmod, SoundFlags sf);
    SoundFlagsの定義がenum classとなっていて参照型と勘違いしたのだと思いますが、名前空間付きのenumなので値型です。

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 回答としてマーク koujichiu 2015年1月17日 18:26
    2015年1月16日 17:30
  • C++/CLIではC++ Interopといって、通常のC++と同様にWindows APIを呼び出すことができます。ですので、PlaySound()もドキュメントに従い#include <Windows.h>すればそのまま呼び出せますし、fdwSoundの定義も自分で記述する必要はありません。
    # なお、Windows APIの日本語ドキュメントはWindows xpまでを対象とした古いものですので、英語版を参照すべきです。
    2015年1月16日 21:57
  • gekka 様、 ご回答ありがとうございます

    出かけておりまして、お返事が遅くなってしまいました。

    ご指摘頂いたとおり、 引数sfの型をハンドル演算子^をはずした型にしましたら
    無事に音が出てtrueが戻るようになりました。 ありがとう御座いました。

    enum classというのは、
    どうもDateTime::NowやConsole::WriteLineなどのようにインスタンスを作らなくても静的に呼び出せる?
    のですね。

    このあたりの、
    「名前空間付きのenum」 「参照型 値型」 「静的メソッド」 「C++/CLI ハンドル」
    などをテーマにして調べていこうと思います。



    • 編集済み koujichiu 2015年1月17日 15:07
    2015年1月17日 14:54
  • 佐祐理 様、 ご回答ありがとうございました。

    「dllを読み込むのではなく、静的ライブラリを読み込む?」 というやり方で
    #pragma comment (lib, "winmm.lib")
    #include <windows.h>
    #include <mmsystem.h>
    のようなこともしてみたのですが、

    VisualStudioでウィンドウズフォームアプリの設定でForm1.hとmain.cppを自動作成
    させると、 main.cppでの#include "Form1.h"のせい?か、
    コンパイル時にmain.cppでたくさんエラーがでたので保留していたのですが、

    頂戴したリンク先などを調べながら、
    Win32の関数の使い方などの仕組みを調べていこうと思います。


    • 編集済み koujichiu 2015年1月17日 15:06
    2015年1月17日 15:01
  • 新規にCLIのウィンドウフォームを作りましたら音が鳴ったので、
    追記します m(_ _)m

    // CLI lib読み込み式
    #include <windows.h>
    #include <mmsystem.h>
    #pragma comment(lib, "winmm.lib")

    namespace soundTest_LIB {
      public ref class Form1 : public Form
      {

        private: void button_Click(Object^ sender, EventArgs^ e)
        {
          MessageBox::Show
          ( PlaySound(L"Alarm01.wav", NULL, SND_FILENAME | SND_ASYNC).ToString() );
        }

      }; // ref class
    } // namespace

    2015年1月17日 18:23