2021年12月5日日曜日

4つの数字で10を作るアレ その1

 先日、久しぶりに電車に乗っていたら、"3,4,7,8から10を作れ"と書いてある広告を見かけました。

 昔は切符に4つの数字が書いてあったのでよくやったものです。ICカードになってからは全然やらないですが。


 さておき。パズルを解く気分で少し解いてみました。プログラミングの勉強には比較的良い題材だと思います。


やることは4つの数字から2つ選んで四則演算。それを繰り返して10を作るだけです。

- 1回目の計算:順番を考慮して4つから2つ選ぶ方法は12通り

- 2回目の計算:1回目の計算結果と残りの2つから2つを選ぶ方法は6通り

- 3回目の計算:残っている数字を選ぶ方法は2通り

- 四則演算:4通り

よって、すべての組み合わせは、12 * 4 * 6 * 4 * 2 * 4 = 9216通りです。たかだか1万通りくらいです。Excel VBAでリストアップしてみましょう。


 ソースコードはご自由にご利用ください。ただし、趣味のプログラムなので保証はありません。

------------------------------

Option Explicit


Dim row As Long

Dim col As Long


Const epsilon As Double = 0.000001


Public Sub Calc10()

    Sheet1.Cells.Clear

    

    row = 1

    col = 1

    

    Call Calc10A(1, 1, 9, 9)

End Sub


'演算子の表示

Public Function OperationText(op As Long) As String

    OperationText = ""

    

    If op = 0 Then

        OperationText = "'+"

    ElseIf op = 1 Then

        OperationText = "'-"

    ElseIf op = 2 Then

        OperationText = "'*"

    ElseIf op = 3 Then

        OperationText = "'/"

    End If

End Function


'演算

Public Function OperationCalc(op As Long, a0 As Double, a1 As Double) As Double

    OperationCalc = a0

    

    If op = 0 Then

        OperationCalc = a0 + a1

    ElseIf op = 1 Then

        OperationCalc = a0 - a1

    ElseIf op = 2 Then

        OperationCalc = a0 * a1

    ElseIf op = 3 Then

        If Math.Abs(a1) < epsilon Then

            OperationCalc = a0

        Else

            OperationCalc = a0 / a1

        End If

    End If

End Function


'a(0) - a(3)    :   0 - 9の数字4つ

'a(4)   :   1回目の演算結果

'a(5)   :   2回目の演算結果

'a(6)   :   3回目の演算結果

Public Sub Calc10A(a0 As Long, a1 As Long, a2 As Long, a3 As Long)

    '---------- 演算子選択のIndex ----------

    Dim i0 As Long

    Dim i1 As Long

    Dim i2 As Long

    

    '---------- 数字選択のIndex ----------

    Dim j0 As Long

    Dim j1 As Long

    Dim j2 As Long

    Dim j3 As Long

    Dim j4 As Long

    Dim j5 As Long

    

    '------------------------------

    Dim a(6) As Double

    

    a(0) = a0

    a(1) = a1

    a(2) = a2

    a(3) = a3

    a(4) = 0

    a(5) = 0

    a(6) = 0

    

    '---------- 1回目の演算 ----------

    For i0 = 0 To 3

        For j0 = 0 To 3

            For j1 = 0 To 3

                If j1 <> j0 Then

                

                    a(4) = OperationCalc(i0, a(j0), a(j1))

                                      

                    '---------- 2回目の演算 ----------

                    For i1 = 0 To 3

                        For j2 = 0 To 4

                            If j2 <> j0 And j2 <> j1 Then

                                For j3 = 0 To 4

                                    If j3 <> j0 And j3 <> j1 And j3 <> j2 Then

                                    

                                        a(5) = OperationCalc(i1, a(j2), a(j3))

                                                            

                                        '---------- 3回目の演算 ----------

                                        For i2 = 0 To 3

                                            For j4 = 0 To 5

                                                If j4 <> j0 And j4 <> j1 And j4 <> j2 And j4 <> j3 Then

                                                    For j5 = 0 To 5

                                                        If j5 <> j0 And j5 <> j1 And j5 <> j2 And j5 <> j3 And j5 <> j4 Then

                                                        

                                                            a(6) = OperationCalc(i2, a(j4), a(j5))

                                                            

                                                            '---------- 1回目の演算の表示 ----------

                                                            Sheet1.Cells(row, col + 0) = OperationText(i0)

                                                            Sheet1.Cells(row, col + 1) = a(j0)

                                                            Sheet1.Cells(row, col + 2) = a(j1)

                                                            col = col + 3

                                                            

                                                            If i0 = 3 And Math.Abs(a(j1)) < epsilon Then

                                                                Sheet1.Cells(row, col) = "Divided by Zero"

                                                                GoTo label

                                                            End If

                                                                

                                                            '---------- 2回目の演算の表示 ----------

                                                            Sheet1.Cells(row, col + 0) = OperationText(i1)

                                                            Sheet1.Cells(row, col + 1) = a(j2)

                                                            Sheet1.Cells(row, col + 2) = a(j3)

                                                            col = col + 3

                                                            

                                                            If i1 = 3 And Math.Abs(a(j3)) < epsilon Then

                                                                Sheet1.Cells(row, col) = "Divided by Zero"

                                                                GoTo label

                                                            End If

                                                            

                                                            '---------- 3回目の演算の表示 ----------

                                                            Sheet1.Cells(row, col + 0) = OperationText(i2)

                                                            Sheet1.Cells(row, col + 1) = a(j4)

                                                            Sheet1.Cells(row, col + 2) = a(j5)

                                                            col = col + 3

                                                            

                                                            If i2 = 3 And Math.Abs(a(j5)) < epsilon Then

                                                                Sheet1.Cells(row, col) = "Divided by Zero"

                                                                GoTo label

                                                            End If

                                                            

                                                            '------------------------------

                                                            Sheet1.Cells(row, 10) = a(6)

label:

                                                            row = row + 1

                                                            col = 1

                                                        End If

                                                    Next j5

                                                End If

                                            Next j4

                                        Next i2

                                        '------------------------------

                                    End If

                                Next j3

                            End If

                        Next j2

                    Next i1

                    '------------------------------

                End If

            Next j1

        Next j0

    Next i0

    '------------------------------

End Sub


4つの数字で10を作るアレ その2

  前回作成したマクロは、ループの書き方がカッコ悪い感じです。再帰関数を使って、少し見やすくしてみます。

 ついでに無駄な計算を少し省略します。以下の2つは省略可能です。

- 四則演算のうち、足し算と掛け算は可換なので半分は不要

- 1回目の計算と2回目の計算が交換できる場合も半分は不要


 ソースコードはご自由にご利用ください。ただし、趣味のプログラムなので保証はありません。

