ورود

View Full Version : مقاله: ساخت سرويس ويندوز با دلفي 2010



BORHAN TEC
جمعه 02 تیر 1391, 10:31 صبح
دستتون درد نکنه. واقعاً مقاله جالبی بود.

بر خودم لازم میدانم که پاره ای از توضیحات را خدمت دوستان عرض کنم:

1- موقعی که یک پروژه Service Application را ایجاد می کنیم در یونیت اصلی پروژه توضیحاتی در خصوص Windows Server 2003 قرار می گیرید که بد نیست آنرا نیز مورد توجه قرار دهید. به عبارتی اگر لازم بود که سرویس مورد نظر در ویندوزهای معمولی و ویندوزهای سرور اجرا شود می توانید این موضوع را با کد نویسی مورد بررسی قرار دهید.

2- نوع Thread در تایمرهای معمولی از نوع کم اهمیت است و بنابراین ممکن است در شرایطی خاص از اجرای کدهای نوشته شده در آنها ممانعت به عمل آید. البته در مثالی که شما در این مقاله زدید این مورد مشکلی را ایجاد نخواهد کرد ولی اگر اهمیت اجرای کدهای یک سرویس بالا باشد و نیاز به اجرای مداوم و با فاصله های زمانی کم داشته باشد می توانید از کامپوننتی مثل JvTimer و یا JvThreadTimer که در مجموعه JVCL قرار دارد استفاده کنید. توجه داشته باشید که این کامپوننت های تایمر خصوصیتی تحت عنوان Periority دارند که می توانید اهمیت ترد مربوطه را هم بنا به نیاز خود تنظیم کنید. البته در این حالت بنا به نیاز می توان از تردها و حتی تکنیکهای Hook هم استفاده کرد.

3- توجه داشته باشید که برای ساخت یک سرویس روشهای دیگری هم هست که برای کاربردهای خاص تر ایجاد شده اند به عنوان مثال دوستانی که از DataSnap برای ساخت برنامه های سازمانی استفاده می کنند می دانند که حتی می توانند نرم افزار سرویس دهنده را به صورت یک Windows Service ایجاد کنند که با توجه به ویژگی های بسیار خوبی که ویندوز به سرویس ها می بخشد می توان برنامه های سازمانی را با قابلیت اطمینان اجرای بیشتری ایجاد کرد چرا که همانطور که دوست عزیزمان در مقاله گفتند می توان کاری کرد که سرویس مورد در صورت بروز مشکل از نو اجرا شود. این مورد موقعی اهمیت زیادی پیدا می کند که تعداد کاربرای سیستم زیاد باشند و برنامه سمت سرور هم در یک سیستم راه دور قرار داشته باشد (مثلاً در یک کشور دیگر). در این خصوص می توانید به عکس زیر توجه کنید.
http://barnamenevis.org/attachment.php?attachmentid=88598&d=1340346661&thumb=1&stc=1

SayeyeZohor
جمعه 02 تیر 1391, 12:40 عصر
ممنون ازت

