我使用Visual Studio 2013 for Visual Basic,并且希望能够测试扬声器是插入扬声器还是从扬声器插孔中拔出。可能吗?

最佳答案

可以使用设备拓扑API来完成。 IKsJackDescription接口(interface)可用于获取KSJACK_DESCRIPTION结构,该结构具有IsConnected成员。但是,并非每个设备都支持电缆存在检测,以防万一它不是API总是报告它已连接的情况。

COM对象声明

Imports System
Imports System.Collections.Generic
Imports System.Text
Imports System.Runtime.InteropServices
Imports System.IO
Imports System.Runtime.CompilerServices

Namespace com_test

    Class Native


        <DllImport("ole32.Dll")> _
        Public Shared Function CoCreateInstance(ByRef clsid As Guid, <MarshalAs(UnmanagedType.IUnknown)> inner As Object, context As UInteger, ByRef uuid As Guid, <MarshalAs(UnmanagedType.IUnknown)> ByRef rReturnedComObject As Object) As UInteger
        End Function

        '************************************************************************

        <DllImport("ole32.dll")> _
        Private Shared Function PropVariantClear(ByRef pvar As PropVariant) As Integer
        End Function



        Public Const DEVICE_STATE_ACTIVE As Integer = &H1

        Public Const DEVICE_STATE_DISABLE As Integer = &H2

        Public Const DEVICE_STATE_NOTPRESENT As Integer = &H4

        Public Const DEVICE_STATE_UNPLUGGED As Integer = &H8

        Public Const DEVICE_STATEMASK_ALL As Integer = &Hf


        Public Shared PKEY_Device_FriendlyName As New PROPERTYKEY(&Ha45c254eUI, &Hdf1c, &H4efd, &H80, &H20, &H67, _
            &Hd1, &H46, &Ha8, &H50, &He0, 14)




        Public Shared PKEY_AudioEndpoint_FormFactor As New PROPERTYKEY(&H1da5d803, &Hd492, &H4edd, &H8c, &H23, &He0, _
            &Hc0, &Hff, &Hee, &H7f, &He, 0)



    End Class



    Enum EndpointFormFactor


        RemoteNetworkDevice = 0

        Speakers = (RemoteNetworkDevice + 1)

        LineLevel = (Speakers + 1)

        Headphones = (LineLevel + 1)

        Microphone = (Headphones + 1)

        Headset = (Microphone + 1)

        Handset = (Headset + 1)

        UnknownDigitalPassthrough = (Handset + 1)

        SPDIF = (UnknownDigitalPassthrough + 1)

        DigitalAudioDisplayDevice = (SPDIF + 1)

        UnknownFormFactor = (DigitalAudioDisplayDevice + 1)

        EndpointFormFactor_enum_count = (UnknownFormFactor + 1)

    End Enum



    Enum EPcxConnectionType


        eConnTypeUnknown = 0

        eConnType3Point5mm

        eConnTypeQuarter

        eConnTypeAtapiInternal

        eConnTypeRCA

        eConnTypeOptical

        eConnTypeOtherDigital

        eConnTypeOtherAnalog

        eConnTypeMultichannelAnalogDIN

        eConnTypeXlrProfessional

        eConnTypeRJ11Modem

        eConnTypeCombination

    End Enum



    Enum EPcxGeoLocation


        eGeoLocRear = &H1

        eGeoLocFront

        eGeoLocLeft

        eGeoLocRight

        eGeoLocTop

        eGeoLocBottom

        eGeoLocRearPanel

        eGeoLocRiser

        eGeoLocInsideMobileLid

        eGeoLocDrivebay

        eGeoLocHDMI

        eGeoLocOutsideMobileLid

        eGeoLocATAPI

        eGeoLocNotApplicable

        eGeoLocReserved6

        EPcxGeoLocation_enum_count

    End Enum



    Public Enum EDataFlow


        eRender

        eCapture

        eAll

        EDataFlow_enum_count

    End Enum



    Public Enum ERole


        eConsole

        eMultimedia

        eCommunications

        ERole_enum_count

    End Enum



    Public Enum CLSCTX


        CLSCTX_INPROC_SERVER = &H1

        CLSCTX_INPROC_HANDLER = &H2

        CLSCTX_LOCAL_SERVER = &H4

        CLSCTX_REMOTE_SERVER = &H10


        CLSCTX_SERVER = (CLSCTX_INPROC_SERVER Or CLSCTX_LOCAL_SERVER Or CLSCTX_REMOTE_SERVER)

        CLSCTX_ALL = (CLSCTX_INPROC_HANDLER Or CLSCTX_SERVER)

    End Enum



    'Windows Core Audio API declarations

    'http://www.java2s.com/Code/CSharp/Windows/SoundUtils.htm





    <Guid("0BD7A1BE-7A1A-44DB-8397-CC5392387B5E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
    Public Interface IMMDeviceCollection


        Function GetCount(ByRef pcDevices As UInteger) As Integer

        Function Item(nDevice As UInteger, <Out, MarshalAs(UnmanagedType.[Interface])> ByRef ppDevice As Object) As Integer

    End Interface





    <Guid("D666063F-1587-4E43-81F1-B948E807363F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
    Public Interface IMMDevice



        Function Activate(ByRef iid As Guid, dwClsCtx As UInteger, pActivationParams As IntPtr, <Out, MarshalAs(UnmanagedType.[Interface])> ByRef ppInterface As Object) As Integer



        Function OpenPropertyStore(stgmAccess As Integer, <Out, MarshalAs(UnmanagedType.[Interface])> ByRef ppProperties As Object) As Integer



        Function GetId(ByRef ppstrId As StringBuilder) As Integer



        Function GetState(ByRef pdwState As Integer) As Integer

    End Interface




    <ComImport, Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")> _
    Class MMDeviceEnumerator


    End Class





    <Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
    Public Interface IMMDeviceEnumerator





        Function EnumAudioEndpoints(dataFlow As EDataFlow, dwStateMask As Integer, <Out, MarshalAs(UnmanagedType.[Interface])> ByRef ppDevices As Object) As Integer




        Function GetDefaultAudioEndpoint(dataFlow As EDataFlow, role As ERole, <Out, MarshalAs(UnmanagedType.[Interface])> ByRef ppEndpoint As Object) As Integer



        Function GetDevice(pwstrId As String, ByRef ppDevice As IntPtr) As Integer



        Function RegisterEndpointNotificationCallback(pClient As IntPtr) As Integer



        Function UnregisterEndpointNotificationCallback(pClient As IntPtr) As Integer

    End Interface





    '*********** Property store *****************************



    ' https://blogs.msdn.microsoft.com/adamroot/2008/04/11/interop-with-propvariants-in-net/




    <ComImport, Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
    Interface IPropertyStore



        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType := MethodCodeType.Runtime)> _
        Sub GetCount(<Out> ByRef cProps As UInteger)




        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType := MethodCodeType.Runtime)> _
        Sub GetAt(<[In]> iProp As UInteger, ByRef pkey As PROPERTYKEY)




        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType := MethodCodeType.Runtime)> _
        Function GetValue(<[In]> ByRef key As PROPERTYKEY, ByRef pv As PropVariant) As Integer




        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType := MethodCodeType.Runtime)> _
        Sub SetValue(<[In]> ByRef key As PROPERTYKEY, <[In]> ByRef pv As Object)




        <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType := MethodCodeType.Runtime)> _
        Sub Commit()

    End Interface




    <StructLayout(LayoutKind.Sequential, Pack := 4)> _
    Structure PROPERTYKEY


        Public fmtid As Guid

        Public pid As UInteger



        Public Sub New(guid As Guid, propertyId As Integer)


            Me.fmtid = guid


            Me.pid = CUInt(propertyId)
        End Sub

        Public Sub New(formatId As String, propertyId As Integer)

            Me.New(New Guid(formatId), propertyId)


        End Sub


        Public Sub New(a As UInteger, b As UInteger, c As UInteger, d As UInteger, e As UInteger, f As UInteger, _
            g As UInteger, h As UInteger, i As UInteger, j As UInteger, k As UInteger, propertyId As Integer)


            Me.New(New Guid(CUInt(a), CUShort(b), CUShort(c), CByte(d), CByte(e), CByte(f), _
                CByte(g), CByte(h), CByte(i), CByte(j), CByte(k)), propertyId)


        End Sub

    End Structure




    <StructLayout(LayoutKind.Sequential)> _
    Public Structure PropVariant


        Private vt As UShort

        Private wReserved1 As UShort

        Private wReserved2 As UShort

        Private wReserved3 As UShort

        Private p As IntPtr

        Private p2 As Integer



        Private Function GetDataBytes() As Byte()


            Dim ret As Byte() = New Byte(IntPtr.Size + (4 - 1)) {}

            If IntPtr.Size = 4 Then

                BitConverter.GetBytes(p.ToInt32()).CopyTo(ret, 0)

            ElseIf IntPtr.Size = 8 Then

                BitConverter.GetBytes(p.ToInt64()).CopyTo(ret, 0)
            End If

            BitConverter.GetBytes(p2).CopyTo(ret, IntPtr.Size)

            Return ret

        End Function



        Private ReadOnly Property cVal() As SByte
            ' CHAR cVal;

            Get
                Return CSByte(GetDataBytes()(0))
            End Get
        End Property




        Private ReadOnly Property iVal() As Short
            ' SHORT iVal;

            Get
                Return BitConverter.ToInt16(GetDataBytes(), 0)
            End Get
        End Property




        Private ReadOnly Property lVal() As Integer
            ' LONG lVal;

            Get
                Return BitConverter.ToInt32(GetDataBytes(), 0)
            End Get
        End Property




        Private ReadOnly Property hVal() As Long
            ' LARGE_INTEGER hVal;

            Get
                Return BitConverter.ToInt64(GetDataBytes(), 0)
            End Get
        End Property




        Private ReadOnly Property fltVal() As Single
            ' FLOAT fltVal;

            Get
                Return BitConverter.ToSingle(GetDataBytes(), 0)
            End Get
        End Property




        Public ReadOnly Property Value() As Object


            Get


                Select Case CType(vt, VarEnum)


                    Case VarEnum.VT_I1

                        Return cVal

                    Case VarEnum.VT_I2

                        Return iVal


                    Case VarEnum.VT_I4, VarEnum.VT_INT

                        Return lVal


                    Case VarEnum.VT_UI4, VarEnum.VT_I8

                        Return hVal

                    Case VarEnum.VT_R4

                        Return fltVal

                    Case VarEnum.VT_FILETIME
                        Return DateTime.FromFileTime(hVal)

                    Case VarEnum.VT_BSTR

                        Return Marshal.PtrToStringBSTR(p)

                    Case VarEnum.VT_BLOB

                        Dim blobData As Byte() = New Byte(lVal - 1) {}

                        Dim pBlobData As IntPtr

                        If IntPtr.Size = 4 Then



                            pBlobData = New IntPtr(p2)

                        ElseIf IntPtr.Size = 8 Then



                            pBlobData = New IntPtr(BitConverter.ToInt64(GetDataBytes(), 4))
                        Else


                            Throw New NotSupportedException()
                        End If

                        Marshal.Copy(pBlobData, blobData, 0, lVal)

                        Return blobData

                    Case VarEnum.VT_LPSTR

                        Return Marshal.PtrToStringAnsi(p)

                    Case VarEnum.VT_LPWSTR

                        Return Marshal.PtrToStringUni(p)

                    Case VarEnum.VT_UNKNOWN

                        Return Marshal.GetObjectForIUnknown(p)

                    Case VarEnum.VT_DISPATCH

                        Return p
                    Case Else


                        Throw New NotSupportedException("0x" + vt.ToString("X4") + " type not supported")


                End Select
            End Get
        End Property




    End Structure

    '*****************************************************



    'Device Topology declarations





    <Guid("2A07407E-6497-4A18-9787-32F79BD0D98F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
    Public Interface IDeviceTopology


        Function GetConnectorCount(<Out> ByRef pConnectorCount As Integer) As Integer

        Function GetConnector(nIndex As Integer, ByRef ppConnector As IConnector) As Integer

        Function GetSubunitCount(<Out> ByRef pCount As Integer) As Integer

        'ISubunit
        Function GetSubunit(nIndex As Integer, ByRef ppSubunit As Object) As Integer

        Function GetPartById(nId As Integer, ByRef ppPart As IPart) As Integer

        Function GetDeviceId(<Out, MarshalAs(UnmanagedType.LPWStr)> ByRef ppwstrDeviceId As String) As Integer

        'IPartsList
        Function GetSignalPath(pIPartFrom As IPart, pIPartTo As IPart, bRejectMixedPaths As Boolean, ppParts As Object) As Integer

    End Interface







    <InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("9c2c4058-23f5-41de-877a-df3af236a09e")> _
    Public Interface IConnector


        Function [GetType](ByRef pType As Integer) As Integer

        Function GetDataFlow(ByRef dataFlow As EDataFlow) As Integer

        Function ConnectTo(<[In]> connector As IConnector) As Integer

        Function Disconnect() As Integer

        Function IsConnected(ByRef pbConnected As Boolean) As Integer

        Function GetConnectedTo(<MarshalAs(UnmanagedType.[Interface])> ByRef ppConTo As Object) As Integer

        Function GetConnectorIdConnectedTo(ByRef ppwstrConnectorId As String) As Integer

        Function GetDeviceIdConnectedTo(ByRef ppwstrDeviceId As String) As Integer

    End Interface





    <Guid("AE2DE0E4-5BCA-4F2D-AA46-5D13F8FDB3A9"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
    Public Interface IPart


        Function GetName(ByRef ppwstrName As StringBuilder) As Integer

        Function GetLocalId(ByRef pnId As Integer) As Integer

        Function GetGlobalId(ByRef ppwstrGlobalId As StringBuilder) As Integer

        Function GetPartType(ByRef pPartType As Integer) As Integer

        Function GetSubType(ByRef pSubType As Guid) As Integer

        Function GetControlInterfaceCount(ByRef pCount As UInteger) As Integer



        'IControlInterface
        Function GetControlInterface(nIndex As Integer, ByRef ppFunction As Object) As Integer

        'IPartsList[]
        Function EnumPartsIncoming(ByRef ppParts As Object) As Integer

        'IPartsList[]
        Function EnumPartsOutgoing(ByRef ppParts As Object) As Integer



        Function GetTopologyObject(<Out, MarshalAs(UnmanagedType.[Interface])> ByRef ppTopology As Object) As Integer






        Function Activate(dwClsContext As UInteger, ByRef refiid As Guid, <MarshalAs(UnmanagedType.[Interface])> ByRef interfacePointer As Object) As Integer

        'IControlChangeNotify
        Function RegisterControlChangeCallback(ByRef riid As Guid, pNofity As Object) As Integer

        'IControlChangeNotify
        Function UnregisterControlChangeCallback(pNotify As Object) As Integer

    End Interface



    <ComVisible(False)> _
    <ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("4509F757-2D46-4637-8E62-CE7DB944F57B")> _
    Public Interface IKsJackDescription


        Function GetJackCount(ByRef jacks As UInteger) As Integer

        Function GetJackDescription(jack As UInteger, ByRef pDescription As KSJACK_DESCRIPTION) As Integer

    End Interface




    <StructLayout(LayoutKind.Sequential)> _
    Public Structure KSJACK_DESCRIPTION


        Public ChannelMapping As UInteger

        Public Color As UInteger

        Public ConnectionType As UInteger

        Public GeoLocation As UInteger

        Public GenLocation As UInteger

        Public PortConnection As UInteger

        Public IsConnected As UInteger

    End Structure


End Namespace

示例如何获取有关当前默认设备的插孔信息的信息
Imports System
Imports System.Collections.Generic
Imports System.Data
Imports System.Text
Imports System.Windows.Forms
Imports System.Runtime.InteropServices
Imports System.ComponentModel

Namespace com_test
    Public Partial Class Form1
        Inherits Form

        'displays device
        Private Function PrintDevice(dev As IMMDevice) As String
            Dim propertyStore As IPropertyStore = Nothing
            Dim pDeviceTopology As IDeviceTopology = Nothing
            Dim pConnFrom As IConnector = Nothing
            Dim pConnTo As IConnector = Nothing
            Dim pPart As IPart = Nothing
            Dim pJackDesc As IKsJackDescription = Nothing
            Dim desc As New KSJACK_DESCRIPTION()

            Dim res As New StringBuilder(300)
            Dim o As Object = Nothing

            Dim state As Integer = 0
            Dim con_count As UInteger = 0

            Try
                'device name
                'STGM_READ
                dev.OpenPropertyStore(0, o)
                propertyStore = TryCast(o, IPropertyStore)

                Dim friendlyName As New PropVariant()
                propertyStore.GetValue(Native.PKEY_Device_FriendlyName, friendlyName)
                res.AppendLine(friendlyName.Value.ToString())


                'form factor
                Dim FormFactor As New PropVariant()
                propertyStore.GetValue(Native.PKEY_AudioEndpoint_FormFactor, FormFactor)
                Dim f As EndpointFormFactor = EndpointFormFactor.UnknownFormFactor
                [Enum].TryParse(Of EndpointFormFactor)(FormFactor.Value.ToString(), f)
                res.AppendLine("Form factor: " + f.ToString())

                dev.GetState(state)

                Dim str As String = ""
                Select Case state
                    Case Native.DEVICE_STATE_DISABLE
                        str = ("Disabled")
                        Exit Select
                    Case Native.DEVICE_STATE_NOTPRESENT
                        str = ("Not present")
                        Exit Select
                    Case Native.DEVICE_STATE_UNPLUGGED
                        str = ("Unplugged")
                        Exit Select
                End Select
                If str <> "" Then
                    res.AppendLine(str)
                End If


                ' DEVICE TOPOLOGY

                Dim iidDeviceTopology As New Guid("2A07407E-6497-4A18-9787-32F79BD0D98F")
                dev.Activate(iidDeviceTopology, CUInt(CLSCTX.CLSCTX_ALL), IntPtr.Zero, o)
                pDeviceTopology = TryCast(o, IDeviceTopology)

                pDeviceTopology.GetConnector(0, pConnFrom)

                Try
                    o = Nothing
                    pConnFrom.GetConnectedTo(o)
                    pConnTo = TryCast(o, IConnector)

                    pPart = CType(pConnTo, IPart)
                    'QueryInterface
                    Dim iidKsJackDescription As New Guid("4509F757-2D46-4637-8E62-CE7DB944F57B")
                    pPart.Activate(CUInt(CLSCTX.CLSCTX_INPROC_SERVER), iidKsJackDescription, o)
                    pJackDesc = CType(o, IKsJackDescription)

                    If pJackDesc IsNot Nothing Then
                        con_count = 0
                        pJackDesc.GetJackCount(con_count)
                        If con_count > 0 Then
                            Dim sb As StringBuilder

                            'display jacks
                            For i As UInteger = 0 To con_count - 1
                                pJackDesc.GetJackDescription(i, desc)

                                sb = New StringBuilder(100)
                                Dim con_type As EPcxConnectionType = CType(desc.ConnectionType, EPcxConnectionType)
                                Dim loc As EPcxGeoLocation = CType(desc.GeoLocation, EPcxGeoLocation)
                                res.Append("* ")

                                Select Case con_type
                                    Case EPcxConnectionType.eConnType3Point5mm
                                        sb.Append("Jack 3.5 mm ")
                                        Exit Select
                                    Case EPcxConnectionType.eConnTypeAtapiInternal
                                        sb.Append("ATAPI jack")
                                        Exit Select
                                    Case EPcxConnectionType.eConnTypeRCA
                                        sb.Append("RCA jack")
                                        Exit Select
                                    Case EPcxConnectionType.eConnTypeQuarter
                                        sb.Append("1/2 in. jack ")
                                        Exit Select
                                    Case EPcxConnectionType.eConnTypeOtherAnalog
                                        sb.Append("Analog jack ")
                                        Exit Select
                                    Case EPcxConnectionType.eConnTypeOtherDigital
                                        sb.Append("Digital jack ")
                                        Exit Select
                                    Case Else
                                        sb.Append(con_type.ToString() + " ")
                                        Exit Select
                                End Select

                                sb.Append("- " + loc.ToString())
                                'jack location
                                res.Append(sb.ToString())

                                If desc.IsConnected = 0 Then
                                    res.AppendLine(": Disconnected")
                                Else
                                    res.AppendLine(": Connected")


                                End If
                                'end for
                            Next
                        Else
                            res.AppendLine("* No jacks")

                        End If
                    Else
                        res.AppendLine("* Unable to get jacks")
                    End If



                Catch ex As COMException
                    If CUInt(ex.HResult) = &H80070490UI Then
                        'E_NOTFOUND
                        res.AppendLine("Disconnected")
                    Else
                        res.AppendLine("COM error while getting jacks: " + ex.Message)
                    End If
                Catch ex As Exception
                    res.AppendLine("Error while getting jacks: " + ex.Message)

                End Try
            Finally
                'clean up resources
                If dev IsNot Nothing Then
                    Marshal.ReleaseComObject(dev)
                End If
                If propertyStore IsNot Nothing Then
                    Marshal.ReleaseComObject(propertyStore)
                End If

                If pDeviceTopology IsNot Nothing Then
                    Marshal.ReleaseComObject(pDeviceTopology)
                    pDeviceTopology = Nothing
                End If
                If pConnFrom IsNot Nothing Then
                    Marshal.ReleaseComObject(pConnFrom)
                    pConnFrom = Nothing
                End If
                If pConnTo IsNot Nothing Then
                    Marshal.ReleaseComObject(pConnTo)
                    pConnTo = Nothing
                End If
                If pPart IsNot Nothing Then
                    Marshal.ReleaseComObject(pPart)
                    pPart = Nothing
                End If
                If pJackDesc IsNot Nothing Then
                    Marshal.ReleaseComObject(pJackDesc)
                    pJackDesc = Nothing
                End If
            End Try

            Return res.ToString()
        End Function


        Public Sub New()
            InitializeComponent()
        End Sub

        Private Sub button_Click(sender As Object, e As EventArgs)
            Dim devenum As New MMDeviceEnumerator()
            'Create enumerator
            Dim deviceEnumerator As IMMDeviceEnumerator = CType(devenum, IMMDeviceEnumerator)

            Dim defDevice As IMMDevice = Nothing
            Dim propertyStore As IPropertyStore = Nothing

            Try
                Dim o As Object = Nothing

                ' * get default device *
                deviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eConsole, o)
                defDevice = TryCast(o, IMMDevice)

                textBox1.Text = "Default sound device: " + Environment.NewLine + Environment.NewLine

                textBox1.Text += PrintDevice(defDevice)
            Catch ex As Exception
                MessageBox.Show(ex.ToString())
            Finally
                'clean up resources
                If devenum IsNot Nothing Then
                    Marshal.ReleaseComObject(devenum)
                End If
                If deviceEnumerator IsNot Nothing Then
                    Marshal.ReleaseComObject(deviceEnumerator)
                End If
                If defDevice IsNot Nothing Then
                    Marshal.ReleaseComObject(defDevice)
                End If
                If propertyStore IsNot Nothing Then
                    Marshal.ReleaseComObject(propertyStore)
                End If
            End Try
        End Sub


    End Class
End Namespace

关于vb.net - 如何获取扬声器是否已插入,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41097521/

10-12 07:25