Jump to content
Sign in to follow this  
Søren Rasmussen

C# Com Videotext

Recommended Posts

Søren Rasmussen

Hi.

 

First the basic code which I've used to initialize DVBViewer:

 

DVBViewerServer.DVBViewer dvb = new DVBViewerServer.DVBViewer();

dvb.CurrentChannelNr = 0;

dvb.Videotext.onDataArrive += new ITeletextEvents_onDataArriveEventHandler(Videotext_onDataArrive);

 

The above referenced event handler get called a couple of hundred times if I only print eg. a dot on screen, and roughly about six times when I use dvb.Videotext.GetPageAsHTML() to store the data in a string.

 

The exception below is caught in a method which tries to change dvb.CurrentChannelNr after the reception has stopped. For reference, it is fired by a timer.

 

 

Exception caught in ChangeChannel(): System.Runtime.InteropServices.InvalidComObjectException:

COM object that has been separated from its underlying RCW cannot be used.

 

at System.Runtime.InteropServices.ComTypes.IConnectionPoint.Advise(Object pUnkSink, Int32& pdwCookie)

at DVBViewerServer.ITeletextEvents_EventProvider.add_onDataArrive(ITeletextEvents_o

nDataArriveEventHandler )

at DVBViewerServer.TeletextmanagerClass.add_onDataArrive(ITeletextEvents_onDataArri

veEventHandler )

at tttst.Teletext.ChangeChannel() in E:\dp...

 

I'm totally out of clues here and any help is very much appreciated.

 

 

Regards,

 

Søren Rasmussen

Share this post


Link to post
Lars_MQ

Take a look here how to use the DVBViewer with c# http://www.DVBViewer.info/forum/index.php?...84&hl=erwin

 

If the problem still persist maybe you could provide a small sample programcode to reproduce the error and I'll check it against the viewer in debug mode.

Share this post


Link to post
JMS
DVBViewerServer.DVBViewer dvb = new DVBViewerServer.DVBViewer();

dvb.CurrentChannelNr = 0;

dvb.Videotext.onDataArrive += new ITeletextEvents_onDataArriveEventHandler(Videotext_onDataArrive);

Exception caught in ChangeChannel(): System.Runtime.InteropServices.InvalidComObjectException:

COM object that has been separated from its underlying RCW cannot be used.

 

at System.Runtime.InteropServices.ComTypes.IConnectionPoint.Advise(Object pUnkSink, Int32& pdwCookie)

at DVBViewerServer.ITeletextEvents_EventProvider.add_onDataArrive(ITeletextEvents_o

nDataArriveEventHandler )

at DVBViewerServer.TeletextmanagerClass.add_onDataArrive(ITeletextEvents_onDataArri

veEventHandler )

at tttst.Teletext.ChangeChannel() in E:\dp...

 

The combination of the code and the exception looks strange. Is dvb really a local variable? Could you try to add a GC.KeepAlive(dvb); after the += statement?

 

Jochen

Share this post


Link to post
JMS
Take a look here how to use the DVBViewer with c# http://www.DVBViewer.info/forum/index.php?...84&hl=erwin

 

If the problem still persist maybe you could provide a small sample programcode to reproduce the error and I'll check it against the viewer in debug mode.

 

Actually the exception looks a bit like a pure .NET problem, eventually garbage collection related. In fact a bit more sample code would help since at least to me the three lines of code seem to be fine.

 

Jochen

Share this post


Link to post
Lars_MQ

One important thing: Avoid at all costs timeconsuming processing in the event itself. If you need to do it, push the data into a fifo and use a worker thread to do all the processing.

Share this post


Link to post
Søren Rasmussen
Take a look here how to use the DVBViewer with c# http://www.DVBViewer.info/forum/index.php?...84&hl=erwin

 

If the problem still persist maybe you could provide a small sample programcode to reproduce the error and I'll check it against the viewer in debug mode.

 