دانلود مقاله با افزودن نظر آقاي شاهين عشايري (http://s3.picofile.com/file/7415919030/Windows_Service_in_Delphi_Interface_91_04_02.rar.h tml)

N30TheM4TRIX
جمعه 02 تیر 1391, 23:17 عصر
خداییش دم همتون گرم

اما اگه بخوام با XE این کارو بکنم خیلی فرق داره چون من فقط با xe کارکردم

اگه نباید سوال میکردم شرمنده تازه وازدی اینا هم داره:لبخند:

SayeyeZohor
جمعه 02 تیر 1391, 23:19 عصر
نه
من تصور نكنم فرقي كنه
شما براي ساخت سرويس يك روش را طي مي كنيد
مهم نيست با چه برنامه اي و چه ورژني
موفق باشيد

Mask
یک شنبه 04 تیر 1391, 15:32 عصر
ممنون دوست عزیز.
امروز وقت کردم ، فایل و مقالتون رو دیدم و خوندم.
اول از همه باید تشکر کنم ازت ، بابت وقتی که گزاشتی .
بریم سراغ انتقاد ::لبخندساده:
خیلی نکته قابل اصلاح داشت این مقاله (اما در کل خوب بود)
در قسمتی از این مقاله نوشتید

در ساخت اين سرويس ، نياز به يك تايمر داريم ، مي دانيد كه استفاده از تايمر بسيار ساده است كافيست يك كنترل از نوع تايمر در صفحه قرار داده و خاصيت interval آن را ست نماييد اما متاسفانه شما نمي
توانيد از اين كنترل در Windows Service ها استفاده كنيد ، اين يكي از كليدي ترين نكات ساخت سرويس هاي ويندوز است
این موضوع رو شما بر چه اساسی نوشتید؟ من در چندین پروژه از تایمر در سرویس هام دارم استفاده میکنم و به خوبی و بدون مشکل داره کار میکنه. حتی خودتون تو سمپل اول از شی تایمر استفاده کردید.
نکته بعدی : در سمپلی که در فایل pdf گزاشتید . اومدید بدون اینکه شی تایمر رو بسازید بهش ایونت و خاصیت دادید . (خوابت میومده ، هر چی شده نوشتیا :))
نکته بعدی : اصلا این برنامه ای که نوشتی رو خودت اجرا کردی؟
ShowMessage ی که نوشتی رو اصلا خودت ، تونستی ببینی؟
سعی کنید مقاله رو دوباره بخونید و اصلاح کنید .
کدهای زیر در رابطه با کارکرد سرویس هاست. میتونی بعد از اصلاح مقاله این کد ها رو درش جا بدی.
من اگه جای شما باشم. چون شروع به نوشتن این مقاله کردید ، و جهت کاملتر و بی عیب شدنش از لینک زیر کمک میگرفتم و ازش استفاده میکردم.
http://barnamenevis.org/showthread.php?12902-%DA%86%DA%AF%D9%88%D9%86%DA%AF%DB%8C-%DA%A9%D8%A7%D8%B1-%D8%A8%D8%A7-service-application-%D8%AF%D8%B1-%D8%AF%D9%84%D9%81%DB%8C&p=67160#post67160

نصب سرویس :

procedure InstallService(ServiceName, DisplayName: pchar; FileName: string);
var
SCManager: SC_HANDLE;
Service: SC_HANDLE;
Args: pchar;
begin
SCManager := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
if SCManager = 0 then Exit;
try
Service := CreateService(SCManager, ServiceName, DisplayName, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS or SERVICE_INTERACTIVE_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_IGNORE, pchar(FileName), nil, nil, nil, nil, nil);
Args := nil;
StartService(Service, 0, Args);
CloseServiceHandle(Service);
finally
CloseServiceHandle(SCManager);
end;
end;

حذف سرویس :

procedure UninstallService(ServiceName: pchar);
var
SCManager: SC_HANDLE;
Service: SC_HANDLE;
begin
SCManager := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
if SCManager = 0 then Exit;
try
Service := OpenService(SCManager, ServiceName, SERVICE_ALL_ACCESS);
ControlService(Service, SERVICE_CONTROL_STOP, Status);
DeleteService(Service);
CloseServiceHandle(Service);
finally
CloseServiceHandle(SCManager);
end;
end;
استارت سرویس :

function ServiceStart(sMachine,sService : string ) : boolean;
var
schm,schs : SC_Handle;
ss : TServiceStatus;
psTemp : PChar;
dwChkP : DWord;
begin
ss.dwCurrentState := 0;
schm := OpenSCManager(PChar(sMachine),Nil,SC_MANAGER_CONNE CT);
if(schm > 0)then
begin
schs := OpenService(schm,PChar(sService),SERVICE_START or SERVICE_QUERY_STATUS);
if(schs > 0)then
begin
psTemp := Nil;
if(StartService(schs,0,psTemp))then
begin
if(QueryServiceStatus(schs,ss))then
begin
while(SERVICE_RUNNING <> ss.dwCurrentState)do
begin
dwChkP := ss.dwCheckPoint;
Sleep(ss.dwWaitHint);
if(not QueryServiceStatus(schs,ss))then
begin
break;
end;
if(ss.dwCheckPoint < dwChkP)then
begin
break;
end;
end;
end;
end;
CloseServiceHandle(schs);
end;
CloseServiceHandle(schm);
end;
Result := SERVICE_RUNNING = ss.dwCurrentState;
end;

