web-dev-qa-db-ja.com

C#を介してヘッドフォンが接続されているかどうかを検出します

ヘッドフォンがC#経由で接続されているかどうかを検出する方法の例はありません。

そのためのイベントになると思います...

WMIを使用するのは理にかなっていますか?

 ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\cimv2",
                                                                  "SELECT * FROM Win32_SoundDevice");

foreach (ManagementObject queryObj in searcher.Get())
{
    Console.WriteLine("-----------------------------------");
    Console.WriteLine("Win32_SoundDevice instance");
    Console.WriteLine("-----------------------------------");
    Console.WriteLine("StatusInfo: {0}", queryObj["StatusInfo"]);
}

誰かがそれを提供してとても喜んでいますか?

ありがとうございました!

13
Developer

この種の変更を検出するには、 IMMDeviceEnumerator :: RegisterEndpointNotificationCallback メソッドを使用します。

これをC#で処理する場合は、AkosMattiassichによって既に実装されているマネージラッパーが必要になります。ここで完全な例を見つけることができます: MMAudioDeviceApi周辺のマネージドラッパー

彼は次のように述べています。

プログラムは選択したデバイスでテストサウンドを再生でき、変更時にリストを自動的に更新します。コントロールパネルを介して、または新しいデバイスを物理的に接続する場合。

9
Markus Safar

COM + APIを自分で使用することはお勧めしません。

NAudio NuGetパッケージ を見てください:

Install-Package NAudio

次のように、プラグが差し込まれた/取り外された状態のオーディオデバイスを列挙できるはずです。

var enumerator = new NAudio.CoreAudioApi.MMDeviceEnumerator();

// Allows you to enumerate rendering devices in certain states
var endpoints = enumerator.EnumerateAudioEndPoints(
    DataFlow.Render,
    DeviceState.Unplugged | DeviceState.Active);
foreach (var endpoint in endpoints)
{
    Console.WriteLine("{0} - {1}", endpoint.DeviceFriendlyName, endpoint.State);
}

// Aswell as hook to the actual event
enumerator.RegisterEndpointNotificationCallback(new NotificationClient());

NotificationClientが次のように実装されている場合:

class NotificationClient : NAudio.CoreAudioApi.Interfaces.IMMNotificationClient
{
    void IMMNotificationClient.OnDeviceStateChanged(string deviceId, DeviceState newState)
    {
        Console.WriteLine("OnDeviceStateChanged\n Device Id -->{0} : Device State {1}", deviceId, newState);
    }

    void IMMNotificationClient.OnDeviceAdded(string pwstrDeviceId) { }
    void IMMNotificationClient.OnDeviceRemoved(string deviceId) { }
    void IMMNotificationClient.OnDefaultDeviceChanged(DataFlow flow, Role role, string defaultDeviceId) { }
    void IMMNotificationClient.OnPropertyValueChanged(string pwstrDeviceId, PropertyKey key) { }
}

次と同様の結果が得られるはずです。

enter image description here

上のスクリーンショットでプラグの抜き差しを2回検出する理由は、Macbookではマイクとヘッドフォンの両方に1つのジャックを使用しているためだと思います。

10
Yannick Motton

以下は、サードパーティのライブラリを必要としない IMMNotificationClientインターフェイス に基づく(最小限の)Windowsフォームアプリケーションのサンプルです。

マルチメディアデバイスが接続/切断されるたびに通知が届きます。次に、デバイスのプロパティを確認して、適切なアクションを実行できます。また、既存のデバイスを列挙して、ヘッドフォンが接続されているかどうかを確認することもできます(IsConnectedプロパティを参照)。

COM相互運用機能の作成

サンプルコードには、関連するCOMオブジェクトの定義が含まれていることに注意してください。本番環境では、おそらく、基になるmmdevapi.dllのCOM相互運用機能アセンブリを作成します。これを行うには、最初にヘッダーファイルからタイプlibを作成します(Windows SDKをインストールする必要があります)。

midl /out c:\tmp /header "C:\Program Files (x86)\Windows Kits\8.1\Include\um\mmdeviceapi.h" "C:\Program Files (x86)\Windows Kits\8.1\Include\um\mmdeviceapi.idl"

次に、tlbimp.exeを使用してtypelibから相互運用機能アセンブリを生成する必要があります。

tlbimp /out:MMDevAPI.Interop.dll mmdeviceapi.tlb

