Problem with services

D

djmob

I am very new to .NET and Windows programming in general so please bare with
me...

I created a Windows service by deriving a class from ServiceBase and
installing it via the 'sc create' commands as follows:

sc create <name> binPath= <path>

Where path is the fully qualified path name. The new service appeared in the
Services GUI and I was able to start and stop it without problems. Next I
recreated the service via the 'sc create' command where binPath used a mapped
drive letter via the subst command i.e. 'subst x: c:\actual\path\name' The
service is created but it does not start and I get the following error
message:

Could not start the <name> service on Local Computer. Error 3: The system
cannot find the path specified.

Unfortunately it is a requirement of my project to be able to used a mapped
driver letter. It appears that when the service is started it has no
knowledge of the drive mappings in my environment. After some research it
also appears that using the subst command is discouraged in later versions of
Windows and the preferred method is to use net commands. I have not been
entirely successful with the net commands and hope there is another approach
to solving this problem. Any suggestions???
 
G

Guest

AFAIK, threre is a problem with .NET apps to work from mapped drive, because
system can't work (use metadata) from that drive.

I reckon u need to write unmanaged service (C++/VB), and it should work

djmob said:
I am very new to .NET and Windows programming in general so please bare with
me...

I created a Windows service by deriving a class from ServiceBase and
installing it via the 'sc create' commands as follows:

sc create <name> binPath= <path>

Where path is the fully qualified path name. The new service appeared in the
Services GUI and I was able to start and stop it without problems. Next I
recreated the service via the 'sc create' command where binPath used a mapped
drive letter via the subst command i.e. 'subst x: c:\actual\path\name' The
service is created but it does not start and I get the following error
message:

Could not start the <name> service on Local Computer. Error 3: The system
cannot find the path specified.

Unfortunately it is a requirement of my project to be able to used a mapped
driver letter. It appears that when the service is started it has no
knowledge of the drive mappings in my environment. After some research it
also appears that using the subst command is discouraged in later versions of
Windows and the preferred method is to use net commands. I have not been
entirely successful with the net commands and hope there is another approach
to solving this problem. Any suggestions???

--
WBR,
Michael Nemtsev :: blog: http://spaces.msn.com/laflour

"At times one remains faithful to a cause only because its opponents do not
cease to be insipid." (c) Friedrich Nietzsche
 
A

Arran Pearce

Are mapped drives not only mapped when a user logs in? Thus how would the
service start when the computer was restarted and the mapped drives does not
exist?
 
A

Amir_Hasan

The cause of this is you have to remember that the Service has to be
running under a certain context.
Whenever any process is run on windows it is run within a Context. (A
context being things like user credentials, current working directory
etc)

When the service starts the CWD will be system32 since it was invoked
by the SCM eg c:\windows\system32

You must change the working directory to the directory of where your
executable in your OnStart or in your Main() of your service
implementation you can do this by doing the following:

protected override void OnStart(string[] args)
{

//EventLog.WriteEntry("Current working Directory Before
Assignment:"+Environment.CurrentDirectory);

Environment.CurrentDirectory =
System.AppDomain.CurrentDomain.BaseDirectory;

//EventLog.WriteEntry("Current working Directory
is:"+Environment.CurrentDirectory);

//rest of OnStart Code here...


}
 
D

djmob

Thanks alot for the help. I will give it a shot and see what happens.

Amir_Hasan said:
The cause of this is you have to remember that the Service has to be
running under a certain context.
Whenever any process is run on windows it is run within a Context. (A
context being things like user credentials, current working directory
etc)

When the service starts the CWD will be system32 since it was invoked
by the SCM eg c:\windows\system32

You must change the working directory to the directory of where your
executable in your OnStart or in your Main() of your service
implementation you can do this by doing the following:

protected override void OnStart(string[] args)
{

//EventLog.WriteEntry("Current working Directory Before
Assignment:"+Environment.CurrentDirectory);

Environment.CurrentDirectory =
System.AppDomain.CurrentDomain.BaseDirectory;

//EventLog.WriteEntry("Current working Directory
is:"+Environment.CurrentDirectory);

//rest of OnStart Code here...

}
I am very new to .NET and Windows programming in general so please bare with
me...
[quoted text clipped - 21 lines]
entirely successful with the net commands and hope there is another approach
to solving this problem. Any suggestions???
 
W

Willy Denoyette [MVP]

