Need C# Help with HyperDeckIterator

Ask software engineering and SDK questions for developers working on Mac OS X, Windows or Linux.
  • Author
  • Message
Offline

Oscar Moreno

  • Posts: 29
  • Joined: Thu Apr 21, 2016 3:28 pm

Need C# Help with HyperDeckIterator

PostThu Jan 12, 2017 12:34 am

Been trying to create an app to control a Hyperdeck Studio through a ATEM 2/ME Production studio 4K. As I undestand, I should be able to do this with the HyperdeckIterator Interface. I've looked at the example C# app that came with the SDK and manged to get a procedure that compiles cleanly but when the procedure is called I get the following error:

Code: Select all
System.InvalidCastException was unhandled
  HResult=-2147467262
  Message=Unable to cast COM object of type 'System.__ComObject' to interface type 'BMDSwitcherAPI.IBMDSwitcher'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{3D480E2F-3CF4-474B-92E7-B7907EE83B41}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).
  Source=mscorlib
  StackTrace:
       at System.StubHelpers.StubHelpers.GetCOMIPFromRCW(Object objSrc, IntPtr pCPCMD, IntPtr& ppTarget, Boolean& pfNeedsRelease)
       at BMDSwitcherAPI.IBMDSwitcher.CreateIterator(Guid& iid, IntPtr& ppv)
       at CasparCGClientForm.WMES.HyperDeckRec() in D:\CasparCG Client\CasparCGClientForm\CasparCGClientForm\Form1.cs:line 81
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException:


I'm not sure how to fix this as the code does not throw any warnings. The error is thrown at the line " m_switcher.CreateIterator(ref HyperDeckIteratorInterfaceID, out HyperDeckIteratorPointer);"

Here's the code:

Code: Select all
using System;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
using CasparCGNETConnector;
using System.Runtime.InteropServices;
using BMDSwitcherAPI;
using System.Data.OleDb;
using System.Media;

namespace CasparCGClientForm
{
    public partial class WMES : Form
    {
        private SoundPlayer _soundplayer;

        //Create a Caspar server connection variable
        private ICasparCGConnection con;

        //Start the ATEM Switcher connection variables
        private IBMDSwitcherDiscovery m_switcherDiscovery;
        private IBMDSwitcher m_switcher;
        private IBMDSwitcherHyperDeck switcherHyperdeck;

        // create variable to check for lower third on or off and server connection
        Boolean servers_OK = false;
 
        public WMES()
        {
            InitializeComponent();
       }

        private void devices_connect_Click(object sender, EventArgs e)
        {
            //Connect to CG Server & ATEM Switcher
            if (Connect_caspar() & Connect_atem())
            {
                servers_OK = true;
                devices_Connect.Text = "Connected!";
                checkmark_symbol.Visible = true;
            }
            else
            {
                servers_OK = false;
                checkmark_symbol.Visible = false;
            }
        }

 
        public Boolean Connect_atem()
        {
            _BMDSwitcherConnectToFailure failReason = 0;
            string address = switchertextBox.Text;
            Boolean atem_connection;

            try
            {
               // Connect to switcher. Do this in a separate thread to prevent the main GUI thread blocking.
                m_switcherDiscovery = new CBMDSwitcherDiscovery();
                if (m_switcherDiscovery == null)
                {
                    MessageBox.Show("Could not create Switcher Discovery Instance.\nATEM Switcher Software may not be installed.", "Error");
                    Environment.Exit(1);
                }

                m_switcherDiscovery.ConnectTo(address, out m_switcher, out failReason);

                //Use threading
                new Thread(() =>
                {
                }).Start();
                atem_connection = true;
                return atem_connection;
                //SwitcherConnected();

            }
            catch (COMException)
            {
                // An exception will be thrown if ConnectTo fails.
                switch (failReason)
                {
                    case _BMDSwitcherConnectToFailure.bmdSwitcherConnectToFailureNoResponse:
                        MessageBox.Show("No response from Switcher", "Error");
                        break;
                    case _BMDSwitcherConnectToFailure.bmdSwitcherConnectToFailureIncompatibleFirmware:
                        MessageBox.Show("Switcher has incompatible firmware", "Error");
                        break;
                    default:
                        MessageBox.Show("Connection failed for unknown reason", "Error");
                        break;
                }
                atem_connection = false;
                return atem_connection;
            }
       }

        private void button32_Click(object sender, EventArgs e)
        {
            _soundplayer = new SoundPlayer("click_spacey.wav");
            _soundplayer.Play();

            if (recordbtnpressed == false)
            {
                recordbtnpressed = true;
            }else { recordbtnpressed = false; }

            if (recordbtnpressed == true)
            {
                VideoRecording = true;
                button32.BackColor = Color.Red;

                timer1.Start();
                Thread t = new Thread(HyperDeckRec);
                t.SetApartmentState(ApartmentState.MTA);
                t.Start();

                //HyperDeckRec();
                //RunMacro(25);
                timer2.Start();

                button29.Enabled = false;
                button23.Enabled = false;
                button30.Enabled = false;
                button27.Enabled = false;

            }
            else
            {
                timer1.Stop();
                timer2.Stop();

                RunMacro(31);
                button32.Visible = true;
                button32.BackColor = Color.DimGray;
                button32.Text = "REC";
                button29.Enabled = true;
                button23.Enabled = true;
                button30.Enabled = true;
                button27.Enabled = true;
            }

        }

