用汇编写系统服务程序

安卓电话补充业务 SS 1. 一些概念知识 补充业务(Supplementary service)简称SS,包括呼叫等待、呼叫转移、呼叫限制、三方通话、USSD等,补充业务可以在VoLTE网络中使用,也可以在3G网络中使用。 XCAP协议(XML Configuration Access Protocol,XML配置访问协议):是一种应用层协议,它允许一个客户端来读,写,修改和删除应用程序配置数据存储在服务器上的XML格式。XCAP映射XML文件子树和元素属性到HTTP URIs,使这些组件可以直接使用HTTP协议的客户端访问 阅读详情

用汇编写系统服务程序
本想写一篇关于服务的文章,结果搜了一遍以后,发现发表于天极网上的一篇文章《Win32程序设计之服务》把要说的大部分东西都说了,为了不做重复劳动,所以在这里首先引用这篇文章来说明服务程序的原理,在后面的补充一节中再补上一些内容和一个用汇编实现服务的源代码。

======================================================================
第一部分:转载《Win32程序设计之服务》

原始位置:http://www.chinabyte.com/20010528/181751.shtml
======================================================================

每个操作系统都需要有在后台执行任务的方法,无论是谁正在使用这部机器,这些任务都可以继续运行,后台任务可以处理各种重要的服务,包括系统的或者用户的。例如,一个信使服务可以监控网络,并且在接收到另一台机子的信息时,可以显示一个对话框。一个发送和接收传真的应用需要在启动的时候运行,并且不断地监控负责传真的modem,看有没有传真进来。一个家庭的或者办公室的安全程序,用来控制一件检测设备时,它需要不时地查询传感器,并且在适当的时候响应它。所有这些任务都需要CPU时间来执行它们,不过由于它们需要的CPU时间很少,因此可以放在后台而不影响用户使用系统。

  在MS-DOS中,后台的任务是通过TSR(Terminate and Stay Resident)程序来处理的。这些程序经由autoexec.bat文件开始。在UNIX中,后台任务是通过Daemons来处理的。在每次启动UNIX的过程中,你都可以看到操作系统启动一些任务,例如定时的程序(Cron)和Finger的daemons,然后才可以让首个用户登录。在Windows NT中,后台的任务被称为服务。服务可在每次NT启动的时候运行,并且不管是谁登陆,都会一直运行下去。

  Windows NT的服务都是通过一般的可执行程序实现的,不同的是,它遵循内部的一个特定协议来设计,以便它们能够与服务控制管理器(SCM,Service Control Manager)进行正确的交互。在这篇文章中,你将学习到如何在Windows NT中创建和安装简单的Win32服务。一旦你懂得了这个简单的服务,你要建立自己的服务也不难了,因为所有的服务,不论是如何地复杂,都必须包含有同样基本的SCM接口代码。只要符合SCM的要求,其实为服务设计的可执行文件和一般的程序并没有多少的区别。

  无论是对于编程者或者系统管理员,了解NT的服务如何工作都是很重要的。编程者就不必说了,因为他们要创建自己的服务,而对于系统管理员,也是同样重要的。因为后台的任务可以是很危险的。MS-DOS和Macintosh系统都是一个病毒的温床,因为它们在安全性方面先天不足,它们都可以允许任何人或者程序在任何时间创建后台的任务。Windows NT和UNIX系统是较安全的,因为只有系统管理员才可以为系统增加后台的任务,不过,如果系统管理员加入了一个破坏性的后台程序,就它就可以为所欲为了。因此系统管理员要了解Windows NT服务的技巧和权限设置,就可以避免加入有潜在危险的后台任务。

基本的概念

  服务有两种不同的形式。驱动器服务使用驱动器协议,让NT可以与特定的硬件进行通信。另一个是Win32服务,通过一般的Win32 API来实现后台任务。这篇文章的重点是谈Win32服务,因为它们更为常见,而且创建起来也很容易。任何的NT编程者通过使用一般的NT SDK(或者Visual C++),并且可以用管理员的身份访问一台NT机器,都可以实现和安装自己的Win32服务。如果你想创建一些在Windows NT启动时就运行的程序,并且要求它会在系统中一直运行,你就要使用Win32的服务。

  在NT中,服务通过控制面板进行管理。在控制面板中,你会发现有一个服务的图标,打开它你会看到所有Win32服务的清单。在那里你可以开始、停止、暂停和继续某个服务。你按下其中的启动按钮后,就会出现一个对话框,你可以修改启动操作以及服务使用的默认帐号。一个服务可以在系统启动的时候自动运行,也可以被完全禁止。或者设置为手动执行。在手动的时候,用户还可以设置启动的参数。要对服务中的项目作修改的话,你需要以一个管理员或者超级用户的身份登录。

  Windows NT自带有一些预装的任务,用来处理诸如网络信使服务的操作或者使用“at”命令定时执行的操作,以及分布的RPC命名。在你创建自己的服务时,你必须执行一个独立的安装步骤,以将服务的信息插入到服务管理工具的列表中,这些信息包括有新服务的名字、执行文件的名字和启动的类型等,都会写入到注册表中,这样在机器下次启动的时候,SCM就会得到新服务的相关信息。