|I am very new to .NET and Windows programming in general so please bare
with
| me...
|
| I created a Windows service by deriving a class from ServiceBase and
| installing it via the 'sc create' commands as follows:
|
| sc create <name> binPath= <path>
|
| Where path is the fully qualified path name. The new service appeared in
the
| Services GUI and I was able to start and stop it without problems. Next I
| recreated the service via the 'sc create' command where binPath used a
mapped
| drive letter via the subst command i.e. 'subst x: c:\actual\path\name'
The
| service is created but it does not start and I get the following error
| message:
|
| Could not start the <name> service on Local Computer. Error 3: The system
| cannot find the path specified.
|
| Unfortunately it is a requirement of my project to be able to used a
mapped
| driver letter. It appears that when the service is started it has no
| knowledge of the drive mappings in my environment. After some research it
| also appears that using the subst command is discouraged in later versions
of
| Windows and the preferred method is to use net commands. I have not been
| entirely successful with the net commands and hope there is another
approach
| to solving this problem. Any suggestions???


Service executables should be stored on local drives, what you are trying is
not a supported scenario. The SCM can not start a service that is located on
a remote server, the reason is that SCM (Service.exe) runs as SYSTEM
(localsystem) which is a local security account that has no network access
token. Note that it's possible for SYSTEM to access remote resources from
domain members running in a W2K Active Directory domain, provided that the
"server" starting the service is granted access to the remote share (the
server name is used to authenticate over the network in this case), but even
then there is in guarantee that the service will get loaded, for instance
what if the remote server is not up?
Honestly, I don't see any reason why you need to load a service from a
remote share, I'm I missing something?.

Willy.
 
A

Amir_Hasan

Drive mappings are associated with a User who is logged in. a user maps
drives in Explorer. Services are run in general under a system account.
You can change a service user to use a specific account but I believe
that this is so that the Context the service is running in can get
specific priviliges.
I don't think this will work altough you can try it

1) using explorer Create a permenant drive mapping to a network
Location
2) using explorer create a txt file with some test data on that network
drive
3) Write a .NET service that will read that file using the drive
mapping file path and write the context it to a local folder
c:\documents and settings\user\my documents\testfile.txt
4) Register the service account details to be that user
5) Set the service to be automatic startup
6) Restart the machine
Logon to the machine as someone else eg local administrator etc who
does not have the drive mapping to see if the file created. (ie was it
able to read the drive mapping)

I believe you won't be able to do it. You can try.
 
W

Willy Denoyette [MVP]

| The cause of this is you have to remember that the Service has to be
| running under a certain context.
| Whenever any process is run on windows it is run within a Context. (A
| context being things like user credentials, current working directory
| etc)
|
| When the service starts the CWD will be system32 since it was invoked
| by the SCM eg c:\windows\system32
|
| You must change the working directory to the directory of where your
| executable in your OnStart or in your Main() of your service
| implementation you can do this by doing the following:
|
| protected override void OnStart(string[] args)
| {
|
| //EventLog.WriteEntry("Current working Directory Before
| Assignment:"+Environment.CurrentDirectory);
|
| Environment.CurrentDirectory =
| System.AppDomain.CurrentDomain.BaseDirectory;
|
| //EventLog.WriteEntry("Current working Directory
| is:"+Environment.CurrentDirectory);
|
| //rest of OnStart Code here...
|
|
| }
|
|


This makes no sense, sorry, the problem is that the service cannot be loaded
so certainly not be started, how would this solve the problem?


Willy.
 
W

Willy Denoyette [MVP]

No, drives can be mapped as long as the 'Workstation' service runs, and they
can be mapped in any logon session.

Willy.



| Are mapped drives not only mapped when a user logs in? Thus how would the
| service start when the computer was restarted and the mapped drives does
not
| exist?
|
|
| >I am very new to .NET and Windows programming in general so please bare
| >with
| > me...
| >
| > I created a Windows service by deriving a class from ServiceBase and
| > installing it via the 'sc create' commands as follows:
| >
| > sc create <name> binPath= <path>
| >
| > Where path is the fully qualified path name. The new service appeared
in
| > the
| > Services GUI and I was able to start and stop it without problems. Next
I
| > recreated the service via the 'sc create' command where binPath used a
| > mapped
| > drive letter via the subst command i.e. 'subst x: c:\actual\path\name'
| > The
| > service is created but it does not start and I get the following error
| > message:
| >
| > Could not start the <name> service on Local Computer. Error 3: The
system
| > cannot find the path specified.
| >
| > Unfortunately it is a requirement of my project to be able to used a
| > mapped
| > driver letter. It appears that when the service is started it has no
| > knowledge of the drive mappings in my environment. After some research
it
| > also appears that using the subst command is discouraged in later
versions
| > of
| > Windows and the preferred method is to use net commands. I have not
been
| > entirely successful with the net commands and hope there is another
| > approach
| > to solving this problem. Any suggestions???
|
|
 
