Skip to content

Commit 36071b2

Browse files
authored
Merge pull request #8 from AHS12/dev
(feat): Add MSI installer
2 parents 0792a57 + fc9ba76 commit 36071b2

File tree

8 files changed

+373
-7
lines changed

8 files changed

+373
-7
lines changed

assets/icon.ico

188 KB
Binary file not shown.

build/build.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Build Configuration
2-
VERSION=1.0.1
2+
VERSION=1.0.3
33
COMPANY_NAME=Click Guardian Project
44
PRODUCT_NAME=Click Guardian
55
DESCRIPTION=Prevents accidental double-clicks with configurable delay protection

build/windows/app-manifest.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
22
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
3-
<assemblyIdentity version="1.0.1.0" processorArchitecture="*" name="ClickGuardian" type="win32" />
3+
<assemblyIdentity version="1.0.3.0" processorArchitecture="*" name="ClickGuardian" type="win32" />
44
<!-- Application information -->
55
<description>Click Guardian - Double-Click Protection</description>
66
<!-- UAC settings - run as normal user -->

build/windows/app.rc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
ICON_ID ICON "app-icon.ico"
44

55
1 VERSIONINFO
6-
FILEVERSION 1,0,1,0
7-
PRODUCTVERSION 1,0,1,0
6+
FILEVERSION 1,0,3,0
7+
PRODUCTVERSION 1,0,3,0
88
FILEFLAGSMASK 0x3fL
99
#ifdef _DEBUG
1010
FILEFLAGS 0x1L
@@ -21,12 +21,12 @@ BEGIN
2121
BEGIN
2222
VALUE "CompanyName", "Click Guardian Project"
2323
VALUE "FileDescription", "Click Guardian - Double-Click Protection"
24-
VALUE "FileVersion", "1.0.1"
24+
VALUE "FileVersion", "1.0.3"
2525
VALUE "InternalName", "click-guardian"
2626
VALUE "LegalCopyright", "© 2025 Azizul hakim"
2727
VALUE "OriginalFilename", "click-guardian.exe"
2828
VALUE "ProductName", "Click Guardian"
29-
VALUE "ProductVersion", "1.0.1"
29+
VALUE "ProductVersion", "1.0.3"
3030
VALUE "Comments", "Prevents accidental double-clicks with configurable delay protection"
3131
END
3232
END

