Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / Interop / October 2005

Tip: Looking for answers? Try searching our database.

Service hangs when accessing ActiveX control

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Lucvdv - 13 Sep 2005 15:57 GMT
Is there something that has to be taken special care of when using an
ActiveX control in a .Net service application?

I'm creating a VB.Net service app that uses an ActiveX control on a hidden
form.

When I start the program as a normal application, it works.

When I try to start it as a service, it hangs when the first method of the
AxtiveX is called (the method never returns).

The ActiveX itself was written in VC++6/MFC.  At this point (the method
that hangs), it does nothing but accept a piece of data and store it in a
CMap class.

The .Net service app is installed with SERVICE_WIN32_OWN_PROCESS and
SERVICE_INTERACTIVE_PROCESS flags so I should see error popups if there are
any, and all unhandled exceptions are caught and written to the event log,
but nothing shows up either way.

Trying to attach the debugger to the running service gives "access denied",
so that way I can't find it either.

To find the exact line where it hangs, I had to write progress messages to
the event log before every line of VB source.
Robert Jordan - 13 Sep 2005 16:12 GMT
> Is there something that has to be taken special care of when using an
> ActiveX control in a .Net service application?

This problem is not related to .NET:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/in
teractive_services.asp


Rob
Lucvdv - 13 Sep 2005 16:15 GMT
> Is there something that has to be taken special care of when using an
> ActiveX control in a .Net service application?

Add: I've used the same ActiveX control before in services written in VS6,
and there it works, so it has to be .Net-related.

Something with the activex interop dll's that makes them unsuited for
services?
Robert Jordan - 13 Sep 2005 17:52 GMT
>>Is there something that has to be taken special care of when using an
>>ActiveX control in a .Net service application?
>
> Add: I've used the same ActiveX control before in services written in VS6,
> and there it works, so it has to be .Net-related.

On the same machine, same OS, same version?

> Something with the activex interop dll's that makes them unsuited for
> services?

No. The interop dll contains just metadata and some glue code.

Rob
Willy Denoyette [MVP] - 13 Sep 2005 19:31 GMT
>> Is there something that has to be taken special care of when using an
>> ActiveX control in a .Net service application?
[quoted text clipped - 4 lines]
> Something with the activex interop dll's that makes them unsuited for
> services?

First off, ActiveX and Windows Forms should never be used from within
Windows Services, they aren't designed for this kind of scenarios.
The reason your call blocks is that both your form and your control must
live in an STA, now for the AX control this is taken care of by COM itself
which will spin-up an STA thread when you create an instance on an MTA
thread, but your Windows Form will run on an MTA thread (unless you created
the form from an STA thread) and as such can't do the required message
pumping in the COM thread (STA). The result is blocking COM calls.

So what you should do is create the from and the control's instance from an
(the same) STA thread, but again, this is not something I strongly advise
against.

Willy.
Lucvdv - 14 Sep 2005 09:00 GMT
> So what you should do is create the from and the control's instance from an
> (the same) STA thread, but again, this is not something I strongly advise
> against.

Thanks.  I suppose there's a "not" too many there?

But it doesn't even work: the form is created in the constructor of the
service class, which is instantiated from a sub Main with <STAThread>
attribute.
The form is used only as a container for the control.

Just to see if there's a difference I changed it into <MTAThread>.
That causes a ThreadStateException when the service is started, so it's not
like the <STAThread> was ignored (which it would be if there was no COM
interop).