'------------------------------

Option Explicit


Dim row As Long

Dim col As Long


Const epsilon As Double = 0.000001




Public Sub Calc10()

    Sheet1.Cells.Clear

    

    row = 1

    col = 1

    

    Call Calc10B(3, 4, 7, 8)

End Sub


'演算子の表示
Public Function OperationText(op As Long) As String
    OperationText = ""
    
    If op = 0 Then
        OperationText = "'+"
    ElseIf op = 1 Then
        OperationText = "'-"
    ElseIf op = 2 Then
        OperationText = "'*"
    ElseIf op = 3 Then
        OperationText = "'/"
    End If
End Function

'演算
Public Function OperationCalc(op As Long, a0 As Double, a1 As Double) As Double
    OperationCalc = a0
    
    If op = 0 Then
        OperationCalc = a0 + a1
    ElseIf op = 1 Then
        OperationCalc = a0 - a1
    ElseIf op = 2 Then
        OperationCalc = a0 * a1
    ElseIf op = 3 Then
        If Math.Abs(a1) < epsilon Then
            OperationCalc = a0
        Else
            OperationCalc = a0 / a1
        End If
    End If
End Function


'再帰関数を使う場合

Public Sub Calc10B(a0 As Long, a1 As Long, a2 As Long, a3 As Long)

    Dim a(6) As Double

    Dim op(2) As Long   '演算子のIndex

    Dim nm(5) As Long   '数字のIndex

    

    a(0) = a0

    a(1) = a1

    a(2) = a2

    a(3) = a3

    a(4) = 0

    a(5) = 0

    a(6) = 0

    

    Call Calc10B_iterate(a, op, nm, 0)

End Sub


Public Sub Calc10B_iterate(ByRef a() As Double, ByRef op() As Long, ByRef nm() As Long, cnt As Long)

    Dim i As Long

    Dim j As Long

    Dim k As Long

    Dim l As Long

    

    If cnt < 3 Then

        '----- Operator -----

        For i = 0 To 3

            op(cnt) = i

            

            '----- 1st number -----

            For j = 0 To 3 + cnt

                For l = 0 To 2 * cnt - 1

                    If j = nm(l) Then

                        Exit For

                    End If

                Next l

            

                If l <> 2 * cnt Then

                    GoTo label0

                End If

                

                nm(l) = j

                    

                '----- 2nd number -----

                For k = 0 To 3 + cnt

                    For l = 0 To 2 * cnt

                        If k = nm(l) Then

                            Exit For

                        End If

                    Next l

                    

                    If l <> 2 * cnt + 1 Then

                        GoTo label1

                    End If

                    

                    nm(l) = k

                    

                    '演算子が交換可能なとき

                    If (i = 0 Or i = 2) And k < j Then

                        GoTo label1

                    End If

                    

                    '1回目の演算と2回目の演算が交換可能なとき

                    '((a0,a1),(a2,a3)), ((a0,a2),(a1,a3)), ((a0,a3),(a1,a2)) の組み合わせは計算する

                    '((a1,a2),(a0+a3)), ((a1,a3),(a0,a2)), ((a2,a3),(a0,a1)) の組み合わせは計算しない

                    If cnt = 1 Then

                        If (j = 0 And (k = 1 Or k = 2 Or k = 3)) _

                        Or ((j = 1 Or j = 2 Or j = 3) And k = 0) Then

                            GoTo label1

                        End If

                    End If

                    

                    '----- Operation -----

                    a(4 + cnt) = OperationCalc(i, a(j), a(k))

                    

                    '----------

                    Call Calc10B_iterate(a, op, nm, cnt + 1)

label1:

                Next k

                '----------

label0:

            Next j

            '----------

        Next i

        '----------

    ElseIf cnt = 3 Then

        Call Calc10B_result(a, op, nm)

    End If

End Sub


Public Sub Calc10B_result(ByRef a() As Double, ByRef op() As Long, ByRef nm() As Long)

        '---------- 1回目の演算 ----------

        Sheet1.Cells(row, col + 0) = OperationText(op(0))

        Sheet1.Cells(row, col + 1) = a(nm(0))

        Sheet1.Cells(row, col + 2) = a(nm(1))

        col = col + 3

        

        If op(0) = 3 And Math.Abs(a(nm(1))) < epsilon Then

            Sheet1.Cells(row, col) = "Divided by Zero"

            GoTo label

        End If

        

        '---------- 2回目の演算 ----------

        Sheet1.Cells(row, col + 0) = OperationText(op(1))

        Sheet1.Cells(row, col + 1) = a(nm(2))

        Sheet1.Cells(row, col + 2) = a(nm(3))

        col = col + 3

        

        If op(1) = 3 And Math.Abs(a(nm(3))) < epsilon Then

            Sheet1.Cells(row, col) = "Divided by Zero"

            GoTo label

        End If

        

        '---------- 3回目の演算 ----------

        Sheet1.Cells(row, col + 0) = OperationText(op(2))

        Sheet1.Cells(row, col + 1) = a(nm(4))

        Sheet1.Cells(row, col + 2) = a(nm(5))

        col = col + 3

        

        If op(2) = 3 And Math.Abs(a(nm(5))) < epsilon Then

            Sheet1.Cells(row, col) = "Divided by Zero"

            GoTo label

        End If

        

        '------------------------------

        Sheet1.Cells(row, col) = a(6)

label:

        row = row + 1

        col = 1

End Sub


4つの数字で10を作るアレ その3

 今回は、4つの数字の組み合わせ全てで計算してみます。

 0から9までの数字を4つ選ぶ方法は10000通りですが、順序の入れ替えを考慮すると715通りです(重複ありの組み合わせです)。715通りで10になるパターンを探すだけなので、計算は意外に重たくないです。

 今回は、再帰関数を使いませんでした。(ちなみに、再帰関数を使った場合、途中でループから抜けるのが、少し面倒です。)


 計算途中に小数が出てくる(3,4,7,8)(1,1,9,9)(1,3,3,7)のようなパターンは少し難しい感じです。


 ソースコードはご自由にご利用ください。ただし、趣味のプログラムなので保証はありません。


'------------------------------

 Option Explicit


Dim row As Long

Dim col As Long


Const epsilon As Double = 0.000001


