当前位置:首页 » 服务器技术
开发技术指南» 文章正文
    引言: 如何编写NT Service在
 

 

 ·书名模式    »显示摘要«
    摘要:个人选书的几个基本原则(编程语言,软件工程,企业级平台) 1,技术发明人写的书?除了那项技术的规范、标准,这是最权威的参考资料了,如the xxx programming language 2,技术发明人伙伴、同事写的书?通常从另一个角度对那项技术进行了阐述,如从初学者的角度,从惯用法的角度等;由于他经历了从学习该项技术到比发明人还熟悉 这项技术,因此这类书通常会解答学习中的常见问题,并提出最佳实践 3,社区活跃分子写的书?首先弄清那些活跃分子是谁:著名杂......
 ·在mfc中使用线程局部数据tls    »显示摘要«
    摘要:对于局部变量,不同的线程每一次调用函数时都会在栈上得到该变量的一份新的拷贝,全局的和静态的变量则只有一份实体,mfc提供了一种机制,使得可以像定义全局变量一样定义线程局部数据,所谓线程局部数据是指对于每一个访问它们的线程都会有一份只属于该线程的拷贝。 可使用宏thread_local(class_name, ident_name)定义线程局部数据,thread_local定义如下: #define thread_local(class_name, iden......


NT Service的几个注意点和示例代码
如何编写nt service在msdn->platform sdk->dlls, processes, and threads->service中说得很清楚了,在这里我就不多说了,这里我就只说一些我个人认为的在编写service过程中要注意的地方。

0、在我们通过控制面板或net start命令启动一个service时, service control manager (scm)从注册表里拿到service的可执行程序名,然后运行这个程序,从程序的入口main方法里得到service的service_main方法,然后就进入service_main运行。 【相关文章:在HTML页面中设置表格水平和垂直方向都

  【扩展阅读:Tribute to Tradition

  【扩展信息:雇用dbunit来维持你的数据环境稳定

一个service程序包含最少包含三个部分,一个是main方法,通常的工作是设置service_main方法与处理命令行参数(例如根据不同的参数执行其他的动作,象安装卸载service,手动启动停止service等等);一个是service_main方法,service程序具体要做的工作就写在这个方法里;一个是servicectrlhandler方法,这个方法在service_main里设置,用来处理由scm发给service的消息,例如service停止,暂停,系统关机等等。

1、手动启动一个service的方法是在service的main方法里调用startservice,startservice根据service的service_table_entry将程序转入相应的service_main。启动service时所要作的工作是写在service_main里的。通常的模式是在进入service_main后设状态为service_start_pending,然后进行一些初始化动作,然后执行一个线程或进程,在其中进行service的工作,然后设状态为service_running。一定要注意的是,启动service后,必须保证在两分钟内service的状态就会被设成service_running,否则会报错。

 

2、停止一个service的方法是在service的main方法里调用controlservice(hservice,service_control_stop,&servstat)发送service_control_stop消息到service control manager (scm),scm收到这个消息后就会通知service,执行servicectrlhandler里case service_control_stop:内的工作。结束动作通常也不能太久,因为在关机时,系统会给每个service大概20秒时间清场(这个时间可以在注册表中设置)

 

3、安装与卸载一个service的方法是在service的main方法里调用createservice方法与deleteservice方法,卸载方法前先要判断service是否在运行,如果在运行要先将服务停止

否则无法删除。

 

4、设置service状态的方法是调用setservicestatus,在写service的启动与停止动作是要设置其状态,分别在上面提到的service_main与servicectrlhandler里。查询service状态的方法是queryservicestatus,在停止服务时,controlservice方法只是发送了一个消息后就立即返回了,因此通常要在执行完controlservice后,利用while、sleep与queryservicestatus来不断查询service的状态,直到状态为service_stopped。startservice与controlservice不同,并不是立即返回的,它会直到service_main内的代码执行完后才返回。

 

5、service_main即使返回,service的程序进程也不会退出,直到service的状态为service_stopped时,才会终止并退出。

 

6、在设置service状态时,通过指定dwwin32exitcode与dwservicespecificexitcode可以设定当service在此状态下出错时的弹出式message。不过只能设定一个错误代码。

 

7、使用changeserviceconfig2添加修改service的描述。

 

8、默认情况下service程序是不能与桌面交互的,即不能打开窗口。通过changeserviceconfig函数设定service_interactive_process属性,或通过控制面板选中"允许服务与桌面交互",则服务程序可以打开窗口。例如在服务中使用createprocess创建了一个进程,只要在startupinfo的wshowwindow与dwflags设定了sw_show与startf_useshowwindow,则进程就会在打开的一个新窗口中运行。

 

