在Windows 7上,StartServiceCtrlDispatcher访问被拒绝

5

我在Windows 7的Visual Studio 2008中有一个C++项目,我试图启动一个新的服务。 我以管理员身份运行Visual Studio。 但我无法启动该服务(serviceMain函数甚至都未被调用)。

这是我的主函数:

wchar_t str[] = {'s','e','s','m'};

int _tmain(int argc, _TCHAR* argv[])
{
    SERVICE_TABLE_ENTRY dispTable[] =
    {
        {(wchar_t*)str, ServiceWork::ServiceMain}, 
        {NULL, NULL}
    };

    int i = StartServiceCtrlDispatcher(dispTable);
    int j = GetLastError();
    return 0; 
}

输出结果为:

. . .

'SessionMonitor.exe':已加载 'C:\Windows\SysWOW64\cryptbase.dll'

'SessionMonitor.exe':已加载 'C:\Windows\SysWOW64\imm32.dll'

'SessionMonitor.exe':已加载 'C:\Windows\SysWOW64\msctf.dll'

在 SessionMonitor.exe 中 0x7638b9bc 处发生一次“First-chance exception: 0x00000005:拒绝访问”。线程“Win32 Thread”(0x129c)已以代码 0 (0x0) 退出。 程序 '[2492] SessionMonitor.exe: Native' 已以代码 0 (0x0) 退出。

调试时,j 的值为1063 - ERROR_FAILED_SERVICE_CONTROLLER_CONNECT

有人遇到过这个问题吗? 有解决方案吗?

谢谢, Liron

6个回答

5
问题在于您正在Visual Studio中启动服务。

这是不可能的。您只需使用Visual Studio编译服务,然后通过使用sc命令(或像这里描述的那样以编程方式)在命令提示符上注册它。所有正确的方法都在问题的已接受答案中进行了描述。

如果您希望调试服务代码,则必须直接发出ServiceMain,例如:

int _tmain(int argc, _TCHAR* argv[])
{
#ifdef AS_SERVICE
    SERVICE_TABLE_ENTRY dispTable[] =
    {
        {(wchar_t*)str, ServiceWork::ServiceMain}, 
        {NULL, NULL}
    };

    int i = StartServiceCtrlDispatcher(dispTable);
    int j = GetLastError();
    return 0;
#else
    ServiceMain(argc, argv);
#endif
}

StartServiceCtrlDispatcher失败且GetLastError返回ERROR_FAILED_SERVICE_CONTROLLER_CONNECT (1063)时,也可能出现同样的问题。


2
如果你想从像Microsoft Visual Studio这样的IDE或命令行启动Windows服务,那么你需要设置一个ConsoleHandler并手动调用ServiceStart,例如:
SetConsoleCtrlHandler(myConsoleHandler, TRUE); ServiceStart(argc, argv, TRUE);
在我们的应用程序中,我们传递一个-debug标志,告诉应用程序以控制台程序而不是Windows服务的方式运行。

2

在Windows 7上访问被拒绝,无法启动服务控制分派程序

我认为这是Windows中的一个错误。根据MSDN StartServiceCtrlDispatcher的说明,失败时应返回零,但微软公司的某个人认为跨API边界抛出自定义(非C ++)异常是一个好主意。

您可以使用AddVectoredExceptionHandler捕获并忽略此特殊类型的异常来解决问题:

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>

LONG WINAPI handle_exception(EXCEPTION_POINTERS* exception_data)
{
  switch (exception_data->ExceptionRecord->ExceptionCode)
  {
  case 0x00000005:  // thrown by StartServiceCtrlDispatcher for fun.
    // Ignore these specific type of exceptions and continue execution.
    // Note: There are several more interesting exceptions to catch here,
    // which are out of scope of this question.
    return EXCEPTION_CONTINUE_SEARCH;

  case 0xE06D7363:  // C++ exception code.
  default:
    // Pass all other type of exceptions to their regular exception handlers.
    return EXCEPTION_EXECUTE_HANDLER;
  }
}

auto handle = AddVectoredExceptionHandler(1, &handle_exception);
// Your code here. Now you can check for the return value of
// StartServiceCtrlDispatcher to see whether the application
// was started as a service or not without crashing.
RemoveVectoredExceptionHandler(handle);

0

这是错误的:

wchar_t str[] = {'s','e','s','m'};

你忘记了加上终止符 NUL。请使用

wchar_t str[] = L"sesm";

0

当你完成代码后,不要调试。 构建它。 当构建成功时,SessionMonitor.exe文件将被创建在Debug文件夹内。 打开命令提示符并安装服务。 sc create "sesm" binPath= "你的SessionMonitor.exe文件所在位置\SessionMonitor.exe"

然后打开运行窗口并输入services.msc 找到sesm服务,运行它,检查ServiceMain中的操作是否有效。


0

你是如何启动服务的?

即使你的用户在管理员组中,程序也不会完全以提升的方式运行,除非你已经通过UAC或者它们是从已经提升的上下文中启动的。如果你想通过Visual Studio进行调试,可能需要右键单击Visual Studio并以管理员身份运行才能正常工作。

如果你想要能够从资源管理器中启动服务,你需要在清单中将requestedExecutionLevel设置为“level=requireAdministrator”。从命令提示符启动将需要相同的操作,除非你使用“net start yourservice”,此时命令提示符将需要提升。从系统服务插件启动不需要特殊准备,并且在Windows 7(而不是Vista)下具有MS签名应用程序的隐藏提升增强功能。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接