MultiMediaNotificationListenerサンプル

using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Windows.Forms;

namespace MultiMediaNotificationListenerSample
{
    class MainWindow : Form
    {
        [STAThread]
        private static void Main(string[] args)
        {
            using (var notificationClient = new MultiMediaNotificationListener())
            {
                Trace.WriteLine(string.Format("Headphone is {0}connected", notificationClient.IsConnected ? "": "not "));
                Application.Run(new MainWindow());
            }
        }
    }

    class MultiMediaNotificationListener : IMMNotificationClient, IDisposable
    {
        private readonly IMMDeviceEnumerator _deviceEnumerator;

        public MultiMediaNotificationListener()
        {
            if (Environment.OSVersion.Version.Major < 6)
            {
                throw new NotSupportedException("This functionality is only supported on Windows Vista or newer.");
            }
            _deviceEnumerator = (IMMDeviceEnumerator)new MMDeviceEnumerator();
            _deviceEnumerator.RegisterEndpointNotificationCallback(this);
        }

        ~MultiMediaNotificationListener()
        {
            Dispose(false);
        }

        public bool IsConnected
        {
            get
            {
                IMMDeviceCollection deviceCollection;
                _deviceEnumerator.EnumAudioEndpoints(EDataFlow.eRender, (uint)DeviceState.DEVICE_STATE_ACTIVE, out deviceCollection);

                uint deviceCount = 0;
                deviceCollection.GetCount(out deviceCount);
                for (uint i = 0; i < deviceCount; i++)
                {
                    IMMDevice device;
                    deviceCollection.Item(i, out device);

                    IPropertyStore propertyStore;
                    device.OpenPropertyStore((uint)STGM.STGM_READ, out propertyStore);

                    PROPVARIANT property;
                    propertyStore.GetValue(ref PropertyKey.PKEY_Device_DeviceDesc, out property);

                    var value = (string)property.Value;
                    Marshal.ReleaseComObject(propertyStore);
                    Marshal.ReleaseComObject(device);

                    if (value == "Headphones")
                    {
                        return true;
                    }
                }

                Marshal.ReleaseComObject(deviceCollection);
                return false;
            }
        }

        public void OnDefaultDeviceChanged(EDataFlow dataFlow, ERole deviceRole, string pwstrDefaultDeviceId)
        {
        }

        public void OnDeviceStateChanged(string pwstrDeviceId, uint dwNewState)
        {
            IMMDevice device;
            _deviceEnumerator.GetDevice(pwstrDeviceId, out device);

            IPropertyStore propertyStore;
            device.OpenPropertyStore((uint)STGM.STGM_READ, out propertyStore);

            Trace.WriteLine(string.Format("OnDeviceStateChanged:\n  Device Id {0}\tDevice State {1}", pwstrDeviceId, (DeviceState)dwNewState));

            var properties = PropertyKey.GetPropertyKeys()
                .Select(
                propertyKey =>
                {
                    PROPVARIANT property;
                    propertyStore.GetValue(ref propertyKey, out property);
                    return new { Key = PropertyKey.GetKeyName(propertyKey), Value = property.Value };
                })
                .Where(@t => @t.Value != null);

            foreach (var property in properties)
            {
                Trace.WriteLine(string.Format("    {0}\t{1}", property.Key, property.Value));
            }

            Marshal.ReleaseComObject(propertyStore);
            Marshal.ReleaseComObject(device);
        }

        public void OnDeviceAdded(string deviceId)
        {
        }

        public void OnDeviceRemoved(string deviceId)
        {
        }

        public void OnPropertyValueChanged(string pwstrDeviceId, PropertyKey key)
        {
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool disposing)
        {
            _deviceEnumerator.UnregisterEndpointNotificationCallback(this);
            Marshal.ReleaseComObject(_deviceEnumerator);
        }
    }

    public enum STGM : uint
    {
        STGM_READ = 0x0,
        STGM_WRITE = 0x1,
        STGM_READWRITE = 0x2
    }

    public enum DeviceState
    {
        DEVICE_STATE_ACTIVE = 0x00000001,
        DEVICE_STATE_DISABLED = 0x00000002,
        DEVICE_STATE_NOTPRESENT = 0x00000004,
        DEVICE_STATE_UNPLUGGED = 0x00000008,
        DEVICE_STATEMASK_ALL = 0x0000000f
    }

