none
Pinvoke on an interface implemented in Windows 7 for Windows Media Player Object RRS feed

  • Question

  • I'm having troubles using pinvoke to access a function in an interface added in Windows 7.  The C/C++ implementation is in the Windows 7 Beta SDK in the file wmprealestate.h (for WMP).  The code for this is below:

    /* interface IWMPAudioRenderConfig */ 
    /* [oleautomation][unique][helpstring][uuid][object] */  
     
     
    EXTERN_C const IID IID_IWMPAudioRenderConfig; 
    #if defined(__cplusplus) && !defined(CINTERFACE) 
         
        MIDL_INTERFACE("e79c6349-5997-4ce4-917c-22a3391ec564"
        IWMPAudioRenderConfig : public IUnknown 
        { 
        public
            virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_audioOutputDevice(  
                /* [retval][out] */ BSTR *pbstrOutputDevice) = 0; 
             
            virtual /* [propput] */ HRESULT STDMETHODCALLTYPE put_audioOutputDevice(  
                /* [unique][in] */ BSTR bstrOutputDevice) = 0; 
             
        }; 
        
    #else     /* C style interface */ 
     
        typedef struct IWMPAudioRenderConfigVtbl 
        { 
            BEGIN_INTERFACE 
             
            HRESULT ( STDMETHODCALLTYPE *QueryInterface )(  
                IWMPAudioRenderConfig * This, 
                /* [in] */ REFIID riid, 
                /* [annotation][iid_is][out] */  
                __RPC__deref_out  void **ppvObject); 
             
            ULONG ( STDMETHODCALLTYPE *AddRef )(  
                IWMPAudioRenderConfig * This); 
             
            ULONG ( STDMETHODCALLTYPE *Release )(  
                IWMPAudioRenderConfig * This); 
             
            /* [propget] */ HRESULT ( STDMETHODCALLTYPE *get_audioOutputDevice )(  
                IWMPAudioRenderConfig * This, 
                /* [retval][out] */ BSTR *pbstrOutputDevice); 
             
            /* [propput] */ HRESULT ( STDMETHODCALLTYPE *put_audioOutputDevice )(  
                IWMPAudioRenderConfig * This, 
                /* [unique][in] */ BSTR bstrOutputDevice); 
             
            END_INTERFACE 
        } IWMPAudioRenderConfigVtbl; 
     
        interface IWMPAudioRenderConfig 
        { 
            CONST_VTBL struct IWMPAudioRenderConfigVtbl *lpVtbl; 
        }; 
        
    #ifdef COBJMACROS 
    #define IWMPAudioRenderConfig_QueryInterface(This,riid,ppvObject)               \ 
        ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )  
    #define IWMPAudioRenderConfig_AddRef(This)             \ 
        ( (This)->lpVtbl -> AddRef(This) )  
    #define IWMPAudioRenderConfig_Release(This)            \ 
        ( (This)->lpVtbl -> Release(This) )  
    #define IWMPAudioRenderConfig_get_audioOutputDevice(This,pbstrOutputDevice)   \ 
        ( (This)->lpVtbl -> get_audioOutputDevice(This,pbstrOutputDevice) )  
    #define IWMPAudioRenderConfig_put_audioOutputDevice(This,bstrOutputDevice)     \ 
        ( (This)->lpVtbl -> put_audioOutputDevice(This,bstrOutputDevice) )  
    #endif /* COBJMACROS */ 
    #endif   /* C style interface */ 
    #endif   /* __IWMPAudioRenderConfig_INTERFACE_DEFINED__ */ 

    I need to access this from C#.  This is for the Windows Media Player SDK.  I was told the following when I asked if these functions were available from the C# activex WMP object:

    " The interface should be defined in wmprealestate.idl/wmprealestate.h, you’ll need to use P/Invoke to call into it because it is not a part of the scriptable interface to Windows Media Player. "

    The WMP object is created by adding a reference to "WMP.dll" in the C:\windows\system32 folder.  The object is instantiated as follows:

    private AxWMPLib.AxWindowsMediaPlayer Player = new AxWMPLib.AxWindowsMediaPlayer();

    Can anyone provide some guidance on how I can access/implement in C#, IWMPAudioRenderConfig put_audioOutputDevice get_audioOutputDevice on the Player object so that I can set the audio output device for that instance of the WMP object.

    Thank you,

    John

    Monday, February 2, 2009 4:54 PM

