AxInterOp/InterOp -> forms -> threading

Hi,

I have got a question about AxInterOp and InterOp.
When I add a com control to my form, it automatically adds two references to my project; Ax<>.dll and <>.dll. After some research I found that the Ax-dll is the actual component used for the form (visibility) and VS automatically uses it when I add that control to my form.

The problem is; I need that control to be running in another thread, and I don't need the control to be visible on a form or something. I thought that would be possible somehow, so I started experimenting a bit. I thought that I could use the <>.dll class for that, because the Ax<>.dll did not work; it resulted in a threading error that I couldn't use it because it wasn't running in a single-threaded apartment.

So after some experimenting I made some code which I thought could work correctly:

'this in Form1_load()
t = New Thread(AddressOf interrupt)
t.Name = "Interrupt"
t.Start()

'this in sub interrupt()
Dim TVicLPT2 As TVICLPTLib.TVicLPT = New TVICLPTLib.TVicLPT()
TVicLPT2.Active = 1
TVicLPT2.IrqNumber = 7
TVicLPT2.UnmaskIrq()
AddHandler TVicLPT2.LptInterrupt, AddressOf TVicLPT2_LptInterrupt

Where I have got the TVICLPTLib and AxTVICLPTLib as the two dll's imported to my project.

But now when I run it, it gives me the following error at the line TVicLPT2.Active = 1 (and it also gives me that error for the Irqnumber and UnmaskIRQ() line. The AddHandler line doesn't produce an error, but the event doesn't fire when trying it):

Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))

I guess this has something to do with using the <>.dll instead of Ax<>.dll and then not being able to do such things. Is this true? If so, is there another way to accomplish what I'm trying to do. If it isn't true, what should I change in my code to make it work?

Thanks in advance,

Floris

[1974 byte] By [Mystret] at [2007-12-24]
# 1
A lot of old ActiveX controls depend on being hosted on a container to get properly initialized. That's probably your problem here. A couple of workarounds you can try. First, a thread starts up by default in a multi-threaded apartment (MTA). ActiveX controls rarely like MTA, they usually need a single-threaded apartment (STA). Call SetApartmentState(ApartmentState.STA) in your thread startup code.

Secondly, judging from the name of the control, you use it to access parallel I/O ports. Check this thread for a non-ActiveX DLL that can do this. It doesn't support interrupts though...

nobugz at 2007-8-31 > top of Msdn Tech,Visual Basic,Visual Basic Language...
# 2

Thanks for your quick reply :)

It helped me a bit

When I use the Ax<>.dll lib now and set the thread to a STA, then I don't get the threading error anymore.

And using the TVicLPT2.CreateControl() command (which I found on another forum), prevents the InvalidActiveXStateException from showing when doing a command.


However, my interrupt handler still doesn't fire when it is supposed to. The addhandler line (as in my first post):
AddHandler TVicLPT2.LptInterrupt, AddressOf TVicLPT2_LptInterrupt

And then the corresponding sub TVicLPT2_LptInterrupt:
PrivateSub TVicLPT2_LptInterrupt(ByVal sender As System.Object, ByVal e As
AxTVICLPTLib._DTVicLPTEvents_LptInterruptEvent)
MessageBox.Show("interrupted... "
)
EndSub

To my knowledge, this should work normally; it does not though. Any ideas why?

And about the other thread about accessing the parallel port; sorry, but the interrupt thing is exactly the kind of thing I need. I had already found another working dll for reading/writing to ports, but the interrupt control is much harder to find.


Thanks for your help,
Floris

Mystret at 2007-8-31 > top of Msdn Tech,Visual Basic,Visual Basic Language...
# 3
Your

code looks correct, it must have something to do with the control

itself or the hardware you are trying to access. Do you know how

to generate an interrupt and do you have the necessary hardware and

registers configured correctly? Sorry, can't help you past that...

nobugz at 2007-8-31 > top of Msdn Tech,Visual Basic,Visual Basic Language...
# 4

Hmm, I think it has something to do with the control itself then. Because I'm a 100% sure the interrupt is generated; it's just not handled by the program. I'll keep working on it, maybe I can get something to work; I hope so.

Maybe you've got some other ideas how to let the program do what I want? I have got a IR-receiver (and some other hardware parts) connected to my parallel port Acknowledge pin and one ground pin. When I press a button on my remote control it generates a series of interrupts in my parallel port. The first program I made for this didn't use interrupt handling, but instead, used constant polling. However, this was pretty much wasting processor time and it wasn't very reliable when my processor had many other things to do (such as playing a video). So I decided to do some more research in interrupts. I looked both at drivers, how to make them, and ready-made packages like the ones I'm using now: http://entechtaiwan.net/dev/lpt/index.shtm . The drivers were way too complicated (or at least they looked very complicated to me, and the nice blue screen of death happened to my computer many times during that time :P), so I decided to use TVicLPT. After a while I got the interrupt handling to work; however it was still quite slow. So I thought it would maybe be better to run it on another thread which would be set to priority.Highest at the beginning of a command. Basically that's where I am now; stuck trying to get it working on another thread.

