Makale Özeti

Merhaba; Launcher eşliğinde Client/Server olarak bir program nasıl güncellenir buna bakacağız. Kısaca programlarımızın ne yapacağına bakalım.Üç tane programımız olacak 1-) Server Programı - Launcherdan gelen version bilgisini kontrol edip eğer eskiyse yeni sürümün versiyonunu ve dosya adını göndericek , eğer aynı ise tamam mesajı gönderir , versiyon uyumsuzsa hata gönderir. 2-) Launcher kendi versiyon bilgisini servera yollayayıp versiyon sürümünü kontrol eder. 3-) Ana program bu değişken bir program ne kullanacaksanız onu koyacaksınız tek farkı versiyon kontrolü için sadece launcherdan açılmasını sağlayacağız. Bu makaleden önce eğer bilginiz yoksa "Soket Programlama" ve "FTP İşlemleri" konularını araştırmanızı tavsiye ederim.

Makale

 Henüz bitmedi....

Öncelikle kısa olduğu için Ana programımızın açılış ayarını yapalım.

Programı "blabla.exe -start" gibi başlatırsak argument olarak programa -start düşer ve eğer bu argument gelmeze başlamasını engelleyebiliriz.

            ProcessStartInfo startInfo = new ProcessStartInfo();
            startInfo.FileName = Application.StartupPath + "\\MainProgram.exe";
            startInfo.Arguments = "-startApp";
            Process.Start(startInfo);
            this.Close();

ProcessStartInfo classı sayesinde programı başlatırken argument gibi özellikler ekleyebiliyoruz.

FileName propertysine başlatıcağımız programın yolunu veriyoruz.

Arguments propertysine programa göndericeğimiz parametreyi yazıyoruz.Bizim için bu -startApp

Process classının statik Start metoduna oluşturduğumuz ProcessStartInfo classını veriyoruz ve programı başlatıyoruz.

Program başlarken Program classındaki Main metodu arg isimli bir string dizi alır.Gönderdiğimiz argumentler bu dizinin içerisinde tutulur.Farklı argumentler gönderilerek farklı işlemler yapılabilir.Bizim yapmak istediğimiz şey programımızın sadece launcherdan açılıyor ise açılmasını sağlamak.Bunun için laucherdan açarken -startApp argumentini gönderiyoruz.


Sıra geldi server dosyamızı yazmaya ancak ondan önce MSSQL imize bir tablo ve procedure ekleyeceğiz tablo sürüm bilgilerini tutacak procedure ise sürüm kontorlünü yapacak.Ben Northwind veritabanı üzerinden işlem yaptım siz isterseniz değiştirebilirsiniz ancak kodlarıda ayarlamanız gerekmektedir.

Tablo Ve Procure Kodlarımız :

USE [Northwind]
GO