Answers

  • Doing COM interop your self is never much fun, I'd say start with something like this :

        [Guid("e79c6349-5997-4ce4-917c-22a3391ec564"),  
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]  
        internal interface IWMPAudioRenderConfig   
        {  
            int get_audioOutputDevice([MarshalAs(UnmanagedType.LPWStr)] out string pbstrOutputDevice);    
            int put_audioOutputDevice(string bstrOutputDevice);    
        };  


    and use it like this

    private AxWMPLib.AxWindowsMediaPlayer Player = new AxWMPLib.AxWindowsMediaPlayer();  
    IWMPAudioRenderConfig  ac = Player as IWMPAudioRenderConfig;  
    if (ac==null)  
    {  
       Console.WriteLine("uh ow... baaaaaad.");  
    }  
    else 
    {  
        string x;  
        ac.get_audioOutputDevice(out x);  
        Console.WriteLine(x);  
    }  
     

    I didn't test any of this so no guarantee it will even compile :)
    • Marked as answer by renzskas Monday, February 9, 2009 10:32 PM
    Monday, February 2, 2009 8:40 PM
  • Don't think the actual calling of the interface is the problem its more the complete lack of documentation on that interface. Guess you have to wait for the next version of the windows SDK and hope they actually documented it.
    • Marked as answer by Zhi-Xin Ye Monday, February 9, 2009 8:38 AM
    Wednesday, February 4, 2009 5:45 AM
  • For anyone who wants the answer (almost 4 years later):

    using System;
    using System.Collections.Generic;
    using System.Runtime.InteropServices;
    using Microsoft.DirectX
    using Microsoft.DirectX.DirectSound
    
        [ComImport]
        [Guid("E79C6349-5997-4CE4-917C-22A3391EC564")]
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        private interface IWMPAudioRenderConfig
        {
            int get_audioOutputDevice([MarshalAs(UnmanagedType.LPWStr)] out string pbstrOutputDevice);
            int put_audioOutputDevice(string bstrOutputDevice);
        }
    
        public static bool SetWMPAudioDeviceOnWindows7(AxWMPLib.AxWindowsMediaPlayer axWMP, string audioDeviceName)
        {
            try
            {
                if (!OSInfo.Is7)
                    return false;
    
                IWMPAudioRenderConfig wmpAudioConfig = (IWMPAudioRenderConfig)axWMP.GetOcx();
    
                if (wmpAudioConfig == null)
                    return false;
    
                wmpAudioConfig.put_audioOutputDevice(DirectXDeviceInformation.GetAudioDeviceID(audioDeviceName));
            }
            catch (Exception ex)
            {
                Utility.LogExceptionChild("SetWMPAudioDeviceOnWindows7+", ex);
            }
    
            return true;
        }
    
    public class DirectXDeviceInformation
        {
    
    public static string GetAudioDeviceID(string audioDeviceName)
            {
                DevicesCollection devList = new DevicesCollection();
    
                foreach (DeviceInformation device in devList)
                {
                    //if windows 7 and wmp, we want to get the device.ModuleName which is the {0.0.0.00000000}.GUID
                    if (string.Compare(device.Description, audioDeviceName, StringComparison.InvariantCultureIgnoreCase) == 0)
                        return device.ModuleName;
                }
    
                return string.Empty;
            }
    }

    • Marked as answer by renzskas Friday, January 18, 2013 4:25 PM
    Friday, January 18, 2013 4:25 PM