docs/INSTALLER_GUIDE.md

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
# 🛠️ Click Guardian — MSI Installer Guide
2+
3+
This guide shows how to create a **Windows MSI installer** for your `click-guardian.exe` using `go-msi`. This includes setting shortcuts, upgrade logic, and system integration.
4+
5+
---
6+
7+
## 📁 Project Structure
8+
9+
```
10+
click-guardian-installer/
11+
├── dist/
12+
│ └── click-guardian.exe # Compiled executable
13+
├── assets/
14+
│ └── icon.ico # Optional icon for shortcuts
15+
├── wix.json # MSI configuration
16+
```
17+
18+
---
19+
20+
## 🔧 Prerequisites
21+
22+
- ✅ Go installed and in `PATH`
23+
- ✅ Windows machine
24+
-**WiX Toolset** installed:
25+
```bash
26+
# Option 1: Download from official site
27+
# https://wixtoolset.org/releases/
28+
29+
# Option 2: Using Chocolatey
30+
choco install wixtoolset
31+
32+
# Option 3: Using winget
33+
winget install WiXToolset.WiXToolset
34+
```
35+
> ⚠️ **Important**: After installation, restart your terminal/command prompt to ensure WiX tools (`candle.exe` and `light.exe`) are in your PATH.
36+
37+
-`go-msi` installed:
38+
```bash
39+
go install github.com/mh-cbon/go-msi@latest
40+
```
41+
42+
---
43+
44+
## 📄 Step 1: Create `wix.json`
45+
46+
Create `wix.json` in the root of your installer folder:
47+
48+
```json
49+
{
50+
"product": "Click Guardian",
51+
"company": "Click Guardian Project",
52+
"version": "1.0.1",
53+
"license": "GPL-3.0",
54+
"upgrade-code": "d900466f-5e04-43c5-b7f4-cbeb7ce26bce",
55+
"product-code": "d900466f-5e04-43c5-b7f4-cbeb7ce26rce",
56+
"base": "dist",
57+
"items": ["click-guardian.exe"],
58+
"files": {
59+
"guid": "ea91758f-b81c-4384-8bbc-ddb21be99e96",
60+
"items": ["click-guardian.exe"]
61+
},
62+
"env": {
63+
"guid": "9779be66-6aea-41d9-a1e5-6657cdb98ea0",
64+
"vars": []
65+
},
66+
"shortcuts": {
67+
"guid": "8a69c043-2d46-4604-954c-648f667b2233",
68+
"items": [
69+
{
70+
"name": "Click Guardian",
71+
"description": "Click Guardian - Double-Click Protection",
72+
"target": "[INSTALLDIR]\\click-guardian.exe",
73+
"wdir": "DesktopFolder",
74+
"arguments": "",
75+
"icon": "../assets/icon.ico"
76+
},
77+
{
78+
"name": "Click Guardian",
79+
"description": "Click Guardian - Double-Click Protection",
80+
"target": "[INSTALLDIR]\\click-guardian.exe",
81+
"wdir": "ProgramMenuFolder",
82+
"arguments": "",
83+
"icon": "../assets/icon.ico"
84+
}
85+
]
86+
},
87+
"choco": {}
88+
}
89+
```
90+
91+
> 🔐 Generate GUIDs with:
92+
93+
```bash
94+
go-msi set-guid
95+
```
96+
97+
or use online tool like this: [https://www.guidgenerator.com/](https://www.guidgenerator.com/)
98+
99+
---
100+
101+
## 🏢 Step 2: Build the Installer
102+
103+
### Option 1: Automated Build (Recommended)
104+
105+
Use the automated release build script:
106+
107+
```bash
108+
scripts\release-build.bat
109+
```
110+
111+
This will:
112+
- ⚙️ Build the executable
113+
- 📎 Create portable ZIP package
114+
- 🔄 Copy icon from `assets/` folder
115+
- 📦 Generate MSI installer with shortcuts
116+
- 🧽 Clean up temporary files
117+
- 📁 List all created distribution files
118+
119+
### Option 2: Manual Build
120+
121+
From the project root, run:
122+
123+
```bash
124+
# Copy icon from assets (required for WiX)
125+
copy assets\icon.ico icon.ico
126+
127+
# Build MSI installer
128+
go-msi make --msi dist/click-guardian-installer.msi --version 1.0.1 --src templates
129+
130+
# Clean up
131+
del icon.ico
132+
```
133+
134+
### What gets created:
135+
136+
- 💻 **click-guardian.exe** - Standalone executable
137+
- 📎 **click-guardian-v1.0.1-windows-portable.zip** - Portable package
138+
- 📦 **click-guardian-installer.msi** - Windows installer with:
139+
- Desktop + Start Menu shortcuts
140+
- Add/Remove Programs entry
141+
- Start Menu search visibility
142+
- Custom icon from assets folder
143+
144+
---
145+
146+
## 🔁 Future Updates
147+
148+
To update the app:
149+
150+
- 🔁 Keep the same `upgrade-code`
151+
- 🆕 Change the `product-code`
152+
- ⬆️ Bump `version`
153+
- ✅ Rebuild `.msi`
154+
155+
Windows will automatically remove the previous version and install the new one.
156+
157+
---
158+
159+
## 🐛 Troubleshooting
160+
161+
### WiX Tools Not Found
162+
```
163+
CreateFile C:\Users\...\go\bin\templates: The system cannot find the file specified.
164+
```
165+
**Solution**: Install WiX Toolset and restart your terminal.
166+
167+
### Icon File Not Found
168+
```
169+
LGHT0103: The system cannot find the file 'icon.ico'.
170+
```
171+
**Solution**: Ensure `assets/icon.ico` exists and the build script copies it correctly.
172+
173+
### Relative Path Errors
174+
```
175+
Rel: can't make K:\...\file.exe relative to C:\...\temp
176+
```
177+
**Solution**: This usually occurs with cross-drive paths. The automated build script handles this by using proper temp directory management.
178+
179+
### MSI Build Fails
180+
**Check**:
181+
1. ✅ WiX Toolset installed (`candle.exe` and `light.exe` in PATH)
182+
2.`go-msi` installed (`go-msi --version` works)
183+
3.`templates/main.wxs` exists
184+
4.`wix.json` syntax is valid
185+
5. ✅ Icon file exists in assets folder
186+
187+
---
188+
189+
## ✅ Bonus Tips
190+
191+
- Add autostart, custom install paths, registry entries, or tray options by extending `wix.json`.
192+
- For more customization, explore [`WiX Toolset`](https://wixtoolset.org/).
193+
- Use `scripts\release-build.bat` for one-command building of all distribution formats.
194+
195+
---
196+
197+
Made with 💡 by Azizul (and Copilot 😄)

scripts/release-build.bat

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ if not exist "dist" mkdir dist
4343
REM Clean previous builds
4444
del /Q dist\*.exe 2>nul
4545
del /Q dist\*.zip 2>nul
46+
del /Q dist\*.msi 2>nul
4647

4748
REM --- Update version in app.rc automatically ---
4849
set VERSION_RC=%VERSION:.=,%,0
@@ -54,6 +55,15 @@ powershell -Command "(Get-Content build\windows\app.rc) -replace 'VALUE \"Produc
5455
REM --- Update version in app-manifest.xml automatically ---
5556
powershell -NoProfile -ExecutionPolicy Bypass -Command "[xml]$xml = Get-Content 'build\windows\app-manifest.xml'; $xml.assembly.assemblyIdentity.version = '%VERSION%.0'; $xml.Save((Resolve-Path 'build\windows\app-manifest.xml').Path)"
5657

58+
REM --- Update version in wix.json automatically ---
59+
powershell -Command "(Get-Content wix.json) -replace '\"version\": \".*\"', '\"version\": \"%VERSION%\"' | Set-Content wix.json"
60+
61+
REM --- Generate new product-code for this version ---
62+
echo Generating new product code for version %VERSION%...
63+
for /f "delims=" %%A in ('powershell -Command "[System.Guid]::NewGuid().ToString()"') do set NEW_PRODUCT_CODE=%%A
64+
powershell -Command "(Get-Content wix.json) -replace '\"product-code\": \".*\"', '\"product-code\": \"%NEW_PRODUCT_CODE%\"' | Set-Content wix.json"
65+
echo New product code: %NEW_PRODUCT_CODE%
66+
5767

5868
REM Generate Windows resource file (icon, manifest, version info)
5969
echo Generating Windows resource file...
@@ -139,14 +149,65 @@ if exist "dist\click-guardian-v%VERSION%-windows-portable.zip" (
139149
echo ❌ Failed to create release package
140150
)
141151

152+
REM Create MSI installer
153+
echo.
154+
echo Creating MSI installer...
155+
REM Copy icon from assets to root for WiX
156+
if exist "assets\icon.ico" (
157+
copy "assets\icon.ico" "icon.ico" >nul
158+
echo Icon copied from assets folder
159+
)
160+
161+
REM Copy executable to project root (go-msi cross-drive fix)
162+
if exist "dist\click-guardian.exe" (
163+
copy "dist\click-guardian.exe" "click-guardian.exe" >nul
164+
echo Executable copied for MSI build (cross-drive fix)
165+
)
166+
167+
REM Get current drive letter for temp directory fix
168+
set CURRENT_DRIVE=%CD:~0,2%
169+
set MSI_TEMP_DIR=%CURRENT_DRIVE%\temp
170+
171+
REM Create temp directory on same drive if it doesn't exist
172+
if not exist "%MSI_TEMP_DIR%" mkdir "%MSI_TEMP_DIR%"
173+
174+
REM Build MSI installer with cross-drive fix
175+
echo Setting temp directory to %MSI_TEMP_DIR% to avoid cross-drive issues...
176+
set ORIGINAL_TMP=%TMP%
177+
set ORIGINAL_TEMP=%TEMP%
178+
set TMP=%MSI_TEMP_DIR%
179+
set TEMP=%MSI_TEMP_DIR%
180+
181+
go-msi make --msi dist\click-guardian-installer.msi --version %VERSION% --src templates
182+
183+
REM Restore original temp directories
184+
set TMP=%ORIGINAL_TMP%
185+
set TEMP=%ORIGINAL_TEMP%
186+
187+
if %ERRORLEVEL% EQU 0 (
188+
echo ✅ MSI installer created: dist\click-guardian-installer.msi
189+
) else (
190+
echo ❌ Failed to create MSI installer
191+
)
192+
193+
REM Clean up temporary files
194+
if exist "icon.ico" (
195+
del "icon.ico" >nul
196+
echo Temporary icon file cleaned up
197+
)
198+
if exist "click-guardian.exe" (
199+
del "click-guardian.exe" >nul
200+
echo Temporary executable file cleaned up
201+
)
202+
142203
:end
143204
echo.
144205
echo =====================================
145206
echo 🎉 RELEASE BUILD COMPLETE!
146207
echo =====================================
147208
echo.
148209
echo Files created:
149-
dir dist\*.exe dist\*.zip 2>nul
210+
dir dist\*.exe dist\*.zip dist\*.msi 2>nul
150211
echo.
151212
echo Version: %VERSION%
152213
echo Ready for distribution! 🚀

templates/main.wxs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
3+
<Product Id="*" Name="{{.Product}}" Language="1033" Version="{{.Version}}" Manufacturer="{{.Company}}" UpgradeCode="{{.UpgradeCode}}">
4+
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" Description="{{.Product}} {{.Version}} Installer" Comments="{{.Product}} version {{.Version}}" />
5+
6+
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
7+
8+
<MediaTemplate EmbedCab="yes" />
9+
10+
{{if .License}}
11+
<WixVariable Id="WixUILicenseRtf" Value="{{.License}}" />
12+
{{end}}
13+
14+
<Feature Id="ProductFeature" Title="{{.Product}}" Level="1">
15+
<ComponentGroupRef Id="ProductComponents" />
16+
{{range $i, $shortcut := .Shortcuts.Items}}
17+
<ComponentRef Id="shortcut_{{$i}}" />
18+
{{end}}
19+
</Feature>
20+
21+
<UI>
22+
<UIRef Id="WixUI_Minimal" />
23+
</UI>
24+
</Product>
25+
26+
<Fragment>
27+
<Directory Id="TARGETDIR" Name="SourceDir">
28+
<Directory Id="ProgramFilesFolder">
29+
<Directory Id="INSTALLDIR" Name="{{.Product}}" />
30+
</Directory>
31+
<Directory Id="ProgramMenuFolder" />
32+
<Directory Id="DesktopFolder" />
33+
</Directory>
34+
</Fragment>
35+
36+
<Fragment>
37+
<ComponentGroup Id="ProductComponents" Directory="INSTALLDIR">
38+
{{range $i, $file := .Files.Items}}
39+
<Component Id="file_{{$i}}" Guid="{{$.Files.GUID}}">
40+
<File Id="file_{{$i}}" Source="{{$file}}" KeyPath="yes" Checksum="yes"/>
41+
</Component>
42+
{{end}}
43+
</ComponentGroup>
44+
45+
{{range $i, $shortcut := .Shortcuts.Items}}
46+
<Component Id="shortcut_{{$i}}" Directory="{{$shortcut.WDir}}" Guid="*">
47+
<Shortcut Id="shortcut_{{$i}}" Name="{{$shortcut.Name}}" Description="{{$shortcut.Description}}" Target="{{$shortcut.Target}}"{{if $shortcut.Arguments}} Arguments="{{$shortcut.Arguments}}"{{end}}{{if $shortcut.Icon}} Icon="ico_{{$i}}"{{end}} />
48+
{{if eq $shortcut.WDir "DesktopFolder"}}
49+
<RemoveFolder Id="remove_desktop_{{$i}}" Directory="DesktopFolder" On="uninstall"/>
50+
{{end}}
51+
{{if eq $shortcut.WDir "ProgramMenuFolder"}}
52+
<RemoveFolder Id="remove_startmenu_{{$i}}" Directory="ProgramMenuFolder" On="uninstall"/>
53+
{{end}}
54+
<RegistryValue Root="HKCU" Key="Software\Microsoft\{{$.Company}}\{{$.Product}}" Name="shortcut_{{$i}}" Type="integer" Value="1" KeyPath="yes"/>
55+
</Component>
56+
{{end}}
57+
</Fragment>
58+
59+
{{if .Shortcuts.Items}}
60+
<Fragment>
61+
{{range $i, $shortcut := .Shortcuts.Items}}
62+
{{if $shortcut.Icon}}
63+
<Icon Id="ico_{{$i}}" SourceFile="{{$shortcut.Icon}}" />
64+
{{end}}
65+
{{end}}
66+
</Fragment>
67+
{{end}}
68+
</Wix>

0 commit comments

Comments
 (0)