创建一个新的服务

  执行服务的程序也是一个EXE文件,不过它必须符合某些特定的规范,以便可以与SCM进行正确的交互。微软很细致地设计了函数调用的流程,你必须遵循这些流程,否则你的服务就不能工作。具体的规定如下所列。你可以在Win32编程者的参考指南中找到以下涉及的函数,这些资料在SDK的Win32在线帮助或者Visual C++都有:

   .服务的代码必须要有一个一般的main或者WinMain函数。这个函数应该会马上调用StartServiceCrtlDispatcher函数。通过调用这个函数,你可以让SCM得到ServiceMain函数的指针,这样在SCM要启动该服务时,就可以调用它

   .在SCM要启动服务的时候,就会调用ServiceMain函数。例如,如果管理员在服务管理器中按下启动的按钮,SCM就会在一个独立的线程中执行ServiceMain函数。ServiceMain应该调用RegisterServiceCtrlHandler函数,这样可以注册一个Handler函数,以便SCM对服务进行控制。Handler函数的名字可以是任意的,不过它会在Handler下的文档中列出来。RegisterServiceCtrlHandler函数会返回一个句柄,在服务需要发送状态信息给SCM时,可以通过该句柄进行。

   .ServiceMain函数也必须启动做该服务实际工作的线程。在服务停止前,ServiceMain函数是不应该有返回的。当它返回的时候,服务已经停止了。

   .Handler函数包含了一个switch语句,用来分析由SCM传送过来的请求。默认的情况,SCM可以发送以下任何的的控制常数:

     SERVICE_CONTROL_STOP - 要服务停止
     SERVICE_CONTROL_PAUSE - 要服务暂停
     SERVICE_CONTROL_CONTINUE - 要服务继续
     SERVICE_CONTROL_INTERROGATE - 要服务马上报告它的状态
     SERVICE_CONTROL_SHUTDOWN - 告诉服务即将关机

  也可以创建自定义的常数(值在128到255之间),并且通过SCM发送给服务。

  如果你创建的EXE包括有以上提到的main、ServiceMain和Handler函数,以及执行服务自身任务的线程函数,那么你的服务程序设计就完成了。以下的图总结了这些不同的函数和SCM之间的交互:

  在本文的最后还有几段程序的列表,其中列表一为我们展示了一个可能是最简单的服务。该服务只发出"嘟"的响声。默认的状态下,它每两秒响一次。你可以通过启动的参数来修改发声的间隔。这个服务挺完整,它可以正确响应SCM传来的每个控制信号。因此,这个程序可作为你创建自己服务的一个很好的模板。

  main函数通过调用StartServiceCtrlDispatcher来注册ServiceMain函数。注册的操作使用了一个SERVICE_TABLE_ENTRY结构的数组。在这个例子中,该程序只包含了一个服务,因此在表中只会有一个项目。不过,对于一个EXE文件,可以创建几个任务,这样在表中就会有几项,以识别不同的ServiceMain函数。在调用StartServiceCtrlDispatcher之前,可在main函数中放入初始化的代码,不过这些代码必须在少于30秒内完成,否则,SCM会认为某些地方出错而终止服务。

  在自动或者手动启动服务时,将会调用ServiceMain函数。ServiceMain函数将包含有以下的步骤:

  1.它马上调用RegisterServiceCtrlHandler来注册Handler函数,作为SCM控制该服务的Handler函数

  2.然后它将调用SendStatusToSCM函数,将当前的进程通报给SCM。第四个参数是一个“click count”值,在程序每次更新状态时,它的值就会增加。SCM和其它的程序可以根据click count的值来知道初始化期间进行的处理。最后的参数是"wait hint",是用来告诉SCM在click count下次更新前,它需要等待的时间(以毫秒计算)。

  3.ServiceMain接着会创建一个事情,该事件在函数的底部使用,可让它一直运行,直到SCM发出一个STOP的请求。

  4.接着,ServiceMain检查启动的参数。参数可在用户手动启动服务时,通过服务管理工具中的启动参数传送过来。这些参数以一个argv形式的数组进入ServiceMain函数。

  5.如果你的服务需要处理其它初始化的任务,它们应该放在这一步,在调用InitService之前。

  6.ServiceMain函数接着调用InitService函数,这将启动线程并做服务的真正工作。如果该调用成功,SverviceMain将会通知SCM服务已经成功启动。

  7.ServiceMain将调用WaitForSingleObject,用来等待terminateEvent事件对象被设置。这个对象通过Handler函数设置,一旦它被设置,ServiceMain将调用终止的函数来做清除的工作,然后就返回并停止服务。

  你从上面可以看到,在这个函数中并没有多少灵活的地方。除了第5步外,你必须按步执行以上提到的任务,否则服务将不可以正确启动。

  终止函数清除所有打开的句柄,并且发送一个状态的信息给SCM,告诉它服务现已停止。

  在SCM要暂停、继续、询问或者停止服务时,它就会调用Handler函数。要停止服务,Handler设置terminateEvent,这样做会导致ServiceMain(它会以一个独立线程的形式执行)终止并且返回。一旦ServiceMain返回,服务就停止了。

  SendStatusToSCM 函数负责发送服务的当前状态给SCM。

  在需要启动服务线程时,ServiceMain就会调用InitService函数。该函数调用CreateThread来为服务创建一个新的线程。

  ServiceThread函数包含有该服务真正要做的工作。在这个例子中,该线程包含有一个无限的循环,以一个预定义的时间间隔发出响声。在你创建自己的服务时,你可以在该线程中放入任何的代码,调用Win32函数或者你自己的函数。

安装和移除服务

  为了使用上面提到的发响声服务,你必须安装它。安装可让SCM知道这个服务,并且让SCM将它加入到控制面板中的服务列表中。表单二的代码展示了如何安装一个服务。

  表单2先通过OpenSCManager函数打开一个到SCM的连接。在OpenSCManager的调用中,你必须指定你要做的东西,以便SCM可以验证这个行为。如果你登录的帐号没有足够的权限,该调用将返回NULL。

  CreateService的调用是真正用来装入新服务的。它使用OpenSCManager返回至SCM的指针、名字、标签和命令行中的EXE文件,还有一些标准的参数值。使用SERVICE_WIN32_OWN_PROCESS表明该服务的EXE文件只包含有一个服务,而SERVICE_DEMAND_START则表明该服务是手动而不是自动启动的。使用命令行安装程序的一个典型格式如下:

   install BeepService "Beeper" c:/winnt/beep.exe

  第一个参数是SCM内部使用的服务名字。这个名字也用在以后移除服务。第二个参数是一个标识符,即服务管理中显示的名字。第三个参数指出该服务的执行文件的路径。在你安装服务后,可在控制面板的服务管理中启动它。如果有错,可在Win32 API的在线文档中查出错误代码的含义。

  要移除服务,你要按列表3的步骤进行。它首先打开一个到SCM的连接,然后使用OpenService函数打开一个与服务的连接。列表3中接着查询服务来看它是否现已停止了。如果不是的话,就会停止它。DeleteService 用来从控制面板中移除服务,移除操作的典型格式如下:

  remove BeepService

  需要的话,你也可以在马上重新安装服务。