When I had the interrupt event and windows form on the same thread I used the QueryPerformanceCounter to time between differrent interruptions, but it seems the time also is one of the arguments given when the interrupt is handled: e.TimeStampLo and e.TimeStamphi. The help file included with the package says this about it:

2. TimeStampLo, TimeStampHi - timestamp shows when a hardware interrupt occurs in the driver, created with RDTSC assembler instruction.


The TimeStampLo usually is a low 4-digit number and increases by one every few seconds. The TimeStampHi always is a large positive or large negative number which seems to be random. I think they both together are the cycles the processor has made since the last reboot, but how can I 'merge' those two numbers together to one large number which is the processor cycle count? I don't see any link or so between them. If I get that timer to work, maybe that makes it fast enough to react on the commands sent by remote control (an interrupt is generated every 1-2ms; when my pc isn't too busy with things it can handle it fine with polling, so in theory interrupts should be even more accurate, wouldn't it?)

Thanks for all your help, I really appreciate it :)

Floris

Mystret at 2007-8-31 > top of Msdn Tech,Visual Basic,Visual Basic Language...
# 5
You

are going to have a hard time making this work reliably. It isn't

a problem to get a 1 msec response to a hardware interrupt in kernel

mode, it is a lot harder to get that kind of response in user

mode. Generically, you'd need a real-time priority thread that is

blocking on an event object that is released by the driver handling the

interrupt. The Windows scheduler will, most likely but not

guaranteed, choose that thread to get the CPU. I doubt you get

that now, ActiveX components rarely do threading. Referencing the

component in your own thread won't help.

Getting the RDTSC timestamp certainly helps though, it lets you

'backtrack' to determine when the actual hardware interrupt

occurred. The RDTSC instruction reads a 64-bit counter on the CPU

that runs at the clock frequency. If you have, say, a 2.5 GHz

CPU, the timestamp will have a resolution of 400 picoseconds.

Good enough for average use. ;-)

You get the 64-bit RDTSC timestamp value handed to you in two 32-bit

parts. The TimeStampLo part will roll over in 2^32 / 2.5E9 =

1.718 seconds. You can combine the low and high parts back into a

.NET ULong value but that isn't really necessary, you are only

measuring the time between two interrupts, less than 2 msec. Just

subtract the TimeStampLo values of two events. Divide the value

by the CPU clock frequency to get the interval in seconds.

The biggest question is what the ActiveX component and driver do when

you aren't reading interrupt data. This is going to happen when

your program's thread doesn't get the CPU for a while. If it

buffers the events, you got a good shot at making it work. If it

doesn't, you'll get weird long gaps in the pulse train, usually around

15 or 30 msec.

nobugz at 2007-8-31 > top of Msdn Tech,Visual Basic,Visual Basic Language...
# 6

"Generically, you'd need a real-time priority thread that is blocking on an event object that is released by the driver handling the interrupt. "

I don't really get the 'blocking on an event object that is released by the driver' part. What does that exactly mean (how could I do such a thing)? I can't have a program running real-time all the time, because then my computer won't be responding to anything else, would it?

I have the RDTSC timestamp working now and it works pretty good. When the processor isn't really busy or when I'm not viewing a video in the same thread (I also have an ActiveX WMP control on my form) then the time usually is less than 0,05ms off from what it should be and it continues to work fine when I'm playing music. However, when I play a video, it doesn't respond anymore at all. This is probably caused, because playing a video takes much more processor time than playing a music file, and therefore the interrupt not getting enough processor power.

I think that in order to get it working while playing video, I need to have that thread in real-time or in kernel mode, but for real-time I don't know how I can let my thread sleep while there is nothing to do and wake up when there's an interrupt, and for a kernel-driver, I'm just not experienced with writing drivers and I have read how annoying and time-consuming writing drivers can be, so I'd rather not use that solution. So maybe you know some more about that real-time thread?

Floris

Mystret at 2007-8-31 > top of Msdn Tech,Visual Basic,Visual Basic Language...
# 7

bump? Anyone please?

Thanks,

Floris

Mystret at 2007-8-31 > top of Msdn Tech,Visual Basic,Visual Basic Language...