Kiriman ini adalah kelanjutan dari bagian pertama artikel di Habré , di mana ia dijelaskan secara rinci tentang menyebarkan tumpukan Django pada MS Windows. Selanjutnya, kami akan memberikan petunjuk langkah demi langkah untuk membuat penginstal yang akan mengotomatiskan proses penginstalan tumpukan di komputer lain tanpa perlu bekerja di baris perintah, membuat mesin virtual, dll., Di mana seluruh urutan tindakan akan dikurangi menjadi tindakan Berikutnya -> Berikutnya -> Selesai.
Jadi apa yang harus dilakukan penginstal:
- Buka paket semua program dan komponen yang diperlukan ke dalam direktori yang ditentukan oleh pengguna.
- Lakukan pemeriksaan pra-instalasi.
- Daftarkan interpreter Python di registri Windows.
- Instal, jika belum diinstal, pustaka ketergantungan perangkat lunak.
- Buat layanan Apache dan PostgreSQL, lalu mulai.
- Nilai tambah tambahannya adalah pembuatan otomatis program uninstaller yang akan menghapus tumpukan yang diinstal jika pengguna menginginkannya.
Di antara opsi yang memungkinkan untuk penginstal, kami akan memilih penginstal gratis Inno Setup, karena ini memungkinkan Anda melakukan semua hal di atas, memungkinkan Anda membuat installer tanpa harus menjalankan banyak skrip. Dibandingkan dengan Wix, sintaks file setup adalah format ini, yang lebih mudah dibaca dan diubah daripada xml. Saat ini ia bersaing dengan dan bahkan melampaui banyak pemasang komersial dalam set fitur dan stabilitas.
Yang terbaik dari semuanya, tidak diperlukan skrip sama sekali untuk membuat penginstal dasar, karena Inno Setup dilengkapi dengan wizard grafis yang secara mengejutkan melakukan pekerjaan yang sangat baik untuk penginstal dasar.
Logika penginstalan dapat ditulis dalam Pascal daripada tindakan kustom yang berbelit-belit di Wix. Satu-satunya kelemahan adalah hanya membuat exe, format file msi tidak didukung.
Langkah 1. Tidak Ada Instalasi Pengaturan
Komentar tambahan tidak diperlukan di sini, karena mengunduh dan menginstal program penginstal itu sepele.
Langkah 2: Membuat Skrip Instalasi Pengaturan Inno
Mari buat sebuah rintisan Inno Setup script (file * .iss) menggunakan Wizard Script Instalasi.
Hasilnya, file * .iss akan dibuat dengan konten berikut:
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "Severcart"
#define MyAppVersion "1.21.0"
#define MyAppPublisher "Severcart Inc."
#define MyAppURL "https://www.severcart.ru/"
[Setup]
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{4FAF87DC-4DBD-42CE-A2A2-B6D559E76BDC}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName=c:\severcart
DefaultGroupName={#MyAppName}
; Uncomment the following line to run in non administrative install mode (install for current user only.)
;PrivilegesRequired=lowest
OutputDir=C:\Users\Developer\Desktop\Output
OutputBaseFilename=mysetup
Compression=lzma
SolidCompression=yes
WizardStyle=modern
[Languages]
Name: "russian"; MessagesFile: "compiler:Languages\Russian.isl"
[Files]
Source: "C:\severcart\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
Langkah 3. Pemeriksaan sebelum instalasi
Sebelum membongkar program ke direktori dan mengubah registri, Anda perlu memeriksa apakah port TCP gratis agar Apache dan PostgreSQL berfungsi, Anda juga perlu memeriksa persyaratan sistem minimum Windows, karena Seperti yang telah disebutkan di bagian pertama artikel ini, versi Python yang terinstal hanya akan berfungsi mulai dari versi MS Windows 8 (kernel versi 6.2) .
Untuk melakukan pemeriksaan yang diperlukan, mari gunakan bagian [Kode] dari file instalasi. [Kode] bagianMerupakan bagian opsional yang mendefinisikan skrip Pascal. Skrip Pascal dapat digunakan untuk menyesuaikan instalasi atau penghapusan instalasi dengan berbagai cara. Perhatikan bahwa membuat skrip Pascal tidaklah mudah dan membutuhkan pengalaman dengan Inno Setup dan keterampilan pemrograman di Pascal atau setidaknya bahasa pemrograman yang serupa. Untuk memeriksa ketersediaan port TCP, kami akan membuat fungsi berikut: Kami akan memanggil fungsi pengujian di fungsi InitializeSetup , yang dipanggil selama inisialisasi instalasi. Mengembalikan False untuk membatalkan penginstalan, jika tidak, True .
function IsWindowsVersionOrNewer(Major, Minor: Integer): Boolean;
var
Version: TWindowsVersion;
begin
GetWindowsVersionEx(Version);
Result := (Version.Major > Major) or ((Version.Major = Major) and (Version.Minor >= Minor));
end;
function IsWindows8OrNewer: Boolean;
begin
Result := IsWindowsVersionOrNewer(6, 2);
end;
function CheckPortOccupied(Port:String):Boolean;
var
ResultCode: Integer;
begin
Exec(ExpandConstant('{cmd}'), '/C netstat -na | findstr'+' /C:":'+Port+' "', '',0,ewWaitUntilTerminated, ResultCode);
if ResultCode <> 1 then
begin
Log('this port('+Port+') is occupied');
Result := True;
end else
begin
Result := False;
end;
end;
function InitializeSetup(): Boolean;
var
port_80_check, port_5432_check: boolean;
begin
if not IsWindows8OrNewer() then begin
MsgBox(' . Windows 2012 Windows 8.0.',mbError,MB_OK);
Abort();
Result := False;
end;
port_80_check := CheckPortOccupied('8080');
if port_80_check then begin
MsgBox(' . TCP 8080 .',mbError,MB_OK);
Abort();
Result := False;
end;
port_5432_check := CheckPortOccupied('5432');
if port_5432_check then begin
MsgBox(' . TCP 5432 .',mbError,MB_OK);
Result := False;
Abort();
end;
Result := True;
Langkah 4. Daftarkan Python di registri Windows
Bagian opsional ini menentukan kunci / nilai registri yang harus dibuat atau dimodifikasi oleh penginstal pada sistem pengguna.
Untuk melakukan ini, tambahkan kunci PYTHONPATH dan PYTHONHOME dan perbarui variabel Path .
sys.path berisi daftar string yang menyediakan lokasi pencarian untuk modul dan paket untuk proyek Python di masa mendatang. Ini diinisialisasi dari variabel lingkungan PYTHONPATH dan pengaturan lainnya.
PYTHONHOME adalah direktori home Python.
PATH adalah variabel lingkungan yang digunakan OS untuk menemukan file yang dapat dieksekusi di baris perintah atau jendela terminal.
[Registry]
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \
ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};{app}\python;{app}\python\Scripts"
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \
ValueType: expandsz; ValueName: "PYTHONPATH"; ValueData: "{app}\python"
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \
ValueType: expandsz; ValueName: "PYTHONHOME"; ValueData: "{app}\python"
Langkah 5. Buat file konfigurasi untuk layanan Apache dan PostgreSQL
Untuk membuat file konfigurasi, kami akan menggunakan 2 skrip Python yang akan menghasilkan konfigurasi berdasarkan jalur instalasi yang ditentukan pengguna.
Skrip akan dipanggil di bagian [Jalankan] dari penginstal.
Bagian [Run] adalah opsional dan menentukan sejumlah program untuk dijalankan setelah program berhasil diinstal, tetapi sebelum penginstal menampilkan kotak dialog terakhir.
Selanjutnya, di bagian yang sama, tambahkan penginstalan tersembunyi Paket Visual Studio Redistributable yang tanpanya layanan Apache dan PostgreSQL tidak akan berfungsi. Isi dari file create_http_conf.py
[Run]
Filename: "{app}\common\VC_redist.x86apache.exe"; Parameters: "/install /passive"; Flags: waituntilterminated
Filename: "{app}\common\vcredist_x86pg.exe"; Parameters: "/install /passive"; Flags: runhidden;
Filename: "{app}\python\python.exe" ;Parameters: "{app}\common\create_http_conf.py"; Flags: runhidden
Filename: "{app}\python\python.exe" ;Parameters: "{app}\common\edit_pg_conf.py"; Flags: runhidden
Filename: "{app}\common\install.bat";Flags: runhidden
Filename: "{app}\common\services_start.bat"; Flags: runhidden
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import sys, os
base_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
base_path_un = base_path.replace('\\', '/')
apache_conf_path = os.path.join(base_path, 'Apache24', 'conf', 'extra', 'httpd-wsgi.conf')
print('base_path=',base_path)
CONF = """
LoadFile "%(base)s/python/python39.dll"
LoadModule wsgi_module "%(base)s/python/lib/site-packages/mod_wsgi/server/mod_wsgi.cp39-win32.pyd"
WSGIPythonHome "%(base)s/python"
Alias /static "%(base)s/app/static"
Alias /media "%(base)s/app/media"
<Directory "%(base)s/app/static">
# for Apache 2.4
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
<Directory "%(base)s/app/media">
# for Apache 2.4
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
WSGIScriptAlias / "%(base)s/app/conf/wsgi_prod.py"
WSGIPythonPath "%(base)s/python/"
<Directory "%(base)s/app/conf/">
<Files wsgi_prod.py>
Require all granted
</Files>
</Directory>
"""
conf_content = CONF % {'base': base_path_un}
with open(apache_conf_path, 'w') as fp:
fp.write(conf_content)
# Read in the file
apache_main = os.path.join(base_path, 'Apache24', 'conf', 'httpd.conf')
with open(apache_main, 'r') as file :
filedata = file.read()
# Replace the target string
replace_pattern = 'Define SRVROOT "%(base)s/Apache24"' % {'base' : base_path_un}
find_pattern = 'Define SRVROOT "C:/severcart/Apache24"'
filedata = filedata.replace(find_pattern, replace_pattern)
# Write the file out again
with open(apache_main, 'w') as file:
file.write(filedata)
Konten edit_pg_conf.py
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import sys, os
"""
c:/djangostack/postgresql/bin/postgres.exe "-D" "c:\djangostack\postgresql\data"
"""
base_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
base_path_un = base_path.replace('\\', '/')
pg_conf_path = os.path.join(base_path, 'postgresql', 'data', 'postmaster.opts')
# Read in the file
pg_conf_path = os.path.join(base_path, 'postgresql', 'data', 'postmaster.opts')
with open(pg_conf_path, 'r') as file :
filedata = file.read()
# Replace the target string
replace_pattern = base_path_un + '/'
find_pattern = "C:/severcart/"
filedata = filedata.replace(find_pattern, replace_pattern)
# Write the file out again
with open(pg_conf_path, 'w') as file:
file.write(filedata)
File install.bat Berisi file services_start.bat
@echo off
..\Apache24\bin\httpd.exe -k install -n "Apache" > install.log 2>&1
..\postgresql\bin\pg_ctl.exe register -N "PostgreSQL" -D ..\postgresql\data > install.log 2>&1
@echo off
net start "Apache"
net start "PostgreSQL"
Langkah 6: Buat uninstaller
Untuk penginstal apa pun, Anda juga perlu menyediakan kemungkinan membuat program uninstaller. Untungnya, Inno Setup akan melakukan pekerjaan itu untuk kita, kecuali beberapa langkah yang perlu diambil untuk membersihkan jejak kehadiran program di OS.
Untuk melakukan ini, di bagian [UninstallRun] , kami akan mendaftarkan eksekusi skrip bat Windows untuk menghentikan layanan yang diinstal, serta menghapusnya. Isi skrip bat: Skrip menghentikan layanan, lalu menghapus layanan Apache dan PostgreSQL dari daftar layanan sistem Windows.
[UninstallRun]
Filename: "{app}\common\remove.bat"; Flags: runhidden
@echo off
SC STOP Apache
SC STOP PostgreSQL
SC DELETE Apache
SC DELETE PostgreSQL
Langkah 7. Menandatangani file yang dapat dijalankan dari penginstal ES pengembang
Sertifikat penandatanganan kode digunakan oleh pengembang perangkat lunak untuk menandatangani aplikasi dan program secara digital untuk membuktikan bahwa file yang diunggah oleh pengguna adalah asli dan tidak dirusak. Hal ini sangat penting terutama bagi penerbit yang mendistribusikan perangkat lunak mereka melalui situs unduhan pihak ketiga yang tidak dapat mereka kendalikan. Sistem operasi utama akan menampilkan pesan kesalahan kepada pengguna akhir jika perangkat lunak yang mereka coba instal tidak ditandatangani oleh otoritas sertifikasi tepercaya.
Anda dapat membeli sertifikat pengembang PFX, misalnya, di sini . Sertifikat dibeli selama satu tahun.
Langkah terakhir untuk bekerja dengan penginstal adalah secara otomatis meluncurkan program signtool.exe untuk menandatangani penginstal yang sudah selesai dalam format exe setelah program Pengaturan Inno menyelesaikan pekerjaannya. SignTool adalah program baris perintah yang menandatangani file secara digital, memverifikasi tanda tangan file dan cap waktu file. Secara default, program signtool.exe tidak disertakan dalam distribusi Windows, jadi kami mengunduh dan menginstal SDK Windows 10 .
Setelah penginstalan selesai, Anda akan menemukan signtool.exe di direktori:
- x86 -> c: \ Program Files (x86) \ Windows Kits \ 10 \ bin \ x86 \
- x64 -> c: \ Program Files (x86) \ Windows Kits \ 10 \ bin \ x64 \
Bagi mereka yang ingin mengenal program penandatanganan, kunjungi situs web resmi pengembang untuk lebih jelasnya . Ini mencantumkan semua opsi baris perintah dan contoh penggunaan. Ayo lanjutkan.
Selanjutnya, mari kita siapkan penandatanganan file secara otomatis. Pilih "Configure Sign Tools ..." dari menu "Tools" .
Selanjutnya, klik pada tombol "Add"
Beri nama alat tersebut. Ini adalah nama yang akan Anda gunakan saat merujuk ke alat di skrip penginstal. Saya menamai saya signtool karena saya menggunakan signtool.exe.
Tempel teks yang Anda gunakan untuk menandatangani file yang dapat dieksekusi dari baris perintah. Ganti nama file yang akan ditandatangani dengan $ f. Inno Setup akan mengganti variabel $ f dengan file yang ditandatangani.
"C: \ Program Files (x86) \ Windows Kits \ 10 \ bin \ x86 \ signtool.exe" sign / f "C: \ MY_CODE_SIGNING.PFX" / t timestamp.comodoca.com/authenticode / p MY_PASSWORD $ f
Setelah menekan OK Anda sudah selesai mengkonfigurasi alat tanda tangan.
Mari tambahkan skrip berikut ke bagian [Setup] untuk menggunakan alat tanda tangan yang baru saja kita konfigurasikan. Ini mengasumsikan Anda menamai alat Anda signtool.
SignTool=signtool
Langkah 8. Merakit penginstal
File pemasang Final InnoSetup
#define MyAppName «Severcart»
#define MyAppVersion «1.21.0»
#define MyAppPublisher «Severcart Inc.»
#define MyAppURL «www.severcart.ru»
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
SignTool=signtool
AppId={{2CF113D5-B49D-47EF-B85F-AE06EB0E78EB}}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName=c:\severcart
DefaultGroupName={#MyAppName}
OutputBaseFilename=setup
Compression=lzma
SolidCompression=yes
ChangesEnvironment=yes
; Uninstall options
Uninstallable=yes
CreateUninstallRegKey=yes
;WizardSmallImageFile=logo3.bmp
[Icons]
Name: "{userdesktop}\severcart"; Filename: «127.0.0.1:8080/»
[Languages]
Name: «russian»; MessagesFile: «compiler:Languages\Russian.isl»
[Files]
Source: «C:\severcart\*»; Excludes: "*.pyc"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
[Registry]
Root: HKLM; Subkey: «SYSTEM\CurrentControlSet\Control\Session Manager\Environment»; \
ValueType: expandsz; ValueName: «Path»; ValueData: "{olddata};{app}\python;{app}\python\Scripts"
Root: HKLM; Subkey: «SYSTEM\CurrentControlSet\Control\Session Manager\Environment»; \
ValueType: expandsz; ValueName: «PYTHONPATH»; ValueData: "{app}\python"
Root: HKLM; Subkey: «SYSTEM\CurrentControlSet\Control\Session Manager\Environment»; \
ValueType: expandsz; ValueName: «PYTHONHOME»; ValueData: "{app}\python"
[Run]
Filename: "{app}\common\VC_redist.x86apache"; Parameters: "/install /passive"; Flags: waituntilterminated
Filename: "{app}\common\vcredist_x86pg"; Parameters: "/install /passive"; Flags: runhidden;
Filename: "{app}\python\python.exe" ;Parameters: "{app}\common\create_http_conf.py"; Flags: runhidden
Filename: "{app}\python\python.exe" ;Parameters: "{app}\common\edit_pg_conf.py"; Flags: runhidden
Filename: "{app}\common\install.bat";Flags: runhidden
Filename: "{app}\common\services_start.bat"; Flags: runhidden
[UninstallRun]
Filename: "{app}\common\remove.bat"; Flags: runhidden
[Code]
function IsWindowsVersionOrNewer(Major, Minor: Integer): Boolean;
var
Version: TWindowsVersion;
begin
GetWindowsVersionEx(Version);
Result :=
(Version.Major > Major) or
((Version.Major = Major) and (Version.Minor >= Minor));
end;
function IsWindows8OrNewer: Boolean;
begin
Result := IsWindowsVersionOrNewer(6, 2);
end;
function CheckPortOccupied(Port:String):Boolean;
var
ResultCode: Integer;
begin
Exec(ExpandConstant('{cmd}'), '/C netstat -na | findstr'+' /C:":'+Port+' "', '',0,ewWaitUntilTerminated, ResultCode);
if ResultCode <> 1 then
begin
Log('this port('+Port+') is occupied');
Result := True;
end else
begin
Result := False;
end;
end;
function InitializeSetup(): Boolean;
var
port_80_check, port_5432_check: boolean;
begin
if not IsWindows8OrNewer() then begin
MsgBox(' . Windows 2012 Windows 8.0.',mbError,MB_OK);
Abort();
Result := False;
end;
port_80_check := CheckPortOccupied('8080');
if port_80_check then begin
MsgBox(' . TCP 8080 .',mbError,MB_OK);
Abort();
Result := False;
end;
port_5432_check := CheckPortOccupied('5432');
if port_5432_check then begin
MsgBox(' . TCP 5432 .',mbError,MB_OK);
Result := False;
Abort();
end;
Result := True;
end;
#define MyAppVersion «1.21.0»
#define MyAppPublisher «Severcart Inc.»
#define MyAppURL «www.severcart.ru»
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
SignTool=signtool
AppId={{2CF113D5-B49D-47EF-B85F-AE06EB0E78EB}}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName=c:\severcart
DefaultGroupName={#MyAppName}
OutputBaseFilename=setup
Compression=lzma
SolidCompression=yes
ChangesEnvironment=yes
; Uninstall options
Uninstallable=yes
CreateUninstallRegKey=yes
;WizardSmallImageFile=logo3.bmp
[Icons]
Name: "{userdesktop}\severcart"; Filename: «127.0.0.1:8080/»
[Languages]
Name: «russian»; MessagesFile: «compiler:Languages\Russian.isl»
[Files]
Source: «C:\severcart\*»; Excludes: "*.pyc"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
[Registry]
Root: HKLM; Subkey: «SYSTEM\CurrentControlSet\Control\Session Manager\Environment»; \
ValueType: expandsz; ValueName: «Path»; ValueData: "{olddata};{app}\python;{app}\python\Scripts"
Root: HKLM; Subkey: «SYSTEM\CurrentControlSet\Control\Session Manager\Environment»; \
ValueType: expandsz; ValueName: «PYTHONPATH»; ValueData: "{app}\python"
Root: HKLM; Subkey: «SYSTEM\CurrentControlSet\Control\Session Manager\Environment»; \
ValueType: expandsz; ValueName: «PYTHONHOME»; ValueData: "{app}\python"
[Run]
Filename: "{app}\common\VC_redist.x86apache"; Parameters: "/install /passive"; Flags: waituntilterminated
Filename: "{app}\common\vcredist_x86pg"; Parameters: "/install /passive"; Flags: runhidden;
Filename: "{app}\python\python.exe" ;Parameters: "{app}\common\create_http_conf.py"; Flags: runhidden
Filename: "{app}\python\python.exe" ;Parameters: "{app}\common\edit_pg_conf.py"; Flags: runhidden
Filename: "{app}\common\install.bat";Flags: runhidden
Filename: "{app}\common\services_start.bat"; Flags: runhidden
[UninstallRun]
Filename: "{app}\common\remove.bat"; Flags: runhidden
[Code]
function IsWindowsVersionOrNewer(Major, Minor: Integer): Boolean;
var
Version: TWindowsVersion;
begin
GetWindowsVersionEx(Version);
Result :=
(Version.Major > Major) or
((Version.Major = Major) and (Version.Minor >= Minor));
end;
function IsWindows8OrNewer: Boolean;
begin
Result := IsWindowsVersionOrNewer(6, 2);
end;
function CheckPortOccupied(Port:String):Boolean;
var
ResultCode: Integer;
begin
Exec(ExpandConstant('{cmd}'), '/C netstat -na | findstr'+' /C:":'+Port+' "', '',0,ewWaitUntilTerminated, ResultCode);
if ResultCode <> 1 then
begin
Log('this port('+Port+') is occupied');
Result := True;
end else
begin
Result := False;
end;
end;
function InitializeSetup(): Boolean;
var
port_80_check, port_5432_check: boolean;
begin
if not IsWindows8OrNewer() then begin
MsgBox(' . Windows 2012 Windows 8.0.',mbError,MB_OK);
Abort();
Result := False;
end;
port_80_check := CheckPortOccupied('8080');
if port_80_check then begin
MsgBox(' . TCP 8080 .',mbError,MB_OK);
Abort();
Result := False;
end;
port_5432_check := CheckPortOccupied('5432');
if port_5432_check then begin
MsgBox(' . TCP 5432 .',mbError,MB_OK);
Result := False;
Abort();
end;
Result := True;
end;
Langkah 9. Memeriksa pekerjaan penginstal
Sekian terima kasih atas perhatiannya.