/****** Object:  Table [dbo].[Version]    Script Date: 09/23/2012 07:45:43 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[Version](
	[Version] [nvarchar](50) NOT NULL,--Sürüm
	[patchName] [nvarchar](50) NOT NULL,--Sürümün patch dosyasının adı
	[hisVersion] [nvarchar](50) NOT NULL,--Bir önceki sürüm
 CONSTRAINT [PK_Version] PRIMARY KEY CLUSTERED 
(
	[Version] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO


---------------------------------------------------------------------------------------------------------------



/****** Object:  StoredProcedure [dbo].[VersionCheck]    Script Date: 09/23/2012 07:35:46 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
Create Proc [dbo].[VersionCheck]
@Version nvarchar(50)--Launcherın şuanki sürümü
As
Declare @lastVersion nvarchar(50)--Son sürümü tutacağımız değişken
Declare @result nvarchar(50)--Sonuç mesajını tutacağımız değişken
Select Top 1 @lastVersion = [Version] From [Version] Dec Order By [Version]--Version tablosundan en son sürümü çekiyoruz

If @Version = @lastVersion--Eğer launcher sürümü son sürüme eşit ise
 Begin
  Set @result = '~cv~cmp'--Sonuca Son Sürüm mesajını yazıyoruz
 End
Else--Eğer eşit değil ise
 Begin 
  Declare @NextVersion nvarchar(50)--Launcherın sonraki yükleyeceği sürüm bilgisini tutacağımız değişkenn
  Declare @patchName nvarchar(50)--Launcherın indireceği dosyanın adı
  
  Select Top 1 @NextVersion = [Version],@patchName = patchName From [Version] Where hisVersion = @Version--Önceki sürümü launcherın şuanki sürümüne eşit olan , sürümü seçiyoruz
  If @@ROWCOUNT >0--Eğer öyle bir sürüm var ise
   Begin
    Set @result = '~cv~upt~nv~'+@NextVersion+'~pn~'+@patchName--Yeni sürümü ve indirilecek dosyanın adını yazıyoruz
    --Mesajımız ~cv~upt~nv~2012~pn~patch2012.zip gibi olacak
   End
  Else--Eğer launcherın sürümü hiç bir yeni sürümün eski sürümü değilse hata mesajı gönderiyoruz
   Begin
   Set @result = '~cv~err'
   End
 End
 Select @result
 

 

Server kodlarımızı yazmanın vakti geldi.

Server programımızın tasarımız aşağıdaki gibi olacak.

Function Classımız :



using System.Data;
using System.Data.SqlClient;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

namespace ProgramUpdateServer
{
    public static class Functions
    {
        [DllImport("kernel32")]
        private static extern long WritePrivateProfileString(string section, string key, string val, string filePath);

        [DllImport("kernel32")]
        private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath);

        /*
         İni dosyalarından okuma yapmamızı sağlar
         */
        public static string ReadIniFile(string section, string key)
        {
            StringBuilder stbINI = new StringBuilder(255);
            GetPrivateProfileString(section, key, "", stbINI, 255, Application.StartupPath + "\\Options.ini");
            return stbINI.ToString();
        }

        /*
         İni dosyalarında yazma yapmamızı sağlar
         */
        public static void WriteIniFile(string section, string key, string value)
        {
            WritePrivateProfileString(section, key, value, "Options.ini");
        }

        //Verdiğimiz string veriyi byte dizisine dönüştürür.
        public static byte[] StringToByte(string data)
        {
            return Encoding.GetEncoding(1254).GetBytes(data);
        }

        //Verdiğimiz byte dizisini stringe çevrir.
        public static string StringFromByte(byte[] data, int len)
        {
            return Encoding.GetEncoding(1254).GetString(data, 0, len);
        }

        //Verdiğimiz versiyonun geçerli olup olmadığını , eski mi yeni mi olduğunu kontrol eder.
        public static string GetVersionInfo(string version)
        {
            string result = "";
            using (SqlConnection connection = new SqlConnection("Data Source=.;Initial Catalog=Northwind;Integrated Security=True"))
            {
                connection.Open();
                using (SqlCommand command = new SqlCommand("VersionCheck", connection))
                {
                    command.CommandType = CommandType.StoredProcedure;
                    command.Parameters.AddWithValue("@Version", version);
                    result = command.ExecuteScalar().ToString();
                    /*
                     Northwind veritabanına bağlanıp VersionCheck Procedure e sini çalıştırıyoruz ve bu procedure bize kullanıcıya göndereceğimiz 
                     mesajı geri döndürüyor...
                     */
                }
            }
            return result;
        }
    }
}

 

Ana Server Kodları :

 
using System;
using System.Drawing;
using System.Net;
using System.Net.Sockets;
using System.Windows.Forms;

namespace ProgramUpdateServer
{
    public partial class frmServer : Form
    {
        public frmServer()
        {
            InitializeComponent();
            CheckForIllegalCrossThreadCalls = false;
        }

        /*
         Gelen komutlar ve anlamları
         ~cv~ : Check Version
         * ~cv~cmp : Version Complete
         * ~cv~upt : Version Update
         * ~cv~err : Version Error
         ~nv~ : New Version 
         ~pn~ : Patch Name
         */

        private Socket server;//Server socketimiz
        byte[] buffer = new byte[1024];// Gelen verileri tutacağımız byte dizimiz

        //Yapılan işlemleri listviewe eklemek için yaptığımız metodumuz
        public void EventsLog(string data, string type)
        {
            //Eğer type err ise kırmızı scc ise yeşil renkte ekliyoruz
            if (type == "err")
            {
                ListViewItem listViewItem = new ListViewItem(data + " " + DateTime.Now.ToShortDateString());
                listViewItem.SubItems[0].ForeColor = Color.Red;
                lstActions.Items.Add(listViewItem);
            }
            else if (type == "scc")
            {
                ListViewItem listViewItem = new ListViewItem(data + " " + DateTime.Now.ToShortDateString());
                listViewItem.SubItems[0].ForeColor = Color.Green;
                lstActions.Items.Add(listViewItem);
            }
        }