Public Sub Calc10All()

    Dim a0 As Long

    Dim a1 As Long

    Dim a2 As Long

    Dim a3 As Long

    

    Sheet1.Cells.Clear

    

    row = 1

    col = 1


    For a0 = 0 To 9

        For a1 = a0 To 9

            For a2 = a1 To 9

                For a3 = a2 To 9

                    Sheet1.Cells(row, col + 0) = a0

                    Sheet1.Cells(row, col + 1) = a1

                    Sheet1.Cells(row, col + 2) = a2

                    Sheet1.Cells(row, col + 3) = a3

                    col = col + 4

                    

                    Call Calc10All_iterate(a0, a1, a2, a3)

                    row = row + 1

                    col = 1

                Next a3

            Next a2

        Next a1

    Next a0

End Sub


'演算子の表示

Public Function OperationText(op As Long) As String

    OperationText = ""

    

    If op = 0 Then

        OperationText = "'+"

    ElseIf op = 1 Then

        OperationText = "'-"

    ElseIf op = 2 Then

        OperationText = "'*"

    ElseIf op = 3 Then

        OperationText = "'/"

    End If

End Function




Public Sub Calc10All_iterate(a0 As Long, a1 As Long, a2 As Long, a3 As Long)

    '---------- 演算子選択のIndex ----------

    Dim i0 As Long

    Dim i1 As Long

    Dim i2 As Long

    

    '---------- 数字選択のIndex ----------

    Dim j0 As Long

    Dim j1 As Long

    Dim j2 As Long

    Dim j3 As Long

    Dim j4 As Long

    Dim j5 As Long

    

    '------------------------------

    Dim a(6) As Double

    

    a(0) = a0

    a(1) = a1

    a(2) = a2

    a(3) = a3

    a(4) = 0

    a(5) = 0

    a(6) = 0

    

    '---------- 1回目の演算 ----------

    For i0 = 0 To 3

        For j0 = 0 To 3

            For j1 = 0 To 3

                If j1 = j0 Then

                    GoTo label0

                End If

                

                a(4) = OperationCalc(i0, a(j0), a(j1))

                                  

                '---------- 2回目の演算 ----------

                For i1 = 0 To 3

                    For j2 = 0 To 4

                        If j2 = j0 Or j2 = j1 Then

                            GoTo label1

                        End If

                            

                        For j3 = 0 To 4

                            If j3 = j0 Or j3 = j1 Or j3 = j2 Then

                                GoTo label2

                            End If

                            

                            a(5) = OperationCalc(i1, a(j2), a(j3))

                                                

                            '---------- 3回目の演算 ----------

                            For i2 = 0 To 3

                                For j4 = 0 To 5

                                    If j4 = j0 Or j4 = j1 Or j4 = j2 Or j4 = j3 Then

                                        GoTo label3

                                    End If

                                    

                                    For j5 = 0 To 5

                                        If j5 = j0 Or j5 = j1 Or j5 = j2 Or j5 = j3 Or j5 = j4 Then

                                            GoTo label4

                                        End If

                                        

                                        a(6) = OperationCalc(i2, a(j4), a(j5))

                                        

                                        '------------------------------

                                        If Math.Abs(a(6) - 10) < epsilon Then

                                            Sheet1.Cells(row, col + 0) = OperationText(i0)

                                            Sheet1.Cells(row, col + 1) = a(j0)

                                            Sheet1.Cells(row, col + 2) = a(j1)

                                            col = col + 3

                                            

                                            Sheet1.Cells(row, col + 0) = OperationText(i1)

                                            Sheet1.Cells(row, col + 1) = a(j2)

                                            Sheet1.Cells(row, col + 2) = a(j3)

                                            col = col + 3

                                            

                                            Sheet1.Cells(row, col + 0) = OperationText(i2)

                                            Sheet1.Cells(row, col + 1) = a(j4)

                                            Sheet1.Cells(row, col + 2) = a(j5)

                                            col = col + 3

                                            

                                            Sheet1.Cells(row, col) = a(6)

                                            

                                            Exit Sub

                                        End If

                                        '------------------------------

label4:

                                    Next j5

label3:

                                Next j4

                            Next i2

                            '------------------------------

label2:

                        Next j3

label1:

                    Next j2

                Next i1

                '------------------------------

label0:

            Next j1

        Next j0

    Next i0

    '------------------------------

    Sheet1.Cells(row, 14) = "Not 10"

End Sub



2021年9月5日日曜日

理解の仕方

 「孫子の兵法」の話の続きです。

 私は、守屋先生の孫子の兵法を読んで以来、それが「孫子の兵法」だと思っていました。


 最近、ふと別の方の「孫子の兵法」に関する著作を読んで、人によって理解の仕方は違うものだなぁと思いました。


 まぁ、当たり前の話ですが。何が重要と考えるかは、人によって違って当然です。


 というわけで、私も自分が理解した内容をまとめてみました。


 かの曹操も、自ら「孫子の兵法」の注釈書を記したらしいです。読んでみたら、また別の発見があって面白いかもしれません。


兵法に学ぶ 4 --- 終わり方 ---

------------------------------

 一般に、物事の終結というのは難しいものです。名君が後継の育成に失敗するという逸話はよくあります。株なんかも、勢いがあって儲かっているときはいいですが、そこからの引き際は非常に難しいと聞きます。


 「孫子の兵法」においては、国家・社会が存続するなら、一つの戦いの終わりは、次への始まりです。つまり準備の段階に戻るだけです。

 きちんとした情報収集と情勢判断ができれば、適切な終結も見えてくるはずです。


------------------------------

「窮寇には迫ることなかれ」「囲師には必ずかき」

 追い込まれた敵は必死の抵抗をしてきます。「窮鼠猫を噛む」という言葉の通りです。死にものぐるいの反撃を受けるくらいなら、あえて敵の逃げ道を作った方が得策でしょう。敵を誘導しているなら、主導権はこちらにあります。


------------------------------

 近頃、正論で相手を論破するというのが流行している気がします。

 相手を論破するというのは派手な勝利に見えますが、追い込まれた相手が無茶苦茶な反撃をすることも考えられます。相手の逃げ道を用意して誘導するのが、兵法に則った戦略だと思います。

 敢えて敵を作る必要はありません。


------------------------------

 古の名将・名君は、一つの勝利に浮かれることなく、先を見越して、次の戦いの準備を進めていたと思います。

 「勝って兜の緒を締めよ」ということです。


兵法に学ぶ 3 --- 行動について ---

------------------------------

「疾きこと風のごとし」

 戦いに勝つための行動の基本は、素早く、勢いよくです。

 第2次大戦時のドイツの電撃作戦しかり、古今東西の戦争では、素早く、勢いのある戦法が勝利しています。


------------------------------

「兵は拙速を聞くも、いまだ巧の久しきをみざるなり」

 拙速というのは、速くても拙い(まずい)ということです。分かり易くパターンを書き出してみると、

 1. 速くて、まずい

 2. 速くて、うまい

 3. 遅くて、まずい

 4. 遅くて、うまい

