Can anyone tell me why Invoke doesn't work from a windows service please.

G

Guy

Hi All,

I am using a COM object and so I have to use a form for it to work.
The problem is I need to run it as a service as well.
When I run it in a test scenario everything works fine and Invoke
works as expected.
However, when I run it as a service the Invoke command just bombs out
without any errors and everything just stops. I have the service
installed using an administrator account and interacting with the
desktop for testing.

The code I use is below. 'Test' is the form with the COM object on it.
This is my test code and everything works as expected if I set
RunAsService to False and run it from the IDE.
If I compile and install as a service and set RunAsService to TRUE,
Start the service from the MMC and then
attach to it. When I get to the Me.Invoke(SP) line it just hangs until
I terminate the process. No errors or anything.
Can anyone tell me why this might be please.

Many thanks,

Mike


Imports System.ServiceProcess
Imports System
Imports System.Diagnostics
Imports System.ComponentModel

Public Class svcTest
Inherits System.ServiceProcess.ServiceBase
Private Delegate Sub InitDelegate(ByVal args() As String)
Private Test As New Test

#Region " Component Designer generated code "

Public Sub New()
MyBase.New()

' This call is required by the Component Designer.
InitializeComponent()

' Add any initialization after the InitializeComponent() call

End Sub

'UserService overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As
Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub

' The main entry point for the process
<MTAThread()> _
Shared Sub Main()
Dim RunAsService As Boolean = False

If RunAsService Then
Dim ServicesToRun() As System.ServiceProcess.ServiceBase
ServicesToRun = New System.ServiceProcess.ServiceBase()
{New svcTest}
System.ServiceProcess.ServiceBase.Run(ServicesToRun)
Else
Dim DebugService As New svcTest
Dim InitDelegate As InitDelegate = New
InitDelegate(AddressOf DebugService.OnStart)
InitDelegate.BeginInvoke(Nothing, Nothing, Nothing)
System.Windows.Forms.Application.Run()
End If

End Sub

'Required by the Component Designer
Private components As System.ComponentModel.IContainer

' NOTE: The following procedure is required by the Component
Designer
' It can be modified using the Component Designer.
' Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> Private Sub
InitializeComponent()
'
'OmegaIPVAD
'
Me.ServiceName = "OmegaIPVAD"

End Sub

#End Region

Protected Overrides Sub OnStart(ByVal args() As String)
' Add code here to start your service. This method should set
things
' in motion so your service can do its work.
Go()
End Sub

Protected Overrides Sub OnStop()

End Sub

Sub Go()
Test.Init()
End Sub
End Class


Imports System.Threading

Public Class Test
Inherits System.Windows.Forms.Form

#Region "Variables"

Private Delegate Sub InvokeDelegateNoParams()

#End Region

Public Sub New()
'Even though this is a windowless form we still need to show
the form
'so that the message loop starts.
MyBase.New()
Me.Show()

'This call is required by the Windows Form Designer.
InitializeComponent()

End Sub

Private Sub InitializeComponent()

Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(168, 144)
Me.Name = "Test"
Me.ShowInTaskbar = False
End Sub

Public Sub Init()
If Me.InvokeRequired = True Then
Dim SP As InvokeDelegateNoParams = New
InvokeDelegateNoParams(AddressOf Init)
Try
Me.Invoke(SP)
Exit Sub
Catch ex As Exception
End Try
End If

DoStuff()
End Sub
End Class
 
D

Dmitriy Lapshin [C# / .NET MVP]

Hi,

It's actually simple. Invoke requires a UI thread to be running as what it
does behind the scenes is marshalling the passed delegate and parameters to
that UI thread to be executed on it.

Now, in the service, you don't have any UI threads (that is, threads that
would have a message loop) - and, in fact, you shouldn't have any. That's
why Invoke fails - it just finds no thread to marshal the call to.

The best solution would be to move all UI related code out of the service.
 
G

Guy

Hi,

Thanks very much for your reply. This makes a lot of sense.
The problem I have is that I need the form to load with the service so
the com components can load and start when the Server is booted up.
I can move all the code into a seperate UI but how do I provide a good
solution when the service simply spawns a form. As far as I know if I
log in and start the service, the form is spawned but when I log off
the service that spawned the form will run but the form itself will
terminate when I log off? Any suggestions

Many Thanks,

Mike
 
P

Pete Loveall

I am also trying to do the same thing. I have some code written around VB 6
using VB6 controls. I have tried to upgrade it without having to completely
rewrite the code (Winsock and MSComm OCX's). The only way I can see to do
it is to spawn a UI thread but I don't see a way to do it in VB. Guess I
will have to use srvany.exe (yuck).

Pete Loveall
 
D

Dmitriy Lapshin [C# / .NET MVP]

Guy,

Unfortunately, I have never written Windows Services, so I won't be of great
help here. I however have seen a setting called something like "Allow this
service to interact with the desktop" in the Service Manager, so I assume
services still CAN have a UI. I think your question should be reposted in
some newsgroup dedicated to Windows Services, not Windows Forms.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top