我现在做的一个C/S程序,服务器端已经做好了,当时忘了做成服务类型的程序了,没法在电脑开机没登录的情况下自动运行,请问,如何把我已经做好的exe程序做成windows服务,我的服务器端程序有VC++,有BCB,现在程序要放在服务器上运行,所以需要做成windows服务,确保开机,用户不用登录的情况下自动启动,就像SQL Server服务端那样.

解决方案 »

  1.   

    用Win2000工具包中的小工具srvany.exe可以实现将任意可执行文件作为服务运行,去网上搜一下资料,多得很啊!
      

  2.   

    我用CreateService函数创建了一个服务器,创建成功了,开机也确实启动了,但是启动20秒左右就自动退出了,我在控制面板的服务里手动启动时提示1053错误,启动不了,不知道什么原因
      

  3.   

    你试一下用"SC"这个命令看行不行。DESCRIPTION:
            SC is a command line program used for communicating with the
            NT Service Controller and services.
    USAGE:
            sc <server> [command] [service name] <option1> <option2>...        The option <server> has the form "\\ServerName"
            Further help on commands can be obtained by typing: "sc [command]"
            Commands:
              query-----------Queries the status for a service, or
                              enumerates the status for types of services.
              queryex---------Queries the extended status for a service, or
                              enumerates the status for types of services.
              start-----------Starts a service.
              pause-----------Sends a PAUSE control request to a service.
              interrogate-----Sends an INTERROGATE control request to a service.
              continue--------Sends a CONTINUE control request to a service.
              stop------------Sends a STOP request to a service.
              config----------Changes the configuration of a service (persistant).
              description-----Changes the description of a service.
              failure---------Changes the actions taken by a service upon failure.
              qc--------------Queries the configuration information for a service.
              qdescription----Queries the description for a service.
              qfailure--------Queries the actions taken by a service upon failure.
              delete----------Deletes a service (from the registry).
              create----------Creates a service. (adds it to the registry).
              control---------Sends a control to a service.
              sdshow----------Displays a service's security descriptor.
              sdset-----------Sets a service's security descriptor.
              GetDisplayName--Gets the DisplayName for a service.
              GetKeyName------Gets the ServiceKeyName for a service.
              EnumDepend------Enumerates Service Dependencies.        The following commands don't require a service name:
            sc <server> <command> <option>
              boot------------(ok | bad) Indicates whether the last boot should
                              be saved as the last-known-good boot configuration
              Lock------------Locks the Service Database
              QueryLock-------Queries the LockStatus for the SCManager Database
    EXAMPLE:
            sc start MyService
      

  4.   

    服务程序在初始化的时候要做一系列“规定”动作,在主函数中调用StartServiceCtrlDispatcher设置一个自己的ServiceMain回调函数,然后返回。在回调函数中调用RegisterServiceCtrlHandlerEx设置一个自己的HandlerEx函数,这个函数中响应各种事件,调用SetServiceStatus让系统知道目前运行的状态。参考MSDN中这几个函数的说明,有例子代码。
      

  5.   

    创建服务,注册服务,把EXE设置好,程序退出后,服务可以重新启动程序的,最好是EXE没有什么BUG,否则做成服务比较难调试啊
      

  6.   

    如果程序没界面的话,可以写一个小的服务程序运行你的exe程序
      

  7.   

    这个答案是正确答案,本人所有的服务程序都是这么做的,那些说什么都不要改动的应该学习一下,想一想,如果你的程序什么都不改,那也就是本身不具备与scm交互的功能,哪么scm怎么与你的程序交互呢?就是怎么从服务管理器里把你的服务关掉呢?一般只要处理好以下几个函数就可以了
    StartServiceCtrlDispatcher
    RegisterServiceCtrlHandlerEx
    ServiceMain
    另外注意不是什么程序都能做成服务的,对话框程序这种租死主线程的是不行的,查查MSDN
      

  8.   

    我现在就是对话框的程序,上面那些说的,用srvany.exe我都做过,不行的
    用createservice创建服务,注册后,服务是做好了,也启动了,就是运行一会就自动退出了,20秒左右就退出了,在控制的服务器管理器里启动时出现1053错误,
    我的程序就是对话框程序,开始,没考虑到那么多,现在弄的很麻烦,我再看看5楼,10楼的方法,要是对话框真的不行的话,那就完了
      

  9.   

    因为SCM长时间没有受到你已经初始化好的消息,当然有1053错误了,这个原因是你根本没有告诉SCM,你初始化好了啊,另外即使你是对话框程序,在关闭的时候,也得告诉SCM你已经关闭了,这些接口你都需要实现的。
      

  10.   

    oc_srv.h//////////////////////////////////////////////////////////////////////////////////////////
    //
    // API: WinNT系统服务驱动
    // 作者: Nieo
    // 2002
    // 相关文件: NTService.H, NTService.LIB
    // 版本: Ver1.0
    // 注释:
    // 调用者主程序应参考相关DEMO书写自安装与反安装的外壳#pragma once
    #include <string>
    namespace OpenCam
    {
    namespace Ring
    {
    enum ServiceStartType{
    Auto =0, //自动
    Manual =1, //手动
    Disable =2, //禁止
    Unknown =3, //未知状态
    };//服务启动类型
    enum ServiceStatus{
    Running =1, //运行中
    Stopped =2, //停止
    Paused =3, //暂停
    Starting =4, //启动中
    Stopping =5, //停止中
    Continuing =6, //恢复中
    Pausing =7, //暂停中
    Disabling =8, //禁止中
    };//服务状态
    typedef struct _stServiceInfo{
    char tcServiceDisplayName[256]; //服务显示名称
    char tcServiceDesc[1000]; //服务描述
    char tcServicePath[260]; //服务执行文件路径
    char tcDependencies[200]; //依存关系,一般存放父服务标识
    ServiceStartType enStartType; //启动状态
    }SERV_INFO,* LPSERV_INFO;//服务信息#define ERROR_OK 0 //无错误
    #define ERROR_SERVICE_SCM 1 //与SCM数据库连接失败
    #define ERROR_SERVICE_HANDLE 2 //创建SCM句柄失败
    #define ERROR_SERVICE_BUFFER 3 //无足够内存完成操作
    #define ERROR_SERVICE_QUERY 4 //查询服务出错
    #define ERROR_SERVICE_IDLE 5 //不需要该操作
    #define ERROR_SERVICE_START 6 //服务启动错误
    #define ERROR_SERVICE_CONTROL 7 //服务控制错误
    #define ERROR_SERVICE_PAUSE 8 //服务暂停错误
    #define ERROR_SERVICE_STOP 9 //服务停止错误
    #define ERROR_SERVICE_CONTINUE 10 //服务恢复错误
    #define ERROR_SERVICE_SETINFO 11 //服务信息设置错误
    #define ERROR_SERVICE_LOCK 12 //SCM数据库被锁定
    #define ERROR_SERVICE_INSTALL 13 //服务安装错误
    #define ERROR_SERVICE_UNINSTALL 14 //服务卸载错误
    #define ERROR_SERVICE_CMDRANGE 15 //服务指令超出范围
    #define ERROR_SERVICE_RUN -1 //服务运行错误
    class NTService
    {
    public:
    NTService(void);
    ~NTService(void);
    public:
    //extern winapi function
    static int  ServiceStop(const char * strServiceName);
    static int  ServicePause(const char * strServiceName);
    static int  ServiceContinue(const char * strServiceName);
    static int  ServiceStart(const char * strServiceName); 
    static int  GetServiceStatus(const char * strServiceName,ServiceStatus & status);
    static int  SetServiceInfo(const char * strServiceName,SERV_INFO info);
    static int  GetServiceInfo(const char * strServiceName,LPSERV_INFO lpInfo);
    static int  SetServiceStartType(const char * strServiceName,ServiceStartType enType);
    static int  GetServiceStartType(const char * strServiceName,ServiceStartType & enType);
    static int  ServiceInstall(const char * strServiceName,SERV_INFO info);
    static int  ServiceUninstall(const char * strServiceName);
    static int  ServiceSendMessage(const char * strServiceName,int uiID);public:
    static std::string QueryExePath();
    static std::string QueryExeFullPath();
    static int Run(NTService * pService,const char * strServiceName);
    virtual bool OnStart()=0;
    virtual void OnStop()=0;
    virtual void OnPause(){;}
    virtual void OnContinue(){;}
    virtual void OnShutdown(){;}
    virtual void OnMessage(int uiID){;}
    };
    }}
      

  11.   

    ntservice.cpp#include "StdAfx.h"
    #include "oc_srv.h"#include <sstream>#include <atlstr.h>
    using namespace std;
    using namespace OpenCam::Ring;//自定义消息在128到255之间,参见MSDN Handle定义
    #define MSG_BASE 128
    #define MSG_MAX 255static string g_strServiceName;
    static SERVICE_STATUS_HANDLE g_hServiceStatusHandle = NULL;
    static NTService * g_pService = NULL;
    static HANDLE g_hStopEvent;
    static HANDLE g_hThreads[3] = {NULL,NULL,NULL};
    static int g_iSleepTime = 1000;static void WINAPI _ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv);
    static void WINAPI _CtrlHandler(DWORD nControlCode);
    static DWORD WINAPI _MainThread(LPVOID param);
    static void SetTheServiceStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode,
                        DWORD dwCheckPoint,   DWORD dwWaitHint);
    static void ErrorStopService(LPTSTR lpszAPI);static void WINAPI _ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv)
    {
    //register the control handle
    g_hServiceStatusHandle = RegisterServiceCtrlHandler(g_strServiceName.c_str(),(LPHANDLER_FUNCTION)_CtrlHandler);
    if(g_hServiceStatusHandle==(SERVICE_STATUS_HANDLE)0)return;
    //interface event call: OnStart
    //ASSERT(g_pService);
    if(!g_pService->OnStart())
    ErrorStopService(TEXT("MainThread")); //create the thread stop event
    g_hStopEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
    if(g_hStopEvent==NULL)ErrorStopService(TEXT("CreateEvent")); //create the main control thread
        DWORD ThreadId;
        DWORD t;
    for(t=0;t<3;t++){
    g_hThreads[t] = ::CreateThread(NULL,0,_MainThread,(LPVOID)t,0,&ThreadId);
    if(g_hThreads[t] == INVALID_HANDLE_VALUE)ErrorStopService(TEXT("CreateThread"));
        } //set the server status to running
    SetTheServiceStatus(SERVICE_RUNNING,NO_ERROR,0,0); //writelog //waiting for server stop,this is the main service loop
    while(WaitForSingleObject(g_hStopEvent, 1000) != WAIT_OBJECT_0){
    } // close the event handle and the thread handle
        for (t=1;TRUE;t++){
    DWORD dwWaitRes;
            if ((dwWaitRes = WaitForMultipleObjects(3,g_hThreads,TRUE,1000))== WAIT_OBJECT_0)
    break;
            else if((dwWaitRes == WAIT_FAILED)||(dwWaitRes==WAIT_ABANDONED))
    ErrorStopService(TEXT("WaitForMultipleObjects"));
            else
                SetTheServiceStatus(SERVICE_STOP_PENDING, 0, t, 3000);
        }
    if(!CloseHandle(g_hStopEvent))ErrorStopService(TEXT("CloseHandle"));
    if (!CloseHandle(g_hThreads[0]))ErrorStopService(TEXT("CloseHandle"));
        if (!CloseHandle(g_hThreads[1]))ErrorStopService(TEXT("CloseHandle"));
        if (!CloseHandle(g_hThreads[2]))ErrorStopService(TEXT("CloseHandle"));
    SetTheServiceStatus(SERVICE_STOPPED, NO_ERROR, 0, 0);}
    static void WINAPI _CtrlHandler(DWORD nControlCode)
    {
    //ASSERT(g_pService);
    DWORD dwState = SERVICE_RUNNING;
    switch(nControlCode){
    case SERVICE_CONTROL_CONTINUE:
    g_pService->OnContinue();
    break;
    case SERVICE_CONTROL_PAUSE:
    g_pService->OnPause();
    break;
    case SERVICE_CONTROL_SHUTDOWN:
    dwState = SERVICE_STOP_PENDING;
    g_pService->OnShutdown();
    break;
    case SERVICE_CONTROL_STOP:
    dwState = SERVICE_STOP_PENDING;
    g_pService->OnStop();
    break;
    case SERVICE_CONTROL_INTERROGATE:
    break;
    default:break;
    }
    SetTheServiceStatus(dwState,NO_ERROR,0,0);
    //add by nieo 2003-4-9 for user-defined message map
    if(nControlCode>=MSG_BASE)
    {
    g_pService->OnMessage(nControlCode-MSG_BASE);
    }
    if ((nControlCode == SERVICE_CONTROL_STOP) ||(nControlCode == SERVICE_CONTROL_SHUTDOWN)){
          if (!SetEvent(g_hStopEvent))
              ErrorStopService(TEXT("SetEvent"));
          else
              OutputDebugString(TEXT("Signal service_main thread\n"));
    }
    }
    static DWORD WINAPI _MainThread(LPVOID param)
    {
    INT nThreadNum = (INT)param;
    TCHAR szOutput[25];
    while(WaitForSingleObject(g_hStopEvent, 1000) != WAIT_OBJECT_0){
    Sleep(g_iSleepTime);
    wsprintf(szOutput,TEXT("\nThread %d says Beep\n"),nThreadNum);
    OutputDebugString(szOutput);
    }
    return 0;
    }
      

  12.   


    static void SetTheServiceStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode,
                            DWORD dwCheckPoint,   DWORD dwWaitHint)
    {
    SERVICE_STATUS ss;  // Current status of the service.      
    // 
    // Disable control requests until the service is started.
    // 
    if (dwCurrentState == SERVICE_START_PENDING)
        ss.dwControlsAccepted = 0;
    else
        ss.dwControlsAccepted =SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_SHUTDOWN;
            // Other flags include SERVICE_ACCEPT_PAUSE_CONTINUE
            // and SERVICE_ACCEPT_SHUTDOWN.      
    // Initialize ss structure.
    ss.dwServiceType             = SERVICE_WIN32_OWN_PROCESS;
    ss.dwServiceSpecificExitCode = 0;
    ss.dwCurrentState            = dwCurrentState;
    ss.dwWin32ExitCode           = dwWin32ExitCode;
    ss.dwCheckPoint              = dwCheckPoint;
    ss.dwWaitHint                = dwWaitHint;      
    // Send status of the service to the Service Controller.
    if (!SetServiceStatus(g_hServiceStatusHandle, &ss)){
        ErrorStopService(TEXT("SetServiceStatus"));
    }
    }
    static void ErrorStopService(LPTSTR lpszAPI)
       {
          INT t;
          TCHAR   buffer[256]  = TEXT("");
          TCHAR   error[1024]  = TEXT("");
          LPVOID lpvMessageBuffer;
          DWORD  dwWaitRes;      
      wsprintf(buffer,TEXT("API = %s, "), lpszAPI);
          lstrcat(error, buffer);
      ZeroMemory(buffer, sizeof(buffer));
          wsprintf(buffer,TEXT("error code = %d, "), GetLastError());
          lstrcat(error, buffer);      // Obtain the error string.
          FormatMessage(
                    FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
                    NULL, GetLastError(),
                    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                    (LPTSTR)&lpvMessageBuffer, 0, NULL);      
      ZeroMemory((LPVOID)buffer, (DWORD)sizeof(buffer));
          wsprintf(buffer,TEXT("message = %s"), (TCHAR *)lpvMessageBuffer);
          lstrcat(error, buffer);      // Free the buffer allocated by the system.
          LocalFree(lpvMessageBuffer);      // Write the error string to the debugger.
          OutputDebugString(error);      // If you have threads running, tell them to stop. Something went
          // wrong, and you need to stop them so you can inform the SCM.
          SetEvent(g_hStopEvent);      // Wait for the threads to stop.
          for (t=1;TRUE;t++)
          {
             if ((dwWaitRes = WaitForMultipleObjects(3,g_hThreads,TRUE,1000))
                                                              == WAIT_OBJECT_0)
                break;
             else if ((dwWaitRes== WAIT_FAILED)||(dwWaitRes== WAIT_ABANDONED))
                break; // Our wait failed
             else
             {
                SetTheServiceStatus(SERVICE_STOP_PENDING, 0, t, 3000);
             }
          }      // Stop the service.
          SetTheServiceStatus(SERVICE_STOPPED, GetLastError(), 0, 0);   
    }int NTService::Run(NTService * pService,const char * strServiceName){
    g_strServiceName = strServiceName;
    g_pService = pService;
    if(g_strServiceName.empty())return ERROR_SERVICE_RUN;
    SERVICE_TABLE_ENTRY serviceTable[2];
    serviceTable[0].lpServiceName= (LPSTR)g_strServiceName.c_str();
    serviceTable[0].lpServiceProc = _ServiceMain;
    serviceTable[1].lpServiceName=NULL;
    serviceTable[1].lpServiceProc=NULL;
    if(!StartServiceCtrlDispatcher(serviceTable))
    {
    return ERROR_SERVICE_RUN;
    }
    return NO_ERROR;
    }static int QueryServiceStatus(const char * strServiceName,LPSERVICE_STATUS lpStatus){
    SC_HANDLE scm = NULL;
    SC_HANDLE hService = NULL;
    int iReturn = NO_ERROR;
    try{
    scm=OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);
    if(!scm)throw(ERROR_SERVICE_SCM);
    hService=OpenService(scm,strServiceName,SERVICE_ALL_ACCESS);
    if(!hService)throw(ERROR_SERVICE_HANDLE);
    if(!QueryServiceStatus(hService,lpStatus))throw(ERROR_SERVICE_QUERY);
    }
    catch(int iCode){
    iReturn = iCode;
    }
    if(hService)CloseServiceHandle(hService);
    if(scm)CloseServiceHandle(scm);
    return iReturn;
    }
    static int ControlService(const char * strServiceName,DWORD dwControl){
    int iReturn = NO_ERROR;
    SC_HANDLE scm = NULL;
    SC_HANDLE hService = NULL;
    try{
    scm=OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);
    if(!scm)throw(ERROR_SERVICE_SCM);
        DWORD fdwAccess = SERVICE_ALL_ACCESS;
    DWORD dwProgType = -1;
        switch (dwControl){
            case SERVICE_CONTROL_STOP: 
                fdwAccess = SERVICE_STOP; 
    dwProgType = SERVICE_STOP_PENDING;
                break;  
            case SERVICE_CONTROL_PAUSE: 
                fdwAccess = SERVICE_PAUSE_CONTINUE; 
    dwProgType = SERVICE_PAUSE_PENDING;
    break;
            case SERVICE_CONTROL_CONTINUE: 
                fdwAccess = SERVICE_PAUSE_CONTINUE; 
    dwProgType = SERVICE_CONTINUE_PENDING;
                break;  
            case SERVICE_CONTROL_INTERROGATE: 
                fdwAccess = SERVICE_INTERROGATE; 
                break;  
            default:;
                fdwAccess = SERVICE_INTERROGATE;
    }
    hService=OpenService(scm,strServiceName,SERVICE_ALL_ACCESS);
    if(!hService)throw(ERROR_SERVICE_HANDLE);
    SERVICE_STATUS status; 
        if(!ControlService(hService,dwControl,&status))throw(ERROR_SERVICE_CONTROL);
    if(dwProgType!=-1){
    SERVICE_STATUS status;
    if(!QueryServiceStatus(hService,&status))throw(ERROR_SERVICE_QUERY);
    DWORD dwStartTickCount = GetTickCount();
    DWORD dwOldCheckPoint = status.dwCheckPoint;
    while(status.dwCurrentState==dwProgType){
    DWORD dwWaitTime = status.dwWaitHint / 10;
        if( dwWaitTime < 1000 )dwWaitTime = 1000;
    else if ( dwWaitTime > 10000 )dwWaitTime = 10000;
    Sleep( dwWaitTime );
    if(!QueryServiceStatus(hService,&status))throw(ERROR_SERVICE_QUERY);
    if(status.dwCheckPoint > dwOldCheckPoint)
    {
    // The service is making progress.
    dwStartTickCount = GetTickCount();
    dwOldCheckPoint = status.dwCheckPoint;
    }
    else
    {
    if(GetTickCount()-dwStartTickCount > status.dwWaitHint)break;
    }
    }//end while
    //if(status.dwCurrentState != fdwAccess)throw(ERROR_SERVICE_CONTROL);
    }
    }
    catch(int iCode){
    iReturn = iCode;
    }
    if(hService)CloseServiceHandle(hService);
    if(scm)CloseServiceHandle(scm);
    return iReturn;
      

  13.   

    谢谢IamNideo,辛苦了,我研究研究