结论

  服务对于Windows NT是很重要的一部分,因为它可让你对操作系统进行扩展。使用列表1的代码作为一个模板,你将会发现要建立一个自己的新服务是非常简单的。

  列表1

  实现可能是最简单NT服务的代码


//***************************************************************
// From the book "Win32 System Services: The Heart of Windows NT"
// by Marshall Brain
// Published by Prentice Hall
file://
// This code implements the simplest possible service.
// It beeps every 2 seconds, or at a user specified interval.
file://***************************************************************

// beepserv.cpp

#include
#include
#include
#include

#define DEFAULT_BEEP_DELAY 2000

// Global variables

// The name of the service
char *SERVICE_NAME = "BeepService";
// Event used to hold ServiceMain from completing
HANDLE terminateEvent = NULL;
// Handle used to communicate status info with
// the SCM. Created by RegisterServiceCtrlHandler
SERVICE_STATUS_HANDLE serviceStatusHandle;
// The beep interval in ms.
int beepDelay = DEFAULT_BEEP_DELAY;
// Flags holding current state of service
BOOL pauseService = FALSE;
BOOL runningService = FALSE;
// Thread for the actual work
HANDLE threadHandle = 0;

void ErrorHandler(char *s, DWORD err)
{
cout s endl;
cout "Error number: " err endl;
ExitProcess(err);
}

// This function consolidates the activities of
// updating the service status with
// SetServiceStatus
BOOL SendStatusToSCM (DWORD dwCurrentState,
DWORD dwWin32ExitCode,
DWORD dwServiceSpecificExitCode,
DWORD dwCheckPoint,
DWORD dwWaitHint)
{
BOOL success;
SERVICE_STATUS serviceStatus;

// Fill in all of the SERVICE_STATUS fields
serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
serviceStatus.dwCurrentState = dwCurrentState;

// If in the process of doing something, then accept
// no control events, else accept anything
if (dwCurrentState == SERVICE_START_PENDING)
serviceStatus.dwControlsAccepted = 0;
else
serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_PAUSE_CONTINUE |
SERVICE_ACCEPT_SHUTDOWN;

// if a specific exit code is defined, set up
// the win32 exit code properly
if (dwServiceSpecificExitCode == 0)
serviceStatus.dwWin32ExitCode = dwWin32ExitCode;
else
serviceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
serviceStatus.dwServiceSpecificExitCode =dwServiceSpecificExitCode;
serviceStatus.dwCheckPoint = dwCheckPoint;
serviceStatus.dwWaitHint = dwWaitHint;

// Pass the status record to the SCM
success = SetServiceStatus (serviceStatusHandle, &serviceStatus);
return success;
}

DWORD ServiceThread(LPDWORD param)
{
while (1)
{
Beep(200,200);
Sleep(beepDelay);
}
return 0;
}

// Initializes the service by starting its thread
BOOL InitService()
{
DWORD id;

// Start the service's thread
threadHandle = CreateThread(0, 0,(LPTHREAD_START_ROUTINE) ServiceThread,0, 0, &id);

if (threadHandle==0)
return FALSE;
else
{
runningService = TRUE;
return TRUE;
}
}

// Dispatches events received from the SCM
VOID Handler (DWORD controlCode)
{
DWORD currentState = 0;
BOOL success;

switch(controlCode)
{
// There is no START option because
// ServiceMain gets called on a start

// Stop the service
case SERVICE_CONTROL_STOP:
// Tell the SCM what's happening
success = SendStatusToSCM(SERVICE_STOP_PENDING,NO_ERROR, 0, 1, 5000);
runningService=FALSE;
// Set the event that is holding ServiceMain
// so that ServiceMain can return
SetEvent(terminateEvent);
return;
// Pause the service
case SERVICE_CONTROL_PAUSE:
if (runningService && !pauseService)
{
// Tell the SCM what's happening
success = SendStatusToSCM(SERVICE_PAUSE_PENDING,
NO_ERROR, 0, 1, 1000);
pauseService = TRUE;
SuspendThread(threadHandle);
currentState = SERVICE_PAUSED;
}
break;
// Resume from a pause
case SERVICE_CONTROL_CONTINUE:
if (runningService && pauseService)
{
// Tell the SCM what's happening
success = SendStatusToSCM(SERVICE_CONTINUE_PENDING,
NO_ERROR, 0, 1, 1000);
pauseService=FALSE;
ResumeThread(threadHandle);
currentState = SERVICE_RUNNING;
}
break;
// Update current status
case SERVICE_CONTROL_INTERROGATE:
// it will fall to bottom and send status
break;
// Do nothing in a shutdown. Could do cleanup
// here but it must be very quick.
case SERVICE_CONTROL_SHUTDOWN:
return;
default:
break;
}
SendStatusToSCM(currentState, NO_ERROR, 0, 0, 0);
}

// Handle an error from ServiceMain by cleaning up
// and telling SCM that the service didn't start.
VOID terminate(DWORD error)
{
// if terminateEvent has been created, close it.
if (terminateEvent) CloseHandle(terminateEvent);

// Send a message to the scm to tell about stopage
if (serviceStatusHandle)
SendStatusToSCM(SERVICE_STOPPED, error,0, 0, 0);

// If the thread has started, kill it off
if (threadHandle) CloseHandle(threadHandle);

// Do not need to close serviceStatusHandle
}

