build/windows, devel-docs: Make Installer stuff human readable and less hardcoded

The Inno installer scripts contents (only 3 files: files, gimp3264 and
32on64) and filenames have been organized, making them much easier to
read, and slightly less hardcoded so less prone to being misunderstood
and pervasively receiving packaging stuff.
Just to be clear, one more time: the Inno installer (or future MSIX)
scripts never should be the center of attention. This "installcentrism"
caused a domino effect of partially "abandoning" the packaging, build.sh
and the meson scripts, which explains the existence of this MR...

(Some things still hardcoded since wildcards in Inno are very limited.
Also, the rational ordering principles of this MR were not applied since
these scripts are heavily based on the x86 .zip package and changing the
order of things here, according to my tests, breaks things quite easily)
This commit is contained in:
Bruno Lopes 2023-12-25 09:10:21 -03:00 committed by Jehan
parent af79bbe028
commit 9af3579f63
17 changed files with 3330 additions and 3345 deletions

View File

@ -1,75 +1,75 @@
//directories to source files from
#if !defined(VERSION)
#error "VERSION must be defined"
#endif
#define public
#if !defined(VER_DIR)
#if defined(REVISION)
#define VER_DIR VERSION + "-" + REVISION
#else
#define VER_DIR VERSION
#endif
#endif
#ifndef DIR32
#define DIR32 "i686-w64-mingw32"
#endif
#ifndef DIR64
#define DIR64 "x86_64-w64-mingw32"
#endif
#ifndef DIRA64
#define DIRA64 "aarch64-w64-mingw32"
#endif
#ifndef GIMP_DIR
#define GIMP_DIR "N:\gimp\output\" + VER_DIR
#endif
#ifndef DEPS_DIR
#define DEPS_DIR "N:\gimp\deps"
#endif
//32-bit GIMP base directory (result of make install)
#ifndef GIMP_DIR32
#define GIMP_DIR32 GIMP_DIR + "\" + DIR32
#endif
//64-bit GIMP base directory (result of make install)
#ifndef GIMP_DIR64
#define GIMP_DIR64 GIMP_DIR + "\" + DIR64
#endif
//AArch64 GIMP base directory (result of make install)
#ifndef GIMP_DIRA64
#define GIMP_DIRA64 GIMP_DIR + "\" + DIR64
#endif
#ifndef DDIR32
#define DDIR32 DIR32
#endif
#ifndef DDIR64
#define DDIR64 DIR64
#endif
#ifndef DDIRA64
#define DDIRA64 DIRA64
#endif
//32-bit dependencies directory
#ifndef DEPS_DIR32
#define DEPS_DIR32 DEPS_DIR + "\" + DDIR32
#endif
//64-bit dependencies directory
#ifndef DEPS_DIR64
#define DEPS_DIR64 DEPS_DIR + "\" + DDIR64
#endif
//AArch64 dependencies directory
#ifndef DEPS_DIR64
#define DEPS_DIRA64 DEPS_DIR + "\" + DDIRA64
#endif
#ifdef PYTHON
//python source directory
#ifndef PY_DIR
#define PY_DIR "N:\common\python2.7"
#endif
#endif
//directories to source files from
#if !defined(VERSION)
#error "VERSION must be defined"
#endif
#define public
#if !defined(VER_DIR)
#if defined(REVISION)
#define VER_DIR VERSION + "-" + REVISION
#else
#define VER_DIR VERSION
#endif
#endif
#ifndef DIR32
#define DIR32 "i686-w64-mingw32"
#endif
#ifndef DIR64
#define DIR64 "x86_64-w64-mingw32"
#endif
#ifndef DIRA64
#define DIRA64 "aarch64-w64-mingw32"
#endif
#ifndef GIMP_DIR
#define GIMP_DIR "N:\gimp\output\" + VER_DIR
#endif
#ifndef DEPS_DIR
#define DEPS_DIR "N:\gimp\deps"
#endif
//32-bit GIMP base directory (result of make install)
#ifndef GIMP_DIR32
#define GIMP_DIR32 GIMP_DIR + "\" + DIR32
#endif
//64-bit GIMP base directory (result of make install)
#ifndef GIMP_DIR64
#define GIMP_DIR64 GIMP_DIR + "\" + DIR64
#endif
//AArch64 GIMP base directory (result of make install)
#ifndef GIMP_DIRA64
#define GIMP_DIRA64 GIMP_DIR + "\" + DIR64
#endif
#ifndef DDIR32
#define DDIR32 DIR32
#endif
#ifndef DDIR64
#define DDIR64 DIR64
#endif
#ifndef DDIRA64
#define DDIRA64 DIRA64
#endif
//32-bit dependencies directory
#ifndef DEPS_DIR32
#define DEPS_DIR32 DEPS_DIR + "\" + DDIR32
#endif
//64-bit dependencies directory
#ifndef DEPS_DIR64
#define DEPS_DIR64 DEPS_DIR + "\" + DDIR64
#endif
//AArch64 dependencies directory
#ifndef DEPS_DIR64
#define DEPS_DIRA64 DEPS_DIR + "\" + DDIRA64
#endif
#ifdef PYTHON
//python source directory
#ifndef PY_DIR
#define PY_DIR "N:\common\python2.7"
#endif
#endif

View File

