MSDN.WhiteKnight - Stack Overflow answers
Ответ на "How to get whether a speaker plugged or unplugged"
Answer 46503072
It can be done with Device Topology API.
IKsJackDescription
interface can be used to getKSJACK_DESCRIPTION
structure, which hasIsConnected
member. However, not every device supports cable presence detection, in case it doesn't the API will always report it's connected.COM objects declarations
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
Example how to get info about current default device's jack information
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
Content is retrieved from StackExchange API.
Auto-generated by ruso-archive tools.