// ServiceMain is called when the SCM wants to
// start the service. When it returns, the service
// has stopped. It therefore waits on an event
// just before the end of the function, and
// that event gets set when it is time to stop.
// It also returns on any error because the
// service cannot start if there is an eror.
VOID ServiceMain(DWORD argc, LPTSTR *argv)
{
BOOL success;

// immediately call Registration function
serviceStatusHandle =
RegisterServiceCtrlHandler(
SERVICE_NAME, (LPHANDLER_FUNCTION)Handler);
if (!serviceStatusHandle) {terminate(GetLastError()); return;}

// Notify SCM of progress
success = SendStatusToSCM(SERVICE_START_PENDING,
NO_ERROR, 0, 1, 5000);
if (!success) {terminate(GetLastError()); return;}

// create the termination event
terminateEvent = CreateEvent (0, TRUE, FALSE, 0);
if (!terminateEvent) {terminate(GetLastError()); return;}

// Notify SCM of progress
success = SendStatusToSCM(SERVICE_START_PENDING,
NO_ERROR, 0, 2, 1000);
if (!success) {terminate(GetLastError()); return;}

// Check for startup params
if (argc == 2)
{
int temp = atoi(argv[1]);
if (temp 1000)
beepDelay = DEFAULT_BEEP_DELAY;
else
beepDelay = temp;
}

// Notify SCM of progress
success = SendStatusToSCM(SERVICE_START_PENDING,
NO_ERROR, 0, 3, 5000);
if (!success) {terminate(GetLastError()); return;}

// Start the service itself
success = InitService();
if (!success) {terminate(GetLastError()); return;}

// The service is now running.
// Notify SCM of progress
success = SendStatusToSCM(SERVICE_RUNNING,
NO_ERROR, 0, 0, 0);
if (!success) {terminate(GetLastError()); return;}

// Wait for stop signal, and then terminate
WaitForSingleObject (terminateEvent, INFINITE);

terminate(0);
}

VOID main(VOID)
{
SERVICE_TABLE_ENTRY serviceTable[] =
{
{ SERVICE_NAME,
(LPSERVICE_MAIN_FUNCTION) ServiceMain},
{ NULL, NULL }
};
BOOL success;

// Register with the SCM
success =
StartServiceCtrlDispatcher(serviceTable);
if (!success)
ErrorHandler("In StartServiceCtrlDispatcher",
GetLastError());
}

列表2
安装NT服务的代码


file://***************************************************************
// From the book "Win32 System Services: The Heart of Windows NT"
// by Marshall Brain
// Published by Prentice Hall
file://
// This code installs a service.
file://***************************************************************

// install.cpp

#include
#include

void ErrorHandler(char *s, DWORD err)
{
cout s endl;
cout "Error number: " err endl;
ExitProcess(err);
}

void main(int argc, char *argv[])
{
SC_HANDLE newService, scm;

if (argc != 4)
{
cout "Usage:/n";
cout " install service_name /
service_label executable/n";
cout " service_name is the /
name used internally by the SCM/n";
cout " service_label is the /
name that appears in the Services applet/n";
cout " (for multiple /
words, put them in double quotes)/n";
cout " executable is the /
full path to the EXE/n/n";
return;
}

// open a connection to the SCM
scm = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
if (!scm) ErrorHandler("In OpenScManager",
GetLastError());

// Install the new service
newService = CreateService(
scm, argv[1], // eg "beep_srv"
argv[2], // eg "Beep Service"
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
argv[3], // eg "c:/winnt/xxx.exe"
0, 0, 0, 0, 0);
if (!newService) ErrorHandler("In CreateService",
GetLastError());
else cout "Service installed/n";

// clean up
CloseServiceHandle(newService);
CloseServiceHandle(scm);
}

列表3
移除NT服务的代码
file://***************************************************************
// From the book "Win32 System Services: The Heart of Windows NT"
// by Marshall Brain
// Published by Prentice Hall
file://
// This code removes a service from the Services applet in the
// Control Panel.
file://***************************************************************

// remove.cpp

#include
#include

void ErrorHandler(char *s, DWORD err)
{
cout s endl;
cout "Error number: " err endl;
ExitProcess(err);
}

void main(int argc, char *argv[])
{
SC_HANDLE service, scm;
BOOL success;
SERVICE_STATUS status;

if (argc != 2)
{
cout "Usage:/n remove service_name/n";
return;
}

// Open a connection to the SCM
scm = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
if (!scm) ErrorHandler("In OpenScManager",
GetLastError());

// Get the service's handle
service = OpenService(scm, argv[1],
SERVICE_ALL_ACCESS | DELETE);
if (!service) ErrorHandler("In OpenService",
GetLastError());

// Stop the service if necessary
success = QueryServiceStatus(service, &status);
if (!success) ErrorHandler("In QueryServiceStatus",
GetLastError());
if (status.dwCurrentState != SERVICE_STOPPED)
{
cout "Stopping service.../n";
success = ControlService(service,
SERVICE_CONTROL_STOP, &status);
if (!success) ErrorHandler("In ControlService",
GetLastError());
}

// Remove the service
success = DeleteService(service);
if (success) cout "Service removed/n";
else ErrorHandler("In DeleteService",
GetLastError());

// Clean up
CloseServiceHandle(service);
CloseServiceHandle(scm);
}


======================================================================
第二部分:用Win32汇编实现系统服务
by:罗云彬

好了,经过了上面这篇文章,大家对服务应该有个初步的了解了,但是要注意分辨文章中提及的 API 名称和程序自己的模块名称,比如CreateService是一个 API,而 ServiceMain 是程序中一个子程序的名称,千万不要把子程序名当系统的 API 去使用了 :)
在这部分的补充中,我再归纳一下实现各种功能所使用的 API 函数名和使用的步骤,并提供一个汇编源程序例子来供大家参考,大家也可以下载整个源代码包并修改使用。
一般来说,整个服务程序系统由两个单独的程序组成:服务程序和服务控制程序,经过了上面的介绍,大家一定明白这两个程序应该由哪些部分组成了:

服务程序的结构

服务程序是被用来实现服务功能的部分,它由相对独立的3个部分组成:

1. 程序入口 -> 调用StartServiceCtrlDispatcher(注册服务主程序)
2. 服务主程序(被SCM调用)-> 调用RegisterServiceCtrlHandler(注册控制handler)-> 调用 SetServiceStatus 设置服务的正确状态 -> 执行服务的功能代码 -> 需要结束服务的时候则返回。
3. 控制Handler -> 设置内部标志以控制第2部分服务主程序中的代码走向,并调用 SetServiceStatus 更新服务的状态。

可见,服务程序必须用到的 API 只有 StartServiceCtrlDispatcher、RegisterServiceCtrlHandler和SetServiceStatus ,其余的大部分代码是执行本身的功能模块。这里有一个服务程序的简单例子,实现的是每秒种让喇叭发声一次的功能。

下面的源代码是 Service.asm 程序:

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Windows NT 服务程序模板
; by 罗云彬, http://asm.yeah.net
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 服务端程序 Ver 1.0
;
; 2002.06.20 ----- 第1版
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.386
.model flat, stdcall
option casemap :none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
include AdvApi32.inc
includelib AdvApi32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data?

stSS SERVICE_STATUS > ;服务的状态
hSS dd ? ;服务的状态句柄
dwOption dd ?
F_STOP equ 0001h ;停止服务

include
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 服务控制程序
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcHandler proc _dwControl

pushad
mov eax,_dwControl
.if eax == SERVICE_CONTROL_STOP
or dwOption,F_STOP
mov stSS.dwCurrentState,SERVICE_STOPPED
invoke SetServiceStatus,hSS,addr stSS
.elseif eax == SERVICE_CONTROL_INTERROGATE
invoke SetServiceStatus,hSS,addr stSS
.endif
popad
ret

_ProcHandler endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 服务主程序
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ServiceMain proc _dwArgc,_lpszArgv

pushad
invoke RegisterServiceCtrlHandler,addr szServiceName,offset _ProcHandler
mov hSS,eax
mov stSS.dwServiceType,SERVICE_WIN32_OWN_PROCESS or SERVICE_INTERACTIVE_PROCESS
mov stSS.dwCurrentState,SERVICE_START_PENDING
mov stSS.dwControlsAccepted,SERVICE_ACCEPT_STOP
mov stSS.dwWin32ExitCode,NO_ERROR
invoke SetServiceStatus,hSS,addr stSS
;********************************************************************
; 如果初始化代码比较多,那么需要首先把状态设置为 pending,等完成以后
; 再设置为 Running。(在这里加入初始化代码)
;********************************************************************
mov stSS.dwCurrentState,SERVICE_RUNNING
invoke SetServiceStatus,hSS,addr stSS
;********************************************************************
; 服务的具体执行代码
; 在这里是每隔1秒种让喇叭发声
;********************************************************************
.repeat
invoke MessageBeep,-1
invoke Sleep,1000
.until dwOption & F_STOP
popad
ret

_ServiceMain endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 主程序
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_WinMain proc
local @stSTE[2]:SERVICE_TABLE_ENTRY

invoke RtlZeroMemory,addr @stSTE,sizeof @stSTE
mov @stSTE[0].lpServiceName,offset szServiceName
mov @stSTE[0].lpServiceProc,offset _ServiceMain
invoke StartServiceCtrlDispatcher,addr @stSTE
ret

_WinMain endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
invoke _WinMain
invoke ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
end start

这里是服务名称的定义文件 Define.inc,这个文件已经在前面用include语句包含进来:

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 公用文本信息
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.const

szServiceEXE db 'Service.exe',0 ;在这里定义运行服务的 exe 文件名
szServiceName db 'ServiceTemplate',0 ;在这里定义服务的名称
szDisplayName db 'Service Template for test',0 ;在这里定义服务显示的名称
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


要注意的是,服务程序部分的代码并没有什么灵活性可言,它必须按照这样的步骤来实现,否则Windows就不认为它是一个服务程序了,另外,需要补充说明的是:

1. StartServiceCtrlDispatcher 函数被调用后并不马上返回,这时系统会去调用服务主程序(上面的_ServiceMain子程序),只有当服务主程序返回的时候,函数才会返回,这时主程序继续执行并执行 ExitProcess 终止执行。
2. 从第1点可以发现:在服务程序中,服务主程序的退出就意味着服务自行终止了,所以假如程序创建了多个线程来执行功能代码的话,在线程被创建以后,主程序还需要在这里等待,否则子程序返回以后服务进程就结束了,这些线程又怎么能继续执行呢?

服务控制程序的结构

好了,有了服务程序以后,还需要把服务正确安装才能让它运行,这个工作就是服务控制程序的事情了,一般来说,服务控制程序的结构并没有什么特殊的要求,它只是一个普通的Win32可执行文件而已,在服务控制程序中可以使用下面的 API 来进行各种控制,这些 API的具体语法请查看 Win32 API 手册:

1. 在进行和服务相关的各种操作之前,必须使用OpenSCManager来联系服务管理器,并从这个 API 得到一个
服务管理器的句柄 hSCM。
2. 操作某个具体的服务前,需要使用OpenService来打开服务,并得到服务的句柄hService,接下来就可以使用这个句柄来控制服务(当然,安装服务的时候并不需要此步骤,这时服务还不存在呢,又如何打开?)
3. 安装服务:使用 CreateService 函数,这个函数将服务程序的可执行文件在SCM中注册,注意:“注册”并不意味着执行,它只是在SCM的数据库中登记一条包含可执行文件名、启动方式、服务名称等信息的数据而已,执行这个函数以后,在控制面板的服务一栏中就可以看到服务列表中已经出现这个服务了,由于这仅仅是“注册”,所以系统并不检查可执行文件的合法性,也就是说,即使注册一个不存在的可执行文件,注册操作仍然会成功,但这样以后要启动服务的时候就会失败。注册过一次以后,SCM数据库中的信息会被自动保存,所以“注册”操作是一次性的过程,并不需要在每次启动服务的时候都去注册一遍。
4. 启动服务:当安装了服务以后,可以用StartService函数来启动服务,这时系统才真正根据注册的文件名去执行服务程序。
5. 删除服务:删除服务是安装服务的逆过程,也就是在SCM的数据库中将服务程序的信息删除,删除服务使用DeleteService函数。
6. 服务的控制:服务的暂停、停止等工作都可以由服务控制函数ControlService来完成,需要的仅仅是指定不同的参数而已。
7. 服务状态的查询可以由QueryServiceStatus函数来完成。
8. 句柄的关闭:和上面的操作相关的句柄(包括SCM句柄和服务句柄)在不再使用以后需要用CloseServiceHandle函数关闭。

