Article by Ayman Alheraki on January 11 2026 10:36 AM
In recent years, there has been a noticeable shift away from traditional desktop applications in favor of web-based solutions within enterprise networks. This trend is often attributed to the perceived complexities of managing desktop software updates, especially in environments with numerous workstations. However, desktop applications still offer significant advantages in terms of performance, control, and offline capabilities.
One of the primary challenges associated with desktop applications is the process of distributing updates to a large number of workstations. This can be a time-consuming and error-prone task, particularly when dealing with complex software installations and configurations. Additionally, coordinating updates can be difficult, especially when users are working remotely or during critical business operations.
To address these challenges, we propose a solution that leverages a central server to manage the distribution of desktop application updates. Here's a breakdown of how this approach works:
Small Update Client: A lightweight application is installed on each workstation. This client's sole purpose is to periodically check the central server for updates.
Central Database: The server maintains a database containing information about the latest version of the application, along with the necessary installation files.
Update Process: When the client detects a new version, it downloads the update files and installs them automatically, replacing the older version.
Remote Access: For remote users, a secure remote desktop protocol can be implemented, allowing them to connect to their workstations and access the updated application. Alternatively, a web-based interface can be provided for specific functionalities.
Simplified Updates: Automated updates eliminate the need for manual intervention, saving IT administrators time and effort.
Centralized Management: All updates are managed from a central location, ensuring consistency and reducing the risk of errors.
Improved Security: By automatically applying security patches and updates, organizations can reduce their vulnerability to cyberattacks.
Enhanced User Experience: Users always have access to the latest version of the application, without any manual intervention.
Cost-Effective: This approach can be more cost-effective than relying on cloud-based solutions, especially for organizations with significant on-premises IT infrastructure.
By implementing an automated update system for desktop applications, organizations can reap the benefits of both desktop and web-based applications. This approach offers a flexible and scalable solution that addresses the challenges associated with managing software updates in enterprise environments.
Key Considerations:
Security: Implement robust security measures to protect the central server and communication channels.
Compatibility: Ensure that the update mechanism is compatible with the operating systems and hardware used in the organization.
User Experience: Design the update process to be as seamless as possible, minimizing disruption to users.
By carefully considering these factors, organizations can successfully deploy and maintain desktop applications that meet their specific needs.
Example using C++Builder for a real project :
xxxxxxxxxx//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
TFlogin *Flogin; AnsiString msgSMS = ""; AnsiString vLast4Digits = "";
//---------------------------------------------------------------------------__fastcall TFlogin::TFlogin(TComponent* Owner) : TForm(Owner){SystemParametersInfo(SPI_SETBEEP, FALSE, NULL, 0); // turn of the beep
}//---------------------------------------------------------------------------void __fastcall TFlogin::btnLogInClick(TObject *Sender){
if(txtApproved->Visible == false ) {
FMain->vLogInStatus = 0; WideString strS = ""; strS += "Select * From users WHERE userLogID='" + txtUserLogID->Text.Trim(); strS += "' AND userLogPassword='" + StringToHex(AnsiString(txtUserPassword->Text).c_str()); strS += "' AND userActive=1";
TMSQuery *Qc = new TMSQuery(this); if(MSSelectQ(strS,Qc, FMain->connDB)==0) return;
if( Qc->RecordCount == 0 ) { errorFlag = errorFlag + 1; lblMemo->Caption = ""; lblMemo->Font->Color = clRed; AnsiString lbb = "اسم المستخدم أو الرقم السري غير صحيح"; lblMemo->Caption = lbb;
FMain->vLogInStatus = 0;
if(errorFlag > 3) { Application->Terminate(); } else { return; } } else { if(FMain->IdNetworkCalculator1->IsAddressInNetwork(FMain->IdIPWatch1->LocalIP()) != true) { AnsiString vUserID = Qc->FieldByName("userID")->AsString; AnsiString vUserMobile = Qc->FieldByName("userMobile")->AsString; AnsiString vUserName = Qc->FieldByName("userFullName")->AsString; AnsiString vUserLogID = txtUserLogID->Text.Trim(); if(Qc->FieldByName("userSMS")->AsInteger == 0) { txtApproved->Visible = true; lblApproved->Visible = true; txtApproved->SetFocus();
long int rnd = RandomRange(1000,9999); vRandomNum = AnsiString(rnd); vLast4Digits = vUserMobile.SubString(7,4); AnsiString msgSMS = vRandomNum;
TStringList *memAll = new TStringList(); memAll->Add("userID=" + vUserID ); memAll->Add("userMobile=" + vUserMobile ); memAll->Add("msg=" + msgSMS); memAll->Add("userLogID=" + vUserLogID); IdHTTP1->Request->ContentType = "application/x-www-form-urlencoded"; IdHTTP1->Request->CharSet = "UTF-8"; IdHTTP1->ConnectTimeout = 20000; IdHTTP1->ReadTimeout = 20000;
WideString Resp = IdHTTP1->Post("http://0.0.0.0:9000/PasswordSMS",memAll); FMain->vUserID = Qc->FieldByName("userID")->AsInteger; FMain->vUserLogID = Qc->FieldByName("userLogID")->AsAnsiString; FMain->vUserPassword = Qc->FieldByName("userLogPassword")->AsAnsiString; UpdateRegKey("UserLogID",txtUserLogID->Text.Trim()); Timer1->Enabled = true; lblTime->Caption = 60; start = GetTickCount(); } else { FMain->vUserID = Qc->FieldByName("userID")->AsInteger; FMain->vUserLogID = Qc->FieldByName("userLogID")->AsAnsiString; FMain->vUserPassword = Qc->FieldByName("userLogPassword")->AsAnsiString; UpdateRegKey("UserLogID",txtUserLogID->Text.Trim()); FMain->vLogInStatus = 1; this->Close(); } } else if(FMain->IdNetworkCalculator1->IsAddressInNetwork(FMain->IdIPWatch1->LocalIP()) == true) { FMain->vUserID = Qc->FieldByName("userID")->AsInteger; FMain->vUserLogID = Qc->FieldByName("userLogID")->AsAnsiString; FMain->vUserPassword = Qc->FieldByName("userLogPassword")->AsAnsiString; UpdateRegKey("UserLogID",txtUserLogID->Text.Trim()); AnsiString vUserID = Qc->FieldByName("userID")->AsString; AnsiString vUserMobile = Qc->FieldByName("userMobile")->AsString; AnsiString vUserName = Qc->FieldByName("userFullName")->AsString; AnsiString vUserLogID = txtUserLogID->Text.Trim();
if(Qc->FieldByName("userSMS")->AsInteger == 0) {
AnsiString SQLSTR = " SELECT usersLogInActions.userID "; SQLSTR += " FROM usersLogInActions "; SQLSTR += " where "; SQLSTR += " Convert(date,actionTime) = Convert(date,getDate()) "; SQLSTR += " AND usersLogInActions.userID = " + FMain->vUserID + " and inout = 1 "; SQLSTR += " AND substring(usersLogInActions.userIP,1,3) = '172' ";
TMSQuery *Q1 = new TMSQuery(this); if(MSSelectQ(SQLSTR,Q1, FMain->connDB)==0) return;
if(Q1->RecordCount == 0) { FMain->vLogInStatus = 1; this->Close(); } else { FMain->vLogInStatus = 1; this->Close(); } } else { FMain->vLogInStatus = 1; this->Close(); }
} } } else { if(txtApproved->Visible == true && txtApproved->Text.Length() == 0) { ShowMessageA("الرجاء إدخال رمز التفعيل المرسل لك "); return; } if(txtApproved->Visible == true && txtApproved->Text.Length() > 0) { if(txtApproved->Text.Trim() == vRandomNum ) {
FMain->vLogInStatus = 1; this->Close();
} else { errorFlag = errorFlag + 1; lblMemo->Caption = ""; lblMemo->Font->Color = clRed; AnsiString lbb = "رمز التفعيل المدخل غير صحيح"; lblMemo->Caption = lbb;
FMain->vLogInStatus = 0;
if(errorFlag > 3) { Application->Terminate(); } else { return; }
} } }
}//---------------------------------------------------------------------------void __fastcall TFlogin::txtUserLogIDKeyPress(TObject *Sender, System::WideChar &Key)
{ if(Key == 13) { txtUserPassword->SetFocus(); }}//---------------------------------------------------------------------------
void __fastcall TFlogin::txtUserPasswordKeyPress(TObject *Sender, System::WideChar &Key)
{ if(Key == 13) { btnLogInClick(Sender); }}//---------------------------------------------------------------------------void __fastcall TFlogin::FormShow(TObject *Sender){
if (PixelsPerInch != 96) { ScaleBy(96, PixelsPerInch); }
FMain->vLogInStatus = 0; txtUserPassword->SetFocus(); if(ReadRegistry("UserLogID") != "0") { txtUserLogID->Text = ReadRegistry("UserLogID"); }
if(txtUserLogID->Text == "") { txtUserLogID->Text = ""; txtUserPassword->Text = ""; lblMemo->Caption = "يمكن تغيير الرقم السري من قائمة المساعدة"; }
}//---------------------------------------------------------------------------void __fastcall TFlogin::btnExitClick(TObject *Sender){ FMain->vLogInStatus = 0; Application->Terminate();}//---------------------------------------------------------------------------
void __fastcall TFlogin::btnGetPasswordClick(TObject *Sender){ AnsiString vLast4Digits = ""; if(txtUserLogID->Text.Trim().Length() < 10 || IsDigit(txtUserLogID->Text.Trim(),1) == false) { ShowMessageA("الرجاء التأكد من إدخال رقم الهوية بشكل صحيح"); txtUserLogID->SetFocus(); return; } else { WideString strS = "Select * From users WHERE userLogID='" + txtUserLogID->Text.Trim() + "' AND userActive=1"; TMSQuery *Qc = new TMSQuery(this); if(MSSelectQ(strS,Qc, FMain->connDB)==0) return; if(Qc->RecordCount == 1) { AnsiString vUserID = Qc->FieldByName("userID")->AsString; AnsiString vUserMobile = Qc->FieldByName("userMobile")->AsString; AnsiString vUserName = Qc->FieldByName("userFullName")->AsString; AnsiString vUserLogID = txtUserLogID->Text.Trim();
long int rnd = RandomRange(100000,999999); AnsiString vRandomNum = AnsiString(rnd); vLast4Digits = vUserMobile.SubString(7,4);
AnsiString msgSMS = vRandomNum;
TStringList *memAll = new TStringList(); memAll->Add("userID=" + vUserID ); memAll->Add("userMobile=" + vUserMobile ); memAll->Add("msg=" + vRandomNum); memAll->Add("userLogID=" + vUserLogID);
IdHTTP1->Request->ContentType = "application/x-www-form-urlencoded"; IdHTTP1->Request->CharSet = "UTF-8"; IdHTTP1->ConnectTimeout = 20000; IdHTTP1->ReadTimeout = 20000;
WideString Resp = ""; if(FMain->IdNetworkCalculator1->IsAddressInNetwork(FMain->IdIPWatch1->LocalIP()) == true) { Resp = IdHTTP1->Post("http://0.0.0.0:9000/PasswordSMS",memAll); } else { Resp = IdHTTP1->Post("http://0.0.0.0:9000/PasswordSMS",memAll); }
if(Resp.Trim() == "200") { WideString strS = "UPDATE Users set userLogPassword='" + StringToHex(vRandomNum.c_str()) + "' WHERE userID=" + vUserID; MSCommandSQL(strS, FMain->connDB); } else { WideString msgErr = "فشل النظام في إرسال الرقم السري - الرجاء المحاولة مرة أخرى بعد التأكد من الاتصال بالانترنت"; ShowMessageA(msgErr); }
WideString msg1 = "تم إرسال الرقم السري الجديد لرقم الجوال الذي نهايته \n "; msg1 += vLast4Digits ;
ShowMessageA(msg1);
} else { ShowMessageA("----"); } }
}//---------------------------------------------------------------------------
void __fastcall TFlogin::Timer1Timer(TObject *Sender){ AnsiString tt = (lblTime->Caption.ToInt() - 1); lblTime->Caption = tt; if(tt < 0) Application->Terminate();}//---------------------------------------------------------------------------