        //bufferımızı temizlemek için yazdığımız metodumuz.
        void Clear()
        {
            buffer = new byte[1024];
        }

        private void frmServer_Load(object sender, EventArgs e)
        {
            EventsLog("Server is started", "scc");
            //Server soketimizi oluşturuyoruz.
            server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //Soketi bağlıyoruz , 4407 portu şart değil sizde hangisi açıksa veya kullanacaksınız onu yazabilirsiniz.
            server.Bind(new IPEndPoint(IPAddress.Any, 4407));
            server.Listen(1000);//Serverı dinletmeye başlıyoruz 1000 aynı anda kaç tane client dinleyeceğini 
            server.BeginAccept(new AsyncCallback(GetRequest), null);// Ve Begin Accept ile gelen bağlanma isteklerini asenkron olarak kabul ediyoruz.

        }

        void GetRequest(IAsyncResult asyncResult)
        {
            Socket clientSocket = server.EndAccept(asyncResult);// EndAccept metodu bize gelen clientın soketini geri döndürür.
            EventsLog(clientSocket.RemoteEndPoint + " is connected", "scc");
            Clear();//Bufferı temizliyoruz 
            int bufferLen = clientSocket.Receive(buffer);//Receive metodu clientten gelen mesajı alır buffera yazar ve boyutunu geri döndürür.Ancak asenkron bir metot değildir ve mesaj gelene kadar program kitlenir
            string data = Functions.StringFromByte(buffer, bufferLen);
            string command = data.Substring(0, 4);//gelen mesajın ilk 4 harfi komutu belirttiği için onu alıyoruz
            string content = data.Substring(4);//4. indexten başlayarak kalan mesajı alır
            switch (command)
            {
                case "~cv~"://Eğer gelen komut ~cv~ ise kodları çalıştır
                    string versionInfo = Functions.GetVersionInfo(content);//Kullanıcıya gönderilecek mesajı alıyoruz
                    clientSocket.Send(Functions.StringToByte(versionInfo.Trim()));//Ve byte e çevirip kullanıcıya yolluyoruz.
                    EventsLog(clientSocket.RemoteEndPoint + " Version Info is sented...", "scc");
                    break;
            }

            server.BeginAccept(new AsyncCallback(GetRequest), null);//BeginAccept metodu asenkron olarak servera gelen bağlanma isteklerini alır ve new AsyncCallback(GetRequest) bize bağlantı isteği geldiğinde GetRequest metodunun çalışacağını belirtiyor.
            Clear();//Bufferı temizliyoruz.
            clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(GetReceive), clientSocket);//Kullanıcıdan gelebilecek her hangi bir komutu asenkron olarak alıyoruz bir mesaj geldiğinde GetReceive metodu çalışacaktır.
            //GetReceive metodu içnidede kullanmak için BeginReceive metodunun state parametresine Clientın soketini atıyoruz.
        }

        void GetReceive(IAsyncResult asyncResult)
        {
            Socket clientSocket = asyncResult.AsyncState as Socket;//AsynState BeginReceive de verdiğimiz statei bize geri döndürür.
            int bufferLen = clientSocket.EndReceive(asyncResult);//EndReceive metodu gelen mesajın boyutunu döndürür
            string data = Functions.StringFromByte(buffer, bufferLen);
            string command = data.Substring(0, 4);//gelen mesajın ilk 4 harfi komutu belirttiği için onu alıyoruz
            string content = data.Substring(4);//4. indexten başlayarak kalan mesajı alır
            Clear();
            switch (command)
            {
                case "~cv~"://Eğer gelen komut ~cv~ ise kodları çalıştır
                    string versionInfo = Functions.GetVersionInfo(content);//Kullanıcıya gönderilecek mesajı alıyoruz
                    clientSocket.Send(Functions.StringToByte(versionInfo.Trim()));//Ve byte e çevirip kullanıcıya yolluyoruz.
                    EventsLog(clientSocket.RemoteEndPoint + " Version Info is sented...", "scc");
                    break;
            }

            clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(GetReceive), clientSocket);//Kullanıcıdan gelebilecek her hangi bir komutu asenkron olarak alıyoruz bir mesaj geldiğinde GetReceive metodu çalışacaktır.
            //GetReceive metodu içnidede kullanmak için BeginReceive metodunun state parametresine Clientın soketini atıyoruz.
        }

        private void frmServer_FormClosing(object sender, FormClosingEventArgs e)
        {
            server.Close();//program kapatılırken soketide kapatıyoruz.
        }


    }
}