All replies

  • Doing COM interop your self is never much fun, I'd say start with something like this :

        [Guid("e79c6349-5997-4ce4-917c-22a3391ec564"),  
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]  
        internal interface IWMPAudioRenderConfig   
        {  
            int get_audioOutputDevice([MarshalAs(UnmanagedType.LPWStr)] out string pbstrOutputDevice);    
            int put_audioOutputDevice(string bstrOutputDevice);    
        };  


    and use it like this

    private AxWMPLib.AxWindowsMediaPlayer Player = new AxWMPLib.AxWindowsMediaPlayer();  
    IWMPAudioRenderConfig  ac = Player as IWMPAudioRenderConfig;  
    if (ac==null)  
    {  
       Console.WriteLine("uh ow... baaaaaad.");  
    }  
    else 
    {  
        string x;  
        ac.get_audioOutputDevice(out x);  
        Console.WriteLine(x);  
    }  
     

    I didn't test any of this so no guarantee it will even compile :)
    • Marked as answer by renzskas Monday, February 9, 2009 10:32 PM
    Monday, February 2, 2009 8:40 PM
  • I modified your example a little:

    [ComImport] 
    [Guid("E79C6349-5997-4CE4-917C-22A3391EC564")] 
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
    internal interface IWMPAudioRenderConfig 
       int get_audioOutputDevice([MarshalAs(UnmanagedType.LPWStr)] out string pbstrOutputDevice); 
       int put_audioOutputDevice(string bstrOutputDevice); 
    };   
     
     
    private AxWMPLib.AxWindowsMediaPlayer Player = new AxWMPLib.AxWindowsMediaPlayer();   
    IWMPAudioRenderConfig  ac = Player.GetOcx() as IWMPAudioRenderConfig;   
    if (ac==null)   
    {   
       Console.WriteLine("uh ow... baaaaaad.");   
    }   
    else  
    {   
        string x;   
        ac.get_audioOutputDevice(out x);   
        Console.WriteLine(x);   
    }   
      
     
     
     

    But it always returns null.  When trying to use the "put_" with a string I get "Value is out of valid range" (paraphrased).  I'm trying to get the docs from the WMP SDK team but if anyone has any further insight to what the problem is I'd be grateful.

    Thank you,

    John
    • Marked as answer by renzskas Monday, February 9, 2009 10:32 PM
    • Unmarked as answer by renzskas Monday, February 9, 2009 10:32 PM
    Tuesday, February 3, 2009 4:55 AM
  • I would delcare the interface like this

    [ComImport]
    [Guid("E79C6349-5997-4CE4-917C-22A3391EC564")] 
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
    internal interface IWMPAudioRenderConfig 
       void get_audioOutputDevice(out string pbstrOutputDevice); 
       void put_audioOutputDevice(string bstrOutputDevice); 
    }   

    Mattias, C# MVP
    Tuesday, February 3, 2009 3:47 PM
    Moderator
  • Still no go.  I still get null and when setting I get "Value does not fall within the expected range.".

    Any other ideas or anyone else with Windows 7 that can help test this?

    Thanks,

    John
    Wednesday, February 4, 2009 1:48 AM
  • Don't think the actual calling of the interface is the problem its more the complete lack of documentation on that interface. Guess you have to wait for the next version of the windows SDK and hope they actually documented it.
    • Marked as answer by Zhi-Xin Ye Monday, February 9, 2009 8:38 AM
    Wednesday, February 4, 2009 5:45 AM
  • You are correct that the interface is correct.  With that help, I have resolved the issue.

    Thank you,

    John

    Monday, February 9, 2009 10:32 PM
  • For anyone who wants the answer (almost 4 years later):

    using System;
    using System.Collections.Generic;
    using System.Runtime.InteropServices;
    using Microsoft.DirectX
    using Microsoft.DirectX.DirectSound
    
        [ComImport]
        [Guid("E79C6349-5997-4CE4-917C-22A3391EC564")]
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        private interface IWMPAudioRenderConfig
        {
            int get_audioOutputDevice([MarshalAs(UnmanagedType.LPWStr)] out string pbstrOutputDevice);
            int put_audioOutputDevice(string bstrOutputDevice);
        }
    
        public static bool SetWMPAudioDeviceOnWindows7(AxWMPLib.AxWindowsMediaPlayer axWMP, string audioDeviceName)
        {
            try
            {
                if (!OSInfo.Is7)
                    return false;
    
                IWMPAudioRenderConfig wmpAudioConfig = (IWMPAudioRenderConfig)axWMP.GetOcx();
    
                if (wmpAudioConfig == null)
                    return false;
    
                wmpAudioConfig.put_audioOutputDevice(DirectXDeviceInformation.GetAudioDeviceID(audioDeviceName));
            }
            catch (Exception ex)
            {
                Utility.LogExceptionChild("SetWMPAudioDeviceOnWindows7+", ex);
            }
    
            return true;
        }
    
    public class DirectXDeviceInformation
        {
    
    public static string GetAudioDeviceID(string audioDeviceName)
            {
                DevicesCollection devList = new DevicesCollection();
    
                foreach (DeviceInformation device in devList)
                {
                    //if windows 7 and wmp, we want to get the device.ModuleName which is the {0.0.0.00000000}.GUID
                    if (string.Compare(device.Description, audioDeviceName, StringComparison.InvariantCultureIgnoreCase) == 0)
                        return device.ModuleName;
                }
    
                return string.Empty;
            }
    }

    • Marked as answer by renzskas Friday, January 18, 2013 4:25 PM
    Friday, January 18, 2013 4:25 PM