如何把已经做好的exe程序做成Windows服务程序

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

24 个解决方案

#1


不会, 来学习的...

#2


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

#3


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

#4


你试一下用"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

#5


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

#6


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


正解,不用改程序

#7


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

#8


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

#9


如果单纯就是为了在用户登录以前运行,注册表里边就能搞定,去查下资料...

#10


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

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

#11


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

#12


学习一下

#13


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

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

#14


帮顶

#15


自己写个最基本的服务启动程序,然后在那程序中再启动你的那个"要以服务启动的程序就是".

如果你自己有代码,自己加上代码进那个程序中去就是.

#16


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){;}
};
}}

#17


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 255

static 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;
}

#18



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;
}



 

#19


顶,学习中

#20


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

#21


没搞定,最后做了一个另外的服务程序来启动我的程序

#22


我也遇到了这个问题,需求答案中

#23


呵呵。拷过去

#24


计划任务,简单,并快!可以试试

#1


不会, 来学习的...

#2


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

#3


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

#4


你试一下用"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

#5


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

#6


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


正解,不用改程序

#7


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

#8


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

#9


如果单纯就是为了在用户登录以前运行,注册表里边就能搞定,去查下资料...

#10


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

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

#11


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

#12


学习一下

#13


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

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

#14


帮顶

#15


自己写个最基本的服务启动程序,然后在那程序中再启动你的那个"要以服务启动的程序就是".

如果你自己有代码,自己加上代码进那个程序中去就是.

#16


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){;}
};
}}

#17


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 255

static 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;
}

#18



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;
}



 

#19


顶,学习中

#20


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

#21


没搞定,最后做了一个另外的服务程序来启动我的程序

#22


我也遇到了这个问题,需求答案中

#23


呵呵。拷过去

#24


计划任务,简单,并快!可以试试