استوپ سرویس :

function ServiceStop(sMachine,sService : string ) : boolean;
var
schm,schs : SC_Handle;
ss : TServiceStatus;
dwChkP : DWord;
begin
schm := OpenSCManager(PChar(sMachine),Nil,SC_MANAGER_CONNE CT);
if(schm > 0)then
begin
schs := OpenService(schm,PChar(sService),SERVICE_STOP or SERVICE_QUERY_STATUS);
if(schs > 0)then
begin
if(ControlService(schs,SERVICE_CONTROL_STOP,ss))th en
begin
if(QueryServiceStatus(schs,ss))then
begin
while(SERVICE_STOPPED <> ss.dwCurrentState)do
begin
dwChkP := ss.dwCheckPoint;
Sleep(ss.dwWaitHint);

if(not QueryServiceStatus(schs,ss))then
begin
break;
end;

if(ss.dwCheckPoint < dwChkP)then
begin
break;
end;
end;
end;
end;
CloseServiceHandle(schs);
end;
CloseServiceHandle(schm);
end;
Result := SERVICE_STOPPED = ss.dwCurrentState;
end;
به دست آوردن وضعیت سرویس :

function ServiceGetStatus(sMachine, sService: PChar): DWORD;
{******************************************}
{*** Parameters: ***}
{*** sService: specifies the name of the service to open
{*** sMachine: specifies the name of the target computer
{*** ***}
{*** Return Values: ***}
{*** -1 = Error opening service ***}
{*** 1 = SERVICE_STOPPED ***}
{*** 2 = SERVICE_START_PENDING ***}
{*** 3 = SERVICE_STOP_PENDING ***}
{*** 4 = SERVICE_RUNNING ***}
{*** 5 = SERVICE_CONTINUE_PENDING ***}
{*** 6 = SERVICE_PAUSE_PENDING ***}
{*** 7 = SERVICE_PAUSED ***}
{******************************************}
var
SCManHandle, SvcHandle: SC_Handle;
SS: TServiceStatus;
dwStat: DWORD;
begin
dwStat := 0;
// Open service manager handle.
SCManHandle := OpenSCManager(sMachine, nil, SC_MANAGER_CONNECT);
if (SCManHandle > 0) then
begin
SvcHandle := OpenService(SCManHandle, sService, SERVICE_QUERY_STATUS);
// if Service installed
if (SvcHandle > 0) then
begin
// SS structure holds the service status (TServiceStatus);
if (QueryServiceStatus(SvcHandle, SS)) then
dwStat := ss.dwCurrentState;
CloseServiceHandle(SvcHandle);
end;
CloseServiceHandle(SCManHandle);
end;
Result := dwStat;
end;

function ServiceRunning(sMachine, sService: PChar): Boolean;
begin
Result := SERVICE_RUNNING = ServiceGetStatus(sMachine, sService);
end;
به دست آوردن لیست سرویسهای فعال بر روی سیستم.

const
SERVICE_KERNEL_DRIVER = $00000001;
SERVICE_FILE_SYSTEM_DRIVER = $00000002;
SERVICE_ADAPTER = $00000004;
SERVICE_RECOGNIZER_DRIVER = $00000008;

SERVICE_DRIVER =
(SERVICE_KERNEL_DRIVER or
SERVICE_FILE_SYSTEM_DRIVER or
SERVICE_RECOGNIZER_DRIVER);

SERVICE_WIN32_OWN_PROCESS = $00000010;
SERVICE_WIN32_SHARE_PROCESS = $00000020;
SERVICE_WIN32 =
(SERVICE_WIN32_OWN_PROCESS or
SERVICE_WIN32_SHARE_PROCESS);

SERVICE_INTERACTIVE_PROCESS = $00000100;

SERVICE_TYPE_ALL =
(SERVICE_WIN32 or
SERVICE_ADAPTER or
SERVICE_DRIVER or
SERVICE_INTERACTIVE_PROCESS);

function ServiceGetList(sMachine : string;dwServiceType,dwServiceState : DWord;
slServicesList : TStrings ): boolean;
const
cnMaxServices = 4096;
type
TSvcA = array[0..cnMaxServices]of TEnumServiceStatus;
PSvcA = ^TSvcA;
var
j : integer;
schm : SC_Handle;
nBytesNeeded,
nServices,
nResumeHandle : DWord;
ssa : PSvcA;
begin
Result := false;
schm := OpenSCManager(
PChar(sMachine),
Nil,
SC_MANAGER_ALL_ACCESS);
if(schm > 0)then
begin
nResumeHandle := 0;
New(ssa);
EnumServicesStatus(
schm,
dwServiceType,
dwServiceState,
ssa^[0],
SizeOf(ssa^),
nBytesNeeded,
nServices,
nResumeHandle );
for j := 0 to nServices-1 do
begin
slServicesList.
Add( StrPas(
ssa^[j].lpDisplayName ) );
end;
Result := true;
Dispose(ssa);
// close service control
// manager handle
CloseServiceHandle(schm);
end;
end;


procedure TForm1.Button1Click(Sender: TObject);
begin
ServiceGetList( '',SERVICE_WIN32, SERVICE_STATE_ALL, ListBox1.Items )
end;
به دست آوردن مسیر سرویس :

function GetServiceExecutablePath(strMachine: string; strServiceName: string): String;
var
hSCManager,hSCService: SC_Handle;
lpServiceConfig: PQueryServiceConfigW;
nSize, nBytesNeeded: DWord;
begin
Result := '';
hSCManager := OpenSCManager(PChar(strMachine), nil, SC_MANAGER_CONNECT);
if (hSCManager > 0) then
begin
hSCService := OpenService(hSCManager, PChar(strServiceName), SERVICE_QUERY_CONFIG);
if (hSCService > 0) then
begin
QueryServiceConfig(hSCService, nil, 0, nSize);
lpServiceConfig := AllocMem(nSize);
try
if not QueryServiceConfig(
hSCService, lpServiceConfig, nSize, nBytesNeeded) Then Exit;
Result := lpServiceConfig^.lpBinaryPathName;
finally
Dispose(lpServiceConfig);
end;
CloseServiceHandle(hSCService);
end;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
Edit2.Text:=GetServiceExecutablePath('',Edit1.Text )
end;
موفق باشید.

SayeyeZohor
دوشنبه 05 تیر 1391, 10:16 صبح
با سلام خدمت دوست عزيزم Gold
اول ممنون از نقداي توپت
دوم :

فقط خواهشي كه دارم اينه كه هر دوستي كه اين مقاله رو خوند نظرشو بگه و چون احتمال اشتباه در مقاله ام زياده ، از دوستان عزيزم خواهش مي كنم كمك كنين رفعش كنم تا آموزش كامل فارسي داشته باشيم
من كه گفته بودم مقاله امكان اشتباهات زيادي داره ، چون وقت زيادي نداشتم و فقط چند شب بعد از كار تونستم روش وقت بذارم
خواستم با كمك شما دوستان خوب تكميل بشه و بذارم براي استفاده همه ، فقط جهت قدرداني از كمك هاي زياد بچه هاي سايت برنامه نويس.همين :اشتباه:

بريم سراغ نقد هاتون
1-
در قسمتی از این مقاله نوشتید

در ساخت اين سرويس ، نياز به يك تايمر داريم ، مي دانيد كه استفاده از تايمر بسيار ساده است كافيست يك كنترل از نوع تايمر در صفحه قرار داده و خاصيت interval آن را ست نماييد اما متاسفانه شما نمي توانيد از اين كنترل در Windows Service ها استفاده كنيد ، اين يكي از كليدي ترين نكات ساخت سرويس هاي ويندوز است
این موضوع رو شما بر چه اساسی نوشتید؟ من در چندین پروژه از تایمر در سرویس هام دارم استفاده میکنم و به خوبی و بدون مشکل داره کار میکنه. حتی خودتون تو سمپل اول از شی تایمر استفاده کردید.

اين نقدتون وارده ، من يك عذرخواهي به همه بدهكارم شرمنده :خجالت:
با اين حال منم از خودم ننوشتم تو يكي از اين رفرنس هايي كه در فايل Pdf ضميمه كرده بودم ، راجع به اين كه قرار دادن شي تايمر به صورت معمول در فرم درست نيست. بعد من تست كردم تايمر رو در فرم قرار دادم و در ويندوز xp تست كردم ، مشكلي نداشت ولي در ويندوز 7 64بيتي جواب نداد
اين سوال رو يادم رفته بود بپرسم و كوتاهي از من بود
-- خواهش : مي شه يك پروژه با تايمر بذارين كه درست جواب بده؟

2-
نکته بعدی : در سمپلی که در فایل pdf گزاشتید . اومدید بدون اینکه شی تایمر رو بسازید بهش ایونت و خاصیت دادید . (خوابت میومده ، هر چی شده نوشتیا :))

(خوابت میومده ، هر چی شده نوشتیا :))

