Draw VST Editor in UserControl

Aug 22, 2015 at 11:08 PM
I've been opening VST editors in a popup. However, I'd like to open the editor in my existing UI. There's probably some issues around real estate, but I'd like to try to get that right. The problem I'm facing is that I can't get the window handle from a standard WPF panel. Here is my popup code:

Note: The equivalent code for getting the Window Handle returns null when the control inherits from Canvas.
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Interop;
using host = Jacobi.Vst.Core.Host;
using interophost = Jacobi.Vst.Interop.Host;

namespace MySynth
{
    /// <summary>
    /// Interaction logic for PluginPopup.xaml
    /// </summary>
    public partial class PluginPopup : Window
    {
        #region Events
        public event EventHandler ParametersLoaded;
        #endregion

        #region Fields
        private interophost.VstPluginContext _ExternalVstContext;
        private ParameterInfoDictionary _PluginParameters = new ParameterInfoDictionary();
        #endregion

        #region Constructor
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Vst")]
        public PluginPopup( interophost.VstPluginContext externalVstContext)
        {
            _ExternalVstContext = externalVstContext;
            InitializeComponent();
        }
        #endregion

        #region Overrides
        protected override void OnClosing(CancelEventArgs e)
        {
            _ExternalVstContext.PluginCommandStub.EditorClose();
            base.OnClosing(e);
        }

        #endregion

        #region Public Properties
        public host.IVstPluginCommandStub PluginCommandStub
        {
            get
            {
                return _ExternalVstContext.PluginCommandStub;
            }
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Vst")]
        public host.IVstPluginContext ExternalVstContext
        {
            get
            {
                return _ExternalVstContext;
            }
        }

        private IntPtr WindowHandle
        {
            get
            {
                var source = PresentationSource.FromVisual(this) as HwndSource;
                return source.Handle;
            }
        }

        public ParameterInfoDictionary PluginParameters
        {
            get
            {
                return _PluginParameters;
            }
        }
        #endregion

        #region Public Methods
        public void OpenEditor()
        {
            System.Drawing.Rectangle wndRect;

            if (_ExternalVstContext.PluginCommandStub.EditorGetRect(out wndRect))
            {
                _ExternalVstContext.PluginCommandStub.EditorOpen(WindowHandle);
            }

            GetParameters();

            if (ParametersLoaded != null)
            {
                ParametersLoaded(this, new EventArgs());
            }

            Show();
        }
        #endregion

        #region Private Methods
        private void GetParameters()
        {
            //Iterate through all parameters for the VST
            for (int i = 0; i < _ExternalVstContext.PluginCommandStub.PluginContext.PluginInfo.ParameterCount; i++)
            {
                var name = _ExternalVstContext.PluginCommandStub.GetParameterName(i);

                if (PluginParameters.ContainsKey(name))
                {
                    //Ignore dupes?
                    continue;
                }

                PluginParameters.Add(name, new ParameterInfo
                {
                    Name = name,
                    Label = _ExternalVstContext.PluginCommandStub.GetParameterLabel(i),
                    Display = _ExternalVstContext.PluginCommandStub.GetParameterDisplay(i),
                    Index = i,
                    ParameterProperties = _ExternalVstContext.PluginCommandStub.GetParameterProperties(i)
                }
                );
            }
        }
        #endregion
    }
}
Aug 22, 2015 at 11:11 PM
Specifically, this line returns null for Canvas, or UserControl...
var source = PresentationSource.FromVisual(this) as HwndSource;
Aug 22, 2015 at 11:31 PM
Well, I guess that really, what I am asking is not so much how to get the window handle of the UserControl - I guess I need to use the Window Handle of the parent Window - not the UserControl.

I guess what I really need to be asking is, how do I draw the editor at a particular set of offsets within the Window?
Coordinator
Aug 23, 2015 at 6:19 AM
I have also seen:
new WindowInteropHelper(this).Handle

[2c]
Marc
Aug 23, 2015 at 4:29 PM
I don't think this is gonna work smoothly. Windows are a special case in WPF rendering pipeline, other controls needs to comply with the visual/logical trees interfaces. I'm using a Windows Form Panel inside a WindowsFormsHost control. The WindowsFormsHost supports much of the features of a WPF user control.
Aug 23, 2015 at 10:52 PM
Right! That's a great trick. I'll try it.
Have you found that this works well for you Yury?
Doco here: https://msdn.microsoft.com/en-us/library/system.windows.forms.integration.windowsformshost(v=vs.110).aspx

Thanks Marc. I have a feeling that that code does the same thing as the code I posted. My guess is that a UserControl doesn't actually have it's own window handle now that I understand things better. But, I will try it nonetheless!
Aug 23, 2015 at 11:55 PM
Yeah it works draw using a Windows.Forms.Panel handle. Put that panel inside WindowsFormsHost control. WPF doesn't treat each control as a HWND with proper message pump but WinForms does.
Aug 23, 2015 at 11:59 PM
and remember to call host idle periodically too ;)