VBA / Excel VBA 播放音檔

這個是臉書社群的問題

研究了一下

我一開始的構想是用 cmd 執行播放程式,例如:windows media player

後來爬文知道 cmd 就是預設用 windows media player 來開啟音檔

而在VBA 可以用 Shell函數 或者引用  WScript.Shell物件來執行cmd

但是其實也可以直接用 Shell函數 或者 WScript.Shell物件執行 windows media player

不需要再調用 cmd來執行 windows media player

後來爬文發現另一個方式是調用winmm.dll 的sndPlaySoundA 或 PlaySoundA

以下分別說明這幾種方式的應用

Shell函數

Code Embed: No embed code was found for CODE-4616

Windowstyle 常數 描述
vbHide 0 隱藏視窗,且將焦點傳遞給隱藏視窗。 VbHide 常數不適用於 Macintosh 平台。
vbNormalFocus 1 視窗有焦點並還原成原始的大小和位置。
vbMinimizedFocus 2 視窗顯示為具有焦點的圖示。
vbMaximizedFocus 3 視窗最大化且具有焦點。
vbNormalNoFocus 4 視窗還原為最近的大小和位置。 目前的作用中視窗仍維持作用中。
vbMinimizedNoFocus 6 視窗顯示為圖示。 目前的作用中視窗仍維持作用中。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Public Sub Shell_1()

    Dim RetVal '接收回傳執行情況
    
    RetVal = Shell("C:\Program Files (x86)\Windows Media Player\wmplayer.exe C:\windows\media\chord.wav", 0)
    
    If RetVal = 0 Then
        MsgBox "執行失敗"
    End If
    
End Sub
'
'
Public Sub Shell_2()

    Dim RetVal '接收回傳執行情況
    
    'cmd 語法
    'https://learn.microsoft.com/zh-tw/windows-server/administration/windows-commands/cmd
    RetVal = Shell("cmd.exe /S /C" & "C:\windows\media\chord.wav", 0)
  
    If RetVal = 0 Then
        MsgBox "執行失敗"
    End If
    
End Sub

 

WScript.Shell

語法 .Run(ByVal Command As String, [ByVal WindowStyle], [ByVal WaitOnReturn]) As Integer

WindowStyle:跟Shell函數一樣

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
Public Sub ws1()

    Dim wsh As Object
    Set wsh = CreateObject("WScript.Shell")
    
    'cmd 語法
    'https://learn.microsoft.com/zh-tw/windows-server/administration/windows-commands/cmd
    wsh.Run "cmd.exe /S /C" & "C:\windows\media\chord.wav", 0, 0

End Sub
'
'
Public Sub ws2()
    Dim wsh As Object
    Set wsh = CreateObject("WScript.Shell")

    wsh.Run "wmplayer.exe C:\windows\media\chord.wav", 0, 0
End Sub

 

無論是Shell函數 還是 WScript.Shell 只要是透過執行cmd來啟動 wmplayer.exe

windows media player都會顯示視窗,無法隱藏,原因在於wmplayer.exe是被cmd啟動的

sndPlaySoundA

引用 winmm.dll 的sndPlaySoundA

參數1 pszSoundName

檔案路徑

參數2 uFlags

SND_ASYNC 異步/非同步 ,也可以用1,播放開始後即往下執行

SND_SYNC 同步,也可以用0,播放完了才往下執行

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#If VBA7 Then
'Office 2013 & above
    #If Win64 Then
    'x64 host
    Private Declare PtrSafe Function sndPlaySound32 Lib "winmm.dll" _
    Alias "sndPlaySoundA" (ByVal lpszSoundName _
    As String, ByVal uFlags As LongPtr) As LongPtr
    #Else
    'x86 host
    Private Declare PtrSafe Function sndPlaySound32 Lib "winmm.dll" _
    Alias "sndPlaySoundA" (ByVal lpszSoundName _
    As String, ByVal uFlags As Long) As Long
    #End If
#Else
'Office 2010 & under:
    Private Declare Function sndPlaySound32 Lib "winmm.dll" _
    Alias "sndPlaySoundA" (ByVal lpszSoundName _
    As String, ByVal uFlags As Long) As Long
#End If

 

1
2
3
4
5
Sub SndPly()
 
    Call sndPlaySound32("C:\windows\media\chord.wav", 1)

End Sub

 

PlaySoundA

引用 winmm.dll 的PlaySoundA

參數1 lpszName

檔案路徑

參數2 hModule

必須是0

參數3 dwFlags

SND_ASYNC 異步/非同步 ,也可以用1,播放開始後即往下執行

SND_SYNC 同步,也可以用0,播放完了才往下執行

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#If VBA7 Then
'Office 2013 & above
    #If Win64 Then
    'x64 host
    Private Declare PtrSafe Function PlaySound Lib "winmm.dll" _
    Alias "PlaySoundA" (ByVal lpszName As String, ByVal hModule As LongPtr, ByVal dwFlags As LongPtr) As LongPtr
    #Else
    'x86 host
    Private Declare PtrSafe Function PlaySound Lib "winmm.dll" _
    Alias "PlaySoundA" (ByVal lpszName As String, ByVal hModule As Long, ByVal dwFlags As Long) As Long
    #End If
#Else
'Office 2010 & under:
    Private Declare Function PlaySound Lib "winmm.dll" _
    Alias "PlaySoundA" (ByVal lpszName As String, ByVal hModule As Long, ByVal dwFlags As Long) As Long
#End If

 

1
2
3
4
5
Sub Ply()
 
    Call PlaySound("C:\windows\media\chord.wav", 0, 1)

End Sub

 

在工作簿的應用

自訂function beepFn()呼叫程序

1
2
3
4
5
Function beeFn()
 
    Call sndPlaySound32("C:\windows\media\chord.wav", 1)

End Function

 

在公式引用 自訂function beepFn()

E2=IF(AND(C2<>"",C3 <>""),IF(C2=C3,"PASS","FAIL" & beepFn()),"")

缺點:因為是在公式裡引用,所以開啟檔案的時候會自動執行一次


備註1:關於程式路徑

cmd.exe 無論在Shell函數還是WScript.Shell

都可以省略路徑

而wmplayer.exe在WScript.Shell可以省略路徑,但是在Shell函數必須有完整路徑

這應該是跟環境參數的設定有關

備註2:關於同步/非同步

Shell函數只能非同步執行,也就是執行之後,不會等執行結束,程序就會立即接著執行後面的程式碼

WScript.Shell 、sndPlaySoundA、PlaySoundA,都可以設定同步/非同步

參考資料

VBS中WScript.Shell对象的run和exec的使用及区别

VBA关于声音的多种实现方法