Windows 2000/XP 및 2003은 "서비스 프로그램"이라는 것을 지원합니다.
(1) 시스템에 로그인하지 않고 실행할 수 있습니다.
(2) 시스템 권한이 있으므로 프로세스 관리자에서는 끝날 수 없습니다.
2003 년에 회사의 셋톱 박스 프로젝트를 개발할 때 코스웨어 업로드 및 미디어 서비스를 작성했습니다.
Delphi7을 실행하고 메뉴 파일을 선택하십시오-> New-> 기타 ---> 서비스 프로그램을위한 프레임 워크가 ServiceEmo.dpr 및 init_main.pas를 저장합니다. 우리는 우리가 만든 프레임 워크에 몇 가지 속성이 있습니다.
(1) DisplayName : 서비스의 표시 이름
(2) 이름 : 서비스 이름.
여기에서는 "Delphi Service Demo"로 표시되고 "Delphiservice"로 변경하면 CMD 모드를 입력하고 프로젝트가 시작됩니다. "Service.Exe /install"을 실행하면 "Net Start Delphiservice"가 시작됩니다. 그러나 서비스 및 현재 상태는 현재 코드를 작성하지 않았기 때문에 지금은 아무것도 할 수 없습니다. Delphi7의 IDE로 돌아갑니다.
우리의 계획은이 서비스를위한 기본 창을 추가하는 것입니다. 작업 표시 줄은 프로그램 아이콘을 두 번 클릭하면 버튼이 표시됩니다 기능.
실제로 서비스 프로그램이 Winlogon 데스크탑에서 작동한다고 생각하지 마십시오. 제어판을 열고 방금 수행 한 서비스의 속성을 볼 수 있습니다. 진드기. haha, IDE에 가면 부울 속성에주의하십시오.
파일-> new-> 양식은 서비스에 창 frmmain을 추가하고 단위를 init_frmmain으로 저장 하고이 창을 수동으로 만들도록 설정합니다.
Unit_main;
인터페이스
용도
창, 메시지, 시스템, 클래스, 그래픽, 컨트롤, svcmgr, 대화 상자, unit_frmmain;
유형
tdelphiservice = class (tservice)
절차 servicecontinue (발신자 : tservice; var 계속 : 부울);
절차 ServiceExecute (발신자 : Tservice);
절차 servicePause (발신자 : tservice; var paused : boolean);
절차 Serviceshutdown (발신자 : Tservice);
절차 servicestart (sender : tservice; var start : boolean);
절차 servicestop (발신자 : tservice; var stopped : boolean);
사적인
{개인 선언}
공공의
기능 GetServiceController : TserviceController;
{공개 선언}
끝;
var
delphiservice : tdelphiservice;
frmmain : tfrmmain;
구현
{$ r *.dfm}
절차 servicecontroller (ctrlcode : dword);
시작하다
delphiservice.controller (ctrlcode);
끝;
함수 tdelphiservice.getServiceController : tserviceController;
시작하다
결과 : = ServiceController;
끝;
절차 tdelphiservice.servicecontinue (sender : tservice;
var 계속 : 부울);
시작하다
종료되지는 않지만
시작하다
수면 (10);
servicethread.processrequests (false);
끝;
끝;
절차 tdelphiservice.serviceExecute (sender : tservice);
시작하다
종료되지는 않지만
시작하다
수면 (10);
servicethread.processrequests (false);
끝;
끝;
절차 tdelphiservice.servicePause (발신자 : tservice;
var 일시 중지 : 부울);
시작하다
일시 중지 : = 참;
끝;
절차 tdelphiservice.serviceshutdown (발신자 : tservice);
시작하다
gbcanclose : = 참;
frmmain.free;
상태 : = csstopped;
reportstatus ();
끝;
절차 tdelphiservice.servicestart (발신자 : tservice;
var 시작 : 부울);
시작하다
시작 : = 참;
svcmgr.application.createform (tfrmmain, frmmain);
gbcanclose : = 거짓;
frmmain.hide;
끝;
절차 tdelphiservice.servicestop (발신자 : tservice;
var 중지 : 부울);
시작하다
중지 : = 참;
gbcanclose : = 참;
frmmain.free;
끝;
끝.
기본 창 단위는 다음과 같습니다.
Unit_frmmain;
인터페이스
용도
Windows, 메시지, sysutils, 변형, 클래스, Shellapi, 그래픽, 컨트롤, 양식,
대화, extctrls, stdctrls;
Const
WM_TRAYICON = WM_USER + 1234;
유형
tfrmmain = class (tform)
Timer1 : Ttimer;
버튼 1 : tbutton;
프로 시저 Formcreate (sender : tobject);
절차 formclosequery (sender : tobject; var canclose : boolean);
절차 formdestroy (sender : tobject);
절차 Timer1Timer (Sender : Tobject);
절차 버튼 1Click (sender : tobject);
사적인
{개인 선언}
Icondata : tnotifyicondata;
절차 중독자;
절차 DeliconFromTray;
절차 trayiconmessage (var msg : tmessage);
절차 sysbuttonmsg (var msg : tmessage);
공공의
{공개 선언}
끝;
var
frmmain : tfrmmain;
gbcanclose : 부울;
구현
{$ r *.dfm}
절차 tfrmmain.formcreate (sender : tobject);
시작하다
formstyle : = fsstayontop;
setwindowlong (application.handle, gwl_exstyle, ws_ex_toolwindow);
gbcanclose : = 거짓;
TIMER1.interval : = 1000;
timer1.enabled : = true;
끝;
절차 tfrmmain.formcloseQuery (발신자 : tobject; var canclose : boolean);
시작하다
canclose : = gbcanclose;
그렇지 않다면
시작하다
숨다;
끝;
끝;
절차 tfrmmain.formdestroy (sender : tobject);
시작하다
timer1.enabled : = false;
DeliconfromTray;
끝;
절차 tfrmmain.addicontotray;
시작하다
Zeromemory (@icondata, sizeof (tnotifyicondata));
icondata.cbsize : = sizeof (tnotifyicondata);
icondata.wnd : = 핸들;
icondata.uid : = 1;
icondata.uflags : = nif_message 또는 nif_icon 또는 nif_tip;
icondata.ucallbackmessage : = wm_trayicon;
icondata.hicon : = application.icon.handle;
icondata.sztip : = '델파이 서비스 데모 프로그램';
shell_notifyicon (nim_add, @icondata);
끝;
절차 tfrmmain.deliconfromtray;
시작하다
shell_notifyicon (nim_delete, @icondata);
끝;
절차 tfrmmain.sysbuttonmsg (var msg : tmessage);
시작하다
if (msg.wparam = sc_close) 또는
(msg.wparam = sc_minimize) 그런 다음 숨기십시오
그렇지 않으면 상속; // 기본 조치를 수행합니다
끝;
절차 tfrmmain.trayiconmessage (var msg : tmessage);
시작하다
if (msg.lparam = wm_lbuttondblclk) 다음 show ();
끝;
절차 tfrmmain.timer1timer (sender : tobject);
시작하다
중독자;
끝;
절차 sendhokkey; stdcall;
var
hdesk_wl : hdesk;
시작하다
hdesk_wl : = opendesktop ( 'winlogon', 0, false, goodtop_journalplayback);
if (hdesk_wl <> 0) 그러면
if (setthreaddesktop (hdesk_wl) = true)
postMessage (hwnd_broadcast, wm_hotkey, 0, makelong (mod_alt 또는 mod_control, vk_delete));
끝;
절차 tfrmmain.button1click (sender : tobject);
var
dwthreadid : dword;
시작하다
CreateThread (nil, 0, @sendhokkey, nil, 0, dwthreadid);
끝;
끝.
다시 채우다:
(1) 더 많은 서비스 프로그램 데모 프로그램은 시스템 서비스를 제어하고 관리하는 방법을 보여주는 여러 코드가 포함 된 다음 URL을 방문하십시오.
(2) 기억하십시오 : Windows는 실제로 여러 개의 데스크탑이 있습니다. 화면 전송이 발생하면 시스템이 잠겨 있거나 데스크톱에 로그인하지 않을 수 있습니다. 이 시점에서는 화면을 데스크탑으로 전환해야합니다.
(3) 서비스 프로그램과 데스크탑 사이의 상호 작용을위한 동적 스위칭 방법도 다음과 같습니다.
유닛 서비스;
인터페이스
기능 initservicedesktop : 부울;
절차 doneservicedesktop;
구현
창, sysutils를 사용합니다.
Const
DefaultWindowStation = 'Winsta0';
DefaultDeskTop = '기본값';
var
Hwinstasave : Hwinsta;
HDESKSAVE : HDESK;
Hwinstauser : Hwinsta;
HDESKUSER : HDESK;
기능 initservicedesktop : 부울;
var
dwthreadid : dword;
시작하다
dwthreadid : = getCurrentThreadId;
// 서비스 윈도우 스테이션 및 데스크탑에 연결하고
// 손잡이를 저장합니다.
Hwinstasave : = GetProcessWindowStation;
hdesksave : = getThreadDeskTop (dwthreadid);
hwinstauser : = OpenWindowStation (DefaultWindowStation, False, Maximum_allowed);
hwinstauser = 0이면
시작하다
OutputDeBugString (PCHA ( 'OpenWindowStation 실패' + SyserRormessage (getLasterror)));
결과 : = 거짓;
출구;
끝;
SetProcessWindowStation (hwinstauser)이 아닌 경우
시작하다
OutputDeBugString ( 'SetProcessWindowStation 실패');
결과 : = 거짓;
출구;
끝;
hdeskuser : = opendesktop (defaultdesktop, 0, false, maximum_allowed);
hdeskuser = 0이면
시작하다
outputDebugstring ( 'opendesktop 실패');
SetProcessWindowStation (Hwinstasave);
CrophindowStation (Hwinstauser);
결과 : = 거짓;
출구;
끝;
결과 : = setThreadDeskTop (hdeskuser);
결과가 아니라면
OutputDeBugString (PCHA ( 'setThreadDeskTop' + syserRormessage (getLasterror)));
끝;
절차 doneservicedesktop;
시작하다
// 창 스테이션과 데스크탑을 복원합니다.
setThreadDeskTop (hdesksave);
SetProcessWindowStation (Hwinstasave);
hwinstauser <> 0이면
CrophindowStation (Hwinstauser);
hdeskuser <> 0이면
ClosedEsktop (Hdeskuser);
끝;
초기화
initservicedesktop;
마무리
doneservicedesktop;
끝.
보다 자세한 데모 코드는 http://www.torry.net/samples/samples/os/isarticle.zip을 참조하십시오
(4) 서비스를 설치하는 방법은 다음과 같습니다 방금 HKEY_LOCAL_MACHINE/SYSTER/CONTROLSET001에 위치하고 있습니다 다음 :
단위 Winsvcex;
인터페이스
Windows, WinSVC를 사용합니다.
Const
//
// 서비스 구성 정보 수준
//
service_config_description = 1;
service_config_failure_actions = 2;
//
// 가져온 함수의 DLL 이름
//
advapidll = 'advapi32.dll';
유형
//
// 서비스 설명 문자열
//
pserviceScriptiona = ^tservicedEscriptiona;
pserviceScriptionw = ^tservicedEscriptionw;
pserviceScription = pservicedEscriptiona;
{$ externalsym _service_descriptiona}
_service_descriptiona = 레코드
LPDESCRIPTION : PANSICHAR;
끝;
{$ externalsym _service_descriptionw}
_service_descriptionw = 레코드
lpdescription : pwidechar;
끝;
{$ externalsym _service_description}
_service_description = _service_descriptiona;
{$ externalsym service_descriptiona}
service_descriptiona = _service_descriptiona;
{$ externalsym service_descriptionw}
service_descriptionw = _service_descriptionw;
{$ externalsym service_description}
service_description = _service_descriptiona;
tservicedEscriptiona = _service_descriptiona;
tservicedEscriptionw = _service_descriptionw;
tserviceScription = tservicedEscriptiona;
//
// 서비스 실패에 대한 조치
//
{$ externalsym _sc_action_type}
_sc_action_type = (sc_action_none, sc_action_restart, sc_action_reboot, sc_action_run_command);
{$ externalsym sc_action_type}
SC_ACTION_TYPE = _SC_ACTION_TYPE;
PSERVICEACTION = ^TSERVICEACTION;
{$ externalsym _sc_action}
_SC_ACTION = 레코드
atype : sc_action_type;
지연 : dword;
끝;
{$ externalsym sc_action}
SC_ACTION = _SC_ACTION;
tserviceaction = _Sc_Action;
pservicefailureactionsa = ^tservicefailureactionsa;
pserviceFailUreActionsw = ^tserviceFailUreActionss;
pservicefailureactions = pservicefailureactionsa;
{$ externalsym _service_failure_actionsa}
_Service_failure_AccionA = 레코드
dwresetperiod : dword;
lprebootmsg : lpstr;
lpcommand : lpstr;
CACTION : DWORD;
lpsaactions : ^sc_action;
끝;
{$ externalsym _service_failure_actionsw}
_Service_failure_Actionsw = 레코드
dwresetperiod : dword;
lprebootmsg : lpwstr;
lpcommand : lpwstr;
CACTION : DWORD;
lpsaactions : ^sc_action;
끝;
{$ externalsym _service_failure_actions}
_Service_failure_Actions = _Service_Failure_Actionsa;
{$ externalsym service_failure_actionsa}
Service_Failure_AcCionSA = _Service_Failure_Actionsa;
{$ externalsym service_failure_actionsw}
Service_Failure_Actionsw = _Service_Failure_Actionsw;
{$ externalsym service_failure_actions}
Service_Failure_Actions = _Service_Failure_ActionsA;
tservicefailureactionsa = _service_failure_actionsa;
TSERVICEFAILUEACTIONSW = _SERVICE_FAILUE_ACTIONSW;
tservicefailureactions = tservicefailureactionsa;
//////////////////////////////////////////////////////////////////////////////////4 //////////////////////////////////////////////////////////////////////////////////4 ///////
// API 기능 프로토 타입
//////////////////////////////////////////////////////////////////////////////////4 //////////////////////////////////////////////////////////////////////////////////4 ///////
tqueryserviceconfig2 = function (hservice : sc_handle; dwinfolevel : dword; lpbuffer : 포인터;
cbbufsize : dword;
tChangerviceConfig2 = 함수 (Hservice : sc_handle; dwinfolevel; dword; lpinfo : 포인터) : bool;
var
hdll : thandle;
libloaded : 부울;
var
Osversioninfo : tosversioninfo;
{$ externalsym queryserviceconfig2a}
queryserviceconfig2a : tqueryserviceconfig2;
{$ externalsym queryserviceconfig2w}
queryserviceconfig2w : tqueryserviceconfig2;
{$ externalsym queryserviceconfig2}
queryserviceconfig2 : tqueryserviceconfig2;
{$ externalsym changeserviceconfig2a}
ChangeserviceConfig2a : tchangeserviceconfig2;
{$ externalsym changeserviceconfig2w}
changeserviceconfig2w : tchangeserviceconfig2;
{$ externalsym changeserviceconfig2}
ChangeserviceConfig2 : tchangeserviceconfig2;
구현
초기화
osversioninfo.dwosversioninfosize : = sizeof (osversioninfo);
getVersionEx (OsversionInfo);
if (osversioninfo.dwplatformid = ver_platform_win32_nt) 및 (osversioninfo.dwmajorversion> = 5)
시작하다
hdll = 0이면
시작하다
hdll : = getModuleHandle (advapidll);
libloaded : = false;
hdll = 0이면
시작하다
hdll : = loadlibrary (advapidll);
libloaded : = true;
끝;
끝;
hdll <> 0이면
시작하다
@QueryServiceConfig2a : = getProcadDress (hdll, 'QueryServiceConfig2a');
@QueryServiceConfig2w : = getProcadDress (hdll, 'QueryServiceConfig2w');
@QueryServiceConfig2 : = @QueryServiceConfig2a;
@changeserviceconfig2a : = getProcadDress (hdll, 'changesviceconfig2a');
@changeserviceconfig2w : = getProcadDress (hdll, 'changesviceConfig2w');
@changeserviceconfig2 : = @changeserviceconfig2a;
끝;
끝
또 다른
시작하다
@QueryServiceConfig2a : = nil;
@QueryServiceConfig2w : = nil;
@QueryServiceConfig2 : = nil;
@changeserviceconfig2a : = nil;
@changeserviceconfig2w : = nil;
@changeserviceconfig2 : = nil;
끝;
마무리
if (hdll <> 0)이고 libloaded
Freelibrary (HDLL);
끝.
유닛 winntservice;
인터페이스
용도
Windows, Winsvc, Winsvcex;
함수 installservice (const strserviceName, strdisplayName, strdescription, strfilename : String) : boolean;
// eG : installService ( '서비스 이름', '디스플레이 이름', '설명 정보', '서비스 파일');
프로 시저 제거 서비스 (strserviceName : String);
구현
함수 strlcopy (dest : pchar; const 출처 : pchar; maxlen) : pchar;
ASM
EDI를 푸시하십시오
ESI를 푸시하십시오
Ebx를 푸시하십시오
Mov Esi, Eax
Mov Edi, edx
Mov Ebx, Ecx
Xor al, al
ECX, ECX를 테스트합니다
jz @@ 1
Repne Scasb
jne @@ 1
ecx
@@ 1 : Sub Ebx, Ecx
Mov Edi, esi
Mov Esi, edx
Mov Edx, Edi
Mov Ecx, Ebx
SHR ECX, 2
담당자 MOVSD
Mov Ecx, Ebx
및 ECX, 3
담당자 MOVSB
스토브
Mov EAX, edx
팝 엑스
팝 ESI
팝 에디
끝;
함수 strpchar (dest : pchar; const 소스 : 문자열) : pchar;
시작하다
결과 : = strlcopy (dest, pchar (소스), 길이 (소스));
끝;
함수 installservice (const strserviceName, strdisplayName, strdescription, strfilename : String) : boolean;
var
// ss : tservicestatus;
// pSTEMP : PCHA;
HSCM, HSCS : Thandle;
srvdesc : pservicedescription;
DESC : 문자열;
// srvtype : dword;
lpserviceargvectors : pchar;
시작하다
결과 : = 거짓;
// pstemp : = nil;
// srvtype : = service_win32_own_process 및 service_interactive_process;
HSCM : = OpenSCManager (nil, nil, sc_manager_all_access); // 서비스 데이터베이스를 연결합니다
hscm = 0이면 종료; // messagebox (hhandle, pchar (syserrormessage (getLasterror)), '서비스 프로그램 관리자', MB_ICONERROR+MB_TOP MESTE);
HSCS : = CreateService (// 서비스 기능 생성
HSCM, // 서비스 제어 관리 핸들
pchar (strserviceName), // 서비스 이름
pchar (strdisplayname), // 서비스 이름이 표시됩니다
service_all_access, // 액세스 권한
service_win32_own_process 또는 service_interactive_process, // 서비스 유형 service_win32_share_process
service_auto_start, // 시작 유형
service_error_ignore, // 오류 제어 유형
pchar (strfilename), // 서비스 프로그램
nil, // 그룹 서비스 이름
nil, // 그룹 ID
nil, // 종속 서비스
nil, // 서비스 계정을 시작합니다
nil); / 서비스 비밀번호를 시작합니다
hscs = 0 인 경우 종료; // messagebox (hhandle, pchar (syserrormessage (getlasterror)), pchar (applact.title), mb_iconerror+mb_top most);
할당 된 경우 (ChangeserViceConfig2)
시작하다
desc : = 복사 (strdescription, 1,1024);
getmem (srvdesc, sizeof (tservicedescription));
getmem (srvdesc^.lpdescription, 길이 (desc) + 1);
노력하다
strpcopy (srvdesc^.lpdescription, desc);
ChangeserViceConfig2 (HSCS, Service_config_description, srvdesc);
마지막으로
Freemem (srvdesc^.lpdescription);
Freemem (srvdesc);
끝;
끝;
lpserviceargvectors : = nil;
STARKERVICE (HSCS, 0, LPSERVICEARGVECTORS)가 아닌 경우 // 서비스를 시작하십시오
출구; //meragebox(hhandle ,pchar(syserrormessage(getlasterror) ),pchar(application.title);
CloseServiceHandle (HSCS);
결과 : = 참;
끝;
프로 시저 제거 서비스 (strserviceName : String);
var
scmanager : sc_handle;
서비스 : sc_handle;
상태 : Tservicestatus;
시작하다
scmanager : = OpenSCManager (nil, nil, sc_manager_all_access);
scmanager = 0이면 종료;
노력하다
서비스 : = OpenService (scmanager, pchar (strservicename), service_all_access);
ControlService (service, service_control_stop, 상태);
deleteservice (서비스);
CloseServiceHandle (서비스);
마지막으로
CloseServiceHandle (scmanager);
끝;
끝;
끝.
(5) 서비스 프로그램을 잔인하게 닫고 이전 "NT Toolbox"의 기능을 실현하는 방법은 프로세스 이름을 기반으로 프로세스를 죽이는 방법은 다음과 같습니다.
tlhelp32를 사용합니다.
함수 killtask (exefilename : string) : 정수;
Const
process_terminate = $ 0001;
var
Continueloop : bool;
FSNAPSHOTHANDLE : Thandle;
fprocessentry32 : tprocessentry32;
시작하다
결과 : = 0;
fsnapshothandle : = CreateToolHelp32SnapShot (TH32CS_SNAPROCESS, 0);
fprocessentry32.dwsize : = sizeof (fprocessentry32);
continueloop : = process32first (fsnapshothandle, fprocessentry32);
정수 (continueloop) <> 0
시작하다
if ((대문자 (extracesfilename) (fprocessentry32.szexefile) =
대문자 (exefilename)) 또는 (대문자 (fprocessentry32.szexefile) =
그런 다음 대문자 (exefilename))
결과 : = 정수 (종료 프로세스)
OpenProcess (Process_terminate,
bool (0),
fprocessentry32.th32processid),
0));
continueloop : = process32next (fsnapshothandle, fprocessentry32);
끝;
CloseHandle (fsnapshothandle);
끝;
그러나 서비스 프로그램의 경우 실제로 프로그램에 디버그 권한이있는 한 다음과 같습니다.
기능 enabledebugprivilege : 부울;
기능 enable -privilege (htoken : 추기경; pribname : string; benable : boolean) : 부울;
var
TP : TOKEN_PRIVILEGES;
더미 : 추기경;
시작하다
tp.privilegecount : = 1;
LookUpPrivileGeValue (NIL, PCHAR (PRICNAME), TP.Privileges [0] .luid);
그렇다면 벤치가 있다면
tp.privileges [0] .attributes : = se_privilege_enabled
else tp. privileges [0] .attributes : = 0;
AdvernTokenPrivileges (htoken, false, tp, sizeof (tp), nil, dummy);
결과 : = getLasterror = ERROR_SUCCESS;
끝;
var
htoken : 추기경;
시작하다
OpenProcessToken (GetCurrentProcess, Token_AdJust_Privileges, HTOKEN);
결과 : = enableprivilege (htoken, 'sedebugprivilege', true);
CloseHandle (htoken);
끝;
사용 방법 :
enabledebugprivilege; // 권한을 높이십시오
killtask ( 'xxxx.exe'); // 서비스 프로그램을 닫습니다.
--------------------------------------------------------- --------------------------------------------------------- --------------------------------------------------------- --------------------------------------------------------- --------------------------------------------------------- ------ ---------