SensorInput event stops firing?

Post questions, comments and feedback to our 3Dconnexion Windows Development Team.

Moderator: Moderators

Post Reply
porcus
Posts: 2
Joined: Sat Aug 18, 2007 2:23 pm
Location: Denham Springs, Louisiana

SensorInput event stops firing?

Post by porcus »

I'm trying to write a very simple .NET (C#) test application to receive an interpret data from a SpaceNavigator PE. After downloading the SDK, it seemed like using the TDxInput.dll COM library would be the easiest way to get up and running, so I set up my test app (registering an event handler for the device's Sensor.SensorInput event), built it, and gave it a run, and guess what? It worked just as I expected it would!! ... that was, until somewhere around 50 SensorInput events had fired, and then it seemed the event would never fire again.

I've re-tested this repeatedly, but the results are roughly the same every time. The number of times that my event handler is called (for the SensorInput event) varies -- it's usually somewhere around 50 or 60 times and sometimes over 200 -- but it always stops working after receiving a small number of reports.

Also, I don't know if there's anything special about how event handlers work under COM, but I've noticed that after I call Connect and subscribe to the event, I can always register additional event handlers without any ill effect, but after the events stop firing, if I attempt to register another event handler, I get a NullReferenceException having the following stack trace:
at System.Runtime.InteropServices.ComTypes.IConnectionPoint.Advise(Object pUnkSink, Int32& pdwCookie)
at TDxInput._ISensorEvents_EventProvider.add_SensorInput(_ISensorEvents_SensorInputEventHandler )
at TDxInput.SensorClass.add_SensorInput(_ISensorEvents_SensorInputEventHandler )
at TDxTests.Form1.btnTestConnection_Click(Object sender, EventArgs e)
[snip]

Does anyone have any idea what might be going on here? In all other respects, the device appears to be working flawlessly.

