Link to home
Start Free TrialLog in
Avatar of plq
plqFlag for United Kingdom of Great Britain and Northern Ireland

asked on

How to tell if a visualbasic.net program is attached to a windows session or not

I've got a VB.net 2005 windows program which can be launched either from a shell in a separate windows service program, or it can be launched by the end user.

As expected, when its running from a service, the program does not display on the monitor because its not attached to a logged in session. I'm ok with that but if there is a way to display it in the logged in session please let me know (I didn't think so).

So I just want to be able to detect if the app is attached to a user session or not, so I know whether to send error message to the event log or to the screen with a msgbox.

thanks
Avatar of Jason Evans
Jason Evans
Flag of United Kingdom of Great Britain and Northern Ireland image

Hi there.

Appologies for the vague response, but it might be an idea to hunt on the web for .NET code that show you how to get your .NET application's process details, and from those details get the account name that started your application. These details include stuff like security priviledges, thread info, etc, but they might also include info about the account that started your .NET app.

By doing that, you could analyse the user information and maybe build some logic around that.

Sorry I can't give much details as it's only an idea I had in my head just now and it's not something I've done before.

Hope it gives you an idea though.
Jas.
Avatar of Bob Learned
You should still be able to look through the processes by name using Process.GetProcessesByName.

Bob
Avatar of plq

ASKER

The process name and account are identical whether you run from a windows service or from a start menu item, since the app only works if you are a domain admin. I was hoping there would be some flag somewhere in the framework that tells me if the form is actually attached to a session or not.

thanks
If your application can execute as a Windows Service or a WinForms app, how do you differentiate in the code which mode to operate in?  Do you have separate entry classes?

Bob
Avatar of plq

ASKER

No, its not itself a windows service, its launched from a windows service using shell or process.execute etc, so its in the same "session" as a windows service, but its a separate exe file. A sessionless program cannot interact with desktop as far as I know.

I am firstly going to take inspiration from MrClyfar's advice and go a step further by catching the thing in the debugger when its running shelled from a service, and then inspect the attributes of the thread and the process, the forms, ... to see if there's anything different from . I will report back here.
ASKER CERTIFIED SOLUTION
Avatar of jkr
jkr
Flag of Germany 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
SOLUTION
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
Avatar of plq

ASKER

Thanks for these. I am confident that one way or another jkr has given me the answer I need here, which is not how to push content from a localsystem launched exe onto a visible window in a users session (ok I did ask that but I already thought it was fundamentally impossible..), but more HOW TO DETECT that the current process belongs to local system and not a users session.

Worst case I have to convert jkrs program into windows api calls which is easy enough, best case I will be able to retrieve the sid with .net framework and then either pick up a property or do an api call to compare sids from current session against the localsystem sid

Whatever happens, I'll be back., unless I get run over by a bus

thanks
I think that you can pass in arguments through command line arguments that dictate what mode your running in, and detect that within the application.

Bob
>>I think that you can pass in arguments through command line arguments that
>>dictate what mode your running in

Then you have to determine that in the launching app. Just shifting the problem.
>>Worst case I have to convert jkrs program into windows api calls

Make that a DLL that you call via PInvoke - that would mean the least effort.
Avatar of plq

ASKER

OK I couldn't go the DLL route since the architecture requires a clickonce EXE distributable so all the code is contained in the one exe.

However once I knew I was looking for "window station", I found a set of APIs that are callable from vb.net.

Sadly I couldn't find a managed code .net framework equivalent, but that doesn't mean it doesnt exist !!

So, here's a piece of reuseable vb.net that returns the name of the current window station.

Return values (letter case might be wrong):

In xp logged in session :  "Wrksta0"
In Exe launched from a service : "Service-0x0-4c2e72$"
In 2003 logged in session : "Winsta0"

----------------------------------------------------------------------------

    Public Declare Auto Function GetProcessWindowStation Lib "User32.dll" () As Integer
    Public Declare Auto Function GetUserObjectInformation Lib "User32.dll" (ByVal lHandle As Integer, ByVal lIndex As Integer, ByVal sOutput As String, ByVal lLength As Integer, ByRef lOutLen As Integer) As Integer


    Public Function GetWindowStation() As String
        Dim h As Integer = GetProcessWindowStation()
        Dim sSta As New String(" "c, 255)
        Dim l As Integer = 0
        Dim ret As Integer = GetUserObjectInformation(h, 2, sSta, 255, l)
        If ret = 1 Then
            Return sSta
        Else
            Return "Unknown"
        End If
    End Function

usage:
   dim sWinStation as string = GetWindowStation()

Avatar of plq

ASKER

OK, here's a better solution.

GetUserObjectInformation with a lIndex of 4 returns a 0-255 bitwise flag of which the highest bit (128) is whether or not the window station has access to a visible terminal.



    Public Declare Auto Function GetProcessWindowStation Lib "User32.dll" () As Integer
    Public Declare Auto Function GetUserObjectInformation Lib "User32.dll" (ByVal lHandle As Integer, ByVal lIndex As Integer, ByVal sOutput As String, ByVal lLength As Integer, ByRef lOutLen As Integer) As Integer

    Public Function GetWindowStation() As String
        Dim h As Integer = GetProcessWindowStation()
        Dim sSta As New String(" "c, 255)
        Dim l As Integer = 0
        Dim ret As Integer = GetUserObjectInformation(h, 2, sSta, 255, l)
        If ret = 1 Then
            Return sSta
        Else
            Return "Unknown"
        End If
    End Function

    Public Function GetWindowStationVisible() As Boolean
        Dim h As Integer = GetProcessWindowStation()
        Dim sSta As New String(" "c, 255)
        Dim l As Integer = 0
        Dim ret As Integer = GetUserObjectInformation(h, 4, sSta, 255, l)
        Return CBool(Microsoft.VisualBasic.Asc(sSta(0)) And 128)
    End Function

usage:
   ' to get the name of a window station
   dim sWinStation as string = GetWindowStation()

   ' to get whether the window station is visible or not
   dim bWindowStationVisible as Boolean = GetWindowStationVisible()



Of course, a more elegant api call would be to pass an integer byref, but can't be bothered, so I've left it with "asc"

thanks for helping folks.. I am sharing points as I think appropriate