の4パターンが考えられます (ラーメン屋ではありませんが)。このうち、4.のパターンは基本的にはあり得ません。遅い=時間がかかる、というのは、それだけで消耗しているからです。2.が最良、1が次善であれば、とにかく速く行動することは、望ましいことです。


 もちろん、速ければ何でもいいわけではありません。「急いてはことを仕損じる」という言葉もあります。どんなに行動が速くても、内容が良くなければ、やっぱり失敗です。

 目指すべきは速くて巧いです。


 言い換えるなら、夏休みの宿題は早々に手を付けましょう、ということです。


------------------------------

「人を致して人に致されず」

 後手後手の対策には、スピードもなく、勢いもありません。主導権を取って、先手で行動することが大事です。

 事前の準備が整っていれば、必ず先手の行動がとれるはずです。


------------------------------

「死地に陥れて然る後に生く」

 "背水の陣"というのがあります。自軍をあえて危機的な状況に追い込み、兵を死にものぐるいで戦わせる、という戦術です。死にものぐるいなのだから、勢いはあるでしょう。


 社員に危機感を煽ろうとする経営者がいたりします。背水の陣のやり方でしょう。がむしゃらに働けば、活路が見いだされるかもしれません。


 ただし、常に危機感を煽ってばかりでは、社員が疲弊するだけです。社員が疲弊していたら、勢いが出ません。


 また、危機感だけ煽っても、取り組むべき課題が見えていなければ、迷走するだけです。やはり勢いが出ません。これは状況分析が不足しています。


------------------------------

 話はそれますが、兵法書の呉子には、"将軍は手続きを簡素化すべき"、といったことが書かれているそうです。

 行動を起こすときに、煩雑な手続きがあると、勢いがそがれてしまいます。「孫子の兵法」と同じ思考だと思います。


 ・・・お役所の手続きも簡素化して欲しいものです。


------------------------------

「人をして慮ることを得ざらしむ」

 一度行動を起こしたら、その後は深く考えず、勢いに任せて突き進むのがうまいやり方です。


 「孫子の兵法」には、"作戦は将軍が考え、兵隊は何も考えないでいい"、とあります。少し悩ましいです。


 私が思うに、勢いのある行動は大事なんですが、兵隊は何も考えないでいいわけではないです。将軍が間違っていたら、何も考えないうちに全滅してしまいます。


 複雑化した現代社会において、必ずしもリーダーの選択が正しいとは限りません。リーダーの間違いに気づくためには、部下もしっかり考えた方がいいでしょう。


兵法に学ぶ 2 --- 準備について ---

------------------------------

「彼を知り己れを知れば、百戦してあやうからず」

 「孫子の兵法」の戦略の基本は綿密な準備です。事前の情報収集が完璧なら負けることはありません。勝てない可能性はありますが、負けなければ、いつかは勝てます。


 完璧な情報を集めることは難しいですが、労力を惜しんではいけません。労力を惜しんで、負けてしまったら、すべてが終わりです。


------------------------------

「勝ち易きに勝つ」

 綿密な調査を行い、勝てる見込みがあるところで戦えば、勝ちは手堅いでしょう。


 ハイリスク・ハイリターンという言葉もありますが、国がリスクを冒して滅んでしまっては最悪です。最低でも"負けない見込み"は確保すべきです。


------------------------------

「兵を形するの極は無形に至る」

 「孫子の兵法」には勝つための答えが書いてあるわけではありません。"最強の陣形"があるわけではないのです。

 情報を集めて、考えて、状況に応じて臨機応変に変化することが大事です。


------------------------------

 過去の事例を学んで、アイデアをいくつも持っているというのは大切なことです。実績のある方法は参考になります。

 ですが、それに従ってばかりではいけません。情勢は常に変化します。過去の事例と同じ状況にはなりません。

 考えることを怠ると、馬謖と同じ道を辿ります。


 情報を集めて、考えて、状況に応じて臨機応変に変化する、そうすれば負けることはないはずです。


------------------------------

 ちなみに、戦う相手も兵法に習熟していたらどうなるでしょう?

 自分と相手の力がほぼ対等で、どちらも十分に情勢を見極められるなら、おそらくは、お互い負けないところに収まるでしょう。


兵法に学ぶ 1 --- 目標について ---

------------------------------

「兵は国の大事」

 兵法とは戦争に勝つための方法ですが、「孫子の兵法」が目的とするところは、単に戦争に勝つことではありません。国家・社会を存続 (繁栄) させることです。


 戦争には大きな労力が必要です。負ければ国家・社会の存続を危うくします。だからこそ負けるわけにはいかないんです。負けなければ、いつか勝ちが見えることもあるでしょう。


------------------------------

「百戦百勝は善の善たるものにあらず」

 戦争は大きな労力を消費するのだから、戦わずに勝てるなら、それが最善です。逆に、戦って消耗して負けるのが最悪です。戦って負けるくらいなら、戦わずに撤退を選ぶべきです。


 勝つことを目的と勘違いして、戦いを繰り返し、国家・社会を疲弊させてしまっては、本末転倒です。

 目的を正しく見据えないといけません。


------------------------------

 正しい目標を見据えることは、戦争に限らず、とても重要なことです。


 目標が間違っていたら、本来望んでいる結果が得られないかもしれません。それでは本末転倒です。正しい目標を設定することは、とても重要です。


 (例えば、経済政策の目標として、株価の上昇を掲げるのは、正しい目標でしょうか?数値目標を設定するのは分かり易いですが、よく考える必要があります。)


------------------------------

 その昔、房玄齢杜如晦という名宰相がいたそうです。

 どちらも名宰相として知られているのに、目立った成果を残していないとのことです。本当の名宰相であれば、仮に問題が発生したとしても、それが大きくなる前に対処するので、目立った成果にはならないでしょう。目立った成果にならなかったとしても、目的は達成されています。


------------------------------

 近頃は、成果主義を採用する企業も多いようです。ですが、目立った成果を上げることばかりが評価項目ではないはずです。


 評価される成果をアピールするために、何かしらのイベントを繰り返す。どこぞの政治家がやりそうなことですが、それは兵法の教えとは相容れない感じです。


 特に大きな成果はないが大きな問題もなく、時世が変化する中でさえも、安定に繁栄を続けたなら、それは偉大な仕事です。


兵法に学ぶ --- はじめに ---

 守屋先生の孫子の兵法を読みました。


 昔から何度か読んでいる本です。孫子の兵法に書かれている内容は非常に合理的で、学ぶべきところがあると思います。


 というわけで、少し私なりの解釈を書いてみようと思います。


Amazon 孫子の兵法


2021年8月7日土曜日

