C# Servis İle Başka Program Çalıştırmak #2

0
C# Servis İle Başka Program Çalıştırmak #2

Herkese merhaba bu yazıda yadığımız servis uygulaması ile herhangi bir programın istediğimiz zamanlarda tetiklenmesini yani programın bizden bağımsız otomatik olarak çalışmasını sağlayacağız. Örnek vermek gerekirse bir program yazdığımızda bunun bilgisayarın her açılışında otomatik olarak çalışmasını isteyebiliriz. Servis kendi otomatik çalışarak programı açıp kapatabilir kullanıcıya herhangi bir mesaj vermek istersek servisler aracılığı ile yapabiliriz. Bir emlakcı için program yazdığımızı düşümelim, burada emlakcının bir çok kiracısı olacaktır muhtemelen, emlakcıya otomatik olarak kira borcu yaklaşan kiracıları hatırlatmak için servisleri kullanabiliriz. Servisimiz sistemde ki tarihi ve kira tarihini her bilgisayar açılışında karşılaştırıp emlkacıyı durumdan haberdar edebilir. Böylelikle emlakcı her seferinde o kadar kiracıya tek tek bakıp hangisinin kira süresi gelmiş diye bakmış olmaz. Burada amaç sistemi tamamen otomatik hale dönüştürüp kullanıcıya maksimum fayda sağlamak ve olabildiğince işlerini kolay halledebilmesini sağlamaktır. Bir başka küçük örnek vermek gerekirse virüs programları bize sürekli uyarı verirler biz onları kapatırız ama onlar sürekli arka planda çalışırlar ve sistemde bir tehlike olduğunda vs. bize uyarı verirler işte burada da servis kullanılır. Şimdi başka bir programı tetikleyebilmemiz için Microsoft’un sitesinden bulduğum bir sınıfı kullanacağız. Oluşturduğumuz servis içinde bu sınıftan bir nesne türeteceğiz ve çalıştırmak isteğimiz uygulamayı işaretleyeceğiz servisimizde o uygulamayı çalıştıracak bizim yazacağımız programda 10 saniye de bir program tetiklenecek. Şimid bahsettiğim hazır sınıfı aşağıda veriyorum. Bu sınıf ile hiç oynamayıp direkt olarak kullanacağız, dediğim gibi biz servisten programımızın yolunu vereceğiz aşağıda ki sınıfta belirtilen programı çalıştıracak.

using System;
using System.Runtime.InteropServices;