D

djmob

Yes that is correct. The problem is with the service being loaded from a
locally mapped drive. Currently the drive is mapped using the subst command
i.e. 'subst x: c:\pathToService'.
| The cause of this is you have to remember that the Service has to be
| running under a certain context.
[quoted text clipped - 24 lines]
|
| }

This makes no sense, sorry, the problem is that the service cannot be loaded
so certainly not be started, how would this solve the problem?

Willy.
 
D

djmob

When you say the "The SCM can not start a service that is located on
a remote server" you mean even if it is mapped to the local drive i.e. 'subst x: c:\path'.

The reason this is a requirement is that I am turning an existing application
into a service and it is important for us to preserve this drive mapping to
support our current development environment (the exact details of why this is
important is a little sketchy to me too). The only reason I brought up the
net commands is that I thought there was something inherent in the subst
command for it not to work with a service.

As I said before this is very new to me so I hope I am making some sense.
|I am very new to .NET and Windows programming in general so please bare with
| me...
[quoted text clipped - 21 lines]
| entirely successful with the net commands and hope there is another approach
| to solving this problem. Any suggestions???

Service executables should be stored on local drives, what you are trying is
not a supported scenario. The SCM can not start a service that is located on
a remote server, the reason is that SCM (Service.exe) runs as SYSTEM
(localsystem) which is a local security account that has no network access
token. Note that it's possible for SYSTEM to access remote resources from
domain members running in a W2K Active Directory domain, provided that the
"server" starting the service is granted access to the remote share (the
server name is used to authenticate over the network in this case), but even
then there is in guarantee that the service will get loaded, for instance
what if the remote server is not up?
Honestly, I don't see any reason why you need to load a service from a
remote share, I'm I missing something?.

Willy.
 
A

Amir_Hasan

Your right I was assuming the Service Implementation is within the same
assembly as the executable (the exe assembly with the Main.) If it is
not you have to make sure that Appdomain Private Path contains the
path of the assembly that is implementing the service (and any of its
dependencies) so that the CLR can find it. You will then have to use
Reflection to load it using Activator.CreateInstance

This can be done by appending private path to the appdomain in the
static Main e.g.
static void Main(string [] args)
{
AppDomain.CurrentDomain.AppendPrivatePath("serviceimp"); //note this
assumes the assembly with YourServiceAssembly.dll is in a subfolder
(with its private dependencies ) called serviceimp
System.ServiceProcess.ServiceBase[] ServicesToRun;
System.ServiceProcess.ServiceBase impl =
Activator.CreateInstance("YourServiceAssembly,ServiceImpl.MyService");
// note the fully qualified class name is ServiceImpl.MyService where
ServiceImpl is the namespace
ServicesToRun = new System.ServiceProcess.ServiceBase[] { impl };
System.ServiceProcess.ServiceBase.Run(ServicesToRun);
}

I hope this makes sense.

..
 
A

Amir_Hasan

Sorry I am not addressing the underlying issue. Your basically stuffed.
Mapped and substited drives are in terms of a user who has logged in.
the SCM that is running up your service is running under the system
account and so does not know anything about the substituted X:. This is
even before the CLR has loaded or kicked in there is basically nothing
you can do. Please ignore my previous posts
 
W

Willy Denoyette [MVP]

The SCM knows x: is not a real local drive, so it asks the 'Workstation'
service (also called the redirector)to resolve the path, which is not
possible as per my previous explaination, and it's not what you are after
anyway.

What you need to do is:
1. Load your service from a local drive (loading from a remote drive would
not give access to that drive from within your service anyway) and run it as
a user account with access privileges to the remote share, that is as:
- a domain account or
- a shadow account, that is a local account with the same credentials (user
name and password) that exists on both servers.

2. Don't use drive letters to access the remote share, use UNC paths instead
(like : \\server\shared\filename ).

If you can't use UNC paths (I see no reason why not), you need to map the
drive from withing your service.
This can be done using:
1 - PInvoke "NetUserAdd" or "WNetAddConnection2, or
2 - a by invoking the utility "net.exe" using Process.Start from within your
service.
complete command looks something like:
net use x: \\servername\share /user:remoteservername\userName pwd
where: remoteservername is the name of the remote machine
userName is the name o a user on above with valid access privileges
to the share
pwd is it's password.

