I believe it's all to do with "window stations" Steven. Processes connect to
a "window station". The window station associated with the interactive user
can receive input, but others (e.g. for Windows Services) may be
non-interactive. I don't really know a lot about this area (except that I
had to once write a bit of code to enable a common module to determine
whether it was connected to an interactive windows station), so all I can do
is recommend you read up on this in MSDN or on the Web.
P.S. let us know if you find a solution :-)
Tony Proctor
Dear Tony,
Thank you so much for the hint about window stations. I had no idea that
something like that existed although now that I have read up on them it
makes absolute sense for such a system to be in effect.
I have been tinkering around with a test application (only has code for
the Window Stations stuff) that I call through the same COM+ component
on the same machine.
The future is looking very bleak as I am trying to marry the worlds of
VB and VC++ and it's not going very well.
I will attach my code in hope that someone (maybe you Tony) will be able
to make any comments.
This is new territory for me and I have not fully understood how the low
level distinction of a process and thread in VC++ can be reflected in
VB to take full advantage of the functions that deal with Window Stations.
The theory is briefly (merging on adequately) described at:
http://msdn.microsoft.com/library/en-us/dllproc/base/window_station_and_desktop_
functions.asp
Looking forward to hearing from you!
My code so far (the fso stuff is for error logging):
'API function declarations
Public Declare Function SetProcessWindowStation Lib "user32" (ByVal
hWinSta As Long) As Long
Public Declare Function OpenWindowStation Lib "user32" Alias
"OpenWindowStationA" (ByVal lpszWinSta As String, ByVal fInherit As
Long, ByVal dwDesiredAccess As Long) As Long
Public Declare Function OpenInputDesktop Lib "user32" (ByVal dwFlags As
Long, ByVal fInherit As Long, ByVal dwDesiredAccess As Long) As Long
Public Declare Function SetThreadDesktop Lib "user32" (ByVal hDesktop As
Long) As Long
'The window station we wish to assign to the application
Public Const INTERACTIVE_WINDOW_STATION = "Winsta0"
'ACCESS_MASK values
Public Const MAXIMUM_ALLOWED = &H2000000
Public Const GENERIC_ALL = &H10000000
Public Const GENERIC_READ_AND_WRITE = &HC0000000
'Handle to the window station
Dim hndWindowStation As Long
'Handle to the desktop
Dim hndDesktop As Long
Sub Main()
Dim lngReturn As Integer
Dim fso As New FileSystemObject, txt As TextStream
hndWindowStation = OpenWindowStation(INTERACTIVE_WINDOW_STATION, 0,
GENERIC_READ_AND_WRITE)
If IsNull(hndWindowStation) Then
Set txt = fso.CreateTextFile(App.Path & "\log.log", True, False)
txt.WriteLine ("Window Station Handle IS NULL")
txt.Close
Set txt = Nothing
End
Else
lngReturn = SetProcessWindowStation(hndWindowStation)
If lngReturn = 0 Then
Set txt = fso.CreateTextFile(App.Path & "\log.log", True,
False)
txt.WriteLine ("SetProcessWindowStation " & Err.LastDllError)
txt.Close
Set txt = Nothing
End
End If
hndDesktop = OpenInputDesktop(0, 0, GENERIC_READ_AND_WRITE)
If IsNull(hndDesktop) Then
Set txt = fso.CreateTextFile(App.Path & "\log.log", True,
False)
txt.WriteLine ("Desktop Handle IS NULL")
txt.Close
Set txt = Nothing
End
Else
lngReturn = SetThreadDesktop(hndDesktop)
If lngReturn = 0 Then
Set txt = fso.CreateTextFile(App.Path & "\log.log",
True, False)
txt.WriteLine ("SetThreadDesktop " & Err.LastDllError)
txt.Close
Set txt = Nothing
End
End If
End If
End If
Set fso = Nothing
Load Form1
End Sub
> I believe it's all to do with "window stations" Steven. Processes connect to
> a "window station". The window station associated with the interactive user
[quoted text clipped - 42 lines]
>>>Thanks in advance for your time and help,
>>>Steven Moschidis
Steven Moschidis - 17 Mar 2005 11:32 GMT
Hello again!
I've done it! I don't believe it, but I have actually made it work...
Explaining how I came about the solution would probably require a lot of
time and space, but I can describe the solution itself (or what worked
for me, I should say...) (I will not attach the code as it is too long,
but if anyone is having the same problem then please feel free to
contact me and I will email them the code!)
Please note that the account I used for the following solution had local
admin rights on the server. I have not yet tested it with another user
type (e.g. power user) and I am a bit hesitant to do so in case I break
it...
So here we go.
When I first encountered the problem all I was doing was calling the
Shell command from within the COM+ component and expected it to work.
I had no idea of what actually went on in the background just by me
calling Shell.
You must have a user account that must have local admin rights, because
we are going to use the "CreateProcessWithLogonW" API call to call the
executable.
You have to then assign the correct rights to the user so that the user
can have access to the Interactive Window Station and Default Desktop of
that window station.
This is done by using the following:
--get a handle to the interactive window station (using OpenWindowStation)
--get the old DACL (Discretionary Access Control List) information from
the window station (using GetSecurityInfo)
--build an EXPLICIT_STRUCTURE structure that allows the user full access
to the window station (using BuildExplicitAccessWithName)
--merge the old DACL and new DACL (using SetEntriesInAcl)
--assign the newly formed DACL to the window station (SetSecurityInfo)
[make sure you free all the handles and memory using the functions
indicated at the function specifications on MSDN]
Once this was done all I had to do was start the executable:
--populate the STARTUPINFO structure with the right values
--call CreateProcessWithLogonW
The MSDN articles I used as a starting point were:
How To Start a Process as Another User from Visual Basic --
http://support.microsoft.com/default.aspx?scid=kb;en-us;285879
How To Use High-Level Access Control APIs from Visual Basic --
http://support.microsoft.com/kb/295004/EN-US/
Window Stations and Desktops --
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/wi
ndow_stations_and_desktops.asp
Converting C Declarations to Visual Basic --
http://msdn.microsoft.com/library/en-us/vbcon98/html/vbconconvertingcdeclaration
stovisualbasic.asp?frame=true
[this last one proved invaluable as all the processes and structures and
variables used had to be ported from Win32 API. I used no VB code apart
from the error handling]
In closing I would like to thank you Tony once more for opening the door
to a side of Windows I never knew anything about, but now I can
confidently say that I still don't know much! ;) But at least I have got
a vague idea and basic understanding of what goes on with window
stations and desktops! Cheers!
Kind Regards,
Steven Moschidis
Tony Proctor - 18 Mar 2005 12:09 GMT
Thanks for the update Steven. There's a lot of useful stuff in this
Tony Proctor
> Hello again!
> I've done it! I don't believe it, but I have actually made it work...
[quoted text clipped - 44 lines]
>
> Window Stations and Desktops --
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/wi
ndow_stations_and_desktops.asp
> Converting C Declarations to Visual Basic --
http://msdn.microsoft.com/library/en-us/vbcon98/html/vbconconvertingcdeclaration
stovisualbasic.asp?frame=true
> [this last one proved invaluable as all the processes and structures and
> variables used had to be ported from Win32 API. I used no VB code apart
[quoted text clipped - 8 lines]
> Kind Regards,
> Steven Moschidis
Steven Moschidis - 22 Mar 2005 13:07 GMT
I have tried it with a normal member of the Domain User group (the user
we are using to run the COM+ on our web servers) and it worked fine!
> Hello again!
> I've done it! I don't believe it, but I have actually made it work...
[quoted text clipped - 61 lines]
> Kind Regards,
> Steven Moschidis