Link to home
Start Free TrialLog in
Avatar of mahmood66
mahmood66Flag for United Arab Emirates

asked on

problem in windows service in windows 7

Dear Experts,

i have a window service which would call an exe(my application) in a timely manner.
(Note : this service has been developed in VS2008 C#.My application is developed in
VS2003 C#).
In windows XP,this service is working perfectly.
In windows 7, whenever my service calls my exe ,windows 7 prompt a pop up( as i attached image). (but if i directly run the exe it is working in the same desktop without any issue.)
User generated image

 if i click 'view message',  my exe ( application) is running in different environment unlike desktop along with one more small window(i couldn't able take even screen shot of that environment) .

I am using following code to call my exe(application)

 
Process lobj_process = new Process();
                lobj_process.StartInfo.FileName = "MyApp.exe";
                lobj_process.StartInfo.WorkingDirectory = ls_path;
                lobj_process.StartInfo.RedirectStandardInput = true;
                lobj_process.StartInfo.UseShellExecute = false;

                lobj_process.StartInfo.CreateNoWindow = false;
                lobj_process.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
                lobj_process.Start();
                ProcessWindowStyle ws = lobj_process.StartInfo.WindowStyle;
                if (ws == ProcessWindowStyle.Hidden)
                    lobj_process.StartInfo.WindowStyle = ProcessWindowStyle.Normal;

                
                lobj_process.WaitForExit();
                lobj_process.Close();

Open in new window


kindly suggest me solution  to run my application properly via my service.

Thanks
Avatar of jagrut_patel
jagrut_patel
Flag of India image

Launching an interactive application via Windows Service is not recommended.

Still to do so you can try this option and check.

In Property of your service > LogOn tab > Select Local System Account > Check "Allow service to interact with desktop" option.
Avatar of nffvrxqgrcfqvvc
nffvrxqgrcfqvvc

Windows Vista and later interactive services has been disabled by default. Instead of using the Process Class to open your executable use the following ServiceShell.Start() method will get the token of the current user and open the executable onto the users desktop instead of the services session. Your service can be set to LocalSystem
Imports System.Runtime.InteropServices
Imports System.Text

Public NotInheritable Class ServiceShell
    Private Sub New()
    End Sub
    
    Private Const CreateUnicodeEnvironment As Integer = &H400

    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _
    Private Structure StartupInfo
        Dim cb As Integer
        <MarshalAs(UnmanagedType.LPTStr)> Dim lpReserved As String
        <MarshalAs(UnmanagedType.LPTStr)> Dim lpDesktop As String
        <MarshalAs(UnmanagedType.LPTStr)> Dim lpTitle As String
        Dim dwX As Integer
        Dim dwY As Integer
        Dim dwXSize As Integer
        Dim dwXCountChars As Integer
        Dim dwYCountChars As Integer
        Dim dwFillAttribute As Integer
        Dim dwFlags As Integer
        Dim wShowWindow As Short
        Dim cbReserved2 As Short
        Dim lpReserved2 As IntPtr
        Dim hStdInput As IntPtr
        Dim hStdOutput As IntPtr
        Dim hStdError As IntPtr
    End Structure

    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _
    Private Structure ProcessInformation
        Dim hProcess As IntPtr
        Dim hThread As IntPtr
        Dim dwProcessID As Integer
        Dim dwThreadID As Integer
    End Structure

    <DllImport("Advapi32.dll", ExactSpelling:=False, SetLastError:=True, CharSet:=CharSet.Unicode)> _
    Private Shared Function CreateProcessAsUser(ByVal hToken As IntPtr, ByVal lpApplicationName As String, <[In](), Out(), [Optional]()> ByVal lpCommandLine As StringBuilder, ByVal lpProcessAttributes As IntPtr, ByVal lpThreadAttributes As IntPtr, <MarshalAs(UnmanagedType.Bool)> ByVal bInheritHandles As Boolean, ByVal dwCreationFlags As Integer, ByVal lpEnvironment As IntPtr, ByVal lpCurrentDirectory As String, <[In]()> ByRef lpStartupInfo As StartupInfo, <Out()> ByRef lpProcessInformation As ProcessInformation) As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function
    <DllImport("Userenv.dll", ExactSpelling:=True, SetLastError:=True, CharSet:=CharSet.Unicode)> _
    Private Shared Function CreateEnvironmentBlock(ByRef lpEnvironment As IntPtr, ByVal hToken As IntPtr, <MarshalAs(UnmanagedType.Bool)> ByVal bInherit As Boolean) As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function
    <DllImport("Userenv.dll", ExactSpelling:=True, SetLastError:=True, CharSet:=CharSet.Unicode)> _
    Private Shared Function DestroyEnvironmentBlock(ByVal lpEnvironment As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function
    <DllImport("Wtsapi32.dll", ExactSpelling:=True, SetLastError:=True, CharSet:=CharSet.Unicode)> _
    Private Shared Function WTSQueryUserToken(ByVal SessionId As Integer, ByRef phToken As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function
    <DllImport("Kernel32.dll", ExactSpelling:=True, SetLastError:=True, CharSet:=CharSet.Unicode)> _
    Private Shared Function WTSGetActiveConsoleSessionId() As Integer
    End Function
    <DllImport("Kernel32.dll", ExactSpelling:=True, SetLastError:=True, CharSet:=CharSet.Unicode)> _
    Private Shared Function CloseHandle(ByVal hObject As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function

    Public Shared Sub Start(ByVal filename As String, ByVal commandLine As String, ByVal workingDirectory As String, Optional ByVal sessionId As Integer = -1)

        Dim hToken As IntPtr
        Dim pEnvBlock As IntPtr
        Dim dwSessionId As Integer
        Dim pi As ProcessInformation = Nothing
        Dim si As StartupInfo = Nothing

        '   If no session Id was specified defaults to using the session Id
        '   that is currently attached to the physical console.
        If sessionId = (-1) Then

            dwSessionId = WTSGetActiveConsoleSessionId()

        Else

            dwSessionId = sessionId

        End If


        '   Obtain the primary access token of the logged-on user specified by the session
        '   * Note: This can only be called successfully under LocalSystem context.
        If WTSQueryUserToken(dwSessionId, hToken) Then

            '   Get the enviorment block pointer for the user session.
            If CreateEnvironmentBlock(pEnvBlock, hToken, False) Then

                ' Setup command line buffer for unicode version
                Dim cmdLine As New StringBuilder(commandLine, 32768)

                If CreateProcessAsUser(hToken, filename, cmdLine, IntPtr.Zero, IntPtr.Zero, False, _
                                       CreateUnicodeEnvironment, pEnvBlock, workingDirectory, si, pi) Then

                    '   cleanup handle information
                    CloseHandle(pi.hProcess)
                    CloseHandle(pi.hThread)

                End If

                '   Destroy enviorment block pointer.
                DestroyEnvironmentBlock(pEnvBlock)

            End If

            '   cleanup user session token handle.
            CloseHandle(hToken)

        End If

    End Sub

End Class

Open in new window

'// usage
ServiceShell.Start("c:\myapp.exe", " -commandlines", "c:\")
ServiceShell.Start("c:\myapp.exe", nothing, nothing)

Open in new window

Avatar of mahmood66

ASKER

Dear egl1044,

i converted above code to C# as my code is in C#.
while calling Start() function

dwSessionId = WTSGetActiveConsoleSessionId()

the above function always returns '0'.so my application is not opening.
kindly suggest me what i need to do.

thanks
Is your service set to LocalSystem?
Deat eg1044,

how can i set my service to localsystem?
Check the properties section of your service and service installer files. The option should be in there
dear eg1044,

i couldn't able find where i can set my service to local system?
(except the place which i have mentioned in attached screen shot.)

 User generated image

kindly suggest me.

thanks


 

Just a note. This was the place I referrred to in my post 36708597.
Yes. I'm referring to your actual service not the services.msc console but your service application within .NET. In Vista and later interactive services are disabled by default so you don't want to select "Interact with desktop option". You need to open your service in .NET and go to the properties section and turn off "interact with desktop" and only select LocalSystem.
Have a look here http://msdn.microsoft.com/en-us/library/zt39148a(v=vs.80).aspx and scroll to the section "To create the installers for your service"

" In the designer, click ServiceProcessInstaller1 (for a Visual Basic project), or serviceProcessInstaller1 (for a Visual C# or Visual J# project). Set the Account property to LocalService. This will cause the service to be installed and to run on a local service account. "

Make sure you don't have interact with desktop enabled. You may have to un-install your service first, compile the changes and then re-install.
Dear jagrut & eg1044,

1) i already set the above mentioned property.still my application opening in such environement in windows 7.


2) while debugging below code(which is suggested by you [ eg1044]),
 
 Public Shared Sub Start(ByVal filename As String, ByVal commandLine As String, ByVal workingDirectory As String, Optional ByVal sessionId As Integer = -1)

        Dim hToken As IntPtr
        Dim pEnvBlock As IntPtr
        Dim dwSessionId As Integer
        Dim pi As ProcessInformation = Nothing
        Dim si As StartupInfo = Nothing

        '   If no session Id was specified defaults to using the session Id
        '   that is currently attached to the physical console.
        If sessionId = (-1) Then

            dwSessionId = WTSGetActiveConsoleSessionId()

        Else

            dwSessionId = sessionId

        End If


        '   Obtain the primary access token of the logged-on user specified by the session
        '   * Note: This can only be called successfully under LocalSystem context.
        If WTSQueryUserToken(dwSessionId, hToken) Then

            '   Get the enviorment block pointer for the user session.
            If CreateEnvironmentBlock(pEnvBlock, hToken, False) Then

                ' Setup command line buffer for unicode version
                Dim cmdLine As New StringBuilder(commandLine, 32768)

                If CreateProcessAsUser(hToken, filename, cmdLine, IntPtr.Zero, IntPtr.Zero, False, _
                                       CreateUnicodeEnvironment, pEnvBlock, workingDirectory, si, pi) Then

                    '   cleanup handle information
                    CloseHandle(pi.hProcess)
                    CloseHandle(pi.hThread)

                End If

                '   Destroy enviorment block pointer.
                DestroyEnvironmentBlock(pEnvBlock)

            End If

            '   cleanup user session token handle.
            CloseHandle(hToken)

        End If

    End Sub


 this function("WTSGetActiveConsoleSessionId()") always returns '0 ' as sessionId.
so my application is not opening(if i use that code)...



3) is there any other way to avoid opening of my application in such environment in windows 7?
should i approach some other method specially for windows 7.?
because my service opens the same application in XP without any problem, as i mentioned in my question


kindly suggest me..

thanks
This is the correct way to launch an application from a service onto the desktop. The example provided works as intended but there must be some minor problem on your side. In XP the option "interact with desktop" is what allows the service to display the application on the desktop however on Vista and later this has been removed. The easiest way to make it work for XP, Vista , Win7 is to NOT enable "interactive with desktop" option and use the example code to launch your application. The example code will open your program on the current desktop.
Dear (egl1044) Experts,

i have created a new service as suggested in previous post(ID: 36716188).
i followed the instruction and i did the code.
i used the suggested code to call an exe.(suggested By egl1044 ID :36708830)
(but i have converted the code into c#.)
still this is not working..

kindly send me one sample project to achieve my target..


thanks


mahmood66, just to re-emphasis my point I would like to repeat that services are not meant to open a windows form. Just consider the case where computer is started but user does not log-in. Service is started in such case but how can it show the UI.

It is my suggestion that if possible you should think of other alternative like having a System tray application that can start automatically when application starts.

can you give me coding example for that.
ASKER CERTIFIED SOLUTION
Avatar of jagrut_patel
jagrut_patel
Flag of India image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Dear Jagrut,

Thanks for your suggestion.it works.
it works