Willy.


| Yes that is correct. The problem is with the service being loaded from a
| locally mapped drive. Currently the drive is mapped using the subst
command
| i.e. 'subst x: c:\pathToService'.
|
| Willy Denoyette [MVP] wrote:
| >| The cause of this is you have to remember that the Service has to be
| >| running under a certain context.
| >[quoted text clipped - 24 lines]
| >|
| >| }
| >
| >This makes no sense, sorry, the problem is that the service cannot be
loaded
| >so certainly not be started, how would this solve the problem?
| >
| >Willy.
 
W

Willy Denoyette [MVP]

Sorry but, you got it wrong again, the problem can not be solved in the
service code, the problem is that the Service Control Manager (the SCM)
cannot load the exeutable from the path as defined by the configuration
utility.
The service path is configured like : x:\myservice.exe, but the SCM does not
know what x: is all about so he asks the Workstation service to resolve the
mapping, which is not possible either, because it's the result of "subst"
command done in the interactive users logon context. So, it's not a network
share redirection either, which is finaly what the OP is trying to sumulate
(wrongly).

Willy.

| Your right I was assuming the Service Implementation is within the same
| assembly as the executable (the exe assembly with the Main.) If it is
| not you have to make sure that Appdomain Private Path contains the
| path of the assembly that is implementing the service (and any of its
| dependencies) so that the CLR can find it. You will then have to use
| Reflection to load it using Activator.CreateInstance
|
| This can be done by appending private path to the appdomain in the
| static Main e.g.
| static void Main(string [] args)
| {
| AppDomain.CurrentDomain.AppendPrivatePath("serviceimp"); //note this
| assumes the assembly with YourServiceAssembly.dll is in a subfolder
| (with its private dependencies ) called serviceimp
| System.ServiceProcess.ServiceBase[] ServicesToRun;
| System.ServiceProcess.ServiceBase impl =
| Activator.CreateInstance("YourServiceAssembly,ServiceImpl.MyService");
| // note the fully qualified class name is ServiceImpl.MyService where
| ServiceImpl is the namespace
| ServicesToRun = new System.ServiceProcess.ServiceBase[] { impl };
| System.ServiceProcess.ServiceBase.Run(ServicesToRun);
| }
|
| I hope this makes sense.
|
| .
|
 
W

Willy Denoyette [MVP]

| When you say the "The SCM can not start a service that is located on
| >a remote server" you mean even if it is mapped to the local drive i.e.
'subst x: c:\path'.
|
| The reason this is a requirement is that I am turning an existing
application
| into a service and it is important for us to preserve this drive mapping
to
| support our current development environment (the exact details of why this
is
| important is a little sketchy to me too). The only reason I brought up
the
| net commands is that I thought there was something inherent in the subst
| command for it not to work with a service.
|

Service are not regular application, this is something you need to consider
when turning regular applications into Services, something that is common
place since the introduction of .NET.
Everyone seems to need services these day's, which IMO, is terribly wrong in
most circumstances.

I have explained what you have to do in an other reply, but before you do,
make sure you know what services are all about, what they are meant to solve
and what their restrictions are. Failing to do your homework will bite you
sooner that later.
What you need to know to begin with is (non exhaustive!):
- Services are meant to run in a restricted security context, they need
(preferably) to run under service users credentials (localsystem, local
service or network service). Running them under domain credentials is a
security threat.
- The run in a secured desktop (in the background as the sage goes) that has
no access to the active (visible) desktop, the active desktop has no access
to the service(s) desktop(s) either. That means they should not have a UI,
nor should they assume they can access, the UI of a running programs, by
whatever means.
- They don't have access to the profile data of the currently logged on user
(interactive), nor should the assume the presence of such a user.
- They have access to the services hives for their private profile storage,
these are mapped as:
- HKU\.Default or S-1-5-18 for localsystem and all other accounts
running the service (local or domain)
- HKU \S-1-5-19 for Local Service
- HKU \S-1-5-20 for Network Service

None of these hives contain configuration data like printers and persistent
mapped network shares, application paths like MyDocuments, MyPictures etc;
paths to document folders etc...

They run their threads in an MTA, so, be sure your COM objects can live
safely in this context, inspect your COM servers requirements first.
They should not use any library that requires a UI to be present even not a
hidden window (think System.Drawing and managed/unmanaged DirectX).


Willy.
 

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