C#でMusic Playerを作ろう 2

 前回はmciSendString関数を色々試したので、今回はそれを使って簡単なMusic Playerを作ります。ソースコードは530行だけなので簡単です。


 今回のソフトを作るときに一番苦労したのはUIのデザインです。

 最初は、曲を移動するための"Next"、"Prev"ボタンとか、リストから1曲削除するボタンとか、"Pause/Resume"機能とかも作ったのですが、結局、やめました。とにかく単純にしたかったから。

 ちなみに、音量操作をトラックバーではなく、ボタンにしたのは、見た目が理由です。トラックバーだと、再生位置用のトラックバーとかぶるんで。

 リストの保存とか、ファイルの拡張子の制限とか、ほかにも機能は色々追加できるんですが。まぁ、なくてもいいかなぁ、という感じです。

 結果、コンパイルしたら12KBでした。こういう軽いソフトが好きなんです。


 ソースコードはご自由にご利用ください。ただし、趣味のプログラムなので保証はありません。



using System;

using System.IO;

using System.Text;

using System.Drawing;

using System.Windows.Forms;

using System.Runtime.InteropServices;

using System.Collections.Generic;


/*--------------------------------------------------*/

class Program

{

[STAThread]


static void Main()

{

Application.Run( new MusicPlayer());

}

}


/*--------------------------------------------------*/

class MusicPlayer : Form