9、不论是否设定service_interactive_process,在service中都可以通过messagebox方法弹出messagebox。这个函数的第一个参数指定为null,表示不指定父窗口。在第四个参数中指定mb_default_desktop_only或mb_service_notification表示以桌面为父窗口。

 

10.如果要停止的一个service上有其他正在运行的服务依赖着,这时直接停止这个服务就会出错,因此如果需要停止的服务有可能被其他服务所依赖,在停止前必须用enumdependentservices()方法取得所有依赖于这个服务的服务,将这些服务依次停止后才行。具体代码示例请看msdn->howto->id:q245230。

 

11、启动service时可以使用启动参数,在定义service_main方法时其两个参数(dword argc, lptstr *argv),第一个即为参数个数,第二个则是一个参数数组指针。如何传入参数呢,由于service_main并不是程序入口,因此参数是通过main从命令行传至startservice方法,而调用startservice时,startservice的第二第三个参数,就是传入service_main的参数。如果service是auto-started的,每次开机时就会自动启动,没有给我们手工通过命令行传入参数的机会,这时我们只有在安装service的时候,就把参数传入。在createservice时,将createservice的lpbinarypathname值设成例如simpleservice.exe arg1 arg2的样子,这样每当scm启动service时scm就会从main方法中获得参数并将其传入这个service的service_main中。

 

12.在启动一个service之后,在service的状态是”已启动(service_running)”之前,这段时间内,是无法启动另一个service的。

 

例子代码:

#include

#include

#include

#include

#include

#include

#include

#define service_name "tsservice"

#define service_dispname "vpbx pathfinder tsservice"

#define service_descriptionname "start vpbx pathfinder service"

#define service_exename "\\serviceframe.exe"

#define log_filename "\\service.log"

#define start_exename "\\vpbxw.exe"

#define stop_exename "\\stopserver.exe"

#define cmd_exename " -svc"

#define reg_item "software\\visionnex\\vpbx_server"

#define reg_key "home"

#define flag_filename "\\portkeeper.svc"

#define start_delay 10000

#define stop_delay 2000

#define count_delay 50

#define time_delay 2000

service_status m_servicestatus;

service_status_handle m_servicestatushandle;

bool brunning=false;

char path[256];

void winapi servicemain(dword argc, lptstr *argv);

void winapi servicectrlhandler(dword opcode);

bool installservice(int flag);

bool deleteservice();

bool startupservice();

bool stopservice();

bool changeservice();

bool endservice();

bool queryreg ();

dword getstatus(sc_handle service);

void logservice(char* error);

bool testts(int sleep, int count, int sec);

bool waittsstartup(int sleep, int count, int sec);

 

int main(int argc, char* argv[])

{

  if(!queryreg()) return 1;

  if(argc>1) {

  if(strcmp(argv[1],"-i")==0) {

   installservice(0);

  }

    else if (strcmp(argv[1],"-id")==0){

      installservice(1);

    }

  else if(strcmp(argv[1],"-d")==0) {

   deleteservice();

  }

    else if(strcmp(argv[1],"-r")==0) {

   startupservice();

  }

    else if(strcmp(argv[1],"-s")==0) {

   stopservice();

  }

    else if(strcmp(argv[1],"-c")==0) {

      changeservice();

    }

    else if(strcmp(argv[1],"-v")==0) {

   printf("serivce frame version:1.0.0.5: debug=pipe(limit -0.3)");

  }

  else {

   printf("unknown switch usage\nfor install use -i, for uninstall use -d, for run use -r, for stop use -s\n");

  }

 }

 else {

  service_table_entry dispatchtable[]={{service_name, servicemain},{null,null}}; 

  startservicectrldispatcher(dispatchtable);

 }

 return 0;

}

void winapi servicemain(dword argc, lptstr *argv)

{

  dword status;

  dword specificerror;

  logservice("service startup...");

  m_servicestatus.dwservicetype        = service_win32;

  m_servicestatus.dwcurrentstate       = service_start_pending;

  m_servicestatus.dwcontrolsaccepted   = service_accept_stop | service_accept_shutdown;

  m_servicestatus.dwwin32exitcode      = 0;

  m_servicestatus.dwservicespecificexitcode = 0;

  m_servicestatus.dwcheckpoint         = 0;


...   下一页
    摘要: j2me平台中有几个重要的概念,例如内存、cldc、midp等。初学j2me往往对这些概念理解不深,甚至出现偏差。本文的目的在于对j2me中的相关重要概念进行阐述。 内存 我们一直在强调,移动信息设备的内存非常小,使用起来应该加倍的珍惜,但是我们却很少知道这些内存是如何分类的,下面将做详细的介绍。事实上midp设备的内存分为三种,programme memory、heap、persistent storage。 programme memory是移动信息......
» 本期热门文章:

©2000-2007 All Rights Reserved. 最佳浏览:1024X768 MSIE