下面的几个子程序举例说明了安装服务、删除服务、启动服务和停止服务的操作方法,注意子程序中用到的hSCM已经在其他地方首先调用OpenSCManager函数获取了。更具体的源代码请查看文章附带的源代码包中的Control.asm文件。


;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 安装服务
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_InstallService proc
local @hService,@dwReturn

mov @dwReturn,FALSE
;********************************************************************
; 创建服务
;********************************************************************
invoke CreateService,hSCM,addr szServiceName,addr szDisplayName,/
SERVICE_ALL_ACCESS,SERVICE_WIN32_OWN_PROCESS or SERVICE_INTERACTIVE_PROCESS,/
SERVICE_AUTO_START,SERVICE_ERROR_NORMAL,addr szServiceFile,/
NULL,NULL,NULL,NULL,NULL
.if ! eax
invoke GetLastError
.if eax == ERROR_DUP_NAME || eax == ERROR_SERVICE_EXISTS
mov @dwReturn,TRUE
.else
mov @dwReturn,FALSE
.endif
jmp @F
.endif
mov @hService,eax
mov @dwReturn,TRUE
;********************************************************************
invoke CloseServiceHandle,@hService
@@:
mov eax,@dwReturn
ret

_InstallService endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 删除服务
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_DeleteService proc
local @hService,@dwReturn
local @stStatus:SERVICE_STATUS

mov @dwReturn,FALSE
;********************************************************************
; 打开服务
;********************************************************************
invoke OpenService,hSCM,addr szServiceName,SERVICE_ALL_ACCESS
.if ! eax
jmp @F
.endif
mov @hService,eax
;********************************************************************
; 停止服务并删除服务
;********************************************************************
call _StopService
invoke DeleteService,@hService
.if eax
mov @dwReturn,TRUE
.endif
invoke CloseServiceHandle,@hService
@@:
mov eax,@dwReturn
ret

_DeleteService endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 启动服务
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_StartService proc
local @hService

invoke OpenService,hSCM,addr szServiceName,SERVICE_START
.if eax
mov @hService,eax
invoke StartService,@hService,0,NULL
.if eax
mov eax,TRUE
.else
mov eax,FALSE
.endif
push eax
invoke CloseServiceHandle,@hService
pop eax
.else
mov eax,FALSE
.endif
ret

_StartService endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 停止服务
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_StopService proc
local @hService
local @stStatus:SERVICE_STATUS

invoke OpenService,hSCM,addr szServiceName,SERVICE_ALL_ACCESS
.if eax
mov @hService,eax
invoke QueryServiceStatus,@hService,addr @stStatus
invoke ControlService,@hService,SERVICE_CONTROL_STOP,addr @stStatus
.if eax
mov eax,TRUE
.else
mov eax,FALSE
.endif
push eax
invoke CloseServiceHandle,@hService
pop eax
.else
mov eax,FALSE
.endif
ret

_StopService endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


合并服务程序和服务控制程序

在上面的例子中,将服务程序和服务控制程序分开是为了更好地从概念上说明两者的区别,但在实际应用中,还是有很多的程序将两个部分合在同一个可执行文件中实现,这时两部分仅仅是在物理上被放在同一个exe文件中,在结构上还是无不相干,完全独立的。
虽然两个部分的实现方式是完全不同的,但只要在程序的入口处就按照不同的情况去执行不同部分的代码,将它们合在一个文件中还是可行的,其关键就是分辨程序被执行的时候是作为服务程序执行还是被作为服务控制程序执行的,常见的方法有:

1. 用命令行参数来分辨,使用CreateService函数安装服务的时候递交文件名字符串时可以在文件名后面跟参数,这样程序入口处用GetCommandLine函数获取命令行参数,检测到特定参数则按照服务方式执行,否则按照服务控制程序方式运行。
2. 用运行路径分辨,一些病毒程序初始化的时候将自己的副本拷贝到Windows目录下并将这个副本注册为服务,所以到它检测到当前路径是Windows目录的时候,就按照服务方式运行。

Android来电拦截及拦截后的提示音 1. 电话拦截这个功能大家可能都知道了,就是利用反射原理调用ITelephony的隐藏方法来实现。这个就不说了,在附件的代码里有。2.拦截后提示忙音/空号/已关机/已停机这个功能其实是要用到MMI指令,具体如何设置呼叫转移的指定可以参考这里 http://baike.baidu. 阅读详情

相关推荐

ChatGPT电话接入:PSTN语音交互的工程实现与场景价值

语音助手本质上是人机交互的桥梁,其核心在于语音识别(ASR)、语义理解与语音合成(TTS)三大技术模块的协同。传统App语音受限于网络稳定性、系统权限和用户认知门槛,而基于PSTN电话网的AI语音交互,则依托电信级信令容错、离线知识快照与强意图锚定等设计,在信号弱、环境噪、操作简等真实约束下保障关键信息可达。这种‘为场景而生’的架构,显著提升了医疗咨询、老年服务、应急响应等高可靠性需求场景的可用性。ChatGPT电话版正是将ASR鲁棒性、TTS韵律控制与本地化知识图谱深度融合的典型实践,代表了AI从数字原生

weixin_30553777的博客 371

Windows下的服务控制管理器(SCM)