{

/*--------------------------------------------------*/

[DllImport( "Winmm.dll")]

extern static int mciSendString( string cmd, System.Text.StringBuilder retStr, uint ret, IntPtr hwnd);


/*--------------------------------------------------*/

private MenuStrip ms;

private ToolStripMenuItem[][] tsmi;


private Label lbl;

private ListBox lbx;

private List<string> lst;


private TextBox tbx;

private TrackBar tbr;


private Button[] btn;


private const string DeviceID = "mysound";


private int volume;


private Timer tmr;


/*--------------------------------------------------*/

public MusicPlayer()

{

/*--------------------------------------------------*/

this.ClientSize = new Size( 280, 360);

this.Text = "Music Player";


this.Load += new EventHandler( this.Form_Load);

this.Closed += new EventHandler( this.Form_Closed);


this.AllowDrop = true;

this.DragEnter += new DragEventHandler( this.Form_DragEnter);

this.DragDrop += new DragEventHandler( this.Form_DragDrop);


/*--------------------------------------------------*/

this.CreateMenu();


/*--------------------------------------------------*/

this.lbl = new Label();

this.lbl.SetBounds( 20, 30, 240, 30);

this.lbl.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right;

this.lbl.TextAlign = ContentAlignment.MiddleLeft;

this.lbl.Text = "Play List";

this.Controls.Add( this.lbl);


/*--------------------------------------------------*/

this.lbx = new ListBox();

this.lbx.SetBounds( 20, 60, 240, 160);

this.lbx.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom;

this.lbx.HorizontalScrollbar = true;

this.Controls.Add( this.lbx);


/*--------------------------------------------------*/

this.tbx = new TextBox();

this.tbx.SetBounds( 20, 230, 240, 20);

this.tbx.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom;

this.tbx.BorderStyle = BorderStyle.None;

this.tbx.ReadOnly = true;

this.Controls.Add( this.tbx);

this.tbr = new TrackBar();

this.tbr.SetBounds( 20, 250, 240, 50);

this.tbr.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom;

this.tbr.MouseUp += new MouseEventHandler( this.tbr_MouseUp);

this.Controls.Add( this.tbr);


/*--------------------------------------------------*/

this.btn = new Button[4];


this.btn[0] = new Button();

this.btn[0].SetBounds( 20, 300, 60, 40);

this.btn[0].Anchor = AnchorStyles.Bottom;

this.btn[0].Text = ">";

this.btn[0].Click += new EventHandler( this.btn_Play_Click);

this.Controls.Add( this.btn[0]);


this.btn[1] = new Button();

this.btn[1].SetBounds( 80, 300, 60, 40);

this.btn[1].Anchor = AnchorStyles.Bottom;

this.btn[1].Text = "||";

this.btn[1].Click += new EventHandler( this.btn_Stop_Click);

this.Controls.Add( this.btn[1]);


this.btn[2] = new Button();

this.btn[2].SetBounds( 140, 300, 60, 40);

this.btn[2].Anchor = AnchorStyles.Bottom;

this.btn[2].Text = "Vol.-";

this.btn[2].Click += new EventHandler( this.btn_VolumeDown_Click);

this.Controls.Add( this.btn[2]);


this.btn[3] = new Button();

this.btn[3].SetBounds( 200, 300, 60, 40);

this.btn[3].Anchor = AnchorStyles.Bottom;

this.btn[3].Text = "Vol.+";

this.btn[3].Click += new EventHandler( this.btn_VolumeUp_Click);

this.Controls.Add( this.btn[3]);

}


/*--------------------------------------------------*/

private void Form_Load( object sender, EventArgs e)

{

Console.WriteLine( "Form_Load");


this.lst = new List<string>();


this.volume = 10;


this.tmr = new Timer();

this.tmr.Interval = 1000;

this.tmr.Tick += new EventHandler( this.timer_Tick);

}

private void Form_Closed( object sender, EventArgs e)

{

Console.WriteLine( "Form_Closed");


this.tmr.Enabled = false;


string cmd = "stop " + MusicPlayer.DeviceID;

int ret = mciSendString( cmd, null, 0, IntPtr.Zero);

Console.WriteLine( cmd);


cmd = "close " + MusicPlayer.DeviceID;

ret = mciSendString( cmd, null, 0, IntPtr.Zero);

Console.WriteLine( cmd);

}


/*--------------------------------------------------*/

private void Form_DragEnter( object sender, DragEventArgs e)

{

if( e.Data.GetDataPresent( DataFormats.FileDrop))

{

e.Effect = DragDropEffects.Move;

}

}

private void Form_DragDrop( object sender, DragEventArgs e)

{

string[] filenames = (string[]) e.Data.GetData( DataFormats.FileDrop, false);


this.lbx_Add( filenames);

}


/*--------------------------------------------------*/

private void CreateMenu()

{

this.ms = new MenuStrip();


this.tsmi = new ToolStripMenuItem[2][];

this.tsmi[0] = new ToolStripMenuItem[4];

this.tsmi[1] = new ToolStripMenuItem[3];


for( int i = 0; i < this.tsmi.Length; i++)

{

for( int j = 0; j < this.tsmi[i].Length; j++)

{

this.tsmi[i][j] = new ToolStripMenuItem();

}

}


this.tsmi[0][0].Text = "File";

this.tsmi[0][1].Text = "Select";

this.tsmi[0][2].Text = "Clear";

this.tsmi[0][3].Text = "Exit (&X)";

this.tsmi[1][0].Text = "MCI";

this.tsmi[1][1].Text = "Play";

this.tsmi[1][2].Text = "Stop";


for( int i = 0; i < this.tsmi.Length; i++)

{

this.ms.Items.Add( this.tsmi[i][0]);


for( int j = 1; j < this.tsmi[i].Length; j++)

{

this.tsmi[i][0].DropDownItems.Add( this.tsmi[i][j]);

this.tsmi[i][j].Click += new EventHandler( this.Menu_Click);

}

}


this.Controls.Add( this.ms);

this.MainMenuStrip = ms;

}


/*--------------------------------------------------*/

/* Menuのイベント処理 */

/*--------------------------------------------------*/

private void Menu_Click( object sender, EventArgs e)

{

Console.WriteLine( sender.ToString());


if( sender == this.tsmi[0][1])

{

OpenFileDialog ofd = new OpenFileDialog();

ofd.Filter = "All files | *.*";

ofd.Multiselect = true;


if( ofd.ShowDialog() == DialogResult.OK)

{

this.lbx_Add( ofd.FileNames);

}

}

else if( sender == this.tsmi[0][2])

{

this.lbx_Clear();

}

else if( sender == this.tsmi[0][3])

{

this.Close();

}

else if( sender == this.tsmi[1][1])

{

this.btn_Play_Click( null, null);

}

else if( sender == this.tsmi[1][2])

{

this.btn_Stop_Click( null, null);

}

}


/*--------------------------------------------------*/

/* リストの処理 */

/*--------------------------------------------------*/

private void lbx_Add( string[] filenames)

{

for( int i = 0; i < filenames.Length; i++)

{

Console.WriteLine( filenames[i]);


this.lst.Add( filenames[i]);

this.lbx.Items.Add( Path.GetFileName( filenames[i]));

this.lbx.SelectedIndex = this.lbx.Items.Count - 1;

}

}


private void lbx_Clear()

{

this.lst.Clear();

this.lbx.Items.Clear();

}


/*--------------------------------------------------*/

/* Buttonのイベント処理 */

/*--------------------------------------------------*/

private void btn_Play_Click( object sender, EventArgs e)

{

Console.WriteLine( "btn_Play_Click");


string status = this.mciGetStatus();


if( status == "")

{

if( this.lbx.SelectedIndex == -1)

{

return;

}


this.mciOpen( this.lst[this.lbx.SelectedIndex]);

this.mciPlay();

}

else if( status  == "playing")

{

return;

}

else if( status  == "stopped")

{

this.mciPlay();

}

}


private void btn_Stop_Click( object sender, EventArgs e)

{

Console.WriteLine( "btn_Stop_Click");

string status = this.mciGetStatus();


if( status == "")

{

return;

}

else if( status  == "playing")

{

this.mciStop();

}

else if( status  == "stopped")

{

this.mciClose();

}

}


private void btn_VolumeDown_Click( object sender, EventArgs e)

{

Console.WriteLine( "btn_VolumeDown_Click");


string status = this.mciGetStatus();


if( status != "")

{

this.mciVolumeDown();

}

}


private void btn_VolumeUp_Click( object sender, EventArgs e)

{

Console.WriteLine( "btn_VolumeUp_Click");


string status = this.mciGetStatus();


if( status != "")

{

this.mciVolumeUp();

}

}


/*--------------------------------------------------*/

/* TrackBarのイベント処理 */

/*--------------------------------------------------*/

private void tbr_MouseUp( object sender, MouseEventArgs e)

{

Console.WriteLine( "tbr_MouseUp");


string status = this.mciGetStatus();


if( status != "")

{

this.tmr.Enabled = false;

this.mciSeek( this.tbr.Value);

}

}


/*--------------------------------------------------*/

/* 再生中のタイマーイベント */

/*--------------------------------------------------*/

private void timer_Tick( object sender, EventArgs e)

{

Console.WriteLine( "timer tick");


/*--------------------------------------------------*/

string str = this.mciGetStatus();


/*--------------------------------------------------*/

StringBuilder retStr = new StringBuilder( 256);

string cmd = "status " + MusicPlayer.DeviceID + " position";

int ret = mciSendString( cmd, retStr, (uint) retStr.Capacity, IntPtr.Zero);


str += ", pos.:" + retStr.ToString();


this.tbr.Value = Convert.ToInt32( retStr.ToString());


cmd = "status " + MusicPlayer.DeviceID + " length";

ret = mciSendString( cmd, retStr, (uint) retStr.Capacity, IntPtr.Zero);


str += " / " + retStr.ToString();


/*--------------------------------------------------*/

cmd = "status " + MusicPlayer.DeviceID + " volume";

ret = mciSendString( cmd, retStr, (uint) retStr.Capacity, IntPtr.Zero);


str += ", vol.:" + retStr.ToString();


/*--------------------------------------------------*/

this.tbx.Text = str;

}


/*--------------------------------------------------*/

/* Notifyイベントの処理 */

/* 曲が終わったら、リストの次の曲を再生する (Stop or Seekから呼ばれた場合はreturn)

/*--------------------------------------------------*/

protected override void WndProc( ref Message m)

{

base.WndProc( ref m);


if( m.Msg == 0x03B9) //MM_MCINOTIFY message

{

Console.WriteLine( "Notify");


if( this.tmr.Enabled == false)

{

return;

}


this.mciStop();

this.mciClose();


if( ! ( 0 <= this.lbx.SelectedIndex && this.lbx.SelectedIndex < this.lbx.Items.Count - 1))

{

return;

}


this.lbx.SelectedIndex++;


this.mciOpen( this.lst[this.lbx.SelectedIndex]);

this.mciPlay();

}

}


/*--------------------------------------------------*/

/* MCIの状態を返す ("", "playing", "stopped"のいずれかになるはず) */

/*--------------------------------------------------*/

private string mciGetStatus()

{

StringBuilder retStr = new StringBuilder( 256);


string cmd = "status " + MusicPlayer.DeviceID + " mode";

int ret = mciSendString( cmd, retStr, (uint) retStr.Capacity, IntPtr.Zero);


Console.WriteLine( "mode : " + retStr);


return retStr.ToString();

}


/*--------------------------------------------------*/

/* MCI Open, Play, Stop, Close */

/*--------------------------------------------------*/

private void mciOpen( string filename)

{

/*--------------------------------------------------*/

string cmd = "open " + "\"" + filename + "\"" + " alias " + MusicPlayer.DeviceID;

int ret = mciSendString( cmd, null, 0, IntPtr.Zero);

Console.WriteLine( cmd);


/*--------------------------------------------------*/

cmd = "setaudio " + MusicPlayer.DeviceID + " volume to " + ( this.volume * 100).ToString();

ret = mciSendString( cmd, null, 0, IntPtr.Zero);

Console.WriteLine( cmd);


/*--------------------------------------------------*/

StringBuilder retStr = new StringBuilder( 256);


cmd = "status " + MusicPlayer.DeviceID + " length";

ret = mciSendString( cmd, retStr, (uint) retStr.Capacity, IntPtr.Zero);


this.tbr.Minimum = 0;

this.tbr.Maximum = Convert.ToInt32( retStr.ToString());

}


private void mciPlay()

{

string cmd = "play " + MusicPlayer.DeviceID + " notify";

int ret = mciSendString( cmd, null, 0, this.Handle);

Console.WriteLine( cmd);


this.tmr.Enabled = true;


this.timer_Tick( null, null);

}


private void mciStop()

{

this.tmr.Enabled = false;


string cmd = "stop " + MusicPlayer.DeviceID;

int ret = mciSendString( cmd, null, 0, IntPtr.Zero);

Console.WriteLine( cmd);


this.timer_Tick( null, null);

}


private void mciClose()

{

string cmd = "close " + MusicPlayer.DeviceID;

int ret = mciSendString( cmd, null, 0, IntPtr.Zero);

Console.WriteLine( cmd);


this.tbx.Text = "";

}


/*--------------------------------------------------*/

/* MCI Volume Down/Up */

/*--------------------------------------------------*/

private void mciVolumeDown()

{

this.volume = Math.Max( 0, this.volume - 1);

string cmd = "setaudio " + MusicPlayer.DeviceID + " volume to " + ( this.volume * 100).ToString();

int ret = mciSendString( cmd, null, 0, IntPtr.Zero);

Console.WriteLine( cmd);


this.timer_Tick( null, null);

}


private void mciVolumeUp()

{

this.volume = Math.Min( this.volume + 1, 10);

string cmd = "setaudio " + MusicPlayer.DeviceID + " volume to " + ( this.volume * 100).ToString();

int ret = mciSendString( cmd, null, 0, IntPtr.Zero);

Console.WriteLine( cmd);


this.timer_Tick( null, null);

}


/*--------------------------------------------------*/

/* MCI Seek */

/*--------------------------------------------------*/

private void mciSeek( int position)

{

string cmd = "seek " + MusicPlayer.DeviceID + " to " + position.ToString();

int ret = mciSendString( cmd, null, 0, IntPtr.Zero);

Console.WriteLine( cmd);


this.timer_Tick( null, null);

}

}


