我现在正在编写一个nt服务程序,可是我不知道怎样才能对其调试!我看了SDK中的说明,但是还没有理解他的意思!不知哪位高手能指点小弟一把??

解决方案 »

  1.   

    我以前写服务程序,主要是通过向屏幕打印信息进行调试。《windows2000系统编程》里边有一些有关服务程序调试方法。
      

  2.   

    BOOL                    bDebug = FALSE;
    void CmdDebugService(int argc, char ** argv)
    {
        DWORD dwArgc;
        LPTSTR *lpszArgv;#ifdef UNICODE
        lpszArgv = CommandLineToArgvW(GetCommandLineW(), &(dwArgc) );
    #else
        dwArgc   = (DWORD) argc;
        lpszArgv = argv;
    #endif    _tprintf(TEXT("Debugging %s.\n"), TEXT(SZSERVICEDISPLAYNAME));    SetConsoleCtrlHandler( ControlHandler, TRUE );    ServiceStart( dwArgc, lpszArgv );
    }
      

  3.   

    在调试时,你做的服务程序先不要注册到控制面板中去运行,而是直接运行EXE,这样就可以设置断点、跟踪运行了。等调试完后,再注册到控制面板中去运行。
      

  4.   

    ServiceStart()?
    这个函数好想找不到啊!楼上的仁兄能否说清楚一点?不胜感激!!
      

  5.   

    用VC的Attach功能就可以了。
    在Build-Debug-Process Attach中,选择System的checkbox
    再在ListBox中选择你的服务程序。有些程序是必须作为服务程序才能得到正常的效果,不注册的话就
    不是真实的环境,让人不放心呀。
      

  6.   

    Attach后,再把源代码拖到VC中,就可以设置断点了。然后就和以前一样Debug。。
      

  7.   

    这是我以前写的程序的一个函数 如果你需要例子请给我发邮件
    [email protected]
    VOID ServiceStart (DWORD dwArgc, LPTSTR *lpszArgv)
    {
    SOCKET s;
        SOCKADDR_IN sin;
    SOCKADDR_IN sout;
    int sout_size;
        char *remoteIp;
        unsigned short remoteport;
    // char LogMsg[64];
        struct LOGINUSER *LoginUser;
    int dwSNDBUF=1024;
    // int buflen;
    int dwRCVBUF=1024;
        int err;                                       
        DWORD dwThreadId;
    HANDLE hThreadHandle;
    int ErrorSockCount;
    //char cNum[35];

        //
        // Create a listening socket that we'll use to accept incoming
        // conections.
        //
         // report the status to the service control manager.
        //
        if (!ReportStatusToSCMgr(
            SERVICE_START_PENDING, // service state
            NO_ERROR,              // exit code
            3000))                 // wait hint
            return;    if(!ReadParameters())
    {
            //printf("read parameter error\n");
    return;
    }    if (!ReportStatusToSCMgr(
            SERVICE_START_PENDING, // service state
            NO_ERROR,              // exit code
            3000))                 // wait hint
            return;    if(!CAPIInitKey(szPrvKeyFile))
    {
    //printf("init key failed.\n");
    return;
    }    if (!ReportStatusToSCMgr(
            SERVICE_START_PENDING, // service state
            NO_ERROR,              // exit code
            3000))                 // wait hint
            return;    err = WSAStartup( 0x0101, &WsaData );
        if ( err == SOCKET_ERROR ) {
            //printf( "WSAStartup failed.\n" );
    return;
        }
        
    if (!ReportStatusToSCMgr(
            SERVICE_RUNNING,       // service state
            NO_ERROR,              // exit code
            0))                    // wait hint
            goto cleanup; sListener = socket( AF_INET, SOCK_STREAM, 0 );
        if ( sListener == INVALID_SOCKET ) {
    //WSACleanup();
            return;
        }    //
        // Bind the socket to the port.
        //    sin.sin_family = AF_INET;
        sin.sin_port = htons( REPL_PORT );
        sin.sin_addr.s_addr = INADDR_ANY;    err = bind( sListener, (LPSOCKADDR)&sin, sizeof(sin) );
        if ( err == SOCKET_ERROR )
            goto cleanup;    //
        // Listen for incoming connections on the socket.
        //
        err = listen( sListener, 5 );
        if ( err == SOCKET_ERROR ) 
    goto cleanup;    //
        // End of initialization
        //
        ////////////////////////////////////////////////////////    ////////////////////////////////////////////////////////
        //
        // Service is now running, perform work until shutdown
        //
        dwThreadNum=0;
        while (1)
        {
    sout_size=sizeof(sout);
            s = accept( sListener, (LPSOCKADDR)&sout, &sout_size);
      
    if ( s == INVALID_SOCKET ) {
                if (bServiceTerminating ) 
       break;
          else
    {
       ErrorSockCount++;
                   if(ErrorSockCount>10)
       break;
       else
                continue;
    }
    }
                 
    ErrorSockCount=0;
    //
            // If the service if terminating, exit this thread.
           //        if (bServiceTerminating ) 
    {
    closesocket(s);      
    break;
    //continue;
    }
    //sprintf(cNum,"The thread num is %d",dwThreadNum);
            //WriteMsgToLogFile(cNum);
    if(dwMaxThreadNum!=0){
          if(dwThreadNum>=dwMaxThreadNum)
       {
         closesocket(s);      
        continue;
       }
    }
    err = setsockopt( s, SOL_SOCKET, SO_RCVBUF, (char *)&dwRCVBUF, sizeof(dwRCVBUF) );
            if ( err == SOCKET_ERROR ) {
                closesocket( s );
                continue;
            }
            err=setsockopt(s,SOL_SOCKET,SO_SNDBUF,(char *)&dwSNDBUF,sizeof(dwSNDBUF));
    //err=getsockopt(s,SOL_SOCKET,SO_SNDBUF,(char *)&dwSNDBUF,&buflen);
            //err=setsockopt(s,SOL_SOCKET,SO_RCVBUF,(char *)&dwRCVBUF,sizeof(dwRCVBUF));

            if ( err == SOCKET_ERROR ) {
                closesocket( s );
                continue;
            } remoteIp=inet_ntoa(sout.sin_addr);
    remoteport=sout.sin_port;
    //memset(LogMsg,'\0',64);
    //sprintf(LogMsg,"%s:%d connected, begin login.",remoteIp,remoteport);
    //WriteMsgToLogFile(LogMsg); LoginUser=NULL;
            LoginUser=(struct LOGINUSER *)malloc(sizeof(struct LOGINUSER));
    if(LoginUser==NULL)
    {
    closesocket(s);
    continue;
    }
    LoginUser->s=s;
            sprintf(LoginUser->remoteIp,"%s",remoteIp);
    LoginUser->remotePort=remoteport;
            //free(LoginUser); //printf("send buffer length is %d,length is %d\n",dwSNDBUF,buflen);
    hThreadHandle = CreateThread(
                                NULL,
                                0,
                                WorkerThread,
                                (LPVOID)LoginUser,
                                0,
                                &dwThreadId
                                );
            if ( hThreadHandle == NULL ) {
                closesocket( s );
                continue;
            }
    else
    dwThreadNum=dwThreadNum+1; //sprintf(cNum,"The last thread num is %d",dwThreadNum);    }  cleanup: closesocket(sListener);
    WSACleanup();
    }
      

  8.   

    这是我以前写的程序的一个函数 如果你需要例子请给我发邮件
    [email protected]
    VOID ServiceStart (DWORD dwArgc, LPTSTR *lpszArgv)
    {
    SOCKET s;
        SOCKADDR_IN sin;
    SOCKADDR_IN sout;
    int sout_size;
        char *remoteIp;
        unsigned short remoteport;
    // char LogMsg[64];
        struct LOGINUSER *LoginUser;
    int dwSNDBUF=1024;
    // int buflen;
    int dwRCVBUF=1024;
        int err;                                       
        DWORD dwThreadId;
    HANDLE hThreadHandle;
    int ErrorSockCount;
    //char cNum[35];

        //
        // Create a listening socket that we'll use to accept incoming
        // conections.
        //
         // report the status to the service control manager.
        //
        if (!ReportStatusToSCMgr(
            SERVICE_START_PENDING, // service state
            NO_ERROR,              // exit code
            3000))                 // wait hint
            return;    if(!ReadParameters())
    {
            //printf("read parameter error\n");
    return;
    }    if (!ReportStatusToSCMgr(
            SERVICE_START_PENDING, // service state
            NO_ERROR,              // exit code
            3000))                 // wait hint
            return;    if(!CAPIInitKey(szPrvKeyFile))
    {
    //printf("init key failed.\n");
    return;
    }    if (!ReportStatusToSCMgr(
            SERVICE_START_PENDING, // service state
            NO_ERROR,              // exit code
            3000))                 // wait hint
            return;    err = WSAStartup( 0x0101, &WsaData );
        if ( err == SOCKET_ERROR ) {
            //printf( "WSAStartup failed.\n" );
    return;
        }
        
    if (!ReportStatusToSCMgr(
            SERVICE_RUNNING,       // service state
            NO_ERROR,              // exit code
            0))                    // wait hint
            goto cleanup; sListener = socket( AF_INET, SOCK_STREAM, 0 );
        if ( sListener == INVALID_SOCKET ) {
    //WSACleanup();
            return;
        }    //
        // Bind the socket to the port.
        //    sin.sin_family = AF_INET;
        sin.sin_port = htons( REPL_PORT );
        sin.sin_addr.s_addr = INADDR_ANY;    err = bind( sListener, (LPSOCKADDR)&sin, sizeof(sin) );
        if ( err == SOCKET_ERROR )
            goto cleanup;    //
        // Listen for incoming connections on the socket.
        //
        err = listen( sListener, 5 );
        if ( err == SOCKET_ERROR ) 
    goto cleanup;    //
        // End of initialization
        //
        ////////////////////////////////////////////////////////    ////////////////////////////////////////////////////////
        //
        // Service is now running, perform work until shutdown
        //
        dwThreadNum=0;
        while (1)
        {
    sout_size=sizeof(sout);
            s = accept( sListener, (LPSOCKADDR)&sout, &sout_size);
      
    if ( s == INVALID_SOCKET ) {
                if (bServiceTerminating ) 
       break;
          else
    {
       ErrorSockCount++;
                   if(ErrorSockCount>10)
       break;
       else
                continue;
    }
    }
                 
    ErrorSockCount=0;
    //
            // If the service if terminating, exit this thread.
           //        if (bServiceTerminating ) 
    {
    closesocket(s);      
    break;
    //continue;
    }
    //sprintf(cNum,"The thread num is %d",dwThreadNum);
            //WriteMsgToLogFile(cNum);
    if(dwMaxThreadNum!=0){
          if(dwThreadNum>=dwMaxThreadNum)
       {
         closesocket(s);      
        continue;
       }
    }
    err = setsockopt( s, SOL_SOCKET, SO_RCVBUF, (char *)&dwRCVBUF, sizeof(dwRCVBUF) );
            if ( err == SOCKET_ERROR ) {
                closesocket( s );
                continue;
            }
            err=setsockopt(s,SOL_SOCKET,SO_SNDBUF,(char *)&dwSNDBUF,sizeof(dwSNDBUF));
    //err=getsockopt(s,SOL_SOCKET,SO_SNDBUF,(char *)&dwSNDBUF,&buflen);
            //err=setsockopt(s,SOL_SOCKET,SO_RCVBUF,(char *)&dwRCVBUF,sizeof(dwRCVBUF));

            if ( err == SOCKET_ERROR ) {
                closesocket( s );
                continue;
            } remoteIp=inet_ntoa(sout.sin_addr);
    remoteport=sout.sin_port;
    //memset(LogMsg,'\0',64);
    //sprintf(LogMsg,"%s:%d connected, begin login.",remoteIp,remoteport);
    //WriteMsgToLogFile(LogMsg); LoginUser=NULL;
            LoginUser=(struct LOGINUSER *)malloc(sizeof(struct LOGINUSER));
    if(LoginUser==NULL)
    {
    closesocket(s);
    continue;
    }
    LoginUser->s=s;
            sprintf(LoginUser->remoteIp,"%s",remoteIp);
    LoginUser->remotePort=remoteport;
            //free(LoginUser); //printf("send buffer length is %d,length is %d\n",dwSNDBUF,buflen);
    hThreadHandle = CreateThread(
                                NULL,
                                0,
                                WorkerThread,
                                (LPVOID)LoginUser,
                                0,
                                &dwThreadId
                                );
            if ( hThreadHandle == NULL ) {
                closesocket( s );
                continue;
            }
    else
    dwThreadNum=dwThreadNum+1; //sprintf(cNum,"The last thread num is %d",dwThreadNum);    }  cleanup: closesocket(sListener);
    WSACleanup();
    }
      

  9.   

    其实不要这么麻烦 ServiceStart 是你服务启动后执行的函数
    如果在调试的话就设置表示调试状态的变量 然后执行CmdDebugService
    CmdDebugService传递的参数其实是main函数传进来的参数 我的服务程序是纯C下的
    我在main里调用是   
     else if ( _stricmp( "debug", argv[1]+1 ) == 0 )
            {
                bDebug = TRUE;
                CmdDebugService(argc, argv);
            }
      

  10.   

    如果是的话,很简单,运行后,
    从任务管理器中结束本任务,就可以设置断点
    刚刚开发的pops service 就是这样调试的。
      

  11.   

    是阿 其实不要这么麻烦 ServiceStart 是你服务启动后执行的函数
    如果在调试的话就设置表示调试状态的变量 然后执行CmdDebugService
    CmdDebugService传递的参数其实是main函数传进来的参数 我的服务程序是纯C下的
    我在main里调用是   
     else if ( _stricmp( "debug", argv[1]+1 ) == 0 )
            {
                bDebug = TRUE;
                CmdDebugService(argc, argv);
            }
      

  12.   

    其实msdn里有一篇文章专门讲调试服务的,里边介绍了几钟方法(见
    HOWTO: Debugging a service
    ID: Q98890 )我觉得比较好用的是在程序的开头添加一个DebugBreak()的调用,服务运行后就在这里出现一个软中断框,然后进行调试,就可以向普通应用程序一样调试了。(还需要设置该服务可以和桌面交互操作)
      

  13.   

    我一般是写一个DebugToFile函数向log 文件中输出变量信息。
      

  14.   

    给我你的例子 [email protected]
      

  15.   

    在注册表里设一下,启动时,让服务在VC的debug下开始运行。
      

  16.   

    首先把Service编成debug版(所有相关的Dll也得编成debug版)。
    然后注册运行,在task manager中找到需要调试的Service的线程,
    用鼠标选中后点击右键,在菜单中选择调试,然后再弹出的VC环境中
    加断点调试即可。
      

  17.   

    用SoftIce,用nmsym工具生成调试信息,然后调试很爽
      

  18.   

    如果程序进入点是ServiceStart 那些设置,SETUP,install,等,就不必管他。
    我们设置一个CmdDebugService(argc, argv);就是,如果是debug模式,就由他来进入ServiceStart 。而程序不在调试状态时,SERVICE_TABLE_ENTRY dispatchTable[] 进入ServiceStart 
    void _CRTAPI1 main(int argc, char **argv)
    {
    // Single Process Service
        SERVICE_TABLE_ENTRY dispatchTable[] = {
            { TEXT(SZSERVICENAME), (LPSERVICE_MAIN_FUNCTION)importsrv_main },
            { NULL, NULL }
        }; // -install -> install the service
    // -setup   -> Setup system parameters
    // -remove  -> remove the service from Service Control
    // -service -> Start the service in console
    //printf("Entering main\n");
        if ( (argc > 1) && ((*argv[1] == '-') || (*argv[1] == '/')) ) {
            if ( _stricmp( "install", argv[1]+1 ) == 0 ) {
    //printf("Install service\n");
                CmdInstallService();
            }
    else if ( _stricmp( "setup",  argv[1]+1 ) == 0 ) {
    CmdSetupPara();
    }
    else if ( _stricmp( "remove", argv[1]+1 ) == 0 ) {
                CmdRemoveService();
            }
            else if ( _stricmp( "service", argv[1]+1 ) == 0 ) {
    goto dispatch;
            }
            else {
                gbDebug = TRUE;
                CmdDebugService(argc, argv);
            }
            exit(0);
        }
     dispatch:
            // this is just to be friendly
            _tprintf( "%s -install          install the importsrv service\n", SZAPPNAME );
            _tprintf( "%s -setup            setup consrv registry entries\n", SZAPPNAME );
            _tprintf( "%s -remove           remove the importsrv service\n", SZAPPNAME );
            _tprintf( "%s -service to run as a service\n", SZAPPNAME );
            _tprintf( "\nStartServiceCtrlDispatcher being called.\n" );
            _tprintf( "This may take several seconds.  Please wait.\n" );        if (!StartServiceCtrlDispatcher(dispatchTable)) {
    _tprintf("Service start r failed.");
    WriteLog(MSGPRI_ERR, "service start CtrlDispatcher failed.");
    }
    }下面是主程序不在调试状态下的进入主程序,也就是SERVICE_TABLE_ENTRY dispatchTable[] = {
            { TEXT(SZSERVICENAME), (LPSERVICE_MAIN_FUNCTION)importsrv_main },{ NULL, NULL }    };
    而来的
    void WINAPI importsrv_main(DWORD dwArgc, LPTSTR *lpszArgv)
    {
    DWORD dwErr;    // register our service control handler:
        //
        gsshStatusHandle = 
    RegisterServiceCtrlHandler( TEXT(SZSERVICENAME), 
    service_ctrl);    if (!gsshStatusHandle)
            goto cleanup;    // SERVICE_STATUS members that don't change in example
        //
        gssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
        gssStatus.dwServiceSpecificExitCode = 0;    // report the status to the service control manager.
        //
        if (!ReportStatusToSCMgr( SERVICE_START_PENDING, // service state
      NO_ERROR,              // exit code
      3000))                 // wait hint
    goto cleanup;    ServiceStart( dwArgc, lpszArgv );<-----------------主程序cleanup:    // try to report the stopped status to the service control manager.
        //
    dwErr = NO_ERROR ;
        if (gsshStatusHandle)
            (VOID)ReportStatusToSCMgr( SERVICE_STOPPED,
       dwErr,
                                       0);    return;
    }
    由调试状态进入的主程序:void CmdDebugService(int argc, char ** argv)
    {
        DWORD dwArgc;
        LPTSTR *lpszArgv;#ifdef UNICODE
        lpszArgv = CommandLineToArgvW(GetCommandLineW(), &(dwArgc) );
    #else
        dwArgc   = (DWORD) argc;
        lpszArgv = argv;
    #endif    _tprintf(TEXT("Debugging %s.\n"), TEXT(SZSERVICEDISPLAYNAME));    SetConsoleCtrlHandler( ControlHandler, TRUE );    ServiceStart( dwArgc, lpszArgv );<------------------主程序
    }
      

  19.   

    可以用 gbDebug = TRUE;    CmdDebugService(argc, argv);来判断是不是调试模式,如果是,就进入调试状态,从而进入主程序:ServiceStart (DWORD dwArgc, LPTSTR *lpszArgv)
    如果是正常模式,程序就
     SERVICE_TABLE_ENTRY dispatchTable[] = {
            { TEXT(SZSERVICENAME), (LPSERVICE_MAIN_FUNCTION)uploadsrv_main },
            { NULL, NULL }
        };
        来进入uploadsrv_main()来进入主程序ServiceStart (DWORD dwArgc, LPTSTR *lpszArgv)
        
    这是主要的几步:
    1。void _CRTAPI1 main(int argc, char **argv)
    {
    // Single Process Service
        SERVICE_TABLE_ENTRY dispatchTable[] = {
            { TEXT(SZSERVICENAME), (LPSERVICE_MAIN_FUNCTION)uploadsrv_main },
            { NULL, NULL }
        };
      
    //printf("Entering main\n");
        if ( (argc > 1) && ((*argv[1] == '-') || (*argv[1] == '/')) ) {
            if ( _stricmp( "install", argv[1]+1 ) == 0 ) {
    //printf("Install service\n");
                CmdInstallService();
            }
    else if ( _stricmp( "setup",  argv[1]+1 ) == 0 ) {
    CmdSetupPara();
    }
    else if ( _stricmp( "remove", argv[1]+1 ) == 0 ) {
                CmdRemoveService();
            }
            else if ( _stricmp( "service", argv[1]+1 ) == 0 ) {
    goto dispatch;
            }
            else {
                gbDebug = TRUE;
                CmdDebugService(argc, argv);
            }
            exit(0);
        } // if it doesn't match any of the above parameters
        // the service control manager may be starting the service
        // so we must call StartServiceCtrlDispatcher
        dispatch:
            // this is just to be friendly
            _tprintf( "%s -install          install the uploadsrv service\n", SZAPPNAME );
            _tprintf( "%s -setup            setup consrv registry entries\n", SZAPPNAME );
            _tprintf( "%s -remove           remove the uploadsrv service\n", SZAPPNAME );
            _tprintf( "%s -service to run as a service\n", SZAPPNAME );
            _tprintf( "\nStartServiceCtrlDispatcher being called.\n" );
            _tprintf( "This may take several seconds.  Please wait.\n" );        if (!StartServiceCtrlDispatcher(dispatchTable)) {
    _tprintf("Service start CtrlDispatcher failed.");
    WriteLog(MSGPRI_ERR, "Service start CtrlDispatcher failed.");
    }
    }
    2.
    //  FUNCTION: uploadsrv_main
    //
    //  PURPOSE: To perform actual initialization of the service
    //
    //  PARAMETERS:
    //    dwArgc   - number of command line arguments
    //    lpszArgv - array of command line arguments
    //
    //  RETURN VALUE:
    //    none
    //
    //  COMMENTS:
    //    This routine performs the service initialization and then calls
    //    the user defined ServiceStart() routine to perform majority
    //    of the work.
    //
    void WINAPI uploadsrv_main(DWORD dwArgc, LPTSTR *lpszArgv)
    {
    DWORD dwErr;    // register our service control handler:
        //
        gsshStatusHandle = 
    RegisterServiceCtrlHandler( TEXT(SZSERVICENAME), 
    uploadsrv_ctrl);    if (!gsshStatusHandle)
            goto cleanup;    // SERVICE_STATUS members that don't change in example
        //
        gssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
        gssStatus.dwServiceSpecificExitCode = 0;    // report the status to the service control manager.
        //
        if (!ReportStatusToSCMgr( SERVICE_START_PENDING, // service state
      NO_ERROR,              // exit code
      3000))                 // wait hint
    goto cleanup;    ServiceStart( dwArgc, lpszArgv );cleanup:    // try to report the stopped status to the service control manager.
        //
    dwErr = NO_ERROR ;
        if (gsshStatusHandle)
            (VOID)ReportStatusToSCMgr( SERVICE_STOPPED,
       dwErr,
                                       0);    return;
    }3.debug模式进入点:
    void CmdDebugService(int argc, char ** argv)
    {
        DWORD dwArgc;
        LPTSTR *lpszArgv;#ifdef UNICODE
        lpszArgv = CommandLineToArgvW(GetCommandLineW(), &(dwArgc) );
    #else
        dwArgc   = (DWORD) argc;
        lpszArgv = argv;
    #endif    _tprintf(TEXT("Debugging %s.\n"), TEXT(SZSERVICEDISPLAYNAME));    SetConsoleCtrlHandler( ControlHandler, TRUE );    ServiceStart( dwArgc, lpszArgv );
    }
    主程序:
    VOID ServiceStart (DWORD dwArgc, LPTSTR *lpszArgv)
    {

    }
      

  20.   

    我支持Bingle的方法,一个DebugBreak()函数搞定,简单实用。只要可以设断点跟踪调试就行,何必那么罗嗦?
      

  21.   

    微软提供了一个关于NT服务的例子,使用这个例子里面的CNTService类,你只需要在项目的Debug版本中增加一个参数-D就可以向调试一般的MFC程序一样进行了。关于CNTService的资料,你可以在MSDN中搜索CNTService,就可以找到了。
      

  22.   

    这里是我大学毕业论文的一部分!
    其实MSDN中有说的,你看看这个中文版的吧:)第七节  调试一个服务(Debugging a Service)
      您可以用下面的方式调试您的服务。
    &#8226;使用您自己的调试工具在服务运行时调试服务。首先,获得服务进程的进程标示符(PID)。可以从PView应用程序中获得这些信息。获得PID后,附加到运行的程序上。要获得语法信息,参看您自己调试器的文档。
    &#8226;调用DebugBreak函数请求调试器进行及时调试。
    &#8226;当启动程序时,指定所用的调试器。要这样做,可以在如下的注册表位置创建一个叫做映像文件执行选项的值:
    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion
    创建一个与您的服务名称一样的子键值(例如:MYSERV.EXE)。在此子键下,添加REG_SZ类型,名称为Debugger。串值使用调试器的完整路径。在服务控制面板小程序中,选择你的服务,单击Startup并选中Allow Service to Interact with Desktop。
      注释  要调试自动启动服务的初始化代码,你得暂时以请求-启动的方式安装和运行服务。