نکته بعدی : اصلا این برنامه ای که نوشتی رو خودت اجرا کردی؟
ShowMessage ی که نوشتی رو اصلا خودت ، تونستی ببینی؟
خوابم كه واقعا ميومدش :خجالت:
ولي ساختمش به صورت دايناميك ، خداييش اينقدر گيج نبودم


http://barnamenevis.org/attachment.php?attachmentid=88702


سعی کنید مقاله رو دوباره بخونید و اصلاح کنید .
چشم حتماً


کدهای زیر در رابطه با کارکرد سرویس هاست. میتونی بعد از اصلاح مقاله این کد ها رو درش جا بدی.
بازم به روي چشم



من اگه جای شما باشم. چون شروع به نوشتن این مقاله کردید ، و جهت کاملتر و بی عیب شدنش از لینک زیر کمک میگرفتم و ازش استفاده میکردم.
http://barnamenevis.org/showthread.p...7160#post67160
ابن لينك رو ديدم
نمي دونم چي رو استفاده نكردم ، ممنون مي شم بگيد

براي اين كداتون بايد يونيت WinSvc رو Use كنيم؟
بازم ممنون از نظرات مفيدتون

به محض اينكه جناب Gold پروژه با تايمر رو بذارند مقاله رو تكميل مي كنم و به محض تاييد شدن تو اين تاپيك مي ذارم
منتظرم