I've already tried to get an instance of an already started DVBViewer with the code provided from this link. My conclusions are the same. It still stops receiving events.

 

I'll post the majority of the code here but without the dba class, contents of exception handlers and my vast amounts of debug output. You should be able to figure it out. Oh, and now we're at it, suggestions to get the number of returned rows from a select prior to the actual data retrieval would be much appreciated.

 

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Timers;
using DVBViewerServer;

namespace tttst {
struct Channel {
	public int channelId;
	public int DVBViewerChannelNo;
	public float channelChangeInterval;
};

class Program {
	public static System.Timers.Timer channelChangeTimer;
	private static string sHostName;
	private static Teletext tt = null;

	static void Main(string[] args) {
		try {
			sHostName = Environment.MachineName;

			tt = new Teletext();

			channelChangeTimer = new System.Timers.Timer(1);
			channelChangeTimer.Elapsed += new ElapsedEventHandler(onElapsedChannelChangeTimer);
			channelChangeTimer.AutoReset = true;
			channelChangeTimer.Enabled = true;
			channelChangeTimer.Start();

			Console.WriteLine("<<< Press any key to exit >>>");
			tt.ChangeChannel();
			Console.ReadKey();

			channelChangeTimer.AutoReset = false;
			channelChangeTimer.Enabled = false;
		} catch (Exception ex) {
		} finally {
			if (tt != null) {
				try {
					tt = null;
				} catch (Exception ex) {
				}
			}
		}
	}

	static void onElapsedChannelChangeTimer(object sender, ElapsedEventArgs ea) {
		channelChangeTimer.Stop();
		tt.ChangeChannel();
		channelChangeTimer.Start();
	}
}

class Teletext {
	public DVBViewer dvb = null;
	public Channel[] monitorChannels;
	public int channelIndex = 2;
	private string sHostName;

	public Teletext() {
		dvb = new DVBViewer();
		//dvb = (DVBViewerServer.DVBViewer)System.Runtime.InteropServices.Marshal.GetActiveObject("DVBViewerServer.DVBViewer");
		dvb.Mute(true);

		//dvb.Events.OnChannelChange += new IDVBViewerEvents_OnChannelChangeEventHandler(OnChannelChange);

		monitorChannels = new Channel[1];
		sHostName = Environment.MachineName;
	}

	~Teletext() {
		try {
			dvb.Quit();
		} catch (Exception) {
		}
	}

	public void getChannelList() {
		dba db;
		SqlDataReader rdr = null;
		string sQuery = "";

		try {
			SqlCommand cmd;
			int i;

			db = new dba();

			sQuery = "SELECT COUNT(channelId) FROM tblChannels c"
				+ " INNER JOIN tblServers s ON (c.serverId = s.serverId)"
				+ " WHERE s.serverName = @hostname";
			cmd = new SqlCommand(sQuery, db.conn);
			cmd.Parameters.Add("@hostname", SqlDbType.VarChar).Value = sHostName;
			i = (int)cmd.ExecuteScalar();

			monitorChannels = new Channel[i];
			Console.WriteLine("Database tells us to monitor {0} channels", i);

			sQuery = "SELECT channelId, channelName, DVBViewerChannelNo, channelChangeInterval FROM tblChannels c"
				+ " INNER JOIN tblServers s ON (c.serverId = s.serverId)"
				+ " WHERE s.serverName = @hostname";

			cmd = new SqlCommand(sQuery, db.conn);
			cmd.Parameters.Add("@hostname", SqlDbType.VarChar).Value = sHostName;
			rdr = cmd.ExecuteReader();
			i = 0;
			while (rdr.Read()) {
				monitorChannels[i].channelId = rdr.GetInt32(0);
				monitorChannels[i].DVBViewerChannelNo = rdr.GetInt32(2);
				monitorChannels[i].channelChangeInterval = Convert.ToSingle(rdr.GetInt32(3));
				i++;
			}
		} catch (SqlException ex) {
		} catch (Exception ex) {
		} finally {
			if (rdr != null)
				rdr.Close();
			db = null;
		}
	}