一、概要           服务管理器是用于管理系统服务的管理工具。一般常用于windows系统,使用这个工具你可以启动、停止服务;设置服务是自动、手动启动或禁用;查看某个服务的相关信息;设置服务以什么用户启动等等(一般包括了超级管理员用户、管理员用户和游客用户);设置用户注销,软件等。

xcbeyond|疯狂源自梦想,技术成就辉煌 2万+

Windows 编程之服务-2

四、自定义服务控制码 除了系统定义的五种控制码外(还有一种是:SERVICE_CONTROL_SHUTDOWN), 用户还可自定义控制码,其取值范围是128-255。用户可以通过控制面板中的服务 项向特定服务程序的控制处理函数发送控制码,程序员可以调用系统函数  ControlService 直接向服务程序的控制处理函数发送控制码。其函数原型如下: BOOL ControlServi

u011529563的专栏 939

关于C++对 service 的控制

最简单的方式  ShellExecute( "net   stop   servicename ",...);  ShellExecute( "net   start   servicename ",...);  复杂的就是API函数  SC_HANDLE   OpenSCManager(      LPCTSTR   lpMachineName,       //   computer

xiunai78的专栏 1270

汇编实现的操作系统

后,可以进一步研究x86-64汇编的实战运用,那么该OS操作系统将具有重要的研究价值,不会使你学完只会写demo级别的代码长期停滞用来口嗨,通过该OS的研究和消化学习你会学到更多东西,增强个人计算机底层基础有更好的帮助,非常适合于以C/C++/ASM方向的朋友学习,对于后续驾驭和阅读学习github开源项目如AI tensorflow,pytorch,cuda,gpu编程,Caffe等AI框架技术栈,编译原理,编译器实现,AI编译器,汇编器技术等方向也是有益的。- 用于应用程序的IDE编辑器/汇编器。

北风之神Boreas 1822

【嵌入式】树莓派部署NCNN的YOLOv5模型

树莓派部署NCNN框架的YOLOv5模型

Ace_Spade的博客 3783

windows服务程序二

Windows 服务程序(二) </h1> <div class="clear"></div> <div class="postBody"> <div id="cnblogs_post_body" class="blogpost-body blogpost-body-html"> 服务...

宇之日记 621

每天一个优秀提示词学习收藏 - 文本创作篇(二)

宝子们,今天不藏私啦!我把这段时间四处搜罗、潜心钻研出来的文本创作 Prompt 提示词大礼包双手奉上,这可都是能让你的 AI 创作水平原地起飞的干货!走过路过不要错过,赶紧码住,开启你的 AI 创作进阶之旅吧!

2403

Windows服务编写原理及探讨(四)

(四)一些问题的讨论   前面几章的内容都是服务的一些通用的编写原理,但里面隐含着一些问题,编写简单的服务时看不出来,但遇到复杂的应用就会出现一些问题,所以本章就是用来分析、解决这些问题的,适用于高级应用的开发人员。我这一章的内容都是经过实验得到的,很有实际意义。   我在第一章里面就说过,是由一个服务的主线程执行CtrlHandler函数,它将收到各种控制命令,但是真正处理命令,执行操作的是Se

hbb0b0的专栏 1051

STDP实战:用PyTorch从零搭建脉冲神经网络(附完整代码)

本文提供了基于PyTorch从零搭建脉冲神经网络的实战教程,重点讲解了STDP学习规则的原理与工程实现。通过构建LIF神经元模型和向量化STDP层,并结合泊松编码,详细演示了如何构建一个能够进行无监督特征学习的混合网络架构,为探索神经形态计算和低功耗实时学习方案提供了完整代码与实践指南。

weixin_29056145的博客 267

RDMA 出现背景、如何实现?如何测试连通性?

文章目录一、背景:1、传统的 网络通信:2、传统网络通信的问题:二、RDMA :1、出现背景:2、RDMA 简介:3、如何工作:4、RDMA 与 Infiniband 的关系:5、支持 RDMA 的其他协议:6、RDMA 的优势:7、通过 Infiniband 实现 RDMA :8、如何测试 RDMA 连通性:   一、背景: 1、传统的 网络通信:     &n...

郑泽林 2162

在windows环境使用C++开发一个提示保护眼睛的服务(一)

长时间使用电脑,导致眼睛胀痛,去医院检查,眼压升高,严重可能导致青光眼,进而导致失明。所以准备开发一个程序来提醒自己保护眼睛。程序在后台运行,所以准备开发为服务,开机自启动。我对C++更熟,对C#不熟,所以准备使用C++。服务检测开机与解锁,检测到之后开始计时,比如40分钟,这个可以自己定,之后提示已用时40分钟,需要休息眼睛。windows服务开发文档使用chat3.5翻译的。

paokuflying的博客 1743

Spring AI 实战:5 分钟搭建你的第一个 AI 应用(含完整代码)

能力关键 API适用场景基础对话简单问答、文本生成流式输出实时打字机效果@Bean模型需要调用外部工具结构化输出需要返回 Java 对象多轮对话聊天机器人场景Spring AI 让 Java 开发者可以用最熟悉的方式(Spring Boot + Maven)进入 AI 应用开发领域,不用学新语言,不用换框架,这是它最大的优势。但目前为止,我们的 AI 应用只能回答"它脑子里已有的知识"。如果让它读懂你自己的技术文档、公司内部知识库呢?这就是下一篇文章的主题——RAG(检索增强生成)实战。

qq_17204557的博客 644

ControlService

ControlServiceThe ControlService function sends a control code to a service.BOOL ControlService( SC_HANDLE hService, DWORD dwControl, LPSERVICE_STATUS lpServiceStatus);ParametershService

小发猫 3071

【机器视觉】基于深度学习的托盘PCB识别与计数(有无、正反)

工业机器视觉是指在制造业和工业环境中使用计算机视觉技术来执行检测、测量、识别和控制任务。它结合了硬件(如相机、镜头、光源)与软件(图像处理算法)来自动完成传统上需要人工视觉的任务,从而提高生产效率、产品质量以及工作安全性。工业机器视觉系统通常具有高精度、高速度和高可靠性,能够适应恶劣的工作环境。

专注上位机开发、机器视觉、机器学习、嵌入式软硬件开发 1万+

用 deepseek 写小说(通用版提示词模板)

#Initialization:作为[Role],在[Goals]下,回顾你的[Skill],严格遵守[Constraints],5.第五步:人物大纲,给小说里的每个人物撰写背景故事,深挖人物过去的经历,原生家庭,住所:一栋位于市郊的房子,有三个卧室,房龄 10 年,厨房很大,当中有一个鸟式大理石。示例 2.戈德里洛克先去了熊老爹的工作坊,尝试用大纲法写作,却发现这种方法无聊透顶,1.第一步:一句话概括,一句话概述小说内容,主要包含小说癸型,主角,以及故事中需要。大灰狼的暴行彻底激怒了戈德里洛克,

陈奕昆的博客 2973

3-Windows服务之官方Demo解析

每个服务都有一个控制处理函数,服务在ServiceMain函数中通过调用 RegisterServiceCtrlHandler 或 RegisterServiceCtrlHandlerEx 函数来注册其服务控制处理函数。在服务控制处理函数中,如果处理控制码导致服务状态发生变化,服务必须调用 SetServiceStatus 函数将其新状态报告给 SCM,同时可以启用或禁用接受其他控制码服务控制处理函数必须在 30 秒内返回,否则 SCM 认为发生错误。

weixin_40332490的博客 1242

基于投影法实现扫描文件的光学字符分割——Matlab实现

投影法是指将原图像沿着某个特定的方向进行投影,得到投影线上的像素点的个数或像素值总和,从而可以得到该方向上物体的轮廓信息。对于字符分割,我们可以将图像进行水平和垂直两个方向的投影,从而得到字符之间的分割线。在OCR技术中,字符分割是非常重要的一步骤,因为字符之间的分割对字符识别的准确性有很大的影响。通过对投影值的判断,可以求出字符之间的分割线,这里我们根据垂直方向上的投影值进行判断,选取一个阈值进行筛选即可。使用sum()函数分别计算出水平和垂直方向上的投影值,得到每一行和每一列的投影值。

TechGlide的博客 582

Windows服务编写原理及探讨(3)

(三)对服务的深入讨论之下 现在我们还剩下一个函数可以在细节上讨论,那就是服务的CtrlHandler函数。   当调用RegisterServiceCtrlHandler函数时,SCM得到并保存这个回调函数的地址。一个SCP调一个告诉SCM如何去控制服务的Win32函数,现在已经有10个预定义的控制请求: Control code Meaning

bobopeng 702

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Windows服务程序

有那么一类应用程序,是能够为各种用户(包括本地用户和远程用户)所用的,拥有用户授权级进行管理的能力,并且不论用户是否物理的与正在运行该应用程序的计算机相连都能正常执行,这就是所谓的服务了。(一)服务的基础知识Question 1. 什么是服务?它的特征是什么?  在NT/2000中,服务是一类受到操作系统优待的程序。一个服务首先是一个Win32可执行程序,如果要写一个功能完

plake的专栏 1万+

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Windows服务编写

摘要:几乎所有的操作系统在启动的时候都会启动一些不需要与用户交互的进程,这些进程在Windows中就被称作服务。它由服务程序、服务控制程序(SCP,service control program)和服务控制管理器(SCM,service control manager)三个组件构成。本文针对服务程序与服务控制程序的编写进行综合讲述。    关键词:Windows,服务,VC++•1    

lziog的专栏 1805

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

《Windows核心编程》---Windows服务

Windows服务(Services),是一些运行在WindowsNT、Windows2000和Windows XP等操作系统下用户环境以外的程序。它不同于一般的可执行程序,不需要系统登录便可以运行,以完成某些特定的功能。服务提供了管理能力,可以将后台程序转换成服务,然后就可以用命令或者在系统启动用户登录之前启动,并且也可以暂停、恢复和终止。服务信息在注册表中维护。 为了能够在系统中正确运行,在

seaskying的专栏 979

Windows服务简单一例,捕获关机信号做些处理

Windows服务 创建在 Windows 中的可长时间运行的可执行应用程序。这些服务可以在计算机启动时自动启动,可以暂停和重新启动而且不显示任何用户界面。它非常适合在服务器上使用,或为了不影响在同一台电脑上工作的其他用户需要长时间运行功能时使用,或者是随开机就启动后台默默干活的应用。 通过运行界面,输入services.msc可打开windows自带的服务管理界面对服务进行控制。 一个服务不管有没有被运行,都在你的硬盘里,只有当它真正被运行时,操作系统就会真正给它分配内存、CPU时间片等资源,这一次

猫哥 的沉淀、积累、总结。天天学习,好好向上...c/c++,嵌入式 linux,Android,HarmonyOS,AIOT) 3378

4. 服务控制程序

就像您在第叁章所学的,一个服务控制程序(Service Control Program,SCP)即是一个与执行在本端机器或远端机器之服务控制管理员(Service Control Manager,SCM)通讯的应用程序。我通常会认为一个SCP即是一个控制服务的启动、停止、暂停或继续执行之应用程序。然而,一个SCP可以做到更多:它可以经由增加服务、移除服务与列举已安装服务来操作一个SCM的资料库

showna的专栏 3142

VC++ Service编程(六)Control Handler函数

Control Handler函数     每个服务都有一个控制处理器,HandlerEx函数。当服务程序从一个服务控制程序那里收到一个控制请求时,HandlerEx函数就会被控制调度器调用。因此,这个函数运行在控制调度器的环境中。服务调用RegisterServiceCtrlHandler或者RegisterServiceCtrlHandlerEx函数来注册它的Control Hand

Wang Shen 3509
上一篇: 控制台下修改系统驱动状态的代码
下一篇: win32service
普通网友
博客等级 码龄22年 1万+粉丝 3156原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值