【问题标题】:Does every windows service calls its executable main function?每个 Windows 服务都调用其可执行的 main 函数吗?
【发布时间】:2018-11-24 20:23:18
【问题描述】:

我有一个关于 windows 服务的非常基本的问题,我有这个 main 安装的函数,我可以用它来安装我的服务,还有一些配置数据在 main 函数中加载:

int 
wmain(int argc, WCHAR* argv[])
{
    // it reads config and fill a global struct.
    ReadConfig();

    // if command == 'install'
    install_service();
}

这里是服务的主要功能:

void WINAPI ServiceMain(DWORD argc, WCHAR* argv[])
{
   // this method retrieves the global config object.
   auto config_data = GetConfigData();

   // service stuff
}

这是另一个函数,如果它在没有任何参数的情况下运行(argc = 0 !),则会在我的 wmain 函数中调用:

bool
ServiceRunAsService()
{
    static const SERVICE_TABLE_ENTRY table[] = {
        { SERVICE_NAME, ServiceMain },
        { NULL, NULL }
    };

    g_hStopService = CreateEvent(0, TRUE, FALSE, 0);
    return StartServiceCtrlDispatcher(table) && GetLastError() != ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
}

我的问题是,当 Windows 想要运行我的服务时(在 PC 关闭并再次打开后),它是调用我的 wmain 函数(因此调用 ReadConfig 函数)还是调用注册的ServiceMain 函数? 我想指出install_service 方法,通过GetModuleFileName 找到可执行文件的路径并将其传递给CreateServiceScmManager

【问题讨论】:

  • 为什么不直接检查?输出一条日志消息。
  • 老实说,我发现在服务中记录消息很困难!我不知道如何
  • 当然windows调用exe入口点。所以wmain。系统对ServiceMain一无所知,直到您不致电StartServiceCtrlDispatcher

标签: c++ windows winapi windows-services


【解决方案1】:

当可执行程序启动时,无论出于什么原因,都会调用 exe 入口点(如果进程之前没有崩溃或挂钩)。所以在你的情况下总是wmainCRTStartup(或者你的exe真正入口点的名称是什么)调用你的wmain。所以是的 - 每次启动可执行文件时都会调用您的 wamin

而且系统根本不能只调用ServiceMain。它根本不知道它的地址。它没有注册。当您注册 exe 服务时,您会为您的服务注册命令行,但不会在 exe 中注册任何导出的名称。您的可执行文件成为服务并仅在StartServiceCtrlDispatcher 之后注册ServiceMain,必须从您的wmain 调用

即使 dll 表单服务与 svchost.exe 一起使用 - 您也注册了必须从您的 dll 调用的导出函数作为服务入口点,或者默认为 ServiceMain。但无论如何,即使在这种情况下,首先您的DllMain(dll 入口点)将被调用(如果存在)。如果 exe - 入口点是强制性的,并且总是会被调用

【讨论】:

  • 所以最后我的可执行文件在没有任何参数的情况下被调用,然后导致ServiceRunAsService被调用(当然当argc == 0时被调用)?
  • @Rachmaninoff - 这取决于您如何通过 CreateService 注册服务 - lpBinaryPathName (或注册表中的 ImagePath 中的内容)- 服务实际上可以有而不是空的命令行。如果您混合 exe 以正常启动并作为服务工作 - 您需要分析命令行,检测您作为服务运行并调用 StartServiceCtrlDispatcher。如果您的可执行设计仅作为服务运行(您通过另一个应用程序注册它) - 您无条件调用StartServiceCtrlDispatcher。无论如何-您只有在 StartServiceCtrlDispatcher 调用和 wmain 总是在启动时调用后才成为服务
  • 我把可执行文件的路径给CreateServicelpBinaryPathName
  • @Rachmaninoff - 这不会改变要点。您现在可以使用空命令行。或一些特殊的,用于表明您作为服务运行。在wmain 你基于命令行或调用StartServiceCtrlDispatcher 或执行其他任务,如注册/注销
【解决方案2】:

当操作系统执行你的 EXE 时,它会调用你的 EXE 的入口点,然后调用你的代码的 (w)main() 函数。当作为服务运行时,您的代码必须调用StartServiceCtrlDispatcher(),它会循环处理来自服务控制器的消息并调用您的ServiceMain()

【讨论】:

  • 不,操作系统肯定不会调用main。操作系统将调用在 PE 标头中指定为入口点的任何内容。那不是main,仅仅是因为它甚至没有正确的签名。不清楚,为什么这被赞成。 公然是错误的,并且不承认,这个问题询问的是 Windows 服务,而不仅仅是任何旧的应用程序。
猜你喜欢
  • 2011-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-16
  • 2013-01-12
  • 1970-01-01
相关资源
最近更新 更多