使用文件I / O正确创建和运行win32服务

我已经基于这个代码示例编写了一个非常简单的服务应用程序。

应用程序作为其正常运行的一部分,假定在找到的目录中或在其执行路径中存在文件。

当我’安装’服务然后从控制面板中的服务管理器“启动”服务时。 应用程序失败,因为它找不到要打开和读取的文件(即使该文件与安装的可执行文件位于同一目录中)。

我的问题是什么时候运行Windows服务,这应该是预期的运行路径?

当调用’CreateService’时,似乎只有二进制的路径参数,而不是执行。 有没有办法指出应该从哪里执行二进制文件?

我在Windows Vista和Windows 7上试过这个。得到同样的问题。

由于Windows服务是从与普通用户模式应用程序不同的上下文运行的,因此最好不要对工作目录或相对路径做任何假设。 除了工作目录的差异之外,服务可以使用完全不同的权限集等运行。

使用服务所需文件的绝对路径应完全避免此问题。 无论工作目录如何,绝对路径都将被解释为相同,因此这应该使您的服务的工作目录无关紧要。 有几种方法可以解决这个问题:

  1. 硬编码绝对路径 – 这可能是避免问题的最简单方法,但它也是最不灵活的。 这种方法对于基本的开发和测试工作来说可能很好,但是在其他人开始使用你的程序之前你可能想要一些更复杂的东西。
  2. 将绝对路径存储在环境变量中 – 这为您提供了额外的灵活性,因为现在可以将路径设置为任意值并根据需要进行更改。 由于服务可以作为具有不同环境变量集的不同用户运行,因此仍然存在一些使用此方法的问题。
  3. 在注册表中存储绝对路径 – 这可能是最简单的方法。 从注册表中检索路径将为所有用户帐户提供相同的结果,而且在安装时相对容易设置。

默认情况下,Windows服务的当前目录是System32文件夹。

一个有前途的解决方案是创建一个环境变量,它保留输入位置的完整路径,并在运行时从此变量中检索路径。

如果使用与二进制相同的路径,则只需读取二进制路径并相应地修改它。 但这是一个相当快速的解决方案,而不是设计解决方案。 如果我是你,我会在那里创建系统范围的环境变量和存储值,或者(甚至更好)使用Windows注册表来存储服务配置。

注意:

您需要使用AdjustTokenPrivileges函数为自己添加一些权限,您可以在ModifyPrivilege函数中看到一个示例。

另外一定要使用HKEY_LOCAL_MACHINE而不是HKEY_CURRENT_USER。 服务在不同的用户帐户下运行,因此它的HKCU将与您在注册​​表编辑器中看到的不同。

(第一篇文章很好)

今天我解决了这个问题,因为我正在开发一些软件。

正如上面的人所说的; 你可以将目录硬编码到一个特定的文件 – 但这意味着加载所需的配置文件必须放在那里。

对我来说,这项服务正在安装在> 50,000台计算机上。 我们将其设计为从运行服务可执行文件的目录加载。

现在,这很容易设置和实现非系统进程(我的大部分测试都是作为非系统进程完成的)。 但问题是你使用的系统包装器(我也使用过)使用unicode格式化(并依赖于它),所以传统的方法也不行。

代码的注释部分应该解释这一点。 我知道有一些裁员,但是当我写这篇文章时我只想要一个有效的版本。 幸运的是,您可以使用GetModuleFileNameA以ASCII格式处理它

我使用的代码是:

 char buffer[MAX_PATH]; // create buffer DWORD size = GetModuleFileNameA(NULL, buffer, MAX_PATH); // Get file path in ASCII std::string configLoc; // make string for (int i = 0; i < strlen(buffer); i++) // iterate through characters of buffer { if (buffer[i] == '\\') // if buffer has a '\' in it, replace with doubles { configLoc = configLoc + "\\\\"; // doubles needed for parsing. 4 = 2(str) } else { configLoc = configLoc + buffer[i]; // else just add char as normal } } // Complete location configLoc = configLoc.substr(0, configLoc.length() - 17); //cut the .exe off the end //(change this to fit needs) configLoc += "\\\\login.cfg"; // add config file to end of string 

从这里开始,您可以简单地将configLoc解析为新的ifsteam - 然后处理内容。