@ -0,0 +1,54 @@
//files arch-specific
#if 0
[Files]
#endif
#if PLATFORM==X86
#define DIR DIR32
#define DDIR DDIR32
#define COMPONENT "32"
#elif PLATFORM==X64
#define DIR DIR64
#define DDIR DDIR64
#define COMPONENT "64"
#elif PLATFORM==ARM64
#define DIR DIRA64
#define DDIR DDIRA64
#define COMPONENT "ARM64"
#else
#error "Unknown PLATFORM:" + PLATFORM
#endif
;Required arch-specific components (minimal install)
Source: "{#GIMP_DIR}\{#DIR}\*.dll"; DestDir: "{app}"; Excludes: "bin\libgs*.dll,bin\lua*.dll,bin\libpython*.dll"; Components: gimp{#COMPONENT}; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete
Source: "{#GIMP_DIR}\{#DIR}\*.exe"; DestDir: "{app}"; Excludes: "\lib\gimp\{#DIR_VER}\plug-ins\file-ps\file-ps.exe,\bin\lua*.exe,\bin\python*.exe,\lib\gimp\{#DIR_VER}\plug-ins\twain\twain.exe"; Components: gimp{#COMPONENT}; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete
Source: "{#GIMP_DIR}\{#DIR}\lib\gimp\{#DIR_VER}\extensions\*.*"; DestDir: "{app}\lib\gimp\{#DIR_VER}\extensions"; Excludes: "*.debug"; Components: gimp{#COMPONENT}; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete
Source: "{#GIMP_DIR}\{#DIR}\lib\girepository-1.0\*.*"; DestDir: "{app}\lib\girepository-1.0"; Components: gimp{#COMPONENT}; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete
Source: "{#DEPS_DIR}\{#DDIR}\bin\*.dll"; DestDir: "{app}\bin"; Excludes: "libgimp*.dll,libgs*.dll,lua*.dll,libpython*.dll"; Components: deps{#COMPONENT}; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete
Source: "{#DEPS_DIR}\{#DDIR}\bin\*.exe"; DestDir: "{app}\bin"; Excludes: "gimp*.exe,lua*.exe,python*.exe"; Components: deps{#COMPONENT}; Flags: recursesubdirs restartreplace uninsrestartdelete ignoreversion
Source: "{#DEPS_DIR}\{#DDIR}\lib\*"; DestDir: "{app}\lib"; Excludes: "*.debug,\gimp\*,\lua\*,\python3.11\*"; Components: deps{#COMPONENT}; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete
;Optional arch-specific components (complete install)
#ifdef DEBUG_SYMBOLS
Source: "{#GIMP_DIR}\{#DIR}\*.debug"; DestDir: "{app}"; Components: gimp{#COMPONENT} and debug; Flags: recursesubdirs restartreplace uninsrestartdelete ignoreversion
Source: "{#DEPS_DIR}\{#DDIR}\bin\.debug\*.dll.debug"; DestDir: "{app}\bin\.debug"; Components: deps{#COMPONENT} and debug; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete skipifsourcedoesntexist
Source: "{#GIMP_DIR}\{#DIR}\lib\gimp\{#DIR_VER}\extensions\*.debug"; DestDir: "{app}\lib\gimp\{#DIR_VER}\extensions"; Components: gimp{#COMPONENT} and debug; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete
Source: "{#DEPS_DIR}\{#DDIR}\lib\*.debug"; DestDir: "{app}\lib"; Components: deps{#COMPONENT} and debug; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete skipifsourcedoesntexist
#endif
Source: "{#DEPS_DIR}\{#DDIR}\bin\libgs*.dll"; DestDir: "{app}\bin"; Components: gs and deps{#COMPONENT}; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete
Source: "{#GIMP_DIR}\{#DIR}\lib\gimp\{#DIR_VER}\plug-ins\file-ps\file-ps.exe"; DestDir: "{app}\lib\gimp\{#DIR_VER}\plug-ins\file-ps"; Components: gs and gimp{#COMPONENT}; Flags: restartreplace ignoreversion uninsrestartdelete
#ifdef LUA
Source: "{#DEPS_DIR}\{#DDIR}\bin\lua*.dll"; DestDir: "{app}\bin"; Components: lua and gimp{#COMPONENT}; Flags: restartreplace uninsrestartdelete ignoreversion
Source: "{#DEPS_DIR}\{#DDIR}\bin\lua*.exe"; DestDir: "{app}\bin"; Components: lua and gimp{#COMPONENT}; Flags: restartreplace uninsrestartdelete ignoreversion
Source: "{#DEPS_DIR}\{#DDIR}\lib\lua\*"; DestDir: "{app}\lib\lua"; Excludes: "*.debug"; Components: lua and gimp{#COMPONENT}; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete
#endif
#ifdef PYTHON
Source: "{#DEPS_DIR}\{#DDIR}\bin\libpython*.dll"; DestDir: "{app}\bin"; Components: py and gimp{#COMPONENT}; Flags: restartreplace uninsrestartdelete ignoreversion
Source: "{#DEPS_DIR}\{#DDIR}\bin\python*.exe"; DestDir: "{app}\bin"; Components: py and gimp{#COMPONENT}; Flags: restartreplace uninsrestartdelete ignoreversion
Source: "{#DEPS_DIR}\{#DDIR}\lib\python3.11\*"; DestDir: "{app}\lib\python3.11"; Excludes: "*.debug"; Components: py and gimp{#COMPONENT}; Flags: recursesubdirs restartreplace uninsrestartdelete ignoreversion
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,60 +1,60 @@
#if 0
[Files]
#endif
//process list of 32bit GIMP files that are installed on x64 (for TWAIN support)
#pragma option -e-
#define protected
#define FileHandle
#define FileLine
#define ReplPos
#define ReplStr
#define Line=0
#define SRC_DIR GIMP_DIR32
//avoid too much nesting
#sub DoActualWork
#if Copy(FileLine,Len(FileLine),1)=="\"
//include whole directory
Source: "{#SRC_DIR}\{#FileLine}*"; DestDir: "{app}\32\{#Copy(FileLine,1,Len(FileLine)-1)}"; Components: gimp32on64; Flags: recursesubdirs restartreplace replacesameversion uninsrestartdelete ignoreversion
#else
//include files from a certain directory
#define OutputDir Copy(FileLine,1,RPos("\",FileLine)-1)
Source: "{#SRC_DIR}\{#FileLine}"; DestDir: "{app}\32\{#OutputDir}"; Components: gimp32on64; Flags: restartreplace replacesameversion uninsrestartdelete ignoreversion
#endif
#endsub
#sub Process32on64Line
#if !defined(Finished)
//show that something's happening
#expr Line=Line+1
#pragma message "Processing 32on64.list line " + Str(Line)
#if Copy(FileLine,1,1)=="#" || FileLine==""
//skip comments and empty lines
#elif Copy(FileLine,1,1)=="!"
#if Copy(FileLine,2)=="GIMP"
#expr SRC_DIR=GIMP_DIR32
#elif Copy(FileLine,2)=="GTK"
#expr SRC_DIR=DEPS_DIR32
#elif Copy(FileLine,2)=="end"
#define public Finished 1
//finished
#else
#error "Unknown command: "+FileLine
#endif
#else
#expr DoActualWork
#endif
#endif
#endsub
#for {FileHandle = FileOpen(AddBackslash(SourcePath)+"32on64.list"); \
FileHandle && !FileEof(FileHandle); FileLine = FileRead(FileHandle)} \
Process32on64Line
#if FileHandle
#expr FileClose(FileHandle)
#endif
#if 0
[Files]
#endif
//process list of 32bit GIMP files that are installed on x64 (for TWAIN support)
#pragma option -e-
#define protected
#define FileHandle
#define FileLine
#define ReplPos
#define ReplStr
#define Line=0
#define SRC_DIR GIMP_DIR32
//avoid too much nesting
#sub DoActualWork
#if Copy(FileLine,Len(FileLine),1)=="\"
//include whole directory
Source: "{#SRC_DIR}\{#FileLine}*"; DestDir: "{app}\32\{#Copy(FileLine,1,Len(FileLine)-1)}"; Components: gimp32on64; Flags: recursesubdirs restartreplace replacesameversion uninsrestartdelete ignoreversion
#else
//include files from a certain directory
#define OutputDir Copy(FileLine,1,RPos("\",FileLine)-1)
Source: "{#SRC_DIR}\{#FileLine}"; DestDir: "{app}\32\{#OutputDir}"; Components: gimp32on64; Flags: restartreplace replacesameversion uninsrestartdelete ignoreversion
#endif
#endsub
#sub Process32on64Line
#if !defined(Finished)
//show that something's happening
#expr Line=Line+1
#pragma message "Processing base_twain32on64.list line " + Str(Line)
#if Copy(FileLine,1,1)=="#" || FileLine==""
//skip comments and empty lines
#elif Copy(FileLine,1,1)=="!"
#if Copy(FileLine,2)=="GIMP"
#expr SRC_DIR=GIMP_DIR32
#elif Copy(FileLine,2)=="GTK"
#expr SRC_DIR=DEPS_DIR32
#elif Copy(FileLine,2)=="end"
#define public Finished 1
//finished
#else
#error "Unknown command: "+FileLine
#endif
#else
#expr DoActualWork
#endif
#endif
#endsub
#for {FileHandle = FileOpen(AddBackslash(SourcePath)+"base_twain32on64.list"); \
FileHandle && !FileEof(FileHandle); FileLine = FileRead(FileHandle)} \
Process32on64Line
#if FileHandle
#expr FileClose(FileHandle)
#endif

View File

@ -1,15 +1,13 @@
#list of 32bit files to install on x64
!GTK
etc\fonts\
#lib\gtk-2.0\2.10.0\loaders\*.dll
#lib\gtk-2.0\modules\*.dll
lib\gdk-pixbuf-2.0\2.10.0\loaders\*.dll
lib\gdk-pixbuf-2.0\2.10.0\loaders.cache
lib\babl-0.1\*.dll
lib\gegl-0.4\*.dll
share\themes\
bin\gspawn*.exe
bin\*.dll
!GIMP
bin\*.dll
!end
#list of 32bit files to install on x64
!GTK
etc\fonts\
lib\gdk-pixbuf-2.0\2.10.0\loaders\*.dll
lib\gdk-pixbuf-2.0\2.10.0\loaders.cache
lib\babl-0.1\*.dll
lib\gegl-0.4\*.dll
share\locale\
bin\gspawn*.exe
bin\*.dll
!GIMP
bin\*.dll
!end

View File

@ -43,7 +43,7 @@ shift
goto doparams
:paramsdone
"%INNOPATH%\iscc.exe" -DVERSION="%VER%" -DGIMP_DIR="%GIMP_BASE%" -DDIR32="%GIMP32%" -DDIR64="%GIMP64%" -DDEPS_DIR="%DEPS_BASE%" -DDDIR32="%DEPS32%" -DDDIR64="%DEPS64%" -DDIRA64="%GIMPA64%" -DDDIRA64="%DEPSA64%" -DDEBUG_SYMBOLS -DPYTHON -DLUA %PARAMS% gimp3264.iss
"%INNOPATH%\iscc.exe" -DVERSION="%VER%" -DGIMP_DIR="%GIMP_BASE%" -DDIR32="%GIMP32%" -DDIR64="%GIMP64%" -DDEPS_DIR="%DEPS_BASE%" -DDDIR32="%DEPS32%" -DDDIR64="%DEPS64%" -DDIRA64="%GIMPA64%" -DDDIRA64="%DEPSA64%" -DDEBUG_SYMBOLS -DPYTHON -DLUA %PARAMS% base_gimp3264.iss
goto :eof
:help

View File

@ -1,52 +1,52 @@
[Registry]
#pragma option -e-
#define protected
Root: HKA; Subkey: "Software\Classes\Applications\gimp-{#MAJOR}.{#MINOR}.exe"; Flags: uninsdeletekey
Root: HKA; Subkey: "Software\Classes\Applications\gimp-{#MAJOR}.{#MINOR}.exe"; ValueType: string; ValueName: "FriendlyAppName"; ValueData: "GIMP"
Root: HKA; Subkey: "Software\Classes\Applications\gimp-{#MAJOR}.{#MINOR}.exe\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\bin\gimp-{#MAJOR}.{#MINOR}.exe,1"
Root: HKA; Subkey: "Software\Classes\Applications\gimp-{#MAJOR}.{#MINOR}.exe\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\bin\gimp-{#MAJOR}.{#MINOR}.exe"" ""%1"""
Root: HKA; Subkey: "Software\GIMP {#MAJOR}.{#MINOR}"; Flags: uninsdeletekey
Root: HKA; Subkey: "Software\GIMP {#MAJOR}.{#MINOR}\Capabilities"; ValueType: string; ValueName: "ApplicationName"; ValueData: "GIMP"
Root: HKA; Subkey: "Software\GIMP {#MAJOR}.{#MINOR}\Capabilities"; ValueType: string; ValueName: "ApplicationIcon"; ValueData: "{app}\bin\gimp-{#MAJOR}.{#MINOR}.exe,0"
Root: HKA; Subkey: "Software\GIMP {#MAJOR}.{#MINOR}\Capabilities"; ValueType: string; ValueName: "ApplicationDescription"; ValueData: "GIMP is a free raster graphics editor used for image retouching and editing, free-form drawing, converting between different image formats, and more specialized tasks."
Root: HKA; Subkey: "Software\RegisteredApplications"; ValueType: string; ValueName: "GIMP {#MAJOR}.{#MINOR}"; ValueData: "Software\GIMP {#MAJOR}.{#MINOR}\Capabilities"; Flags: uninsdeletevalue
#define FileHandle
#define FileLine
#define Line=0
#sub ProcessAssociation
#if !defined(Finished)
#if Copy(FileLine,1,1)=="#" || FileLine==""
//skip comments and empty lines
#else
#pragma message "Processing associations.list: " + FileLine
;
Root: HKA; Subkey: "Software\Classes\.{#FileLine}\OpenWithProgids"; ValueType: string; ValueName: "GIMP2.{#FileLine}"; ValueData: ""; Flags: uninsdeletevalue
Root: HKA; Subkey: "Software\Classes\GIMP2.{#FileLine}"; ValueType: string; ValueName: ""; ValueData: "GIMP {#ICON_VERSION} {#UpperCase(FileLine)}"; Flags: uninsdeletekey
Root: HKA; Subkey: "Software\Classes\GIMP2.{#FileLine}\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\bin\gimp-{#MAJOR}.{#MINOR}.exe,1"
Root: HKA; Subkey: "Software\Classes\GIMP2.{#FileLine}\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\bin\gimp-{#MAJOR}.{#MINOR}.exe"" ""%1"""
Root: HKA; Subkey: "Software\Classes\Applications\gimp-{#MAJOR}.{#MINOR}.exe\SupportedTypes"; ValueType: string; ValueName: ".{#FileLine}"; ValueData: ""
Root: HKA; Subkey: "Software\GIMP {#MAJOR}.{#MINOR}\Capabilities\FileAssociations"; ValueType: string; ValueName: ".{#FileLine}"; ValueData: "GIMP2.{#FileLine}"
#endif
#endif
#endsub
#for {FileHandle = FileOpen(AddBackslash(SourcePath)+"associations.list"); \
FileHandle && !FileEof(FileHandle); FileLine = FileRead(FileHandle)} \
ProcessAssociation
#if FileHandle
#expr FileClose(FileHandle)
#endif
;special case for .ico files
Root: HKA; Subkey: "Software\Classes\.ico\OpenWithProgids"; ValueType: string; ValueName: "GIMP2.ico"; ValueData: ""; Flags: uninsdeletevalue
Root: HKA; Subkey: "Software\Classes\GIMP2.ico"; ValueType: string; ValueName: ""; ValueData: "GIMP {#ICON_VERSION}"; Flags: uninsdeletekey
Root: HKA; Subkey: "Software\Classes\GIMP2.ico\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "%1"
Root: HKA; Subkey: "Software\Classes\GIMP2.ico\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\bin\gimp-{#MAJOR}.{#MINOR}.exe"" ""%1"""
Root: HKA; Subkey: "Software\Classes\Applications\gimp-{#MAJOR}.{#MINOR}.exe\SupportedTypes"; ValueType: string; ValueName: ".ico"; ValueData: ""
Root: HKA; Subkey: "Software\GIMP {#MAJOR}.{#MINOR}\Capabilities\FileAssociations"; ValueType: string; ValueName: ".ico"; ValueData: "GIMP2.{#FileLine}"
[Registry]
#pragma option -e-
#define protected
Root: HKA; Subkey: "Software\Classes\Applications\gimp-{#MAJOR}.{#MINOR}.exe"; Flags: uninsdeletekey
Root: HKA; Subkey: "Software\Classes\Applications\gimp-{#MAJOR}.{#MINOR}.exe"; ValueType: string; ValueName: "FriendlyAppName"; ValueData: "GIMP"
Root: HKA; Subkey: "Software\Classes\Applications\gimp-{#MAJOR}.{#MINOR}.exe\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\bin\gimp-{#MAJOR}.{#MINOR}.exe,1"
Root: HKA; Subkey: "Software\Classes\Applications\gimp-{#MAJOR}.{#MINOR}.exe\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\bin\gimp-{#MAJOR}.{#MINOR}.exe"" ""%1"""
Root: HKA; Subkey: "Software\GIMP {#MAJOR}.{#MINOR}"; Flags: uninsdeletekey
Root: HKA; Subkey: "Software\GIMP {#MAJOR}.{#MINOR}\Capabilities"; ValueType: string; ValueName: "ApplicationName"; ValueData: "GIMP"
Root: HKA; Subkey: "Software\GIMP {#MAJOR}.{#MINOR}\Capabilities"; ValueType: string; ValueName: "ApplicationIcon"; ValueData: "{app}\bin\gimp-{#MAJOR}.{#MINOR}.exe,0"
Root: HKA; Subkey: "Software\GIMP {#MAJOR}.{#MINOR}\Capabilities"; ValueType: string; ValueName: "ApplicationDescription"; ValueData: "GIMP is a free raster graphics editor used for image retouching and editing, free-form drawing, converting between different image formats, and more specialized tasks."
Root: HKA; Subkey: "Software\RegisteredApplications"; ValueType: string; ValueName: "GIMP {#MAJOR}.{#MINOR}"; ValueData: "Software\GIMP {#MAJOR}.{#MINOR}\Capabilities"; Flags: uninsdeletevalue
#define FileHandle
#define FileLine
#define Line=0
#sub ProcessAssociation
#if !defined(Finished)
#if Copy(FileLine,1,1)=="#" || FileLine==""
//skip comments and empty lines
#else
#pragma message "Processing data_associations.list: " + FileLine
;
Root: HKA; Subkey: "Software\Classes\.{#FileLine}\OpenWithProgids"; ValueType: string; ValueName: "GIMP2.{#FileLine}"; ValueData: ""; Flags: uninsdeletevalue
Root: HKA; Subkey: "Software\Classes\GIMP2.{#FileLine}"; ValueType: string; ValueName: ""; ValueData: "GIMP {#ICON_VERSION} {#UpperCase(FileLine)}"; Flags: uninsdeletekey
Root: HKA; Subkey: "Software\Classes\GIMP2.{#FileLine}\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\bin\gimp-{#MAJOR}.{#MINOR}.exe,1"
Root: HKA; Subkey: "Software\Classes\GIMP2.{#FileLine}\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\bin\gimp-{#MAJOR}.{#MINOR}.exe"" ""%1"""
Root: HKA; Subkey: "Software\Classes\Applications\gimp-{#MAJOR}.{#MINOR}.exe\SupportedTypes"; ValueType: string; ValueName: ".{#FileLine}"; ValueData: ""
Root: HKA; Subkey: "Software\GIMP {#MAJOR}.{#MINOR}\Capabilities\FileAssociations"; ValueType: string; ValueName: ".{#FileLine}"; ValueData: "GIMP2.{#FileLine}"
#endif
#endif
#endsub
#for {FileHandle = FileOpen(AddBackslash(SourcePath)+"data_associations.list"); \
FileHandle && !FileEof(FileHandle); FileLine = FileRead(FileHandle)} \
ProcessAssociation
#if FileHandle
#expr FileClose(FileHandle)
#endif
;special case for .ico files
Root: HKA; Subkey: "Software\Classes\.ico\OpenWithProgids"; ValueType: string; ValueName: "GIMP2.ico"; ValueData: ""; Flags: uninsdeletevalue
Root: HKA; Subkey: "Software\Classes\GIMP2.ico"; ValueType: string; ValueName: ""; ValueData: "GIMP {#ICON_VERSION}"; Flags: uninsdeletekey
Root: HKA; Subkey: "Software\Classes\GIMP2.ico\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "%1"
Root: HKA; Subkey: "Software\Classes\GIMP2.ico\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\bin\gimp-{#MAJOR}.{#MINOR}.exe"" ""%1"""
Root: HKA; Subkey: "Software\Classes\Applications\gimp-{#MAJOR}.{#MINOR}.exe\SupportedTypes"; ValueType: string; ValueName: ".ico"; ValueData: ""
Root: HKA; Subkey: "Software\GIMP {#MAJOR}.{#MINOR}\Capabilities\FileAssociations"; ValueType: string; ValueName: ".ico"; ValueData: "GIMP2.{#FileLine}"

View File

@ -1,36 +1,36 @@
;allow specific configuration files to be overridden by files in a specific directory
#if 0
[Files]
#endif
#define FindHandle
#define FindResult
#sub ProcessConfigFile
#define FileName FindGetFileName(FindHandle)
Source: "{code:GetExternalConfDir}\{#FileName}"; DestDir: "{app}\{#ConfigDir}"; Flags: external restartreplace; Check: CheckExternalConf('{#FileName}')
#if BaseDir != GIMP_DIR32
Source: "{code:GetExternalConfDir}\{#FileName}"; DestDir: "{app}\32\{#ConfigDir}"; Components: gimp32on64; Flags: external restartreplace; Check: CheckExternalConf('{#FileName}')
#endif
#endsub
#sub ProcessConfigDir
#emit ';; ' + ConfigDir
#emit ';; ' + BaseDir
#for {FindHandle = FindResult = FindFirst(AddBackslash(BaseDir) + AddBackSlash(ConfigDir) + "*", 0); \
FindResult; FindResult = FindNext(FindHandle)} ProcessConfigFile
#if FindHandle
#expr FindClose(FindHandle)
#endif
#endsub
#define public BaseDir GIMP_DIR32
#define public ConfigDir "etc\gimp\2.0"
#expr ProcessConfigDir
#define public BaseDir DEPS_DIR32
#define public ConfigDir "etc\gtk-2.0"
#expr ProcessConfigDir
#define public ConfigDir "etc\fonts"
#expr ProcessConfigDir
;allow specific configuration files to be overridden by files in a specific directory
#if 0
[Files]
#endif
#define FindHandle
#define FindResult
#sub ProcessConfigFile
#define FileName FindGetFileName(FindHandle)
Source: "{code:GetExternalConfDir}\{#FileName}"; DestDir: "{app}\{#ConfigDir}"; Flags: external restartreplace; Check: CheckExternalConf('{#FileName}')
#if BaseDir != GIMP_DIR32
Source: "{code:GetExternalConfDir}\{#FileName}"; DestDir: "{app}\32\{#ConfigDir}"; Components: gimp32on64; Flags: external restartreplace; Check: CheckExternalConf('{#FileName}')
#endif
#endsub
#sub ProcessConfigDir
#emit ';; ' + ConfigDir
#emit ';; ' + BaseDir
#for {FindHandle = FindResult = FindFirst(AddBackslash(BaseDir) + AddBackSlash(ConfigDir) + "*", 0); \
FindResult; FindResult = FindNext(FindHandle)} ProcessConfigFile
#if FindHandle
#expr FindClose(FindHandle)
#endif
#endsub
#define public BaseDir GIMP_DIR32
#define public ConfigDir "etc\gimp\2.0"
#expr ProcessConfigDir
#define public BaseDir DEPS_DIR32
#define public ConfigDir "etc\gtk-2.0"
#expr ProcessConfigDir
#define public ConfigDir "etc\fonts"
#expr ProcessConfigDir

View File

@ -1,70 +0,0 @@
#if 0
[Files]
#endif
#if PLATFORM==X86
#define DIR DIR32
#define DDIR DDIR32
#define COMPONENT "32"
#elif PLATFORM==X64
#define DIR DIR64
#define DDIR DDIR64
#define COMPONENT "64"
#elif PLATFORM==ARM64
#define DIR DIRA64
#define DDIR DDIRA64
#define COMPONENT "ARM64"
#else
#error "Unknown PLATFORM:" + PLATFORM
#endif
Source: "{#GIMP_DIR}\{#DIR}\*.dll"; DestDir: "{app}"; Components: gimp{#COMPONENT}; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete
Source: "{#GIMP_DIR}\{#DIR}\*.exe"; DestDir: "{app}"; Excludes: "\lib\gimp\{#DIR_VER}\plug-ins\twain\twain.exe,\lib\gimp\{#DIR_VER}\plug-ins\file-ps\file-ps.exe,\bin\gimp.exe,\bin\gimp-console.exe"; Components: gimp{#COMPONENT}; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete
#ifdef DEBUG_SYMBOLS
Source: "{#GIMP_DIR}\{#DIR}\*.debug"; DestDir: "{app}"; Components: gimp{#COMPONENT} and debug; Flags: recursesubdirs restartreplace uninsrestartdelete ignoreversion
#endif
Source: "{#GIMP_DIR}\{#DIR}\lib\gimp\{#DIR_VER}\extensions\*.*"; Excludes: "*.debug"; DestDir: "{app}\lib\gimp\{#DIR_VER}\extensions"; Components: gimp{#COMPONENT}; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete
#ifdef DEBUG_SYMBOLS
Source: "{#GIMP_DIR}\{#DIR}\lib\gimp\{#DIR_VER}\extensions\*.debug"; DestDir: "{app}\lib\gimp\{#DIR_VER}\extensions"; Components: gimp{#COMPONENT} and debug; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete
#endif
Source: "{#GIMP_DIR}\{#DIR}\lib\gimp\{#DIR_VER}\plug-ins\file-ps\file-ps.exe"; DestDir: "{app}\lib\gimp\{#DIR_VER}\plug-ins\file-ps"; Components: gs and gimp{#COMPONENT}; Flags: restartreplace ignoreversion uninsrestartdelete
Source: "{#GIMP_DIR}\{#DIR}\lib\girepository-1.0\*.*"; DestDir: "{app}\lib\girepository-1.0"; Components: gimp{#COMPONENT}; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete
Source: "{#DEPS_DIR}\{#DDIR}\lib\girepository-1.0\*.*"; DestDir: "{app}\lib\girepository-1.0"; Components: deps{#COMPONENT}; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete
Source: "{#DEPS_DIR}\{#DDIR}\bin\*.dll"; DestDir: "{app}\bin"; Excludes: "\bin\libgs*.dll,\bin\lua*.dll"; Components: deps{#COMPONENT}; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete
Source: "{#DEPS_DIR}\{#DDIR}\bin\libgs*.dll"; DestDir: "{app}\bin"; Components: gs and deps{#COMPONENT}; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete
#ifdef DEBUG_SYMBOLS
Source: "{#DEPS_DIR}\{#DDIR}\bin\.debug\*.dll.debug"; DestDir: "{app}\bin\.debug"; Components: deps{#COMPONENT} and debug; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete skipifsourcedoesntexist
Source: "{#DEPS_DIR}\{#DDIR}\lib\*.debug"; DestDir: "{app}\lib"; Components: deps{#COMPONENT} and debug; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete skipifsourcedoesntexist
#endif
Source: "{#DEPS_DIR}\{#DDIR}\bin\gspawn-win*.exe"; DestDir: "{app}\bin"; Components: deps{#COMPONENT}; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete
Source: "{#DEPS_DIR}\{#DDIR}\bin\gdk-pixbuf-query-loaders.exe"; DestDir: "{app}\bin"; Components: deps{#COMPONENT}; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete
Source: "{#DEPS_DIR}\{#DDIR}\bin\bzip2.exe"; DestDir: "{app}\bin"; Components: deps{#COMPONENT}; Flags: recursesubdirs restartreplace uninsrestartdelete ignoreversion
Source: "{#DEPS_DIR}\{#DDIR}\lib\gdk-pixbuf-2.0\2.10.0\loaders.cache"; DestDir: "{app}\lib\gdk-pixbuf-2.0\2.10.0\"; Components: deps{#COMPONENT}; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete
Source: "{#DEPS_DIR}\{#DDIR}\lib\babl-0.1\*.dll"; DestDir: "{app}\lib\babl-0.1"; Components: deps{#COMPONENT}; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete
Source: "{#DEPS_DIR}\{#DDIR}\lib\gdk-pixbuf-2.0\*.dll"; DestDir: "{app}\lib\gdk-pixbuf-2.0"; Components: deps{#COMPONENT}; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete
Source: "{#DEPS_DIR}\{#DDIR}\lib\gegl-0.4\*.dll"; DestDir: "{app}\lib\gegl-0.4"; Components: deps{#COMPONENT}; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete
Source: "{#DEPS_DIR}\{#DDIR}\lib\gio\*.dll"; DestDir: "{app}\lib\gio"; Components: deps{#COMPONENT}; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete
;Source: "{#DEPS_DIR}\{#DDIR}\lib\gtk-3.0\*.dll"; DestDir: "{app}\lib\gtk-3.0"; Components: deps{#COMPONENT}; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete
;python scripts
#ifdef PYTHON
Source: "{#DEPS_DIR}\{#DDIR}\bin\python3w.exe"; DestDir: "{app}\bin"; DestName: "pythonw.exe"; Components: py and gimp{#COMPONENT}; Flags: restartreplace uninsrestartdelete ignoreversion
Source: "{#DEPS_DIR}\{#DDIR}\bin\python3.exe"; DestDir: "{app}\bin"; DestName: "python.exe"; Components: py and gimp{#COMPONENT}; Flags: restartreplace uninsrestartdelete ignoreversion
Source: "{#DEPS_DIR}\{#DDIR}\bin\libpython3.11.dll"; DestDir: "{app}\bin"; Components: py and gimp{#COMPONENT}; Flags: restartreplace uninsrestartdelete ignoreversion
Source: "{#DEPS_DIR}\{#DDIR}\lib\python3.11\*"; DestDir: "{app}\lib\python3.11"; Components: py and gimp{#COMPONENT}; Flags: recursesubdirs restartreplace uninsrestartdelete ignoreversion
#endif
#ifdef LUA
#if PLATFORM==ARM64
Source: "{#DEPS_DIR}\{#DDIR}\bin\lua5.1.exe"; DestDir: "{app}\bin"; Components: lua and gimp{#COMPONENT}; Flags: restartreplace uninsrestartdelete ignoreversion
#else
Source: "{#DEPS_DIR}\{#DDIR}\bin\luajit.exe"; DestDir: "{app}\bin"; Components: lua and gimp{#COMPONENT}; Flags: restartreplace uninsrestartdelete ignoreversion
#endif
Source: "{#DEPS_DIR}\{#DDIR}\bin\lua51.dll"; DestDir: "{app}\bin"; Components: lua and gimp{#COMPONENT}; Flags: restartreplace uninsrestartdelete ignoreversion
Source: "{#DEPS_DIR}\{#DDIR}\share\lua\*"; DestDir: "{app}\share\lua"; Components: lua and gimp{#COMPONENT}; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete
Source: "{#DEPS_DIR}\{#DDIR}\lib\lua\*"; DestDir: "{app}\lib\lua"; Components: lua and gimp{#COMPONENT}; Flags: recursesubdirs restartreplace ignoreversion uninsrestartdelete
#endif

View File

@ -4,7 +4,7 @@
# translations present. This check step is necessary to not forget new
# installer translations because we have a manual step.
INSTALLER_LANGS=`grep -rI '^Name:.*MessagesFile' ${GIMP_TESTING_ABS_TOP_SRCDIR}/build/windows/installer/gimp3264.iss | \
INSTALLER_LANGS=`grep -rI '^Name:.*MessagesFile' ${GIMP_TESTING_ABS_TOP_SRCDIR}/build/windows/installer/base_gimp3264.iss | \
sed 's/^Name: *"\([a-zA-Z_]*\)".*$/\1/' | sort`
# 'en' doesn't have a gettext file because it is the default.
INSTALLER_LANGS=`echo "$INSTALLER_LANGS" | tr '\n\r' ' ' | sed 's/\<en\> //'`
@ -17,7 +17,7 @@ if [ "$PO_LANGS" != "$INSTALLER_LANGS" ]; then
echo "Error: languages listed in the Windows installer script do not match the .po files in po-windows-installer/."
echo "- PO languages: $PO_LANGS"
echo "- Installer languages: $INSTALLER_LANGS"
echo "Please verify: build/windows/installer/gimp3264.iss"
echo "Please verify: build/windows/installer/base_gimp3264.iss"
echo "Base language files can be found in: https://github.com/jrsoftware/issrc/tree/main/Files/Languages"
echo "If a new language is in Unofficial/, also edit/download it from:"
echo "build/windows/gitlab-ci/4_installer-gimp-msys2.sh"
@ -36,7 +36,7 @@ if [ "$PO_LANGS" != "$MESON_LANGS" ]; then
exit 1
fi
INSTALLER_LANGS=`grep -rI '^Name:.*MessagesFile.*Unofficial' ${GIMP_TESTING_ABS_TOP_SRCDIR}/build/windows/installer/gimp3264.iss | \
INSTALLER_LANGS=`grep -rI '^Name:.*MessagesFile.*Unofficial' ${GIMP_TESTING_ABS_TOP_SRCDIR}/build/windows/installer/base_gimp3264.iss | \
sed 's/^.*Unofficial\\\\\([a-zA-Z_.]*\),.*$/\1/' | sort`
INSTALLER_LANGS=`echo "$INSTALLER_LANGS" | tr '\n\r' ' '`

View File

@ -1,177 +1,177 @@
#if 0
[Code]
#endif
procedure DebugMsg(Const pProc,pMsg: String);
begin
Log('[Code] ' + pProc + #9 + pMsg);
end;
function BoolToStr(const b: Boolean): String;
begin
if b then
Result := 'True'
else
Result := 'False';
end;
function RevPos(const SearchStr, Str: string): Integer;
var i: Integer;
begin
if Length(SearchStr) < Length(Str) then
for i := (Length(Str) - Length(SearchStr) + 1) downto 1 do
begin
if Copy(Str, i, Length(SearchStr)) = SearchStr then
begin
Result := i;
exit;
end;
end;
Result := 0;
end;
function Replace(pSearchFor, pReplaceWith, pText: String): String;
begin
StringChangeEx(pText,pSearchFor,pReplaceWith,True);
Result := pText;
end;
function Count(What, Where: String): Integer;
begin
Result := 0;
if Length(What) = 0 then
exit;
while Pos(What,Where)>0 do
begin
Where := Copy(Where,Pos(What,Where)+Length(What),Length(Where));
Result := Result + 1;
end;
end;
//split text to array
procedure Explode(var ADest: TArrayOfString; aText, aSeparator: String);
var tmp: Integer;
begin
if aSeparator='' then
exit;
SetArrayLength(ADest,Count(aSeparator,aText)+1)
tmp := 0;
repeat
if Pos(aSeparator,aText)>0 then
begin
ADest[tmp] := Copy(aText,1,Pos(aSeparator,aText)-1);
aText := Copy(aText,Pos(aSeparator,aText)+Length(aSeparator),Length(aText));
tmp := tmp + 1;
end else
begin
ADest[tmp] := aText;
aText := '';
end;
until Length(aText)=0;
end;
function String2Utf8(const pInput: String): AnsiString;
var Output: AnsiString;
ret, outLen, nulPos: Integer;
begin
outLen := WideCharToMultiByte(CP_UTF8, 0, pInput, -1, Output, 0, 0, 0);
Output := StringOfChar(#0,outLen);
ret := WideCharToMultiByte(CP_UTF8, 0, pInput, -1, Output, outLen, 0, 0);
if ret = 0 then
RaiseException('WideCharToMultiByte failed: ' + IntToStr(GetLastError));
nulPos := Pos(#0,Output) - 1;
if nulPos = -1 then
nulPos := Length(Output);
Result := Copy(Output,1,nulPos);
end;
function Utf82String(const pInput: AnsiString): String;
var Output: AnsiString;
ret, outLen, nulPos: Integer;
begin
outLen := MultiByteToWideChar(CP_UTF8, 0, pInput, -1, Output, 0);
Output := StringOfChar(#0,outLen);
ret := MultiByteToWideChar(CP_UTF8, 0, pInput, -1, Output, outLen);
if ret = 0 then
RaiseException('MultiByteToWideChar failed: ' + IntToStr(GetLastError));
nulPos := Pos(#0,Output) - 1;
if nulPos = -1 then
nulPos := Length(Output);
Result := Copy(Output,1,nulPos);
end;
function SaveStringToUTF8File(const pFileName, pS: String; const pAppend: Boolean): Boolean;
begin
Result := SaveStringToFile(pFileName, String2Utf8(pS), pAppend);
end;
function LoadStringFromUTF8File(const pFileName: String; var oS: String): Boolean;
var Utf8String: AnsiString;
begin
Result := LoadStringFromFile(pFileName, Utf8String);
oS := Utf82String(Utf8String);
end;
procedure StatusLabel(const Status1,Status2: string);
begin
WizardForm.StatusLabel.Caption := Status1;
WizardForm.FilenameLabel.Caption := Status2;
WizardForm.Refresh();
end;
//reverse encoding done by Encode
function Decode(pText: String): String;
var p: Integer;
tmp: String;
begin
if Pos('%',pText) = 0 then
Result := pText
else
begin
Result := '';
while Length(pText) > 0 do
begin
p := Pos('%',pText);
if p = 0 then
begin
Result := Result + pText;
break;
end;
Result := Result + Copy(pText,1,p-1);
tmp := '$' + Copy(pText,p+1,2);
Result := Result + Chr(StrToIntDef(tmp,32));
pText := Copy(pText,p+3,Length(pText));
end;
end;
end;
#if 0
[Code]
#endif
procedure DebugMsg(Const pProc,pMsg: String);
begin
Log('[Code] ' + pProc + #9 + pMsg);
end;
function BoolToStr(const b: Boolean): String;
begin
if b then
Result := 'True'
else
Result := 'False';
end;
function RevPos(const SearchStr, Str: string): Integer;
var i: Integer;
begin
if Length(SearchStr) < Length(Str) then
for i := (Length(Str) - Length(SearchStr) + 1) downto 1 do
begin
if Copy(Str, i, Length(SearchStr)) = SearchStr then
begin
Result := i;
exit;
end;
end;
Result := 0;
end;
function Replace(pSearchFor, pReplaceWith, pText: String): String;
begin
StringChangeEx(pText,pSearchFor,pReplaceWith,True);
Result := pText;
end;
function Count(What, Where: String): Integer;
begin
Result := 0;
if Length(What) = 0 then
exit;
while Pos(What,Where)>0 do
begin
Where := Copy(Where,Pos(What,Where)+Length(What),Length(Where));
Result := Result + 1;
end;
end;
//split text to array
procedure Explode(var ADest: TArrayOfString; aText, aSeparator: String);
var tmp: Integer;
begin
if aSeparator='' then
exit;
SetArrayLength(ADest,Count(aSeparator,aText)+1)
tmp := 0;
repeat
if Pos(aSeparator,aText)>0 then
begin
ADest[tmp] := Copy(aText,1,Pos(aSeparator,aText)-1);
aText := Copy(aText,Pos(aSeparator,aText)+Length(aSeparator),Length(aText));
tmp := tmp + 1;
end else
begin
ADest[tmp] := aText;
aText := '';
end;
until Length(aText)=0;
end;
function String2Utf8(const pInput: String): AnsiString;
var Output: AnsiString;
ret, outLen, nulPos: Integer;
begin
outLen := WideCharToMultiByte(CP_UTF8, 0, pInput, -1, Output, 0, 0, 0);
Output := StringOfChar(#0,outLen);
ret := WideCharToMultiByte(CP_UTF8, 0, pInput, -1, Output, outLen, 0, 0);
if ret = 0 then
RaiseException('WideCharToMultiByte failed: ' + IntToStr(GetLastError));
nulPos := Pos(#0,Output) - 1;
if nulPos = -1 then
nulPos := Length(Output);
Result := Copy(Output,1,nulPos);
end;
function Utf82String(const pInput: AnsiString): String;
var Output: AnsiString;
ret, outLen, nulPos: Integer;
begin
outLen := MultiByteToWideChar(CP_UTF8, 0, pInput, -1, Output, 0);
Output := StringOfChar(#0,outLen);
ret := MultiByteToWideChar(CP_UTF8, 0, pInput, -1, Output, outLen);
if ret = 0 then
RaiseException('MultiByteToWideChar failed: ' + IntToStr(GetLastError));
nulPos := Pos(#0,Output) - 1;
if nulPos = -1 then
nulPos := Length(Output);
Result := Copy(Output,1,nulPos);
end;
function SaveStringToUTF8File(const pFileName, pS: String; const pAppend: Boolean): Boolean;
begin
Result := SaveStringToFile(pFileName, String2Utf8(pS), pAppend);
end;
function LoadStringFromUTF8File(const pFileName: String; var oS: String): Boolean;
var Utf8String: AnsiString;
begin
Result := LoadStringFromFile(pFileName, Utf8String);
oS := Utf82String(Utf8String);
end;
procedure StatusLabel(const Status1,Status2: string);
begin
WizardForm.StatusLabel.Caption := Status1;
WizardForm.FilenameLabel.Caption := Status2;
WizardForm.Refresh();
end;
//reverse encoding done by Encode
function Decode(pText: String): String;
var p: Integer;
tmp: String;
begin
if Pos('%',pText) = 0 then
Result := pText
else
begin
Result := '';
while Length(pText) > 0 do
begin
p := Pos('%',pText);
if p = 0 then
begin
Result := Result + pText;
break;
end;
Result := Result + Copy(pText,1,p-1);
tmp := '$' + Copy(pText,p+1,2);
Result := Result + Chr(StrToIntDef(tmp,32));
pText := Copy(pText,p+3,Length(pText));
end;
end;
end;

View File

@ -1,130 +1,130 @@
#if 0
[Code]
#endif
function Quote(const S: String): String;
begin
Result := '"' + S + '"';
end;
function AddParam(const S, P, V: String): String;
begin
if V <> '""' then
Result := S + ' /' + P + '=' + V;
end;
function AddSimpleParam(const S, P: String): String;
begin
Result := S + ' /' + P;
end;
procedure CreateRunOnceEntry;
var RunOnceData, SetupRestartData: String;
i: Integer;
begin
DebugMsg('CreateRunOnceEntry','Preparing for restart');
//RunOnce command-line is limited to 256 characters, so keep it to the bare minimum required to start setup
RunOnceData := Quote(ExpandConstant('{srcexe}')) + ' /resumeinstall=1';
RunOnceData := AddParam(RunOnceData, 'LANG', ExpandConstant('{language}'));
SetupRestartData := Quote(ExpandConstant('{srcexe}')) + ' /resumeinstall=2';
SetupRestartData := AddParam(SetupRestartData, 'LANG', ExpandConstant('{language}'));
SetupRestartData := AddParam(SetupRestartData, 'DIR', Quote(WizardDirValue));
//SetupRestartData := AddParam(SetupRestartData, 'GROUP', Quote(WizardGroupValue));
//if WizardNoIcons then
// SetupRestartData := AddSimpleParam(SetupRestartData, 'NOICONS');
SetupRestartData := AddParam(SetupRestartData, 'TYPE', Quote(WizardSetupType(False)));
SetupRestartData := AddParam(SetupRestartData, 'COMPONENTS', Quote(WizardSelectedComponents(False)));
SetupRestartData := AddParam(SetupRestartData, 'TASKS', Quote(WizardSelectedTasks(False)));
if Force32bitInstall then
SetupRestartData := AddSimpleParam(SetupRestartData, '32');
if ExpandConstant('{param:log|*}') <> '*' then
begin
SetupRestartData := AddParam(SetupRestartData, 'LOG', Quote(ExpandConstant('{param:log|*}')));
end else
begin
for i := 0 to ParamCount() do
if LowerCase(ParamStr(i)) = '/log' then
begin
RunOnceData := AddSimpleParam(RunOnceData,'LOG'); //multiple logs are created in %TEMP% when no filename is given
SetupRestartData := AddSimpleParam(SetupRestartData,'LOG');
break;
end;
end;
DebugMsg('CreateRunOnceEntry','RunOnce: ' + RunOnceData);
RegWriteStringValue(HKLM, 'Software\Microsoft\Windows\CurrentVersion\RunOnce', RunOnceName, RunOnceData);
DebugMsg('CreateRunOnceEntry','RunOnce: ' + SetupRestartData);
RegWriteStringValue(HKLM, 'Software\' + RunOnceName, '', SetupRestartData);
end;
procedure RestartMyself();
var CmdLine: String;
ResultCode: Integer;
begin
DebugMsg('RestartMyself','Continuing install after reboot (reexecuting setup)');
if RegValueExists(HKLM, 'Software\' + RunOnceName, '') then
begin
if RegQueryStringValue(HKLM, 'Software\' + RunOnceName, '', CmdLine) then
begin
RegDeleteKeyIncludingSubkeys(HKLM, 'Software\' + RunOnceName); //clean up
if not Exec('>',CmdLine,'',SW_SHOW,ewNoWait,ResultCode) then //bonus: don't block shell from loading, since RunOnce installer exits immediately
MsgBox(FmtMessage(CustomMessage('ErrorRestartingSetup'),[IntToStr(ResultCode)]), mbError, mb_Ok);
DebugMsg('RestartMyself','Result of running ' + CmdLine + ': ' + IntToStr(ResultCode));
end else
begin
MsgBox(FmtMessage(CustomMessage('ErrorRestartingSetup'),['-2']), mbError, mb_Ok);
DebugMsg('RestartMyself','Error reading HKLM\'+RunOnceName);
end;
end else
begin
MsgBox(FmtMessage(CustomMessage('ErrorRestartingSetup'),['-1']), mbError, mb_Ok);
DebugMsg('RestartMyself','HKLM\'+RunOnceName + ' not found in Registy');
end;
end;
function RestartSetupAfterReboot(): Boolean;
begin
if ExpandConstant('{param:resumeinstall|0}') = '1' then //called from RunOnce
begin
Result := False; //setup will just re-execute itself in this run
RestartMyself();
DebugMsg('RestartSetupAfterReboot','Phase 1 complete, exiting');
exit;
end else
if ExpandConstant('{param:resumeinstall|0}') = '2' then //setup re-executed itself
begin
Result := True;
InstallMode := imRebootContinue;
DebugMsg('RestartSetupAfterReboot','Continuing install after reboot');
end else
begin
Result := True; //normal install
end;
if InstallMode <> imRebootContinue then
if RegValueExists(HKLM, 'Software\Microsoft\Windows\CurrentVersion\RunOnce', RunOnceName) then
begin
DebugMsg('RestartSetupAfterReboot','System must be restarted first');
MsgBox(CustomMessage('RebootRequiredFirst'), mbError, mb_Ok);
Result := False;
end;
end;
#if 0
[Code]
#endif
function Quote(const S: String): String;
begin
Result := '"' + S + '"';
end;
function AddParam(const S, P, V: String): String;
begin
if V <> '""' then
Result := S + ' /' + P + '=' + V;
end;
function AddSimpleParam(const S, P: String): String;
begin
Result := S + ' /' + P;
end;
procedure CreateRunOnceEntry;
var RunOnceData, SetupRestartData: String;
i: Integer;
begin
DebugMsg('CreateRunOnceEntry','Preparing for restart');
//RunOnce command-line is limited to 256 characters, so keep it to the bare minimum required to start setup
RunOnceData := Quote(ExpandConstant('{srcexe}')) + ' /resumeinstall=1';
RunOnceData := AddParam(RunOnceData, 'LANG', ExpandConstant('{language}'));
SetupRestartData := Quote(ExpandConstant('{srcexe}')) + ' /resumeinstall=2';
SetupRestartData := AddParam(SetupRestartData, 'LANG', ExpandConstant('{language}'));
SetupRestartData := AddParam(SetupRestartData, 'DIR', Quote(WizardDirValue));
//SetupRestartData := AddParam(SetupRestartData, 'GROUP', Quote(WizardGroupValue));
//if WizardNoIcons then
// SetupRestartData := AddSimpleParam(SetupRestartData, 'NOICONS');
SetupRestartData := AddParam(SetupRestartData, 'TYPE', Quote(WizardSetupType(False)));
SetupRestartData := AddParam(SetupRestartData, 'COMPONENTS', Quote(WizardSelectedComponents(False)));
SetupRestartData := AddParam(SetupRestartData, 'TASKS', Quote(WizardSelectedTasks(False)));
if Force32bitInstall then
SetupRestartData := AddSimpleParam(SetupRestartData, '32');
if ExpandConstant('{param:log|*}') <> '*' then
begin
SetupRestartData := AddParam(SetupRestartData, 'LOG', Quote(ExpandConstant('{param:log|*}')));
end else
begin
for i := 0 to ParamCount() do
if LowerCase(ParamStr(i)) = '/log' then
begin
RunOnceData := AddSimpleParam(RunOnceData,'LOG'); //multiple logs are created in %TEMP% when no filename is given
SetupRestartData := AddSimpleParam(SetupRestartData,'LOG');
break;
end;
end;
DebugMsg('CreateRunOnceEntry','RunOnce: ' + RunOnceData);
RegWriteStringValue(HKLM, 'Software\Microsoft\Windows\CurrentVersion\RunOnce', RunOnceName, RunOnceData);
DebugMsg('CreateRunOnceEntry','RunOnce: ' + SetupRestartData);
RegWriteStringValue(HKLM, 'Software\' + RunOnceName, '', SetupRestartData);
end;
procedure RestartMyself();
var CmdLine: String;
ResultCode: Integer;
begin
DebugMsg('RestartMyself','Continuing install after reboot (reexecuting setup)');
if RegValueExists(HKLM, 'Software\' + RunOnceName, '') then
begin
if RegQueryStringValue(HKLM, 'Software\' + RunOnceName, '', CmdLine) then
begin
RegDeleteKeyIncludingSubkeys(HKLM, 'Software\' + RunOnceName); //clean up
if not Exec('>',CmdLine,'',SW_SHOW,ewNoWait,ResultCode) then //bonus: don't block shell from loading, since RunOnce installer exits immediately
MsgBox(FmtMessage(CustomMessage('ErrorRestartingSetup'),[IntToStr(ResultCode)]), mbError, mb_Ok);
DebugMsg('RestartMyself','Result of running ' + CmdLine + ': ' + IntToStr(ResultCode));
end else
begin
MsgBox(FmtMessage(CustomMessage('ErrorRestartingSetup'),['-2']), mbError, mb_Ok);
DebugMsg('RestartMyself','Error reading HKLM\'+RunOnceName);
end;
end else
begin
MsgBox(FmtMessage(CustomMessage('ErrorRestartingSetup'),['-1']), mbError, mb_Ok);
DebugMsg('RestartMyself','HKLM\'+RunOnceName + ' not found in Registy');
end;
end;
function RestartSetupAfterReboot(): Boolean;
begin
if ExpandConstant('{param:resumeinstall|0}') = '1' then //called from RunOnce
begin
Result := False; //setup will just re-execute itself in this run
RestartMyself();
DebugMsg('RestartSetupAfterReboot','Phase 1 complete, exiting');
exit;
end else
if ExpandConstant('{param:resumeinstall|0}') = '2' then //setup re-executed itself
begin
Result := True;
InstallMode := imRebootContinue;
DebugMsg('RestartSetupAfterReboot','Continuing install after reboot');
end else
begin
Result := True; //normal install
end;
if InstallMode <> imRebootContinue then
if RegValueExists(HKLM, 'Software\Microsoft\Windows\CurrentVersion\RunOnce', RunOnceName) then
begin
DebugMsg('RestartSetupAfterReboot','System must be restarted first');
MsgBox(CustomMessage('RebootRequiredFirst'), mbError, mb_Ok);
Result := False;
end;
end;

View File

@ -1,335 +1,335 @@
#if 0
[Code]
#endif
function SplitRegParams(const pInf: String; var oRootKey: Integer; var oKey,oValue: String): Boolean;
var sRootKey: String;
d: Integer;
begin
Result := False;
d := Pos('/',pInf);
if d = 0 then
begin
DebugMsg('SplitRegParams','Malformed line (missing /): ' + pInf);
exit;
end;
sRootKey := Copy(pInf,1,d - 1);
oKey := Copy(pInf,d + 1,Length(pInf));
if oValue <> 'nil' then
begin
d := RevPos('\',oKey);
if d = 0 then
begin
DebugMsg('SplitRegParams','Malformed line (missing \): ' + pInf);
exit;
end;
oValue := Decode(Copy(oKey,d+1,Length(oKey)));
oKey := Copy(oKey,1,d-1);
end;
DebugMsg('SplitRegParams','Root: '+sRootKey+', Key:'+oKey + ', Value:'+oValue);
case sRootKey of
'HKCR': oRootKey := HKCR;
'HKLM': oRootKey := HKLM;
'HKU': oRootKey := HKU;
'HKCU': oRootKey := HKCU;
else
begin
DebugMsg('SplitRegParams','Unrecognised root key: ' + sRootKey);
exit;
end;
end;
Result := True;
end;
procedure UninstInfRegKey(const pInf: String; const pIfEmpty: Boolean);
var sKey,sVal: String;
iRootKey: Integer;
begin
sVal := 'nil';
if not SplitRegParams(pInf,iRootKey,sKey,sVal) then
exit;
if pIfEmpty then
begin
if not RegDeleteKeyIfEmpty(iRootKey,sKey) then
DebugMsg('UninstInfRegKey','RegDeleteKeyIfEmpty failed');
end
else
begin
if not RegDeleteKeyIncludingSubkeys(iRootKey,sKey) then
DebugMsg('UninstInfRegKey','RegDeleteKeyIncludingSubkeys failed');
end;
end;
procedure UninstInfRegVal(const pInf: String);
var sKey,sVal: String;
iRootKey: Integer;
begin
if not SplitRegParams(pInf,iRootKey,sKey,sVal) then
exit;
if not RegDeleteValue(iRootKey,sKey,sVal) then
DebugMsg('UninstInfREG','RegDeleteKeyIncludingSubkeys failed');
end;
procedure UninstInfFile(const pFile: String);
begin
DebugMsg('UninstInfFile','File: '+pFile);
if not DeleteFile(pFile) then
DebugMsg('UninstInfFile','DeleteFile failed');
end;
procedure UninstInfDir(const pDir: String);
begin
DebugMsg('UninstInfDir','Dir: '+pDir);
if not RemoveDir(pDir) then
DebugMsg('UninstInfDir','RemoveDir failed');
end;
procedure CreateMessageForm(var frmMessage: TForm; const pMessage: String);
var lblMessage: TNewStaticText;
begin
frmMessage := CreateCustomForm();
with frmMessage do
begin
BorderStyle := bsDialog;
ClientWidth := ScaleX(300);
ClientHeight := ScaleY(48);
Caption := CustomMessage('UninstallingAddOnCaption');
Position := poScreenCenter;
BorderIcons := [];
end;
lblMessage := TNewStaticText.Create(frmMessage);
with lblMessage do
begin
Parent := frmMessage;
AutoSize := True;
Caption := pMessage;
Top := (frmMessage.ClientHeight - Height) div 2;
Left := (frmMessage.ClientWidth - Width) div 2;
Visible := True;
end;
frmMessage.Show();
frmMessage.Refresh();
end;
procedure UninstInfRun(const pInf: String);
var Description,Prog,Params: String;
Split, ResultCode, Ctr: Integer;
frmMessage: TForm;
begin
DebugMsg('UninstInfRun',pInf);
Split := Pos('/',pInf);
if Split <> 0 then
begin
Description := Copy(pInf, 1, Split - 1);
Prog := Copy(pInf, Split + 1, Length(pInf));
end else
begin
Prog := pInf;
Description := '';
end;
Split := Pos('/',Prog);
if Split <> 0 then
begin
Params := Copy(Prog, Split + 1, Length(Prog));
Prog := Copy(Prog, 1, Split - 1);
end else
begin
Params := '';
end;
if not UninstallSilent then //can't manipulate uninstaller messages, so create a form instead
CreateMessageForm(frmMessage,Description);
DebugMsg('UninstInfRun','Running: ' + Prog + '; Params: ' + Params);
if Exec(Prog,Params,'',SW_SHOW,ewWaitUntilTerminated,ResultCode) then
begin
DebugMsg('UninstInfRun','Exec result: ' + IntToStr(ResultCode));
Ctr := 0;
while FileExists(Prog) do //wait a few seconds for the uninstaller to be deleted - since this is done by a program
begin //running from a temporary directory, the uninstaller we ran above will exit some time before
Sleep(UNINSTALL_CHECK_TIME); //it's removed from disk
Inc(Ctr);
if Ctr = (UNINSTALL_MAX_WAIT_TIME/UNINSTALL_CHECK_TIME) then //don't wait more than 5 seconds
break;
end;
end else
DebugMsg('UninstInfRun','Exec failed: ' + IntToStr(ResultCode) + ' (' + SysErrorMessage(ResultCode) + ')');
if not UninstallSilent then
frmMessage.Free();
end;
(*
uninst.inf documentation:
- Delete Registry keys (with all subkeys):
RegKey:<RootKey>/<SubKey>
RootKey = HKCR, HKLM, HKCU, HKU
SubKey = subkey to delete (warning: this will delete all keys under subkey, so be very careful with it)
- Delete empty registry keys:
RegKeyEmpty:<RootKey>/<SubKey>
RootKey = HKCR, HKLM, HKCU, HKU
SubKey = subkey to delete if empty
- Delete values from registry:
RegVal:<RootKey>/<SubKey>/Value
RootKey = HKCR, HKLM, HKCU, HKU
SubKey = subkey to delete Value from
Value = value to delete; \ and % must be escaped as %5c and %25
- Delete files:
File:<Path>
Path = full path to file
- Delete empty directories:
Dir:<Path>
- Run program with parameters:
Run:<description>/<path>/<params>
Directives are parsed from the end of the file backwards as the first step of uninstall.
IMPORTANT: From GIMP 2.10.12 onwards (Inno Setup 6 with support for per-user install), Registry keys referring to HKCR will be
processed by the installer as the first step of install (and the entries will be removed from uninst.inf), since file associations
code was rewritten.
*)
procedure ParseUninstInf();
var i,d: Integer;
sWhat: String;
begin
for i := GetArrayLength(asUninstInf) - 1 downto 0 do
begin
DebugMsg('ParseUninstInf',asUninstInf[i]);
if (Length(asUninstInf[i]) = 0) or (asUninstInf[i][1] = '#') then //skip comments and empty lines
continue;
d := Pos(':',asUninstInf[i]);
if d = 0 then
begin
DebugMsg('ParseUninstInf','Malformed line: ' + asUninstInf[i]);
continue;
end;
sWhat := Copy(asUninstInf[i],d+1,Length(asUninstInf[i]));
case Copy(asUninstInf[i],1,d) of
'RegKey:': UninstInfRegKey(sWhat,False);
'RegKeyEmpty:': UninstInfRegKey(sWhat,True);
'RegVal:': UninstInfRegVal(sWhat);
'File:': UninstInfFile(sWhat);
'Dir:': UninstInfDir(sWhat);
'Run:': UninstInfRun(sWhat);
end;
end;
end;
procedure CurUninstallStepChanged(CurStep: TUninstallStep);
begin
DebugMsg('CurUninstallStepChanged','');
case CurStep of
usUninstall:
begin
LoadStringsFromFile(ExpandConstant('{app}\uninst\uninst.inf'),asUninstInf);
ParseUninstInf();
end;
//usPostUninstall:
end;
end;
procedure AssociationsCleanUp();
var i, d, countNew,countUI: Integer;
asTemp, asNew: TArrayOfString;
sKey,sVal: String;
iRootKey: Integer;
begin
if FileExists(ExpandConstant('{app}\uninst\uninst.inf')) then
begin
DebugMsg('AssociationsCleanUp','Parsing old uninst.inf');
LoadStringsFromFile(ExpandConstant('{app}\uninst\uninst.inf'),asTemp);
countNew := 0;
countUI := 0;
SetArrayLength(asNew, GetArrayLength(asTemp));
SetArrayLength(asUninstInf, GetArrayLength(asTemp));
for i := 0 to GetArrayLength(asTemp) - 1 do //extract associations-related entries from uninst.inf
begin
if (Length(asTemp[i]) = 0) or (asTemp[i][1] = '#') then //comment/empty line
begin
asNew[countNew] := asTemp[i];
Inc(countNew);
continue;
end;
d := Pos(':',asTemp[i]);
if d = 0 then //something wrong, ignore
continue;
if Copy(asTemp[i],1,3) = 'Reg' then
begin
sVal := 'nil';
if not SplitRegParams(Copy(asTemp[i], d + 1, Length(asTemp[i])),iRootKey,sKey,sVal) then
continue; //malformed line, ignore
if iRootKey = HKCR then //old association, prepare for cleanup
begin
DebugMsg('AssociationsCleanUp','Preparing for cleanup: '+asTemp[i]);
asUninstInf[countUI] := asTemp[i];
Inc(countUI);
continue;
end;
end;
//something else, keep for new uninst.inf
asNew[countNew] := asTemp[i];
Inc(countNew);
end;
SetArrayLength(asNew, countNew);
SetArrayLength(asUninstInf, countUI);
SaveStringsToUTF8File(ExpandConstant('{app}\uninst\uninst.inf'), asNew, False); //replace uninst.inf with a cleaned one
ParseUninstInf(); //remove old associations
end;
end;
#if 0
[Code]
#endif
function SplitRegParams(const pInf: String; var oRootKey: Integer; var oKey,oValue: String): Boolean;
var sRootKey: String;
d: Integer;
begin
Result := False;
d := Pos('/',pInf);
if d = 0 then
begin
DebugMsg('SplitRegParams','Malformed line (missing /): ' + pInf);
exit;
end;
sRootKey := Copy(pInf,1,d - 1);
oKey := Copy(pInf,d + 1,Length(pInf));
if oValue <> 'nil' then
begin
d := RevPos('\',oKey);
if d = 0 then
begin
DebugMsg('SplitRegParams','Malformed line (missing \): ' + pInf);
exit;
end;
oValue := Decode(Copy(oKey,d+1,Length(oKey)));
oKey := Copy(oKey,1,d-1);
end;
DebugMsg('SplitRegParams','Root: '+sRootKey+', Key:'+oKey + ', Value:'+oValue);
case sRootKey of
'HKCR': oRootKey := HKCR;
'HKLM': oRootKey := HKLM;
'HKU': oRootKey := HKU;
'HKCU': oRootKey := HKCU;
else
begin
DebugMsg('SplitRegParams','Unrecognised root key: ' + sRootKey);
exit;
end;
end;
Result := True;
end;
procedure UninstInfRegKey(const pInf: String; const pIfEmpty: Boolean);
var sKey,sVal: String;
iRootKey: Integer;
begin
sVal := 'nil';
if not SplitRegParams(pInf,iRootKey,sKey,sVal) then
exit;
if pIfEmpty then
begin
if not RegDeleteKeyIfEmpty(iRootKey,sKey) then
DebugMsg('UninstInfRegKey','RegDeleteKeyIfEmpty failed');
end
else
begin
if not RegDeleteKeyIncludingSubkeys(iRootKey,sKey) then
DebugMsg('UninstInfRegKey','RegDeleteKeyIncludingSubkeys failed');
end;
end;
procedure UninstInfRegVal(const pInf: String);
var sKey,sVal: String;
iRootKey: Integer;
begin
if not SplitRegParams(pInf,iRootKey,sKey,sVal) then
exit;
if not RegDeleteValue(iRootKey,sKey,sVal) then
DebugMsg('UninstInfREG','RegDeleteKeyIncludingSubkeys failed');
end;
procedure UninstInfFile(const pFile: String);
begin
DebugMsg('UninstInfFile','File: '+pFile);
if not DeleteFile(pFile) then
DebugMsg('UninstInfFile','DeleteFile failed');
end;
procedure UninstInfDir(const pDir: String);
begin
DebugMsg('UninstInfDir','Dir: '+pDir);
if not RemoveDir(pDir) then
DebugMsg('UninstInfDir','RemoveDir failed');
end;
procedure CreateMessageForm(var frmMessage: TForm; const pMessage: String);
var lblMessage: TNewStaticText;
begin
frmMessage := CreateCustomForm();
with frmMessage do
begin
BorderStyle := bsDialog;
ClientWidth := ScaleX(300);
ClientHeight := ScaleY(48);
Caption := CustomMessage('UninstallingAddOnCaption');
Position := poScreenCenter;
BorderIcons := [];
end;
lblMessage := TNewStaticText.Create(frmMessage);
with lblMessage do
begin
Parent := frmMessage;
AutoSize := True;
Caption := pMessage;
Top := (frmMessage.ClientHeight - Height) div 2;
Left := (frmMessage.ClientWidth - Width) div 2;
Visible := True;
end;
frmMessage.Show();
frmMessage.Refresh();
end;
procedure UninstInfRun(const pInf: String);
var Description,Prog,Params: String;
Split, ResultCode, Ctr: Integer;
frmMessage: TForm;
begin
DebugMsg('UninstInfRun',pInf);
Split := Pos('/',pInf);
if Split <> 0 then
begin
Description := Copy(pInf, 1, Split - 1);
Prog := Copy(pInf, Split + 1, Length(pInf));
end else
begin
Prog := pInf;
Description := '';
end;
Split := Pos('/',Prog);
if Split <> 0 then
begin
Params := Copy(Prog, Split + 1, Length(Prog));
Prog := Copy(Prog, 1, Split - 1);
end else
begin
Params := '';
end;
if not UninstallSilent then //can't manipulate uninstaller messages, so create a form instead
CreateMessageForm(frmMessage,Description);
DebugMsg('UninstInfRun','Running: ' + Prog + '; Params: ' + Params);
if Exec(Prog,Params,'',SW_SHOW,ewWaitUntilTerminated,ResultCode) then
begin
DebugMsg('UninstInfRun','Exec result: ' + IntToStr(ResultCode));
Ctr := 0;
while FileExists(Prog) do //wait a few seconds for the uninstaller to be deleted - since this is done by a program
begin //running from a temporary directory, the uninstaller we ran above will exit some time before
Sleep(UNINSTALL_CHECK_TIME); //it's removed from disk
Inc(Ctr);
if Ctr = (UNINSTALL_MAX_WAIT_TIME/UNINSTALL_CHECK_TIME) then //don't wait more than 5 seconds
break;
end;
end else
DebugMsg('UninstInfRun','Exec failed: ' + IntToStr(ResultCode) + ' (' + SysErrorMessage(ResultCode) + ')');
if not UninstallSilent then
frmMessage.Free();
end;
(*
uninst.inf documentation:
- Delete Registry keys (with all subkeys):
RegKey:<RootKey>/<SubKey>
RootKey = HKCR, HKLM, HKCU, HKU
SubKey = subkey to delete (warning: this will delete all keys under subkey, so be very careful with it)
- Delete empty registry keys:
RegKeyEmpty:<RootKey>/<SubKey>
RootKey = HKCR, HKLM, HKCU, HKU
SubKey = subkey to delete if empty
- Delete values from registry:
RegVal:<RootKey>/<SubKey>/Value
RootKey = HKCR, HKLM, HKCU, HKU
SubKey = subkey to delete Value from
Value = value to delete; \ and % must be escaped as %5c and %25
- Delete files:
File:<Path>
Path = full path to file
- Delete empty directories:
Dir:<Path>
- Run program with parameters:
Run:<description>/<path>/<params>
Directives are parsed from the end of the file backwards as the first step of uninstall.
IMPORTANT: From GIMP 2.10.12 onwards (Inno Setup 6 with support for per-user install), Registry keys referring to HKCR will be
processed by the installer as the first step of install (and the entries will be removed from uninst.inf), since file associations
code was rewritten.
*)
procedure ParseUninstInf();
var i,d: Integer;
sWhat: String;
begin
for i := GetArrayLength(asUninstInf) - 1 downto 0 do
begin
DebugMsg('ParseUninstInf',asUninstInf[i]);
if (Length(asUninstInf[i]) = 0) or (asUninstInf[i][1] = '#') then //skip comments and empty lines
continue;
d := Pos(':',asUninstInf[i]);
if d = 0 then
begin
DebugMsg('ParseUninstInf','Malformed line: ' + asUninstInf[i]);
continue;
end;
sWhat := Copy(asUninstInf[i],d+1,Length(asUninstInf[i]));
case Copy(asUninstInf[i],1,d) of
'RegKey:': UninstInfRegKey(sWhat,False);
'RegKeyEmpty:': UninstInfRegKey(sWhat,True);
'RegVal:': UninstInfRegVal(sWhat);
'File:': UninstInfFile(sWhat);
'Dir:': UninstInfDir(sWhat);
'Run:': UninstInfRun(sWhat);
end;
end;
end;
procedure CurUninstallStepChanged(CurStep: TUninstallStep);
begin
DebugMsg('CurUninstallStepChanged','');
case CurStep of
usUninstall:
begin
LoadStringsFromFile(ExpandConstant('{app}\uninst\uninst.inf'),asUninstInf);
ParseUninstInf();
end;
//usPostUninstall:
end;
end;
procedure AssociationsCleanUp();
var i, d, countNew,countUI: Integer;
asTemp, asNew: TArrayOfString;
sKey,sVal: String;
iRootKey: Integer;
begin
if FileExists(ExpandConstant('{app}\uninst\uninst.inf')) then
begin
DebugMsg('AssociationsCleanUp','Parsing old uninst.inf');
LoadStringsFromFile(ExpandConstant('{app}\uninst\uninst.inf'),asTemp);
countNew := 0;
countUI := 0;
SetArrayLength(asNew, GetArrayLength(asTemp));
SetArrayLength(asUninstInf, GetArrayLength(asTemp));
for i := 0 to GetArrayLength(asTemp) - 1 do //extract associations-related entries from uninst.inf
begin
if (Length(asTemp[i]) = 0) or (asTemp[i][1] = '#') then //comment/empty line
begin
asNew[countNew] := asTemp[i];
Inc(countNew);
continue;
end;
d := Pos(':',asTemp[i]);
if d = 0 then //something wrong, ignore
continue;
if Copy(asTemp[i],1,3) = 'Reg' then
begin
sVal := 'nil';
if not SplitRegParams(Copy(asTemp[i], d + 1, Length(asTemp[i])),iRootKey,sKey,sVal) then
continue; //malformed line, ignore
if iRootKey = HKCR then //old association, prepare for cleanup
begin
DebugMsg('AssociationsCleanUp','Preparing for cleanup: '+asTemp[i]);
asUninstInf[countUI] := asTemp[i];
Inc(countUI);
continue;
end;
end;
//something else, keep for new uninst.inf
asNew[countNew] := asTemp[i];
Inc(countNew);
end;
SetArrayLength(asNew, countNew);
SetArrayLength(asUninstInf, countUI);
SaveStringsToUTF8File(ExpandConstant('{app}\uninst\uninst.inf'), asNew, False); //replace uninst.inf with a cleaned one
ParseUninstInf(); //remove old associations
end;
end;

View File

@ -1,26 +1,26 @@
//set the version string
#define public
#if !Defined(VERSION)
#error "VERSION must be defined"
#endif
#define GTK_VER=GetFileVersion(AddBackslash(DEPS_DIR64) + "bin\libgtk-win32-2.0-0.dll")
#define public
//used in the component list
#define GTK_VERSION=Copy(GTK_VER,1,RPos(".",GTK_VER)-1)
#define MAJOR=Copy(VERSION,1,Pos(".",VERSION)-1)
#define MINOR=Copy(VERSION,Pos(".",VERSION)+1)
#define MICRO=Copy(MINOR,Pos(".",MINOR)+1)
#expr MINOR=Copy(MINOR,1,Pos(".",MINOR)-1)
#if Int(MINOR) % 2 == 1
#define DEVEL="-dev"
#define DIR_VER=MAJOR + "." + MINOR
#else
#define DEVEL=""
#define DIR_VER=MAJOR + ".0"
#endif
//set the version string
#define public
#if !Defined(VERSION)
#error "VERSION must be defined"
#endif
#define GTK_VER=GetFileVersion(AddBackslash(DEPS_DIR64) + "bin\libgtk-win32-2.0-0.dll")
#define public
//used in the component list
#define GTK_VERSION=Copy(GTK_VER,1,RPos(".",GTK_VER)-1)
#define MAJOR=Copy(VERSION,1,Pos(".",VERSION)-1)
#define MINOR=Copy(VERSION,Pos(".",VERSION)+1)
#define MICRO=Copy(MINOR,Pos(".",MINOR)+1)
#expr MINOR=Copy(MINOR,1,Pos(".",MINOR)-1)
#if Int(MINOR) % 2 == 1
#define DEVEL="-dev"
#define DIR_VER=MAJOR + "." + MINOR
#else
#define DEVEL=""
#define DIR_VER=MAJOR + ".0"
#endif

View File

@ -68,7 +68,7 @@ On Linux and MacOS, you simply need a shebang in a plugin text file.
On Windows, you must also define an .interp file.
The .interp files are part of GIMP's installation on Windows.
The .interp files are built when the Windows installer is built.
See the source file: /build/windows/installer/gimp3264.iss .
See the source file: /build/windows/installer/base_gimp3264.iss .
A user can optionally create .interp files on Linux and MacOS.
But they are not usually part of a Linux installation.
@ -196,7 +196,7 @@ If a GIMP developer adds an interpreter to the GIMP package,
they must modify GIMP's build for Windows
to ensure proper .interp files are installed.
See the repo file: /build/windows/installer/gimp3264.iss .
See the repo file: /build/windows/installer/base_gimp3264.iss .
For the convenience of users, we usually install an .interp file having many lines.
Only one "program" line is needed if users only install canonical plugin text files