C#でMusic Playerを作ろう 1

 以前から思っていたのですが、パソコンで音楽を再生するソフトは重たいです。Windows Media Playerとか、Quick Timeとかですね。ただ、BGMが欲しいだけなのに。変な視覚エフェクトとか、ネットワークから情報を集めてきたりとか、そういうのはいらないんですが。。。

 というわけで、音楽再生のソフトを作ろうと思います。まぁ、Win32APIのmciSendString関数を使うだけの簡単なソフトです。


 手始めに、mciSendString関数を使って、色々試してみました。

 Statusの変化するタイミングとか、PauseとStopの違いとか、使ってみないと分からないこともあるもんです。面白かったのが、Volumeの設定です。Volumeは0-1000で変化するみたいですが、例えば800に設定しようとしても803になったりしました。ハードウェアの都合なのかもしれません。へぇー。


 ソースコードはご自由にご利用ください。ただし、趣味のプログラムなので保証はありません。

 (ちなみに、メニューを作っているのは、ウィルス対策ソフトと戦ったからです。)


using System;

using System.IO;

using System.Text;

using System.Drawing;

using System.Windows.Forms;

using System.Runtime.InteropServices;

using System.Collections.Generic;


/*--------------------------------------------------*/

class Program

{

[STAThread]


static void Main()

{

Application.Run( new MciTest());

}

}


/*--------------------------------------------------*/

class MciTest: Form