namespace CSCreateProcessAsUserFromService
{
class CreateProcessAsUserWrapper
{
public static void LaunchChildProcess(string ChildProcName)
{
IntPtr ppSessionInfo = IntPtr.Zero;
UInt32 SessionCount = 0;

if (WTSEnumerateSessions(
(IntPtr)WTS_CURRENT_SERVER_HANDLE,
0,
1,
ref ppSessionInfo,
ref SessionCount
))
{
for (int nCount = 0; nCount < SessionCount; nCount++)
{
WTS_SESSION_INFO tSessionInfo = (WTS_SESSION_INFO)Marshal.PtrToStructure(
ppSessionInfo + nCount * Marshal.SizeOf(typeof(WTS_SESSION_INFO)),
typeof(WTS_SESSION_INFO)
);

if (WTS_CONNECTSTATE_CLASS.WTSActive == tSessionInfo.State)
{
IntPtr hToken = IntPtr.Zero;
if (WTSQueryUserToken(tSessionInfo.SessionID, out hToken))
{
PROCESS_INFORMATION tProcessInfo;
STARTUPINFO tStartUpInfo = new STARTUPINFO();
tStartUpInfo.cb = Marshal.SizeOf(typeof(STARTUPINFO));

bool ChildProcStarted = CreateProcessAsUser(
hToken,
ChildProcName,
null,
IntPtr.Zero,
IntPtr.Zero,
false,
0,
null,
null,
ref tStartUpInfo,
out tProcessInfo
);

if (ChildProcStarted)
{
CloseHandle(tProcessInfo.hThread);
CloseHandle(tProcessInfo.hProcess);
}
else
{
}

CloseHandle(hToken);
break;
}
else
{
}
}
else
{
}
}

WTSFreeMemory(ppSessionInfo);
}
else
{
}
}

&nbsp;

#region P/Invoke WTS APIs

private const int WTS_CURRENT_SERVER_HANDLE = 0;
private enum WTS_CONNECTSTATE_CLASS
{
WTSActive,
WTSConnected,
WTSConnectQuery,
WTSShadow,
WTSDisconnected,
WTSIdle,
WTSListen,
WTSReset,
WTSDown,
WTSInit
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct WTS_SESSION_INFO
{
public UInt32 SessionID;
public string pWinStationName;
public WTS_CONNECTSTATE_CLASS State;
}

[DllImport("WTSAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool WTSEnumerateSessions(
IntPtr hServer,
[MarshalAs(UnmanagedType.U4)] UInt32 Reserved,
[MarshalAs(UnmanagedType.U4)] UInt32 Version,
ref IntPtr ppSessionInfo,
[MarshalAs(UnmanagedType.U4)] ref UInt32 pSessionInfoCount
);

[DllImport("WTSAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
static extern void WTSFreeMemory(IntPtr pMemory);

[DllImport("WTSAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool WTSQueryUserToken(UInt32 sessionId, out IntPtr Token);
#endregion

&nbsp;

#region P/Invoke CreateProcessAsUser

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct STARTUPINFO
{
public Int32 cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public Int32 dwX;
public Int32 dwY;
public Int32 dwXSize;
public Int32 dwYSize;
public Int32 dwXCountChars;
public Int32 dwYCountChars;
public Int32 dwFillAttribute;
public Int32 dwFlags;
public Int16 wShowWindow;
public Int16 cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}

[DllImport("ADVAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool CreateProcessAsUser(
IntPtr hToken,
string lpApplicationName,
string lpCommandLine,
IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes,
bool bInheritHandles,
uint dwCreationFlags,
string lpEnvironment,
string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation
);

[DllImport("KERNEL32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool CloseHandle(IntPtr hHandle);
#endregion
}
}

Yukarıda ki kodun yazılı olduğu sınıfı oluşturduktan sonra bir tane servis oluşturmalıyız daha önceki yazıda servis oluşturmayı anlatmıştım. Şimdi bir servis oluşturalım ve yazdığımız “CreateProcessAsUserWrapper” sınıftan bir nesne türeterek devam edelim ve servisimizin içine yazalım.


using CSCreateProcessAsUserFromService;//yukarıda ki sınıfımızı tanıtıyoruz
public partial class Service1 : ServiceBase
{
String kontrol;
public Service1()
{
InitializeComponent();
}

protected override void OnStart(string[] args)//servis başlatma fonksiyonu
{

Thread ProcessCreationThread = new Thread(MyThreadFunc);//Uygulamamızı sürekli aktif tutmak için thread yazıyoruz
ProcessCreationThread.Start();//yazdığımız thread'i başlatıyoruz
}

public void MyThreadFunc()//thread fonksiyonumuz
{

while(true)//thread sürekli çalışsın
{
Thread.Sleep(10000);//10 saniye bekleme süresi

CreateProcessAsUserWrapper.LaunchChildProcess(@"C:\Users\Acer\Desktop\bildirim\bildirim\bin\Debug\bildirim.exe");//istediğiniz programın yolu
//yukarıda görünen satırda eklediğimiz sınıftan LaunchChildProcess fonksiyonunu çağırarak dilediğimiz programın yolunu vererek programın
//çalışmasını sağlamış oluyoruz
}

}

}

Bu yazıda arka plan da çalışan servis ile hiçbir müdahalede bulunmadan otomatik olarak istediğimiz programın çalışmasını sağlamış olduk. Temel olarak anlatmaya çalıştım, servisler  bir çok proje de yardımcı olabilir burada mühim olan servisler bize grafiksel bir arayüz sunmazlar ama bu şekilde başka programları tetikleyerek çalıştırıp görsel sonuçlar elde edebiliriz.

Herkese iyi çalışmalar.

LEAVE A REPLY