	public void ChangeChannel() {
		try {
			if (channelIndex >= monitorChannels.Length) {
				getChannelList();
				channelIndex = 0;
			}
			Program.channelChangeTimer.Interval = monitorChannels[channelIndex].channelChangeInterval;
			dvb.CurrentChannelNr = monitorChannels[channelIndex++].DVBViewerChannelNo;
			dvb.Videotext.onDataArrive += new ITeletextEvents_onDataArriveEventHandler(Videotext_onDataArrive);
		} catch (Exception ex) {
		}
	}

	public void Videotext_onDataArrive(int PageNo, int SubPageNo) {
		try {
			//Console.WriteLine("Page recieved: {0}, {1}", PageNo, SubPageNo);
//				Console.Write("{0}/{1}\t", PageNo, SubPageNo);
			string ttPage = dvb.Videotext.GetPageAsHTML(PageNo, SubPageNo);
			Console.Write(".");
//				Thread.Sleep(100);
//				ttPage = null;
		} catch (Exception ex) {
		}
	}

}
}

Share this post


Link to post
Søren Rasmussen
One important thing: Avoid at all costs timeconsuming processing in the event itself. If you need to do it, push the data into a fifo and use a worker thread to do all the processing.

 

I've thought about it and its probably the way I'll go given the fact I need to convert the pages to images, but I still need to get a steady flow of events to my handler before doing the more time consuming parts.

Share this post


Link to post
JMS
Oh, and now we're at it, suggestions to get the number of returned rows from a select prior to the actual data retrieval would be much appreciated.

Hmm, wouldn't List<Channel> and filling anything in with Add() do the job (i.e. fill a template struct in the loop and Add it to the List)?

Share this post


Link to post
Søren Rasmussen
Hmm, wouldn't List<Channel> and filling anything in with Add() do the job (i.e. fill a template struct in the loop and Add it to the List)?

 

Sounds reasonable. I'm gonna go with that. Thanks a lot.

Share this post


Link to post
JMS
		public void ChangeChannel() {
		try {
			if (channelIndex >= monitorChannels.Length) {
				getChannelList();
				channelIndex = 0;
			}
			Program.channelChangeTimer.Interval = monitorChannels[channelIndex].channelChangeInterval;
			dvb.CurrentChannelNr = monitorChannels[channelIndex++].DVBViewerChannelNo;
			dvb.Videotext.onDataArrive += new ITeletextEvents_onDataArriveEventHandler(Videotext_onDataArrive);
		} catch (Exception ex) {
		}
	}

At least you could try to register the event only once (e.g. in the Teletext constructor) instead of myriads of times.

 

Jochen

 

<Hint>Maybe DVBViewer requires exactly what you do - I don't know.</Hint>

Edited by JMS

Share this post


Link to post
Søren Rasmussen
At least you could try to register the event only once (e.g. in the Teletext constructor) instead of myriads of times.

 

Jochen

 

That was my assumption at first, but when I do that it stops responding when I change the channel. Registering the event in the loop seemed like the only way it worked.

Share this post


Link to post
JMS

Well, then try to make dvb.Videotext another member of the class and use it instead of calling dvb.Videotext. The call creates a temporary RCW to the COM instance and the garbage collection may decide to make some cleanup on it.

 

Jochen

 

<Add>Then avoid dvb.Videotext in all places and use the member instead.</Add>

Edited by JMS

Share this post


Link to post
Søren Rasmussen
Well, then try to make dvb.Videotext another member of the class and use it instead of calling dvb.Videotext. The call creates a temporary RCW to the COM instance and the garbage collection may decide to make some cleanup on it.

 

Jochen

 

<Add>Then avoid dvb.Videotext in all places and use the member instead.</Add>

 

Preliminary tests reveal that you just might be right. I think we've nailed it! Thanks a lot for the quick replies. I'm grateful.

Share this post


Link to post

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

×
×
  • Create New...