Jump to content

C# Com Videotext


Søren Rasmussen

Recommended Posts

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

Link to comment
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

Link to comment
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

Link to comment

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.

Link to comment
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) {
		}
	}

}
}

Link to comment
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.

Link to comment
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)?

Link to comment
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.

Link to comment
		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
Link to comment
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.

Link to comment

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
Link to comment
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.

Link to comment

Join the conversation

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

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
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.

×
×
  • Create New...