So I guess I'll have to port the control's code to a managed dll.
I've already had to do that with another piece of code in another
application, but this time it doesn't look as if it will be simple, and
time is pressing :(
Robert Jordan - 14 Sep 2005 09:50 GMT
>>So what you should do is create the from and the control's instance from an
>>(the same) STA thread, but again, this is not something I strongly advise
[quoted text clipped - 11 lines]
> like the <STAThread> was ignored (which it would be if there was no COM
> interop).

Main gets ignored when the assembly is used as a service!

> So I guess I'll have to port the control's code to a managed dll.
> I've already had to do that with another piece of code in another
> application, but this time it doesn't look as if it will be simple, and
> time is pressing :(

Willy told you to use another thread for that. For that thread
you can setup a STA:

Thread t = new Thread (ThreadProc);
t.ApartmentState = ApartmentState.STA;
t.Start ();

void ThreadProc()
{
   // create the form with the ax object
   Application.Run (new SomeForm());
}

Rob
Lucvdv - 14 Sep 2005 13:26 GMT
> Main gets ignored when the assembly is used as a service!

The Main function is generated by Visual Studio with the code necessary to
start the service, I assume it is called from ServiceMain when running as a
service.

See http://codebetter.com/blogs/sahil.malik/archive/2004/12/06/35295.aspx,
I'm using it similar to the way Sahil does there (actually a mix of the way
Sahil explains and what I posted in a comment near the bottom of that
page).

If it was ignored, changing its attributes to MTAThread shouldn't make any
difference, or at least that's what I would expect.
Lucvdv - 14 Sep 2005 13:35 GMT
> > Main gets ignored when the assembly is used as a service!
>
[quoted text clipped - 9 lines]
> If it was ignored, changing its attributes to MTAThread shouldn't make any
> difference, or at least that's what I would expect.

To eliminate all doubt, I wrote an entry into the event log from inside the
Main function.  It *is* executed when the assembly is run as a service.
Willy Denoyette [MVP] - 14 Sep 2005 17:14 GMT
>> Main gets ignored when the assembly is used as a service!
>
[quoted text clipped - 11 lines]
> If it was ignored, changing its attributes to MTAThread shouldn't make any
> difference, or at least that's what I would expect.

As I said in another thread, the STAThread/MTAThread attribute is ignored in
a Service.

Only thing you can do is a Robert said, create another thread and initialize
it as a STA.

Willy.
Willy Denoyette [MVP] - 14 Sep 2005 17:11 GMT
>> So what you should do is create the from and the control's instance from
>> an
>> (the same) STA thread, but again, this is not something I strongly advise
>> against.
>
> Thanks.  I suppose there's a "not" too many there?

Yep.

> But it doesn't even work: the form is created in the constructor of the
> service class, which is instantiated from a sub Main with <STAThread>
> attribute.
> The form is used only as a container for the control.

The STAThread attribute is ignored on Main in a service, Service threads run
in an MTA by default, if this is not what you want, you have to create your
own STA thread.

> Just to see if there's a difference I changed it into <MTAThread>.
> That causes a ThreadStateException when the service is started, so it's
> not
> like the <STAThread> was ignored (which it would be if there was no COM
> interop).

Sure there is no difference because ... see above.

> So I guess I'll have to port the control's code to a managed dll.
> I've already had to do that with another piece of code in another
> application, but this time it doesn't look as if it will be simple, and
> time is pressing :(

Won't help you, Controls in .NET are UI elements and have the (almost) same
requirements as AX controls.

Willy.

Lucvdv - 15 Sep 2005 12:47 GMT
> The STAThread attribute is ignored on Main in a service, Service threads run
> in an MTA by default, if this is not what you want, you have to create your
> own STA thread.

But observation indicates the opposite.

Not specifying any attribute or specifying it as STA results in the same
behavior.  Specifing it as MTA is different, in that it causes a
ThreadStateException when the service is started - probably because the COM
interface checks if it is running in STA.

I can only conclude from that, that the attribute is not ignored in a
service and the default is STAThread.

VS.Net *does* explicitly put <MTAThread()> in the declaration (which I
removed because I was using COM), and maybe it does so because it has to be
that way for a service, but that's not the same as ignoring it.

> > Just to see if there's a difference I changed it into <MTAThread>.
> > That causes a ThreadStateException when the service is started, so it's
[quoted text clipped - 11 lines]
> Won't help you, Controls in .NET are UI elements and have the (almost) same
> requirements as AX controls.

I wouldn't make it a control, but a simple class that exposes the same
properties, methods and events (it has no UI elements, in that respect it
behaves like the MS Winsock control among others).
Stephen Martin - 15 Sep 2005 15:12 GMT
While the explanations that you have received so far are incorrect the
solutions offered up are essentially correct.

When a service process starts it starts up exactly like any other process so
Main is called and the STA/MTA attribute is indeed honoured. I'm not sure
how it could be ignored since the process has no idea it is even a service
process until ServiceBase.Run is called. What does happen is that the main
thread of a service process is suspended by the Service Control Manager when
ServiceBase.Run is called and all further interaction (OnStart, OnPause,
etc.) is done on different threads. In your case you have created your form
correctly in an STA on the main thread but you are later calling into this
apartment from a different thread. The COM marshaller attempts to marshal
this call to the correct apartment but that involves sending a message to a
window owned by the original thread. Unfortunately, the main thread is
suspended and can never read the message and so your call hangs.

The correct procedure is, as has been suggested, to create an STA thread in
your OnStart method and then create the form and control in the ThreadStart
procedure of that thread. You must then call either form.ShowDialog or
Application.Run(form) to start the message pump. In your OnStop you can then
Close the form and allow the thread to exit.

There is no inherent reason not to use windows and message pumps in a
service. It is fairly rare to need to do so but it can be very useful
especially in cases such as using legacy components or for inter-thread
communications.

>> The STAThread attribute is ignored on Main in a service, Service threads
>> run
[quoted text clipped - 38 lines]
> properties, methods and events (it has no UI elements, in that respect it
> behaves like the MS Winsock control among others).
Lucvdv - 16 Sep 2005 08:54 GMT
> When a service process starts it starts up exactly like any other process so
> Main is called and the STA/MTA attribute is indeed honoured. I'm not sure
[quoted text clipped - 8 lines]
> window owned by the original thread. Unfortunately, the main thread is
> suspended and can never read the message and so your call hangs.

Thanks, it's perfectly clear now.

[I posted this yesterday too, but the message didn't make it to the
server?]
Mike Samuels - 17 Oct 2005 18:29 GMT
Man, I was hoping that this information of yours would solve my problem!  It
seems so close to the solution.  But ... it didn't.
Could you, or anyone else, would read about my problem, and see if you have
anything to suggest?
I wrote a program which, among other things, creates an Excel spreadsheet.  
It is eventually supposed to run as a service; but in order to facilitate
debugging, I layered my classes so that I could just as easily run it as a
Windows App.  After a sufficient amount of testing, I made it a Windows
service, and that's when I started experiencing difficulties.
Here's what happens:  intermittantly, the first statement that does
something on the WorkSheet object throws an exception.  I hate intermittant
bugs.  They're very difficult to track down.  But, having programmed in a
Windows environment since Windows 3.0, I at least had a theory; namely:  it
has been a fact over all these years, and in whichevery development
environment you use, that when you try to perform some kind of GUI function
from within a background thread, it intermittantly fails.  Microsoft's .net
development environment has addressed this issue by publishing a BeginInvoke
method off of System.Windows.Forms.Control ... so that if you do any GUI
updating via this mechanism, then it's safe, and you won't experience any
failures.  I further theorized that when I am creating an Excel spreadsheet,
that even though I'm not making it visible, nevertheless, it's as if it were
a visible window, and so updating it is subject to the same "intermittent
failures".  So, I decided to utilize this BeginInvoke mechanism.  This was
easy to do when my program is running as a Windows App.  I just utilize the
Form object's BeginInvoke.  But I hadn't been successful trying to create a
Form object from within a Windows service, so I couldn't implement this
stragegy ... this is, until I read these threads.  Now, thanks to the
information I received in these threads -- particularly this one that I'm
responding to -- I am able to create a Form in a Windows service.  And so, as
I said, my hopes soared in that I would now be able to utilize that Form's
BeginInvoke so that I could safely create the Excel spreadsheet.  
Unfortunately, it didn't work.  Perhaps my  "updating GUI from within a
background thread" theory is incorrect.
One last fact:  Once I implemented the BeginInvoke strategy into the code, I
have never since received an error as long as the program is running as a
Windows App.  But ... I'm not totally sure that I ever experienced a problem
when the program was running as a Windows App ... even before I implemented
the BeginInvoke strategy, and even though all of the Excel updating takes
place in background threads.  
Signature

Mike Samuels
Programmer

> While the explanations that you have received so far are incorrect the
> solutions offered up are essentially correct.
[quoted text clipped - 65 lines]
> > properties, methods and events (it has no UI elements, in that respect it
> > behaves like the MS Winsock control among others).
Lucvdv - 19 Oct 2005 12:46 GMT
> Man, I was hoping that this information of yours would solve my problem!  It
> seems so close to the solution.  But ... it didn't.
[quoted text clipped - 35 lines]
> the BeginInvoke strategy, and even though all of the Excel updating takes
> place in background threads.  

One thing to keep in mind is that the docs have always said that a window
may only be accessed by the thread that created it.  All other threads and
processes can send windows messages to its message pump, but they should
never interact with it directly.

That's where Invoke comes in: it makes sure that everything you do is done
by the thread that created the window.

As for your problem, just the thought of running an Office application as a
service gives me the willies ;)

Sometimes they pop up dialog boxes and even start Windows Installer if they
detect some change to the system they /think/ is related to them.
Sometimes it's enough that something is done under a user account the
application doesn't expect (such as local system...)

If your service is running with 'normal' settings (i.e. local system
account and no access to the desktop), you won't see any of those messages,
and your service will mysteriously misbehave.

Look for "Application Popup" type entries in event log: if there are any,
there's a good chance that they'll contain messages from Excel.

I don't know if it will help, but there are two things you can try:
- run the service under a user account instead of local system.
- run it with access to the desktop (so any dialogs are shown).

Finally, and this should solve your problem, but it will reduce your Excel
sheets to minimum capabilities: I have a class (written in VB.Net) that
creates XL version 2.1 spreadsheet files without having the need for Excel
(based on a description of the BIFF format that MS once published, way back
when being open about file formats was still considered a good idea).

I can mail it if you want to, but it's very limited in its capabilities:
- only single-sheet xls files
- writes xls, doesn't read or modify them
- only string, 16-bit integer and double precision datatypes supported, but
you can do dates and times by saving them as .ToOADate and specifying a
date/time format.

It was ported from VB6 code, but the port hasn't been fully completed and
tested yet.  The VB6 version was itself based on code I found on the web,
and that wasn't bug-free to start with.

BTW, it may be even simpler to make your service create .CSV files (Excel
supports them, except that it creates/expects incompatible CSV structure if
your regional settings aren't "US English").
Willy Denoyette [MVP] - 16 Sep 2005 16:55 GMT
Stephen is right, the STA/MTA attribute is honoured on Main in a C# program,
but it's NOT true for a VB.NET program (as it's the case here if I'm not
mistaken) where the thread running Main is always entering an STA, sorry for
being incomplete.
The OnStart and other service control functions run on an MTA thread and
this cannot be changed, anyway you should never run service code in these
functions, you should start another thread initialize it to enter the
correct apartment and create the form and the COM object.

Note also that you should never run windows forms, nor should you create
instances of ActiveX controls  in a windows service, it's inherently unsafe
and it won't work any longer in Vista, be warned!

Willy.

>> The STAThread attribute is ignored on Main in a service, Service threads
>> run
[quoted text clipped - 38 lines]
> properties, methods and events (it has no UI elements, in that respect it
> behaves like the MS Winsock control among others).

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.