Ve son olarak Client dosyamıza geldik.Clientta Zip dosyalarını açmak için bir dll kullanıyoruz bu dll en aşağıdaki projenin olduğu linkte bulunuyor oradan alıp kullanabilirsiniz.

Client Tasarımı :


Kullanacağımız ini dosyası ve yapısı...

[ServerInfo]

 

ServerIP=127.0.0.1

 

Version=2012

 

[FTP]

 

URL=ftp://127.0.0.1/


Functions Classımız :

using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

namespace ProgramUpdateLauncher
{
    public static class Functions
    {
        [DllImport("kernel32")]
        private static extern long WritePrivateProfileString(string section, string key, string val, string filePath);

        [DllImport("kernel32")]
        private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath);

        //İni dosyalarında okuma yapmamızı sağlayan metodumuz
        public static string ReadIniFile(string section, string key)
        {
            string path = Application.StartupPath + "\\Options.ini";
            StringBuilder stbINI = new StringBuilder(255);
            GetPrivateProfileString(section, key, "", stbINI, 255, path);
            return stbINI.ToString();
        }

        //İni dosyalarında yazma yapmamızı sağlayan metodumuz
        public static void WriteIniFile(string section, string key, string value)
        {
            WritePrivateProfileString(section, key, value, Application.StartupPath + "\\Options.ini");
        }

        //Verdiğimiz string veriyi byte dizisine dönüştüren metodumuz
        public static byte[] StringToByte(string data)
        {
            return Encoding.GetEncoding(1254).GetBytes(data);
        }
        
        //Verdiğimiz byte dizisi veriyi stringe dönüştüren metodumuz
        public static string StringFromByte(byte[] data, int len)
        {
            return Encoding.GetEncoding(1254).GetString(data, 0, len);
        }

        //Verdiğimiz long değerinde dosya boyutunu Byte Kilo Byte ve giga byte a dönüştürüp bize string olarak dönüştürür
        public static string CalculateFileSize(long filesize)
        {
            string strFileSize = "";

            if (filesize >= 1073741824)
            {
                strFileSize += (filesize / 1073741824) + " GB ";
                filesize = filesize % 1073741824;
            }

            if (filesize >= 1048576)
            {
                strFileSize += (filesize / 1048576) + " MB ";
                filesize = filesize % 1048576;
            }

            if (filesize >= 1024)
            {
                strFileSize += (filesize / 1024) + " KB ";
                filesize = filesize % 1024;
            }
            strFileSize += filesize + " B ";

            return strFileSize;
        }

    }
}


Ana Launcher Kodlarımız :

 
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;
using Ionic.Zip;//.zip uzantılı dosyaları açmamıza yarıyan metotların bulunduğu Namespaceimiz.

namespace ProgramUpdateLauncher
{
    public partial class frmLauncher : Form
    {
        public frmLauncher()
        {
            InitializeComponent();
            CheckForIllegalCrossThreadCalls = false;
        }

        private Socket clientSocket;//Client soketimiz
        byte[] buffer = new byte[1024];//Gelen mesajları tutacağımız bufferımız

        /*
           ~cv~ : Check Version
           * ~cv~cmp : Version Complete
           * ~cv~upt : Version Update
           * ~cv~err : Version Error
           ~nv~ : New Version 
           ~pn~ : Patch Name
           */