    [ComImport]
    [Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")]
    internal class MMDeviceEnumerator
    {
    }

    public enum EDataFlow
    {
        eRender,
        eCapture,
        eAll,
        EDataFlow_enum_count
    }

    public enum ERole
    {
        eConsole,
        eMultimedia,
        eCommunications,
        ERole_enum_count
    }

    [Guid("0BD7A1BE-7A1A-44DB-8397-CC5392387B5E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), TypeLibType(TypeLibTypeFlags.FNonExtensible)]
    [ComImport]
    public interface IMMDeviceCollection
    {
        [MethodImpl(MethodImplOptions.InternalCall)]
        void GetCount(out uint pcDevices);
        [MethodImpl(MethodImplOptions.InternalCall)]
        void Item([In] uint nDevice, [MarshalAs(UnmanagedType.Interface)] out IMMDevice ppDevice);
    }

    [Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), TypeLibType(TypeLibTypeFlags.FNonExtensible)]
    [ComImport]
    public interface IMMDeviceEnumerator
    {
        [MethodImpl(MethodImplOptions.InternalCall)]
        void EnumAudioEndpoints([ComAliasName("MMDevAPI.Interop.EDataFlow")] [In] EDataFlow dataFlow, [In] uint dwStateMask, [MarshalAs(UnmanagedType.Interface)] out IMMDeviceCollection ppDevices);
        [MethodImpl(MethodImplOptions.InternalCall)]
        void GetDefaultAudioEndpoint([ComAliasName("MMDevAPI.Interop.EDataFlow")] [In] EDataFlow dataFlow, [ComAliasName("MMDevAPI.Interop.ERole")] [In] ERole role, [MarshalAs(UnmanagedType.Interface)] out IMMDevice ppEndpoint);
        [MethodImpl(MethodImplOptions.InternalCall)]
        void GetDevice([MarshalAs(UnmanagedType.LPWStr)] [In] string pwstrId, [MarshalAs(UnmanagedType.Interface)] out IMMDevice ppDevice);
        [MethodImpl(MethodImplOptions.InternalCall)]
        void RegisterEndpointNotificationCallback([MarshalAs(UnmanagedType.Interface)] [In] IMMNotificationClient pClient);
        [MethodImpl(MethodImplOptions.InternalCall)]
        void UnregisterEndpointNotificationCallback([MarshalAs(UnmanagedType.Interface)] [In] IMMNotificationClient pClient);
    }

    [Guid("D666063F-1587-4E43-81F1-B948E807363F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), TypeLibType(TypeLibTypeFlags.FNonExtensible)]
    [ComImport]
    public interface IMMDevice
    {
        [MethodImpl(MethodImplOptions.InternalCall)]
        void Activate([In] ref Guid iid, [In] uint dwClsCtx, [In] IntPtr pActivationParams, [MarshalAs(UnmanagedType.IUnknown)] out object ppInterface);
        [MethodImpl(MethodImplOptions.InternalCall)]
        void OpenPropertyStore([In] uint stgmAccess, [MarshalAs(UnmanagedType.Interface)] out IPropertyStore ppProperties);
        [MethodImpl(MethodImplOptions.InternalCall)]
        void GetId([MarshalAs(UnmanagedType.LPWStr)] out string ppstrId);
        [MethodImpl(MethodImplOptions.InternalCall)]
        void GetState(out uint pdwState);
    }

    [Guid("7991EEC9-7E89-4D85-8390-6C703CEC60C0"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), TypeLibType(TypeLibTypeFlags.FNonExtensible)]
    [ComImport]
    public interface IMMNotificationClient
    {
        [MethodImpl(MethodImplOptions.InternalCall)]
        void OnDeviceStateChanged([MarshalAs(UnmanagedType.LPWStr)] [In] string pwstrDeviceId, [In] uint dwNewState);
        [MethodImpl(MethodImplOptions.InternalCall)]
        void OnDeviceAdded([MarshalAs(UnmanagedType.LPWStr)] [In] string pwstrDeviceId);
        [MethodImpl(MethodImplOptions.InternalCall)]
        void OnDeviceRemoved([MarshalAs(UnmanagedType.LPWStr)] [In] string pwstrDeviceId);
        [MethodImpl(MethodImplOptions.InternalCall)]
        void OnDefaultDeviceChanged([ComAliasName("MMDevAPI.Interop.EDataFlow")] [In] EDataFlow flow, [ComAliasName("MMDevAPI.Interop.ERole")] [In] ERole role, [MarshalAs(UnmanagedType.LPWStr)] [In] string pwstrDefaultDeviceId);
        [MethodImpl(MethodImplOptions.InternalCall)]
        void OnPropertyValueChanged([MarshalAs(UnmanagedType.LPWStr)] [In] string pwstrDeviceId, [In] PropertyKey key);
    }

    [Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [ComImport]
    public interface IPropertyStore
    {
        [MethodImpl(MethodImplOptions.InternalCall)]
        void GetCount(out uint cProps);
        [MethodImpl(MethodImplOptions.InternalCall)]
        void GetAt([In] uint iProp, out PropertyKey pkey);
        [MethodImpl(MethodImplOptions.InternalCall)]
        void GetValue([In] ref PropertyKey key, out PROPVARIANT pv);
        [MethodImpl(MethodImplOptions.InternalCall)]
        void SetValue([In] ref PropertyKey key, [In] ref PROPVARIANT propvar);
        [MethodImpl(MethodImplOptions.InternalCall)]
        void Commit();
    }

    [StructLayout(LayoutKind.Sequential, Pack = 4)]
    public struct PropertyKey
    {
        public static PropertyKey PKEY_Device_DeviceDesc = new PropertyKey { fmtid = new Guid(unchecked((int)0xa45c254e), unchecked((short)0xdf1c), 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0), pid = 2 }; // DEVPROP_TYPE_STRING
        public static PropertyKey PKEY_Device_HardwareIds = new PropertyKey { fmtid = new Guid(unchecked((int)0xa45c254e), unchecked((short)0xdf1c), 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0), pid = 3 }; // DEVPROP_TYPE_STRING_LIST
        public static PropertyKey PKEY_Device_Service = new PropertyKey { fmtid = new Guid(unchecked((int)0xa45c254e), unchecked((short)0xdf1c), 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0), pid = 6 }; // DEVPROP_TYPE_STRING
        public static PropertyKey PKEY_Device_Class = new PropertyKey { fmtid = new Guid(unchecked((int)0xa45c254e), unchecked((short)0xdf1c), 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0), pid = 9 }; // DEVPROP_TYPE_STRING
        public static PropertyKey PKEY_Device_Driver = new PropertyKey { fmtid = new Guid(unchecked((int)0xa45c254e), unchecked((short)0xdf1c), 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0), pid = 11 }; // DEVPROP_TYPE_STRING
        public static PropertyKey PKEY_Device_ConfigFlags = new PropertyKey { fmtid = new Guid(unchecked((int)0xa45c254e), unchecked((short)0xdf1c), 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0), pid = 12 }; // DEVPROP_TYPE_UINT32
        public static PropertyKey PKEY_Device_Manufacturer = new PropertyKey { fmtid = new Guid(unchecked((int)0xa45c254e), unchecked((short)0xdf1c), 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0), pid = 13 }; // DEVPROP_TYPE_STRING
        public static PropertyKey PKEY_Device_FriendlyName = new PropertyKey { fmtid = new Guid(unchecked((int)0xa45c254e), unchecked((short)0xdf1c), 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0), pid = 14 }; // DEVPROP_TYPE_STRING
        public static PropertyKey PKEY_Device_LocationInfo = new PropertyKey { fmtid = new Guid(unchecked((int)0xa45c254e), unchecked((short)0xdf1c), 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0), pid = 15 }; // DEVPROP_TYPE_STRING
        public static PropertyKey PKEY_Device_Capabilities = new PropertyKey { fmtid = new Guid(unchecked((int)0xa45c254e), unchecked((short)0xdf1c), 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0), pid = 17 }; // DEVPROP_TYPE_UNINT32
        public static PropertyKey PKEY_Device_BusNumber = new PropertyKey { fmtid = new Guid(unchecked((int)0xa45c254e), unchecked((short)0xdf1c), 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0), pid = 23 }; // DEVPROP_TYPE_UINT32
        public static PropertyKey PKEY_Device_EnumeratorName = new PropertyKey { fmtid = new Guid(unchecked((int)0xa45c254e), unchecked((short)0xdf1c), 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0), pid = 24 }; // DEVPROP_TYPE_STRING
        public static PropertyKey PKEY_Device_DevType = new PropertyKey { fmtid = new Guid(unchecked((int)0xa45c254e), unchecked((short)0xdf1c), 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0), pid = 27 }; // DEVPROP_TYPE_UINT32
        public static PropertyKey PKEY_Device_Characteristics = new PropertyKey { fmtid = new Guid(unchecked((int)0xa45c254e), unchecked((short)0xdf1c), 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0), pid = 29 }; // DEVPROP_TYPE_UINT32


        public static PropertyKey PKEY_Device_ManufacturerAttributes = new PropertyKey { fmtid = new Guid(unchecked((int)0x80d81ea6), unchecked((short)0x7473), 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b), pid = 4 }; // DEVPROP_TYPE_UINT32

        public static PropertyKey PKEY_DeviceClass_IconPath = new PropertyKey { fmtid = new Guid(unchecked((int)0x259abffc), 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66), pid = 12 }; // DEVPROP_TYPE_STRING_LIST

        public static PropertyKey PKEY_DeviceClass_ClassCoInstallers = new PropertyKey { fmtid = new Guid(unchecked((int)0x713d1703), 0xa2e2, 0x49f5, 0x92, 0x14, 0x56, 0x47, 0x2e, 0xf3, 0xda, 0x5c), pid = 2 }; // DEVPROP_TYPE_STRING_LIST

        public static PropertyKey PKEY_DeviceInterface_FriendlyName = new PropertyKey { fmtid = new Guid(unchecked((int)0x026e516e), 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22), pid = 2 }; // DEVPROP_TYPE_STRING

        public Guid fmtid;
        public uint pid;

        public static IEnumerable<PropertyKey> GetPropertyKeys()
        {
            var keyFields = typeof(PropertyKey).GetFields(BindingFlags.Public | BindingFlags.Static);
            return keyFields.Where(fieldInfo => fieldInfo.FieldType == typeof(PropertyKey))
                            .Select(fieldInfo => (PropertyKey)fieldInfo.GetValue(null));
        }

        public static string GetKeyName(PropertyKey propertyKey)
        {
            var keyFields = typeof(PropertyKey).GetFields(BindingFlags.Public | BindingFlags.Static);
            return keyFields.Select(fieldInfo => new { fieldInfo, value = (PropertyKey)fieldInfo.GetValue(null) })
                            .Where(@t => propertyKey.pid == @t.value.pid && propertyKey.fmtid == @t.value.fmtid)
                            .Select(@t => @t.fieldInfo.Name).FirstOrDefault();
        }
    }

    [StructLayout(LayoutKind.Sequential, Pack = 8)]
    public struct PROPVARIANT
    {
        public ushort variantType;
        public byte wReserved1;
        public byte wReserved2;
        public uint wReserved3;
        public PROPVARIANTVALUE value;

        public object Value
        {
            get
            {
                switch ((VarEnum)variantType)
                {
                    case VarEnum.VT_EMPTY:
                        return null;
                    case VarEnum.VT_NULL:
                        return null;
                    case VarEnum.VT_VARIANT:
                        break;
                    case VarEnum.VT_DECIMAL:
                        return value.cyVal;
                    case VarEnum.VT_VOID:
                        break;
                    case VarEnum.VT_HRESULT:
                        break;
                    case VarEnum.VT_PTR:
                        break;
                    case VarEnum.VT_SAFEARRAY:
                        break;
                    case VarEnum.VT_CARRAY:
                        break;
                    case VarEnum.VT_USERDEFINED:
                        break;
                    case VarEnum.VT_RECORD:
                        break;
                    case VarEnum.VT_STREAM:
                        break;
                    case VarEnum.VT_STORAGE:
                        break;
                    case VarEnum.VT_STREAMED_OBJECT:
                        break;
                    case VarEnum.VT_STORED_OBJECT:
                        break;
                    case VarEnum.VT_BLOB_OBJECT:
                        break;
                    case VarEnum.VT_CF:
                        break;
                    case VarEnum.VT_CLSID:
                        return Marshal.PtrToStructure(value.pVal, typeof(Guid));
                    case VarEnum.VT_VECTOR:
                        break;
                    case VarEnum.VT_ARRAY:
                        break;
                    case VarEnum.VT_BYREF:
                        break;
                    case VarEnum.VT_I1:
                        return value.cVal;
                    case VarEnum.VT_UI1:
                        return value.bVal;
                    case VarEnum.VT_I2:
                        return value.iVal;
                    case VarEnum.VT_UI2:
                        return value.uiVal;
                    case VarEnum.VT_I4:
                    case VarEnum.VT_INT:
                        return value.intVal;
                    case VarEnum.VT_UI4:
                    case VarEnum.VT_UINT:
                        return value.uintVal;
                    case VarEnum.VT_I8:
                        return value.hVal;
                    case VarEnum.VT_UI8:
                        return value.uhVal;
                    case VarEnum.VT_R4:
                        return value.fltVal;
                    case VarEnum.VT_R8:
                        return value.dblVal;
                    case VarEnum.VT_BOOL:
                        return value.boolVal;
                    case VarEnum.VT_ERROR:
                        return value.scode;
                    case VarEnum.VT_CY:
                        return value.cyVal;
                    case VarEnum.VT_DATE:
                        return value.date;
                    case VarEnum.VT_FILETIME:
                        return DateTime.FromFileTime(value.hVal);
                    case VarEnum.VT_BSTR:
                        return Marshal.PtrToStringBSTR(value.pVal);
                    case VarEnum.VT_BLOB:
                        var blob = value.blob;
                        var blobData = new byte[blob.cbSize];
                        Marshal.Copy(blob.pBlobData, blobData, 0, (int)blob.cbSize);
                        return blobData;
                    case VarEnum.VT_LPSTR:
                        return Marshal.PtrToStringAnsi(value.pVal);
                    case VarEnum.VT_LPWSTR:
                        return Marshal.PtrToStringUni(value.pVal);
                    case VarEnum.VT_UNKNOWN:
                        return Marshal.GetObjectForIUnknown(value.pVal);
                    case VarEnum.VT_DISPATCH:
                        return value.pVal;
                    //default:
                    //    throw new NotSupportedException("The type of this variable is not support ('" + variantType + "')");
                }
                return string.Format("unsupported {0}", ((VarEnum)variantType));
                //throw new NotSupportedException("The type of this variable is not support ('" + variantType.ToString() + "')");
            }
        }
    }

    [ComConversionLoss]
    [StructLayout(LayoutKind.Explicit, Pack = 8, Size = 8)]
    public struct PROPVARIANTVALUE
    {
        [FieldOffset(0)]
        public sbyte cVal;
        [FieldOffset(0)]
        public byte bVal;
        [FieldOffset(0)]
        public short iVal;
        [FieldOffset(0)]
        public ushort uiVal;
        [FieldOffset(0)]
        public int intVal;
        [FieldOffset(0)]
        public uint uintVal;
        [FieldOffset(0)]
        public long hVal;
        [FieldOffset(0)]
        public ulong uhVal;
        [FieldOffset(0)]
        public float fltVal;
        [FieldOffset(0)]
        public double dblVal;
        [FieldOffset(0)]
        public short boolVal;
        [FieldOffset(0)]
        [MarshalAs(UnmanagedType.Error)]
        public int scode;
        [FieldOffset(0)]
        [MarshalAs(UnmanagedType.Currency)]
        public decimal cyVal;
        [FieldOffset(0)]
        public DateTime date;
        [FieldOffset(0)]
        public tagFILETIME filetime;
        [FieldOffset(0)]
        public tagARRAY array;
        [FieldOffset(0)]
        public tagBLOB blob;
        [ComConversionLoss]
        [FieldOffset(0)]
        public IntPtr pVal;
    }

    [ComConversionLoss]
    [StructLayout(LayoutKind.Sequential, Pack = 4)]
    public struct tagARRAY
    {
        public uint cElems;
        [ComConversionLoss]
        public IntPtr pElems;
    }

    [ComConversionLoss]
    [StructLayout(LayoutKind.Sequential, Pack = 4)]
    public struct tagBLOB
    {
        public uint cbSize;
        [ComConversionLoss]
        public IntPtr pBlobData;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 4)]
    public struct tagFILETIME
    {
        public uint dwLowDateTime;
        public uint dwHighDateTime;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 8)]
    public struct tagLARGEINTEGER
    {
        public long QuadPart;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 8)]
    public struct tagULARGEINTEGER
    {
        public ulong QuadPart;
    }
}
4
Dirk Vollmar