Mask
دوشنبه 05 تیر 1391, 12:28 عصر
ولي ساختمش به صورت دايناميك ، خداييش اينقدر گيج نبودم
د حواس نداری داداشم.:قلب:
شی تایمر رو پس کجا create کردی.؟ د نکردی!

براي اين كداتون بايد يونيت WinSvc رو Use كنيم؟
حتما.

به محض اينكه جناب Gold پروژه با تايمر رو بذارند مقاله رو تكميل مي كنم و به محض تاييد شدن تو اين تاپيك مي ذارم
چشم. حتما.
جوابه این سوال رو ندادیا :

ShowMessage ی که نوشتی رو اصلا خودت ، تونستی ببینی؟

SayeyeZohor
دوشنبه 05 تیر 1391, 12:43 عصر
د حواس نداری داداشم.
شی تایمر رو پس کجا create کردی.؟ د نکردی!
آره ببشخيد حواس ندارم:قلب::متعجب::اشتباه:

جوابه این سوال رو ندادیا :
ShowMessage ی که نوشتی رو اصلا خودت ، تونستی ببینی؟
نه خداييش گفتم زود تمومش كنم فقط exe گرفتم :خجالت:

SayeyeZohor
چهارشنبه 07 تیر 1391, 02:39 صبح
Mr.GOLD قرار شد Source رو آماده كني پس چي شد؟
منتظريم

Mask
چهارشنبه 07 تیر 1391, 11:50 صبح
Mr.GOLD قرار شد Source رو آماده كني پس چي شد؟
منتظريم

شرمنده . یکم سرم شلوغه. در اولین فرصت، به چشم.

سعید صابری
جمعه 09 تیر 1391, 13:53 عصر
کامپوننت رایگان JVCL یک دونه یونیت داره برای کار با سرویس ها به نام JclSvcCtrl
که عملیاتی مانند نصب،حذف،توقف،اجرا،لیست و......................... را انجام میده .
گفتم شاید بدرد کسی بخوره