        private void frmLauncher_Load(object sender, EventArgs e)
        {


            try
            {
                clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//Client soketimizi oluşturuyoruz
                clientSocket.Bind(new IPEndPoint(IPAddress.Any, 0));//Ve kendisine bağlıyoruz
                string strServerIPAddress = Functions.ReadIniFile("ServerInfo", "ServerIP");//İniden serverın ismini okuyoruz

                clientSocket.BeginConnect(strServerIPAddress, 4407, new AsyncCallback(StartConnect), null);//Servera bağlanmaya çalışıyoruz.Bağlandığımızda StartConnect metodu çalışacak
            }
            catch (Exception exception)
            {
                EventsLog("Not connect to server", "err");
            }
        }
        public void EventsLog(string data, string type)
        {
            if (type == "err")
            {
                ListViewItem listViewItem = new ListViewItem(data + " " + DateTime.Now.ToShortDateString());
                listViewItem.SubItems[0].ForeColor = Color.Red;
                lstActions.Items.Add(listViewItem);
                lblState.Text = data;;
            }
            else if (type == "scc")
            {
                ListViewItem listViewItem = new ListViewItem(data + " " + DateTime.Now.ToShortDateString());
                listViewItem.SubItems[0].ForeColor = Color.Green;
                lstActions.Items.Add(listViewItem);
                lblState.Text = data;
            }
        }

