我有一个用Visual Basic 2010 Express编码的校铃项目。运行我的程序的计算机有两个或多个声卡。首先,我将声卡列出给用户。用户将选择声卡进行工作。最终,我的程序将敲响该声卡的铃声。我的代码一切正常,但我无法列出声卡的名称并按指定的声卡上的铃声。
我使用WMPLib播放音乐。我有这些代码,但出现错误“该值不在预期范围内”。我发现了我的代码中的错误所在:
Public Declare Function waveOutGetNumDevs Lib "winmm" () As Integer
Public Declare Function mciSendCommand Lib "winmm.dll" Alias "mciSendCommandA" (ByVal wDeviceID As Integer, ByVal uMessage As String, ByVal dwParam1 As Integer, ByVal dwParam2 As Object) As Integer
Public Declare Function mciGetErrorString Lib "winmm.dll" Alias "mciGetErrorStringA" (ByVal dwError As Integer, ByVal lpstrBuffer As String, ByVal uLength As Integer) As Integer
Public Declare Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" (ByVal lpstrCommand As String, ByVal lpstrReturnString As String, ByVal uReturnLength As Integer, ByVal hwndCallback As Integer) As Integer
Public Declare Function mciGetDeviceID Lib "winmm.dll" Alias "mciGetDeviceIDA" (ByVal lpstrName As String) As Integer
Public Const MMSYSERR_NOERROR = 0
Public Const MCI_SET = &H80D
Public Const MCI_WAVE_OUTPUT = &H800000
Public Structure MCI_WAVE_SET_PARMS
Dim dwCallback As Integer
Dim dwTimeFormat As Integer
Dim dwAudio As Integer
Dim wInput As Integer
Dim wOutput As Integer
Dim wFormatTag As Short
Dim wReserved2 As Short
Dim nChannels As Short
Dim wReserved3 As Short
Dim nSamplesPerSec As Integer
Dim nAvgBytesPerSec As Integer
Dim nBlockAlign As Short
Dim wReserved4 As Short
Dim wBitsPerSample As Short
Dim wReserved5 As Short
End Structure
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim parms As MCI_WAVE_SET_PARMS
Dim wDeviceID As Integer
Dim ret As Integer
parms.wOutput = 0
wDeviceID = mciGetDeviceID("waveaudio")
' the value is not in the expected range error is here and it spots parms
ret = mciSendCommand(wDeviceID, MCI_SET, MCI_WAVE_OUTPUT, parms)
If (ret <> MMSYSERR_NOERROR) Then
Stop
End If
If ofd.ShowDialog Then
ret = mciSendString("Open " & Chr(34) & ofd.FileName & Chr(34) & " alias audio", CStr(0), 0, 0)
ret = mciSendString("Open audio", CStr(0), 0, 0)
End If
End Sub
答案 0 :(得分:1)
您可以使用WindowsMedia.Net library进行此操作。
以下示例摘自以下链接,该代码是Windows窗体的代码,包含列出所有可用音频设备并选择默认设备(将用作声音输出的设备)所需的功能。 / p>
首先,我将尝试将代码分为2部分:
列出可用设备
Private Sub RefreshInformation()
PopulateDeviceComboBox()
DisplayDefaultWaveOutDevice()
End Sub
Private Sub PopulateDeviceComboBox()
DevicesComboBox.Items.Clear()
' How many wave out devices are there? WaveOutGetNumDevs API call.
Dim waveOutDeviceCount As Integer = waveOut.GetNumDevs()
For i As Integer = 0 To waveOutDeviceCount - 1
Dim caps As New WaveOutCaps
' Get a name - its in a WAVEOUTCAPS structure.
' The name is truncated to 31 chars by the api call. You probably have to
' dig around in the registry to get the full name.
Dim result As Integer = waveOut.GetDevCaps(i, caps, Marshal.SizeOf(caps))
If result <> MMSYSERR.NoError Then
Dim err As MMSYSERR = DirectCast(result, MMSYSERR)
Throw New Win32Exception("GetDevCaps() error, Result: " & result.ToString("x8") & ", " & err.ToString)
End If
DevicesComboBox.Items.Add(New WaveOutDevice(i, caps))
Next
DevicesComboBox.SelectedIndex = 0
End Sub
Private Sub DisplayDefaultWaveOutDevice()
Dim currentDefault As Integer = GetIdOfDefaultWaveOutDevice()
Dim device As WaveOutDevice = DirectCast(DevicesComboBox.Items(currentDefault), WaveOutDevice)
DefaultDeviceLabel.Text = "Defualt: " & device.WaveOutCaps.szPname
End Sub
Private Function GetIdOfDefaultWaveOutDevice() As Integer
Dim id As Integer = 0
Dim hId As IntPtr
Dim flags As Integer = 0
Dim hFlags As IntPtr
Dim result As Integer
Try
' It would be easier to declare a nice overload with ByRef Integers.
hId = Marshal.AllocHGlobal(4)
hFlags = Marshal.AllocHGlobal(4)
' http://msdn.microsoft.com/en-us/library/bb981557.aspx
result = waveOut.Message(WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET, hId, hFlags)
If result <> MMSYSERR.NoError Then
Dim err As MMSYSERR = DirectCast(result, MMSYSERR)
Throw New Win32Exception("waveOutMessage() error, Result: " & result.ToString("x8") & ", " & err.ToString)
End If
id = Marshal.ReadInt32(hId)
flags = Marshal.ReadInt32(hFlags)
Finally
Marshal.FreeHGlobal(hId)
Marshal.FreeHGlobal(hFlags)
End Try
' There is only one flag, DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY, defined as 1
' "When the DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY flag bit is set, ... blah ...,
' the waveIn and waveOut APIs use only the current preferred device and do not search
' for other available devices if the preferred device is unavailable.
Return id
End Function
更改默认设备
Private Sub SetDefaultButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles SetDefaultButton.Click
If DevicesComboBox.Items.Count = 0 Then Return
Dim selectedDevice As WaveOutDevice = DirectCast(DevicesComboBox.SelectedItem, WaveOutDevice)
SetDefault(selectedDevice.Id)
RefreshInformation()
End Sub
Private Sub SetDefault(ByVal id As Integer)
Dim defaultId As Integer = GetIdOfDefaultWaveOutDevice()
If defaultId = id Then Return ' no change.
Dim result As Integer
' So here we say "change the Id of the device that has id id to 0", which makes it the default.
result = waveOut.Message(WAVE_MAPPER, DRVM_MAPPER_PREFERRED_SET, New IntPtr(id), IntPtr.Zero)
If result <> MMSYSERR.NoError Then
Dim err As MMSYSERR = DirectCast(result, MMSYSERR)
Throw New Win32Exception("waveOutMessage() error, Result: " & result.ToString("x8") & ", " & err.ToString)
End If
End Sub
完整代码
Imports MultiMedia
Imports System.Runtime.InteropServices
Imports System.ComponentModel
Public Class Form1
Private DevicesComboBox As New ComboBox
Private DefaultDeviceLabel As New Label
Private WithEvents SetDefaultButton As New Button
Private Const DRVM_MAPPER_PREFERRED_GET As Integer = &H2015
Private Const DRVM_MAPPER_PREFERRED_SET As Integer = &H2016
Private WAVE_MAPPER As New IntPtr(-1)
' This just brings together a device ID and a WaveOutCaps so
' that we can store them in a combobox.
Private Structure WaveOutDevice
Private m_id As Integer
Public Property Id() As Integer
Get
Return m_id
End Get
Set(ByVal value As Integer)
m_id = value
End Set
End Property
Private m_caps As WaveOutCaps
Public Property WaveOutCaps() As WaveOutCaps
Get
Return m_caps
End Get
Set(ByVal value As WaveOutCaps)
m_caps = value
End Set
End Property
Sub New(ByVal id As Integer, ByVal caps As WaveOutCaps)
m_id = id
m_caps = caps
End Sub
Public Overrides Function ToString() As String
Return WaveOutCaps.szPname
End Function
End Structure
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' I do use the IDE for this stuff normally... (in case anyone is wondering)
Me.Controls.AddRange(New Control() {DevicesComboBox, DefaultDeviceLabel, SetDefaultButton})
DevicesComboBox.Location = New Point(5, 5)
DevicesComboBox.DropDownStyle = ComboBoxStyle.DropDownList
DevicesComboBox.Width = Me.ClientSize.Width - 10
DevicesComboBox.Anchor = AnchorStyles.Left Or AnchorStyles.Right
DefaultDeviceLabel.Location = New Point(DevicesComboBox.Left, DevicesComboBox.Bottom + 5)
DefaultDeviceLabel.AutoSize = True
SetDefaultButton.Location = New Point(DefaultDeviceLabel.Left, DefaultDeviceLabel.Bottom + 5)
SetDefaultButton.Text = "Set Default"
SetDefaultButton.AutoSize = True
RefreshInformation()
End Sub
Private Sub RefreshInformation()
PopulateDeviceComboBox()
DisplayDefaultWaveOutDevice()
End Sub
Private Sub PopulateDeviceComboBox()
DevicesComboBox.Items.Clear()
' How many wave out devices are there? WaveOutGetNumDevs API call.
Dim waveOutDeviceCount As Integer = waveOut.GetNumDevs()
For i As Integer = 0 To waveOutDeviceCount - 1
Dim caps As New WaveOutCaps
' Get a name - its in a WAVEOUTCAPS structure.
' The name is truncated to 31 chars by the api call. You probably have to
' dig around in the registry to get the full name.
Dim result As Integer = waveOut.GetDevCaps(i, caps, Marshal.SizeOf(caps))
If result <> MMSYSERR.NoError Then
Dim err As MMSYSERR = DirectCast(result, MMSYSERR)
Throw New Win32Exception("GetDevCaps() error, Result: " & result.ToString("x8") & ", " & err.ToString)
End If
DevicesComboBox.Items.Add(New WaveOutDevice(i, caps))
Next
DevicesComboBox.SelectedIndex = 0
End Sub
Private Sub DisplayDefaultWaveOutDevice()
Dim currentDefault As Integer = GetIdOfDefaultWaveOutDevice()
Dim device As WaveOutDevice = DirectCast(DevicesComboBox.Items(currentDefault), WaveOutDevice)
DefaultDeviceLabel.Text = "Defualt: " & device.WaveOutCaps.szPname
End Sub
Private Function GetIdOfDefaultWaveOutDevice() As Integer
Dim id As Integer = 0
Dim hId As IntPtr
Dim flags As Integer = 0
Dim hFlags As IntPtr
Dim result As Integer
Try
' It would be easier to declare a nice overload with ByRef Integers.
hId = Marshal.AllocHGlobal(4)
hFlags = Marshal.AllocHGlobal(4)
' http://msdn.microsoft.com/en-us/library/bb981557.aspx
result = waveOut.Message(WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET, hId, hFlags)
If result <> MMSYSERR.NoError Then
Dim err As MMSYSERR = DirectCast(result, MMSYSERR)
Throw New Win32Exception("waveOutMessage() error, Result: " & result.ToString("x8") & ", " & err.ToString)
End If
id = Marshal.ReadInt32(hId)
flags = Marshal.ReadInt32(hFlags)
Finally
Marshal.FreeHGlobal(hId)
Marshal.FreeHGlobal(hFlags)
End Try
' There is only one flag, DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY, defined as 1
' "When the DRVM_MAPPER_PREFERRED_FLAGS_PREFERREDONLY flag bit is set, ... blah ...,
' the waveIn and waveOut APIs use only the current preferred device and do not search
' for other available devices if the preferred device is unavailable.
Return id
End Function
Private Sub SetDefaultButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles SetDefaultButton.Click
If DevicesComboBox.Items.Count = 0 Then Return
Dim selectedDevice As WaveOutDevice = DirectCast(DevicesComboBox.SelectedItem, WaveOutDevice)
SetDefault(selectedDevice.Id)
RefreshInformation()
End Sub
Private Sub SetDefault(ByVal id As Integer)
Dim defaultId As Integer = GetIdOfDefaultWaveOutDevice()
If defaultId = id Then Return ' no change.
Dim result As Integer
' So here we say "change the Id of the device that has id id to 0", which makes it the default.
result = waveOut.Message(WAVE_MAPPER, DRVM_MAPPER_PREFERRED_SET, New IntPtr(id), IntPtr.Zero)
If result <> MMSYSERR.NoError Then
Dim err As MMSYSERR = DirectCast(result, MMSYSERR)
Throw New Win32Exception("waveOutMessage() error, Result: " & result.ToString("x8") & ", " & err.ToString)
End If
End Sub
End Class
您可以使用System.Management程序集(它是.Net框架的一部分)来检索可用的音频设备:
ManagementObjectSearcher mo =
new ManagementObjectSearcher("select * from Win32_SoundDevice");
foreach (ManagementObject soundDevice in mo.Get())
{
String deviceId = soundDevice.GetPropertyValue("DeviceId").ToString();
String name = soundDevice.GetPropertyValue("Name").ToString();
//saving the name and device id in array
}
参考