      public void HyperDeckRec()
        {
            IBMDSwitcherHyperDeckIterator m_HyperDeckIterator = null;
            IntPtr HyperDeckIteratorPointer;
            Guid HyperDeckIteratorInterfaceID = typeof(IBMDSwitcherHyperDeckIterator).GUID;

            m_switcher.CreateIterator(ref HyperDeckIteratorInterfaceID, out HyperDeckIteratorPointer);
            if (HyperDeckIteratorPointer == null)
                return;

            m_HyperDeckIterator = (IBMDSwitcherHyperDeckIterator)Marshal.GetObjectForIUnknown(HyperDeckIteratorPointer);
            if (m_HyperDeckIterator == null)
                return;

            IBMDSwitcherHyperDeck switcherHyperdeck;
            m_HyperDeckIterator.Next(out switcherHyperdeck);


            switcherHyperdeck.Record();
        }
}
Offline

Ian Morrish

  • Posts: 580
  • Joined: Sun Jan 18, 2015 9:24 pm
  • Location: New Zealand

Re: Need C# Help with HyperDeckIterator

PostThu Jan 12, 2017 5:29 pm

This is a snippet from how I do it (I have a separate Hyperdeck class and in the while loop I create each to an IList so that up to 4 Hyperdecks can be treated as objects
https://ianmorrish.wordpress.com/2016/09/20/control-hyperdeck-via-atem-with-powershell-script/
)...
public static IBMDSwitcherHyperDeck HyperDeck;


IntPtr hyperdeckIteratorPtr;
Guid hyperdeckIteratorIID = typeof(IBMDSwitcherHyperDeckIterator).GUID;
this.switcher.CreateIterator(ref hyperdeckIteratorIID, out hyperdeckIteratorPtr);
IBMDSwitcherHyperDeckIterator hyperdeckIterator = null;
if (hyperdeckIteratorPtr != null)
{
hyperdeckIterator = (IBMDSwitcherHyperDeckIterator)Marshal.GetObjectForIUnknown(hyperdeckIteratorPtr);
}
int hyperdecknum = 1;

IBMDSwitcherHyperDeck switcherHyperdeck;
hyperdeckIterator.Next(out switcherHyperdeck);
while (switcherHyperdeck != null)
{
switcherHyperdeck. // you will see all the methods and properties here
}
Regards,
Ian Morrish
Video Integrated Scripting Environment
(Windows PowerShell with ATEM driver + more)
https://ianmorrish.wordpress.com
Offline

Ian Morrish

  • Posts: 580
  • Joined: Sun Jan 18, 2015 9:24 pm
  • Location: New Zealand

Re: Need C# Help with HyperDeckIterator

PostThu Jan 12, 2017 6:53 pm

Oops, just noticed that is exactly how you are doing it.
I don't know if the structure of your application is a good model to use. You should create a reference to a hyperdeck object once and then call methods on it like .record as required.

I based a few c# applications for the ATEM from this project https://github.com/imorrish/AtemSharp which is based on WPF UI and deals with the UI threading. Should be easy to add HyperDeck functionality to this.

I will also try creating an example app that uses my switcherlib dll which I currently use from PowerShell.
Regards,
Ian Morrish
Video Integrated Scripting Environment
(Windows PowerShell with ATEM driver + more)
https://ianmorrish.wordpress.com
Offline

Oscar Moreno

  • Posts: 29
  • Joined: Thu Apr 21, 2016 3:28 pm

Re: Need C# Help with HyperDeckIterator

PostFri Jan 13, 2017 10:02 pm

Thanks Ian for the help. I did try try it again but I'm still getting the error at "m_switcher.CreateIterator(ref HyperDeckIteratorInterfaceID, out HyperDeckIteratorPointer);"

I'm thinking that it may be a problem with visual studio. I also read on a blog that it may be a problem with threading.

I'm gonna try the project you mentioned and see if it works. I'll post my findings.
Offline

Oscar Moreno

  • Posts: 29
  • Joined: Thu Apr 21, 2016 3:28 pm

Re: Need C# Help with HyperDeckIterator

PostFri Jan 13, 2017 10:19 pm

What are the possible causes of ERROR:

"No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE))."
Offline

Oscar Moreno

  • Posts: 29
  • Joined: Thu Apr 21, 2016 3:28 pm

Re: Need C# Help with HyperDeckIterator

PostTue Jan 17, 2017 7:54 am

OK. So it appears that the problem stemmed from initializing COM objects in separate threads then trying to call the objects in a thread in which it was not initialized. So initializing the ATEM connection in a separate thread as such:

Code: Select all
       
public Boolean Connect_atem()
        {
                // ...Code

                m_switcherDiscovery.ConnectTo(address, out m_switcher, out failReason);

                //Use threading
                new Thread(() =>
                {
                }).Start();

              // ... Code...
       }

...Then calling m_switcher object from the main thread as listed below throws an error because m_switcher was created in a separate thread. It appears that this is not a problem with .NET dlls but it is a problem in COM dlls:

Code: Select all
 
public void HyperDeckRec()
        {
            //...Code

            m_switcher.CreateIterator(ref HyperDeckIteratorInterfaceID, out HyperDeckIteratorPointer);
           
            //...Code
        }

So basically, I removed threading from the Connect_atem() method and that ran cleanly. Hope this helps someone.

Thanks again IAN.

Return to Software Developers

Who is online

Users browsing this forum: No registered users and 16 guests