Windows services 设置Windows服务';工作目录

Windows services 设置Windows服务';工作目录,windows-services,apache-commons-daemon,Windows Services,Apache Commons Daemon,我正在使用ApacheCommons守护程序将Java应用程序包装为Windows服务。我遇到的问题与服务的工作目录有关,它是C:\Windows\system32。服务所需的配置文件是相对于应用程序引用的(在\conf目录中) 我尝试将--StartPath参数设置为procrun,但它没有影响服务的工作目录。(更新:我现在看到该参数仅在启动exe时起作用。)我正在尝试保持应用程序跨平台,因此除非绝对必要,否则我不想修改配置文件路径 有没有办法设置Windows服务的工作目录?使用--Star

我正在使用ApacheCommons守护程序将Java应用程序包装为Windows服务。我遇到的问题与服务的工作目录有关,它是
C:\Windows\system32
。服务所需的配置文件是相对于应用程序引用的(在
\conf
目录中)

我尝试将
--StartPath
参数设置为
procrun
,但它没有影响服务的工作目录。(更新:我现在看到该参数仅在启动exe时起作用。)我正在尝试保持应用程序跨平台,因此除非绝对必要,否则我不想修改配置文件路径

有没有办法设置Windows服务的工作目录?

使用
--StartPath
jvm
结合使用,而不是像
--StartMode
那样使用
exe
,并使用几个小时前下载的Apache Commons Daemon 1.1

如果没有
--StartPath
,我的守护进程就无法找到它的配置文件,即使在shell上使用具有正确目录的
pushd
启动了
prunsrv
。进程监视器显示,存储了
prunsrv
的目录被用作当前工作目录。有了
--StartPath
,并且只有在我之前的基础上增加了这个配置文件,我的守护进程现在才找到自己的配置文件,并且Logback也在正确初始化,使用它的
Logback.xml
中的相对路径,只有在正确的当前工作目录下才有意义

因此,无论您过去做了什么,它可能是错误的,或者从那时起该功能可能已经被添加。看看源代码,我不觉得
--StartPath
也只依赖或影响EXE:

if (_jni_startup) {
    if (IS_EMPTY_STRING(SO_STARTPATH))
        SO_STARTPATH = gStartPath;
    if (IS_VALID_STRING(SO_STARTPATH)) {
        /* If the Working path is specified change the current directory */
        SetCurrentDirectoryW(SO_STARTPATH);
    }

我们希望这不是未定义的行为,因为文档中的内容确实不同:

开始映像可执行文件的工作路径

OTOH,很长一段时间以来都是这样的:


这可能不是同一个问题。然而,我发现procrun对
--StartPath
参数路径周围双引号的解释存在问题。我的安装批处理文件如下所示:

SET ROOTDIR=%~dp0
"%ROOTDIR%prunsrv.exe" install MyServiceName ... --StartPath="%ROOTDIR%" ...
SET ROOTDIR=%~dp0
"%ROOTDIR%prunsrv.exe" install MyServiceName ... ... --StartPath="%ROOTDIR%
如果没有引号,路径将在
%ROOTDIR%
中的第一个空格处结束。为了处理空格,我在路径周围加了双引号。然后,当我查看注册表时,我可以看到
Computer\HKEY\u LOCAL\u MACHINE\SOFTWARE\WOW6432Node\Apache SOFTWARE Foundation\Procrun 2.0\MyServiceName\Parameters\Start\WorkingPath
的值删除了起始引号,但没有删除终止引号,该值包括以下所有参数。因此,其他注册表项丢失

可怕的解决办法是:

  • 移动
    --StartPath
    作为最后一个参数
  • 使用开始报价,但不要使用结束报价
因此,批处理文件现在看起来像:

SET ROOTDIR=%~dp0
"%ROOTDIR%prunsrv.exe" install MyServiceName ... --StartPath="%ROOTDIR%" ...
SET ROOTDIR=%~dp0
"%ROOTDIR%prunsrv.exe" install MyServiceName ... ... --StartPath="%ROOTDIR%

这将是错误的解决方案。在Java中,应该可以找到应用程序的位置,并且应该计算相对于该位置的路径,而不是相对于当前目录的路径。这不仅仅是Windows的问题,Linux和MacOSX中也是如此——你不应该仅仅假设当前目录与应用程序目录相同。Java应用程序认为它的位置是system32,因为它是作为服务运行的。因此,问题是:否。在服务中,system32是当前目录,也称为工作目录;它不是应用程序目录。Windows不会向应用程序谎报它们的位置。在做了一些研究之后,在Java中实现这一点似乎比我预期的要困难,许多其他人只是对当前目录和应用程序目录之间的区别感到困惑,但我确实找到了您需要的目录。根据您的需要,一个更简单的选项可能是使用
++Environment
选项来
prunsrv
提供环境变量中配置文件的路径。依赖当前工作目录不是错误的解决方案,这就是为什么可以在进程创建期间设置它的原因,Upstart或systemd等工具可以设置它。有时甚至有必要与第三方libs进行适当集成,比如提供包含回登录路径的配置文件本身,这样做容易得多。