{

/*--------------------------------------------------*/

[DllImport( "Winmm.dll")]

extern static int mciSendString( string cmd, System.Text.StringBuilder retStr, uint ret, IntPtr hwnd);


/*--------------------------------------------------*/

private MenuStrip ms;

private ToolStripMenuItem[][] tsmi;


private Button[] btn;


private const string DeviceID = "mysound";


private string filename = @"C:\Windows\Media\Alarm02.wav";


/*--------------------------------------------------*/

public MciTest()

{

/*--------------------------------------------------*/

this.ClientSize = new Size( 360, 240);

this.Text = "MCITest";


this.Load += new EventHandler( this.Form_Load);

this.Closed += new EventHandler( this.Form_Closed);


/*--------------------------------------------------*/

this.CreateMenu();


/*--------------------------------------------------*/

this.btn = new Button[16];


for( int i = 0; i < this.btn.Length; i++)

{

this.btn[i] = new Button();

this.btn[i].SetBounds( 20 + 80 * ( i % 4), 40 + 40 * ( i / 4), 80, 40);

this.btn[i].Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom;

this.btn[i].Text = i.ToString();

this.btn[i].Click += new EventHandler( this.btn_Click);

this.Controls.Add( this.btn[i]);

}


this.btn[0].Text = "open";

this.btn[1].Text = "close";

this.btn[2].Text = "play";

this.btn[3].Text = "stop";


this.btn[4].Text = "pause";

this.btn[5].Text = "resume";

this.btn[6].Text = "seek";

this.btn[7].Text = "position";


this.btn[8].Text = "volume quiet";

this.btn[9].Text = "volume loud";

this.btn[10].Text = "audio on";

this.btn[11].Text = "audio off";


this.btn[12].Text = "info";

this.btn[13].Text = "mode";

}


/*--------------------------------------------------*/

private void Form_Load( object sender, EventArgs e)

{

Console.WriteLine( "Form_Load");

}

private void Form_Closed( object sender, EventArgs e)

{

Console.WriteLine( "Form_Closed");


int ret;

string cmd;


cmd = "stop " + MciTest.DeviceID;

ret = mciSendString( cmd, null, 0, IntPtr.Zero);


cmd = "close " + MciTest.DeviceID;

ret = mciSendString( cmd, null, 0, IntPtr.Zero);

}


/*--------------------------------------------------*/

private void CreateMenu()

{

this.ms = new MenuStrip();


this.tsmi = new ToolStripMenuItem[1][];

this.tsmi[0] = new ToolStripMenuItem[3];


for( int i = 0; i < this.tsmi.Length; i++)

{

for( int j = 0; j < this.tsmi[i].Length; j++)

{

this.tsmi[i][j] = new ToolStripMenuItem();

}

}


this.tsmi[0][0].Text = "Menu (&M)";

this.tsmi[0][1].Text = "File (&F)";

this.tsmi[0][2].Text = "Close (&C)";


for( int i = 0; i < this.tsmi.Length; i++)

{

this.ms.Items.Add( this.tsmi[i][0]);


for( int j = 1; j < this.tsmi[i].Length; j++)

{

this.tsmi[i][0].DropDownItems.Add( this.tsmi[i][j]);

this.tsmi[i][j].Click += new EventHandler( this.Menu_Click);

}

}


this.Controls.Add( this.ms);

this.MainMenuStrip = ms;

}


/*--------------------------------------------------*/

private void Menu_Click( object sender, EventArgs e)

{

Console.WriteLine( sender.ToString());


if( sender == this.tsmi[0][1])

{

MessageBox.Show( Application.ExecutablePath);


OpenFileDialog ofd = new OpenFileDialog();

ofd.Filter = "All files | *.*";

ofd.Multiselect = true;


if( ofd.ShowDialog() == DialogResult.OK)

{

MessageBox.Show( ofd.FileNames[0]);

this.filename = ofd.FileNames[0];

}

}

else if( sender == this.tsmi[0][2])

{

this.Close();

}

}


/*--------------------------------------------------*/

private void btn_Click( object sender, EventArgs e)

{

Console.WriteLine( "btn_Click" + "\t" + ( (Button)sender).Text);


int ret;

string cmd;

StringBuilder retStr = new StringBuilder( 256);


if( ( (Button)sender).Text == "open")

{

cmd = "open " + "\"" + this.filename + "\"" + " alias " + MciTest.DeviceID;

ret = mciSendString( cmd, null, 0, IntPtr.Zero);

Console.WriteLine( cmd);

}

else if( ( (Button)sender).Text == "close")

{

cmd = "close " + MciTest.DeviceID;

ret = mciSendString( cmd, null, 0, IntPtr.Zero);

Console.WriteLine( cmd);

}

else if( ( (Button)sender).Text == "play")

{

cmd = "play " + MciTest.DeviceID + " notify";

ret = mciSendString( cmd, null, 0, this.Handle);

Console.WriteLine( cmd);

}

else if( ( (Button)sender).Text == "stop")

{

cmd = "stop " + MciTest.DeviceID;

ret = mciSendString( cmd, null, 0, IntPtr.Zero);

Console.WriteLine( cmd);

}

else if( ( (Button)sender).Text == "pause")

{

cmd = "pause " + MciTest.DeviceID;

ret = mciSendString( cmd, null, 0, IntPtr.Zero);

Console.WriteLine( cmd);


cmd = "status " + MciTest.DeviceID + " pause timeout";

ret = mciSendString( cmd, retStr, (uint) retStr.Capacity, IntPtr.Zero);

Console.WriteLine( "pause timeout : " + retStr);

}

else if( ( (Button)sender).Text == "resume")

{

cmd = "resume " + MciTest.DeviceID;

ret = mciSendString( cmd, null, 0, IntPtr.Zero);

Console.WriteLine( cmd);

}

else if( ( (Button)sender).Text == "seek")

{

cmd = "seek " + MciTest.DeviceID + " to start";

ret = mciSendString( cmd, null, 0, IntPtr.Zero);

Console.WriteLine( cmd);

}

else if( ( (Button)sender).Text == "position")

{

cmd = "status " + MciTest.DeviceID + " position";

ret = mciSendString( cmd, retStr, (uint) retStr.Capacity, IntPtr.Zero);

Console.Write( "position : " + retStr);


cmd = "status " + MciTest.DeviceID + " length";

ret = mciSendString( cmd, retStr, (uint) retStr.Capacity, IntPtr.Zero);

Console.WriteLine( " / " + retStr);

}

else if( ( (Button)sender).Text == "volume quiet")

{

cmd = "status " + MciTest.DeviceID + " volume";

ret = mciSendString( cmd, retStr, (uint) retStr.Capacity, IntPtr.Zero);

Console.WriteLine( "volume : " + retStr);


cmd = "setaudio " + MciTest.DeviceID + " volume to 200";

ret = mciSendString( cmd, null, 0, IntPtr.Zero);

Console.WriteLine( cmd);


cmd = "status " + MciTest.DeviceID + " volume";

ret = mciSendString( cmd, retStr, (uint) retStr.Capacity, IntPtr.Zero);

Console.WriteLine( "volume : " + retStr);

}

else if( ( (Button)sender).Text == "volume loud")

{

cmd = "status " + MciTest.DeviceID + " volume";

ret = mciSendString( cmd, retStr, (uint) retStr.Capacity, IntPtr.Zero);

Console.WriteLine( "volume : " + retStr);


cmd = "setaudio " + MciTest.DeviceID + " volume to 800";

ret = mciSendString( cmd, null, 0, IntPtr.Zero);

Console.WriteLine( cmd);


cmd = "status " + MciTest.DeviceID + " volume";

ret = mciSendString( cmd, retStr, (uint) retStr.Capacity, IntPtr.Zero);

Console.WriteLine( "volume : " + retStr);

}

else if( ( (Button)sender).Text == "audio on")

{

cmd = "set " + MciTest.DeviceID + " audio all on";

ret = mciSendString( cmd, null, 0, IntPtr.Zero);

Console.WriteLine( cmd);

}

else if( ( (Button)sender).Text == "audio off")

{

cmd = "set " + MciTest.DeviceID + " audio all off";

ret = mciSendString( cmd, null, 0, IntPtr.Zero);

Console.WriteLine( cmd);

}

else if( ( (Button)sender).Text == "info")

{

cmd = "info " + MciTest.DeviceID + " file";

ret = mciSendString( cmd, retStr, (uint) retStr.Capacity, IntPtr.Zero);

Console.WriteLine( "info : " + retStr);

}

else if( ( (Button)sender).Text == "mode")

{

cmd = "status " + MciTest.DeviceID + " mode";

ret = mciSendString( cmd, retStr, (uint) retStr.Capacity, IntPtr.Zero);

Console.WriteLine( "mode : " + retStr);

}

}


/*--------------------------------------------------*/

protected override void WndProc( ref Message m)

{

base.WndProc( ref m);


if( m.Msg == 0x03B9) //MM_MCINOTIFY message

{

Console.WriteLine( "Notify");


StringBuilder retStr = new StringBuilder( 256);


string cmd = "status " + MciTest.DeviceID + " mode";;

int ret = mciSendString( cmd, retStr, (uint) retStr.Capacity, IntPtr.Zero);;


Console.WriteLine( "mode : " + retStr);

}

}

}