        void StartConnect(IAsyncResult asyncResult)
        {
            if (!clientSocket.Connected)//Client bağlanmamışsa bağlanmayı tekrar deniyoruz
            {
                EventsLog("Not connect to server", "err");
                string strServerIPAddress = Functions.ReadIniFile("ServerInfo", "ServerIP");
                clientSocket.BeginConnect(strServerIPAddress, 4407, new AsyncCallback(StartConnect), null);
                Thread.Sleep(5000);
            }
            else//servera bağlı ise
            {

                EventsLog("Connection to the server was provided", "scc");
                string version = Functions.ReadIniFile("ServerInfo", "Version");//İni dosyasından launcherın en sonn yüklediği sürümünü indiriyoruz
                clientSocket.Send(Functions.StringToByte("~cv~" + version));//Ve sürüm ile beraber komutumuzu gönderiyoruz
                /*
                 Server bize yanıt olarak launcherın durumunu göndericek. 
                 */

                EventsLog("Checking Version...", "scc");
                Clear();
                clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveAction), null);
                /*
                 Serverdan gelecek mesajları asenkron beklemeye başlıyoruz bir mesaj geldiğinde ReceiveAction metodu çalışacak
                 */
            }
        }
        void ReceiveAction(IAsyncResult asyncResult)
        {
            int bufferLen = clientSocket.EndReceive(asyncResult);//EndReceive metodu bize gelen mesajın boyutunu geri döndürür.

            string data = Functions.StringFromByte(buffer, bufferLen);//Mesajı ayıklıyoruz
            string command = data.Substring(0, 4);//Mesajdan Komut bölümünü ayırıyoruz
            string content = data.Substring(4);//Mesajın kalanını alıyoruz
            switch (command)
            {
                case "~cv~"://Gelen komut ~cv~ CheckVersion ise
                    EventsLog("Acquiring Version", "scc");
                    string checkCommand = content.Substring(0, 3);
                    /*
                     Gönderdiğimiz komut ~cv~upt (Güncellenmesi Lazım) veya ~cv~cmp (Son Sürüm) veya ~cv~err (Hata) şeklindedir.
                     ~cv~ dan sonraki 3 harfi alıyoruz.
                     */
                    switch (checkCommand)
                    {
                        case "cmp"://Eğer cmp yani Son sürüm ise Start butonunu aktif hale getirip ve progress barı dolduruyoruz
                            EventsLog("Login can be done", "scc");

                            prgState.Style = ProgressBarStyle.Continuous;
                            prgState.Value = 100;
                            btnStart.Enabled = true;
                            break;
                        case "upt"://Eğer upt yani Güncellenmesi Lazım ise 
                            EventsLog("Found in the new version", "scc");
                            string filename = content.Substring(content.IndexOf("~pn~") + 4);//İndirilecek dosyanın adını alıyoruz
                            string nextVersion = content.Substring(content.IndexOf("~nv~") + 4, (content.IndexOf("~pn~") - (content.IndexOf("~nv~") + 4)));//Yeni sürümümüzü alıyoruz
                            FtpWebRequest FTP;

                            string ftpurl = Functions.ReadIniFile("FTP", "URL");//İni dosyamızdan FTP adrenisi çekiyoruz

                            try
                            {
                                FileStream SR = new FileStream(Application.StartupPath + "\\" + filename, FileMode.Create);
                                // Dosyanın alınacağı ftp yolunu belirliyoruz
                                FTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(ftpurl + "/" + filename));
                                // Ftp bağlantısı için UserName ve Şifremizi belirtiyoruz
                                FTP.Credentials = new NetworkCredential("UurDemir", "");
                                // Bu kısımda hangi işlemi yapacağımızı belirtiyoruz, dosya göndereceğimiz için UploadFile methodunu seçiyoruz
                                FTP.Method = WebRequestMethods.Ftp.DownloadFile;
                                // Dosya tranferinin Binary türden yapılacağını belirtiyoruz
                                FTP.UseBinary = true;
                                // Dosya transfer bilgilerini FtpWebResponse türüne çeviriyoruz               
                                FtpWebResponse response = (FtpWebResponse)FTP.GetResponse();
                                // Çevirdiğimiz bilgileri kendi PC'miz için dosya oluşturacak Stream'e eşitliyoruz
                                Stream ftpStream = response.GetResponseStream();
                                // Dosya boyutunu belirtiyoruz
                                long cl = response.ContentLength;
                                // Buffer büyüklüğünü 2KB olarak belirtiyoruz ve değişkenimizi tanımlıyoruz
                                int bufferSize = 2048;
                                int readCount;

                                // Bu kısımda dosyayı binary'e çevirip ftp'den çekiyoruz
                                byte[] ftpbuffer = new byte[bufferSize];
                                readCount = ftpStream.Read(ftpbuffer, 0, bufferSize);

                                EventsLog("Downloading... " + filename, "scc");
                                while (readCount > 0)//Dosyayı okumaya başlıyoruz
                                {
                                    SR.Write(ftpbuffer, 0, readCount);//Okuduğumuz veriyi streame yazıyoruz
                                    lblState.Text = "Downloading... " + Functions.CalculateFileSize(SR.Length);
                                    readCount = ftpStream.Read(ftpbuffer, 0, bufferSize);//Tekrar okuyoruz
                                }
                                ftpStream.Close();
                                SR.Close();
                                response.Close();
                                EventsLog("Dowload Complete... " + filename, "scc");
                                EventsLog("Extracting... " + filename, "scc");
                                using (var zip = ZipFile.Read(filename))//Ionic.Zip namespaceinden gelen ZipFile.Read metoduna zip dosyamızın dosya yolunu verdik
                                {
                                    zip.ExtractAll(Application.StartupPath, ExtractExistingFileAction.OverwriteSilently);//.zip Dosyasını eğer aynısı varsa üzerine yazacak şekilde açıyoruz
                                }
                                File.Delete(Application.StartupPath + "\\" + filename);//Ve .zip dosyamız ile işimiz bitince siliyoruz
                                EventsLog("Extract Complete... " + filename, "scc");
                                Functions.WriteIniFile("ServerInfo", "Version", nextVersion);
                                clientSocket.Send(Functions.StringToByte("~cv~" + nextVersion));//Ve tekrar yeni sürüm var mı diye Servera mesaj atıyoruz

                                EventsLog("Checking Version...", "scc");
                            }
                            catch (Exception exception)
                            {
                                EventsLog(exception.Message, "err");
                            }

                            break;
                        case "err"://Eğer sürüm uyumlu değilse hata gönderiyoruz
                            EventsLog("An error has occurred", "scc");
                            break;
                    }
                    break;
            }
            Clear();

            clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveAction), null);//Ve serverdan gelecek verileri tekrardan okumaya başlıyoruz
        }

        void Clear()
        {
            buffer = new byte[1024];
        }

        private void frmLauncher_FormClosed(object sender, FormClosedEventArgs e)
        {
            clientSocket.Close();//Form kapatılırken soketide kapatıyoruz.
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            //Ana programı başlatağımız komutları yazıyoruz
            ProcessStartInfo startInfo = new ProcessStartInfo();
            startInfo.FileName = Application.StartupPath + "\\MainProgram.exe";//.exe nin yolunu belirtiyoruz
            startInfo.Arguments = "-startApp";//Program sadece bizden gelecek paramaetreye göre çalıştığı için ona göndericeğimiz parametreyi yazıyoruz.
            Process.Start(startInfo);//Ve programı başlatıyoruz
            this.Close();//Launcherı kapatıyoruz
        }
    }
}

 

 Projeyi ve gerekli dosyaları buradan indirebilirsiniz...
https://hotfile.com/dl/173801879/e1a9856/ShareFiles.rar.html