scarlet_yekta
یک شنبه 23 آذر 1393, 13:21 عصر
سلام من تمام مراحل را انجام دادم سرویس را استارت هم میکنه اما هیچ عملیاتی انجام نمیشه
همه عملیات را چندین بار چک کردم که همه چی درست
enable شدن timer
کم نبودن زمان interval
true بودن interactive
اما نمیشه خواهش میکنم اگه کسی تونسته با سرویس کار کنه جواب بده

Mask
یک شنبه 23 آذر 1393, 17:53 عصر
یکی از عملیاتی که داره در سرویس انجام میشه باعث ایجاد Exception میشه و سرویس دراپ میشه.

scarlet_yekta
دوشنبه 24 آذر 1393, 06:46 صبح
آخه کار خاصی انجام نمیده یه تایمر گذاشتم که هر 15 دقیقه(interval=900000) یه پیام را بهم نشون بده

ServiceExecute
begin
Timer1.Enabled := True;
while Terminated do
ServiceThread.ProcessRequests(True);
Timer1.Enabled := False;
end;

.ServiceStart
begin
Timer1.Interval := 900000;
Timer1.Enabled := True;
Timer1.OnTimer := Timer1Timer;
end;

ServiceStop
begin
Timer1.Enabled := False;
end;


و on timer هم

showmessage('test');

Mask
دوشنبه 24 آذر 1393, 23:19 عصر
کدتون رو در بلوک کد قرار بدید تا بشه خوندش.

holythirteen
جمعه 16 خرداد 1399, 10:44 صبح
دستتون درد نکنه. واقعاً مقاله جالبی بود.

بر خودم لازم میدانم که پاره ای از توضیحات را خدمت دوستان عرض کنم:

1- موقعی که یک پروژه Service Application را ایجاد می کنیم در یونیت اصلی پروژه توضیحاتی در خصوص Windows Server 2003 قرار می گیرید که بد نیست آنرا نیز مورد توجه قرار دهید. به عبارتی اگر لازم بود که سرویس مورد نظر در ویندوزهای معمولی و ویندوزهای سرور اجرا شود می توانید این موضوع را با کد نویسی مورد بررسی قرار دهید.

2- نوع Thread در تایمرهای معمولی از نوع کم اهمیت است و بنابراین ممکن است در شرایطی خاص از اجرای کدهای نوشته شده در آنها ممانعت به عمل آید. البته در مثالی که شما در این مقاله زدید این مورد مشکلی را ایجاد نخواهد کرد ولی اگر اهمیت اجرای کدهای یک سرویس بالا باشد و نیاز به اجرای مداوم و با فاصله های زمانی کم داشته باشد می توانید از کامپوننتی مثل JvTimer و یا JvThreadTimer که در مجموعه JVCL قرار دارد استفاده کنید. توجه داشته باشید که این کامپوننت های تایمر خصوصیتی تحت عنوان Periority دارند که می توانید اهمیت ترد مربوطه را هم بنا به نیاز خود تنظیم کنید. البته در این حالت بنا به نیاز می توان از تردها و حتی تکنیکهای Hook هم استفاده کرد.

3- توجه داشته باشید که برای ساخت یک سرویس روشهای دیگری هم هست که برای کاربردهای خاص تر ایجاد شده اند به عنوان مثال دوستانی که از DataSnap برای ساخت برنامه های سازمانی استفاده می کنند می دانند که حتی می توانند نرم افزار سرویس دهنده را به صورت یک Windows Service ایجاد کنند که با توجه به ویژگی های بسیار خوبی که ویندوز به سرویس ها می بخشد می توان برنامه های سازمانی را با قابلیت اطمینان اجرای بیشتری ایجاد کرد چرا که همانطور که دوست عزیزمان در مقاله گفتند می توان کاری کرد که سرویس مورد در صورت بروز مشکل از نو اجرا شود. این مورد موقعی اهمیت زیادی پیدا می کند که تعداد کاربرای سیستم زیاد باشند و برنامه سمت سرور هم در یک سیستم راه دور قرار داشته باشد (مثلاً در یک کشور دیگر). در این خصوص می توانید به عکس زیر توجه کنید.
https://barnamenevis.org/attachment.php?attachmentid=88598&d=1340346661&thumb=1&stc=1


درود بر شما. کارتون قابل تقدیر هست