My system configuration is as follows:
Windows Vista Enterprise (64-bit)
Visual Studio 2005 SP1
(can't think of any other significant variables)

Any help would be much appreciated! Thanks.

(If I can't get this working, then my next step will be to read the input data from the corresponding HID device handle. Having done something like that in the past, I don't imagine this would be too complicated.)
mbonk
Moderator
Moderator
Posts: 181
Joined: Mon Dec 04, 2006 4:06 am

Re: SensorInput event stops firing?

Post by mbonk »

porcus wrote:I'm trying to write a very simple .NET (C#) test application
Could you please send up the project so that we can have a look at what is happening?

We havn't encountered this before: the xna and vb samples on the web-site do not display this behavior

Markus
ngomes
Moderator
Moderator
Posts: 3344
Joined: Mon Nov 27, 2006 7:22 am
Contact:

Re: SensorInput event stops firing?

Post by ngomes »

Hi porcus,
mbonk wrote:
porcus wrote:I'm trying to write a very simple .NET (C#) test application
Could you please send up the project so that we can have a look at what is happening?
Or -- perhaps preferably -- a stripped down project with just the bits that are needed to check the problem up.

If you'd like to send us a project, please contact mbonk or myself on a private message.
Nuno Gomes
ebaklund
Posts: 4
Joined: Thu Sep 06, 2007 5:43 am

Post by ebaklund »

Hi guys,

Please do NOT jump off to private message stream on this.
I have been banging my head on the same issue for the last week.
My objective is to enable our 6 million line enterprise application to appreciate 3DConnection input, but the event stream quickly stops if at all starting.

I am currently trying to create a mini-project that consistently shows the problem. I have a question in that regard:

[b]Is the TDxInput.Device designed so that several instances can coexist within the same process?[/b]

The API indicates that multiple instances are allowed, but in my mini-project, the event stream will only start from the first instance. I wander if that can be the reason why I have problems with my enterprise project since I am also using Open Inventor from Mercury that has its own interface to 3DConnectioin devices.

Kind regards,
Erik
ebaklund
Posts: 4
Joined: Thu Sep 06, 2007 5:43 am

Post by ebaklund »

Ok, I think I understand what is going on.

The TDxInput API exposes the TDxInput.Sensor as an attribute of a TDxInput.Device instance. One would think that the sensor should be accessed by rules that conforms to the attribute idiom - that is wrong.

Despite the attribute signature, the interface behaves like a factory! This means that the returned TDxInput.Sensor instance has to be referenced (cached) by the application for as long as it is going to be used.

This was the root of my problems. Reading the description from porcus earlier in this thread, I suspect that he is not caching the TDxInput.Sensor instance.

Somebody more knowledgeable than me may tell if this non-conformant behavior is due to an artifact of the Interop system from Microsoft or an artifact of the TDxInput COM module.

Anyway, it should be worth stating this behavior explicitly in the TDxInput API documentation.

Kind regards,
Erik
mbonk
Moderator
Moderator
Posts: 181
Joined: Mon Dec 04, 2006 4:06 am

Post by mbonk »

ebaklund wrote:Ok, I think I understand what is going on.

The TDxInput API exposes the TDxInput.Sensor as an attribute of a TDxInput.Device instance. One would think that the sensor should be accessed by rules that conforms to the attribute idiom - that is wrong.

Despite the attribute signature, the interface behaves like a factory! This means that the returned TDxInput.Sensor instance has to be referenced (cached) by the application for as long as it is going to be used.
This is not how the TDxInput API has been designed. Using the Sensor() method of the TDxInput.Device instance will return the TDxInput.Sensor instance belonging to that device.

Thus is is not necessary to keep a reference to the Sensor. It is however necessary to keep a reference to at least one of Device, Keyboard or Sensor for the duration of the connection to the device.

It is highly recommended to only create one instance of the device per application as the cuurent implementation of the system driver does not broadcast the device data to all instances of the TDxInput.Device.

Are you keeping a reference to the device object or why are you creating new instances of the Sensot object?

Markus
ebaklund
Posts: 4
Joined: Thu Sep 06, 2007 5:43 am

Post by ebaklund »

Hi,

Thanks for replying.
This is not how the TDxInput API has been designed. Using the Sensor() method of the TDxInput.Device instance will return the TDxInput.Sensor instance belonging to that device.
That makes sense from a design point of view and also follows the conventions of the attribute idiom.
Thus is is not necessary to keep a reference to the Sensor.
Yes it is. That is where the problem is. I am using the TDx.TDxInput .NET interface through C#. Without keeping a reference to the Sensor, the lifespan of the Sensor is undetermined and the event stream will die as soon the garbage collector kicks in. Maybe the sensor COM object is kept alive, but how does the Interop system work? It would be nice tho have an Interop expert to shed a light on this.
It is highly recommended to only create one instance of the device per application as the cuurent implementation of the system driver does not broadcast the device data to all instances of the TDxInput.Device.
Hm.. I think I can live with that. The reason I am slightly worried is because my component coexists in an application where the Open Inventor API from TGS is being used. The Open Inventor library has its own interface to 3DConnection devices, but I guess it is less likely that the library on its own is going to create a 3D Connection device unless explicitly being told to.
Are you keeping a reference to the device object or why are you creating new instances of the Sensot object?
I construct and keep a reference to the Device around for the whole life cycle of the application. I do NOT construct instances of the Sensor class. I only use the sensor reference retrieved from the TDx.TDxDevice.Sensor interface. It is that reference which has to be kept alive.

Kind regards,
Erik
ebaklund
Posts: 4
Joined: Thu Sep 06, 2007 5:43 am

Post by ebaklund »

Hi,

Just to be explicit. Here is my argument in C#:

Code: Select all

namespace TDxTest
{
  public partial class Form1 : Form
  {
    TDx.TDxInput.Device device;
    TDx.TDxInput.Sensor sensor;
    long counter;

    public Form1()
    {
      InitializeComponent();

      device = new TDx.TDxInput.Device();
      device.Connect();
      sensor = device.Sensor;
      sensor.SensorInput += new TDx.TDxInput._ISensorEvents_SensorInputEventHandler(sensor_SensorInput);
    }

    private void sensor_SensorInput()
    {
      System.Diagnostics.Trace.Write("Sensor Input[" + counter.ToString() + "]\n");
      ++counter;

      if (counter > 10)
      {
        // The following code should by design NOT have an effect on the input stream.
        // BUT IT DOES - On my system the output stream terminates here.
        System.Diagnostics.Trace.Write("Releasing reference to sensor and calling garbage collector.\n");
        sensor = null;
        System.GC.Collect();
      }
    }
  }
}
Kind regards,
Erik
mbonk
Moderator
Moderator
Posts: 181
Joined: Mon Dec 04, 2006 4:06 am

Post by mbonk »

Hi ebaklund,

Initial testing shows that you are right: currently you need to keep a reference to the Sensor to keep on receiving events.
What seems to be happening is that the the garbage collection results in something equivalent to

Code: Select all

sensor.SensorInput -= MyEventHandler;
i.e. The Sensor object still exists and can be accessed from the Device, however the event handler has been removed from the Sensor.

This also happens if you add the event handler using

Code: Select all

device.Sensor.SensorInput += MyEventHandler;
Markus
lhmncantoni
Posts: 18
Joined: Wed May 28, 2008 11:35 am

Post by lhmncantoni »

Win. XP
SpacePilot
C#

I'm having a problem with the event listeners. We'll focus on what's necessary, my program listens for button presses, once a button is pressed it calls load preferences and changes the preferences on my SpacePilot(this is done solely to change the LCD screen). Whenever I call loadPreferences it works THE FIRST TIME ONLY. After the first time it calls loadPreferences my program will still receive button input from the device however any further calls to loadPreferences do not take effect. I'm thinking that my program still receives the data but thinks the device has changed or something and won't load a new preference.

Any help you can offer would be amazing. Thank you in advance,
~Nick~
"Know something about eveyrthing, and everything about something."
mbonk
Moderator
Moderator
Posts: 181
Joined: Mon Dec 04, 2006 4:06 am

Post by mbonk »

Hi Nick,

Did you code it as in viewtopic.php?p=10868#10868?

Markus
lhmncantoni
Posts: 18
Joined: Wed May 28, 2008 11:35 am

Post by lhmncantoni »

Yes, I did that correctly, and I know this is true, because I had it working when I was using DirectInput to poll the device rather than an event handler. Now that I have switched over to an event handler it doesn't work. Also, I'm sure that the config files work correctly and I'm referencing them right because I can get one to display each time I run the program. It's just that I can't get multiple preferences to load.

So I've tested a few theories. At the very beginning of the program I load a basic preference, then later as deemed by button presses I can still change the profile, so it can in fact load multiple in one run of the program.

My system is setup with a switch that jumps to a specific call to load preference depending on which button was pressed. I've tried putting a different loadPreference call at the end of the switch. When this runs, it loads the correct preference then loads the one I put at the end, thus showing it can in fact load multiple preferences in one method, during one run of the program...

I tried putting in multiple calls to loadPreference one right after the other to see if they can load simultaneously, and it works.

However, while the program is running if I press a button, and then after that specific preference loads I push another button a new preference is not loaded, however, I know from some textIO debugging that it is still getting into the correct location in the switch statement, and executes the line before, hits the new call to loadPreferences(but doesn't load it), then executes the line after.

I've also put in breakpoints and walked through the program and it indeed steps onto the every call to load preferences, but only the first one gets executed correctly.

Do I need to disconnect and then reconnect, or maybe even disconnect make a new reference to the device, connect, make new event handlers? I'm really digging for some sort of solution to this, but I can't seem to find it.

Again, thanks for your help,
~Nick~
"Know something about eveyrthing, and everything about something."
jwick
Moderator
Moderator
Posts: 3341
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Post by jwick »

Hi Nick,

Take a look at what the driver is writing to the log file when you call LoadPreferences. The log file is saved in %appdata%/3dconnexion/3dxware.

Jim
sgsrules
Posts: 1
Joined: Sat Dec 27, 2008 1:47 pm

Post by sgsrules »

Has anyone come up with a solution to the original problem posted? I'm having the same problem where the event handler gets dropped after a couple of seconds.
mbonk
Moderator
Moderator
Posts: 181
Joined: Mon Dec 04, 2006 4:06 am

Post by mbonk »

Hi sgsrules,

The solution/work around is to keep a reference to the sensor instance used to add the event handlers. The issue is that the C# rcw does not know that the object still exists after c# releases its last instance...

Markus
Post Reply