From 297e981d328a03f5b149b17380407963251120c1 Mon Sep 17 00:00:00 2001 From: kichik Date: Sat, 9 Nov 2002 12:50:00 +0000 Subject: [PATCH] Even easier paging system, no more Abort and Quit from custom pages creator functions, NSIS does it all! git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@1636 212acab6-be3b-0410-9dea-997c60f758d6 --- Contrib/BgImage/BgImage.cpp | 2 +- Contrib/BgImage/BgImage.dsp | 2 +- Contrib/BgImage/exdll.h | 49 -------- Contrib/ExDLL/exdll.h | 2 + Contrib/InstallOptions/Install Options.html | 10 +- Contrib/InstallOptions/InstallerOptions.cpp | 52 ++------- Contrib/InstallOptions/test.nsi | 23 ++-- Contrib/StartMenu/Example.nsi | 11 +- Contrib/StartMenu/Readme.txt | 9 +- Contrib/StartMenu/StartMenu.c | 60 +++------- Contrib/StartMenu/StartMenu.dsp | 2 +- Contrib/StartMenu/exdll.h | 93 --------------- Docs/src/pages.but | 18 +-- Plugins/InstallOptions.dll | Bin 12288 -> 11776 bytes Plugins/StartMenu.dll | Bin 6656 -> 5632 bytes Source/build.cpp | 4 +- Source/exehead/Ui.c | 121 ++++++++++---------- 17 files changed, 123 insertions(+), 335 deletions(-) delete mode 100644 Contrib/BgImage/exdll.h delete mode 100644 Contrib/StartMenu/exdll.h diff --git a/Contrib/BgImage/BgImage.cpp b/Contrib/BgImage/BgImage.cpp index 03fc9b07..2ff1fd96 100644 --- a/Contrib/BgImage/BgImage.cpp +++ b/Contrib/BgImage/BgImage.cpp @@ -1,6 +1,6 @@ #include #include -#include "exdll.h" +#include "../exdll/exdll.h" int x, y; char temp[MAX_PATH]; diff --git a/Contrib/BgImage/BgImage.dsp b/Contrib/BgImage/BgImage.dsp index be7a129f..ee100eb7 100644 --- a/Contrib/BgImage/BgImage.dsp +++ b/Contrib/BgImage/BgImage.dsp @@ -67,7 +67,7 @@ SOURCE=.\BgImage.cpp # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File -SOURCE=.\exdll.h +SOURCE=..\ExDLL\exdll.h # End Source File # End Group # Begin Group "Resource Files" diff --git a/Contrib/BgImage/exdll.h b/Contrib/BgImage/exdll.h deleted file mode 100644 index 5ecbd013..00000000 --- a/Contrib/BgImage/exdll.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef _EXDLL_H_ -#define _EXDLL_H_ - -// only include this file from one place in your DLL. -// (it is all static, if you use it in two places it will fail) - -#define EXDLL_INIT() { \ - g_hwndParent=hwndParent; \ - g_stringsize=string_size; \ - g_stacktop=stacktop; \ - /*g_variables=variables;*/ } - - -typedef struct _stack_t { - struct _stack_t *next; - char text[1]; // this should be the length of string_size -} stack_t; - - -static int g_stringsize; -static stack_t **g_stacktop; -static HWND g_hwndParent; - -static int popstring(char *str); // 0 on success, 1 on empty stack -static void pushstring(char *str); - -// utility functions (not required but often useful) -static int popstring(char *str) -{ - stack_t *th; - if (!g_stacktop || !*g_stacktop) return 1; - th=(*g_stacktop); - lstrcpy(str,th->text); - *g_stacktop = th->next; - GlobalFree((HGLOBAL)th); - return 0; -} - -static void pushstring(char *str) -{ - stack_t *th; - if (!g_stacktop) return; - th=(stack_t*)GlobalAlloc(GPTR,sizeof(stack_t)+g_stringsize); - lstrcpyn(th->text,str,g_stringsize); - th->next=*g_stacktop; - *g_stacktop=th; -} - -#endif//_EXDLL_H_ \ No newline at end of file diff --git a/Contrib/ExDLL/exdll.h b/Contrib/ExDLL/exdll.h index a64a2ed3..301ec31f 100644 --- a/Contrib/ExDLL/exdll.h +++ b/Contrib/ExDLL/exdll.h @@ -9,6 +9,8 @@ g_stacktop=stacktop; \ g_variables=variables; } +// For page showing plug-ins +#define WM_NOTIFY_OUTER_NEXT (WM_USER+0x8) typedef struct _stack_t { struct _stack_t *next; diff --git a/Contrib/InstallOptions/Install Options.html b/Contrib/InstallOptions/Install Options.html index 29ab2282..50c16c54 100644 --- a/Contrib/InstallOptions/Install Options.html +++ b/Contrib/InstallOptions/Install Options.html @@ -282,10 +282,8 @@ Here is a little example: InstallOptions::show Pop $0 StrCmp $0 "success" done - StrCmp $0 "back" 0 +2 - Abort - StrCmp $0 "cancel" 0 error - Quit + StrCmp $0 "back" done + StrCmp $0 "cancel" done error: MessageBox MB_OK|MB_ICONSTOP "IO error: $0" Quit @@ -404,8 +402,8 @@ Here is a little example:
  • Barely qualifies as a distribution.

-
  Copyright © 2001 Michael Bishop
-  Portions Copyright © 2001 Nullsoft, Inc.
+
  Copyright © 2001 Michael Bishop
+  Portions Copyright © 2001 Nullsoft, Inc.
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/Contrib/InstallOptions/InstallerOptions.cpp b/Contrib/InstallOptions/InstallerOptions.cpp
index 936ae9d2..3da15f66 100644
--- a/Contrib/InstallOptions/InstallerOptions.cpp
+++ b/Contrib/InstallOptions/InstallerOptions.cpp
@@ -165,12 +165,9 @@ HINSTANCE m_hInstance = NULL;
 
 char *pszFilename = NULL;
 char *pszTitle = NULL;
-char *pszCancelQuestion = NULL;
-char *pszCancelQuestionCaption = NULL;
 char *pszCancelButtonText = NULL;
 char *pszNextButtonText = NULL;
 char *pszBackButtonText = NULL;
-unsigned int nCancelConfirmFlags=0;
 BOOL bBackDisabled=FALSE;
 
 BOOL bCancelEnabled=TRUE;  // by ORTIM: 13-August-2002
@@ -455,36 +452,12 @@ char * WINAPI myGetProfileStringDup(LPCTSTR lpAppName, LPCTSTR lpKeyName)
 bool ReadSettings(void) {
   static char szField[25];
   int nIdx;
-  // Messagebox flags
-  static TableEntry MBFlagTable[] = {
-    { "MB_ICONEXCLAMATION", MB_ICONEXCLAMATION },
-//  { "MB_ICONWARNING",     MB_ICONWARNING     }, // same as above
-    { "MB_ICONINFORMATION", MB_ICONINFORMATION },
-//  { "MB_ICONASTERISK",    MB_ICONASTERISK    }, // same as above
-    { "MB_ICONQUESTION",    MB_ICONQUESTION    },
-    { "MB_ICONSTOP",        MB_ICONSTOP        },
-//  { "MB_ICONERROR",       MB_ICONERROR       }, // same as above
-//  { "MB_ICONHAND",        MB_ICONHAND        }, // same as above
-    { "MB_TOPMOST",         MB_TOPMOST         },
-    { "MB_SETFOREGROUND",   MB_SETFOREGROUND   },
-    { "MB_RIGHT",           MB_RIGHT           },
-    { "MB_DEFBUTTON1",      MB_DEFBUTTON1      },
-    { "MB_DEFBUTTON2",      MB_DEFBUTTON2      },
-//  { "MB_DEFBUTTON3",      MB_DEFBUTTON3      }, // useless, as there are only two buttons
-//  { "MB_DEFBUTTON4",      MB_DEFBUTTON4      }, // useless, as there are only two buttons
-    { NULL,                 0                  }
-  };
 
   pszTitle = myGetProfileStringDup("Settings", "Title");
-  pszCancelQuestion = myGetProfileStringDup("Settings", "CancelConfirm");
-  pszCancelQuestionCaption = myGetProfileStringDup("Settings", "CancelConfirmCaption");
   pszCancelButtonText = myGetProfileStringDup("Settings", "CancelButtonText");
   pszNextButtonText = myGetProfileStringDup("Settings", "NextButtonText");
   pszBackButtonText = myGetProfileStringDup("Settings", "BackButtonText");
 
-  myGetProfileString("Settings", "CancelConfirmFlags");
-  nCancelConfirmFlags = LookupTokens(MBFlagTable, szResult);
-
   nNumFields = GetPrivateProfileInt("Settings", "NumFields", 0, pszFilename);
   bBackDisabled = GetPrivateProfileInt("Settings", "BackDisabled", 0, pszFilename);
 
@@ -671,15 +644,9 @@ static void *lpWndProcOld;
 
 static LRESULT CALLBACK ParentWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
-  if (message == WM_CLOSE)
+  if (message == WM_NOTIFY_OUTER_NEXT)
   {
-    message = WM_COMMAND;
-    wParam = IDCANCEL;
-  }
-	if (message == WM_COMMAND && (LOWORD(wParam) == IDCANCEL || LOWORD(wParam) == IDOK || LOWORD(wParam) == 3))
-  {
-		PostMessage(hConfigWindow,WM_USER+666,0,LOWORD(wParam));
-    return 0;
+    PostMessage(hConfigWindow,WM_USER+666,wParam,0);
   }
   return CallWindowProc((long (__stdcall *)(struct HWND__ *,unsigned int,unsigned int,long))lpWndProcOld,hwnd,message,wParam,lParam);
 }
@@ -697,14 +664,11 @@ BOOL CALLBACK cfgDlgProc(HWND   hwndDlg,
     HANDLE_MSG(hwndDlg, WM_COMMAND, WMCommandProc);
     return 0;
     case WM_USER+666:
-      if (lParam != IDCANCEL || !pszCancelQuestion || MessageBox(hwndDlg,pszCancelQuestion,pszCancelQuestionCaption?pszCancelQuestionCaption:"Question",MB_YESNO|nCancelConfirmFlags)==IDYES)
-      {
-        if (lParam == IDCANCEL || lParam == 3 || ValidateFields()) {
-          if (lParam == 3) g_is_back++;
-          if (lParam == IDCANCEL) g_is_cancel++;
-          g_done++;
-          PostMessage(hwndDlg,WM_CLOSE,0,0);
-        }
+      if (wParam == 0xD1E || wParam == -1 || ValidateFields()) {
+        if (wParam == -1) g_is_back++;
+        if (wParam == 0xD1E) g_is_cancel++;
+        g_done++;
+        PostMessage(hwndDlg,WM_CLOSE,0,0);
       }
     break;
     case WM_CTLCOLORSTATIC:
@@ -1036,8 +1000,6 @@ void showCfgDlg()
   if (cw_vis) ShowWindow(childwnd,SW_SHOWNA);
 
   FREE(pszTitle);
-  FREE(pszCancelQuestion);
-  FREE(pszCancelQuestionCaption);
   FREE(pszCancelButtonText);
   FREE(pszNextButtonText);
   FREE(pszBackButtonText);
diff --git a/Contrib/InstallOptions/test.nsi b/Contrib/InstallOptions/test.nsi
index 45ca538a..68aa4598 100644
--- a/Contrib/InstallOptions/test.nsi
+++ b/Contrib/InstallOptions/test.nsi
@@ -61,21 +61,22 @@ FunctionEnd
 
 Function SetCustom
 
- ;Display the Install Options dialog
+  ;Display the Install Options dialog
 
- Push ${TEMP1}
+  Push ${TEMP1}
 
   InstallOptions::dialog "$PLUGINSDIR\test.ini"
   Pop ${TEMP1}
 
-  StrCmp ${TEMP1} "cancel" "" +3
-    Pop ${TEMP1}
-    Quit
+  StrCmp ${TEMP1} "cancel" done
+  StrCmp ${TEMP1} "back" done
+  StrCmp ${TEMP1} "success" 0 error
+    # User clicked Next, all fields validated, read stuff from the INI here or later
+    Goto done
+
+  error:
+    MessageBox MB_OK|MB_ICONSTOP "InstallOptions error:$\r$\n${TEMP1}"
+
+  done: Pop ${TEMP1}
 
-  StrCmp ${TEMP1} "back" "" +3
-    Pop ${TEMP1}
-    Abort
-    
- Pop ${TEMP1}
-  
 FunctionEnd
\ No newline at end of file
diff --git a/Contrib/StartMenu/Example.nsi b/Contrib/StartMenu/Example.nsi
index da8d5916..ba6654dc 100644
--- a/Contrib/StartMenu/Example.nsi
+++ b/Contrib/StartMenu/Example.nsi
@@ -9,7 +9,7 @@ OutFile "StartMenu Test.exe"
 XPStyle on
 
 Page directory
-DirText "This installer will create some shortcuts to MakeNSIS in the start menu.$\nFor this it needs NSIS's folder path." \
+DirText "This installer will create some shortcuts to MakeNSIS in the start menu.$\nFor this it needs NSIS's path." \
   "Please specify the path in which you have installed NSIS:"
 InstallDir "${NSISDIR}"
 Function .onVerifyInstDir
@@ -21,7 +21,7 @@ Page custom StartMenuGroupSelect
 Function StartMenuGroupSelect
 	SendMessage $HWNDPARENT ${WM_SETTEXT} 0 "STR:StartMenu.dll test Setup: Start Menu Folder"
 
-	StartMenu::Select /autoadd "StartMenu.dll test"
+	StartMenu::Select /autoadd /lastused $R0 "StartMenu.dll test"
 	Pop $R1
 
 	StrCpy $R2 $R1 5
@@ -29,11 +29,8 @@ Function StartMenuGroupSelect
 		; error
 		MessageBox MB_OK $R1
 		Return
-	StrCmp $R1 "cancel" 0 +2
-		Quit
-	StrCmp $R1 "back" 0 +2
-		Abort
-	StrCpy $R0 $R1 ; got the dir
+	StrCpy $R0 $R1 ; got the dir, or cancel, but if it's cancel NSIS will exit and
+				   ; then we shouldn't care about the value of $R0
 FunctionEnd
 
 Page instfiles
diff --git a/Contrib/StartMenu/Readme.txt b/Contrib/StartMenu/Readme.txt
index 7ce652bd..e288a529 100644
--- a/Contrib/StartMenu/Readme.txt
+++ b/Contrib/StartMenu/Readme.txt
@@ -5,10 +5,11 @@ To show the dialog use the Select function. This function has one required param
 which is the program group default name, and some more optional parameters:
   /autoadd - automatically adds the program name to the selected folder
   /noicon - doesn't show the icon in the top left corner
-  /text [please select...] - sets the top text to something else than "Select 
-                             the Start Menu folder in which..."
-  /cancelconfirm [text] [caption] [flags] - displays a cancel confirmation 
-              message box when the user click on the cancel button
+  /text [please select...] - sets the top text to something else than
+                             "Select the Start Menu folder in which..."
+  /lastused [folder] - sets the edit box to a specific value folder.
+                       Use this to make this plug-in remember the last
+		       folder selected by the user
 
 The function pushes the folder selection back to the stack. It does not push the 
 full path but only the selected sub-folder. It's up to you to decide if to put 
diff --git a/Contrib/StartMenu/StartMenu.c b/Contrib/StartMenu/StartMenu.c
index c52e8655..bc7af6ae 100644
--- a/Contrib/StartMenu/StartMenu.c
+++ b/Contrib/StartMenu/StartMenu.c
@@ -1,7 +1,9 @@
 #include 
-#include "exdll.h"
+#include "../exdll/exdll.h"
 #include "resource.h"
 
+#define WM_NOTIFY_OUTER_NEXT (WM_USER+0x8)
+
 HINSTANCE g_hInstance;
 
 HWND hwParent;
@@ -15,10 +17,7 @@ HWND hwDirList;
 char buf[MAX_PATH];
 char text[1024];
 char progname[1024];
-char cancelconfirm[1024];
-char cancelconfirmcaption[1024];
-
-unsigned int cancelconfirmflags = 0;
+char lastused[1024];
 
 int autoadd = 0;
 int g_done = 0;
@@ -71,24 +70,9 @@ void __declspec(dllexport) Select(HWND hwndParent, int string_size, char *variab
       {
         autoadd = 1;
       }
-      else if (!lstrcmpi(buf+1, "cancelconfirm"))
+      else if (!lstrcmpi(buf+1, "lastused"))
       {
-        static TableEntry MBFlagTable[] = {
-          { "MB_ICONEXCLAMATION", MB_ICONEXCLAMATION },
-          { "MB_ICONINFORMATION", MB_ICONINFORMATION },
-          { "MB_ICONQUESTION",    MB_ICONQUESTION    },
-          { "MB_ICONSTOP",        MB_ICONSTOP        },
-          { "MB_TOPMOST",         MB_TOPMOST         },
-          { "MB_SETFOREGROUND",   MB_SETFOREGROUND   },
-          { "MB_RIGHT",           MB_RIGHT           },
-          { "MB_DEFBUTTON1",      MB_DEFBUTTON1      },
-          { "MB_DEFBUTTON2",      MB_DEFBUTTON2      },
-          { NULL,                 0                  }
-        };
-        popstring(cancelconfirm);
-        popstring(cancelconfirmcaption);
-        popstring(buf);
-        cancelconfirmflags = LookupTokens(MBFlagTable, buf);
+        popstring(lastused);
       }
       if (popstring(buf))
         *buf = 0;
@@ -131,15 +115,9 @@ void __declspec(dllexport) Select(HWND hwndParent, int string_size, char *variab
 
 static LRESULT CALLBACK ParentWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
-  if (message == WM_CLOSE)
+  if (message == WM_NOTIFY_OUTER_NEXT)
   {
-    message = WM_COMMAND;
-    wParam = IDCANCEL;
-  }
-	if (message == WM_COMMAND && (LOWORD(wParam) == IDCANCEL || LOWORD(wParam) == IDOK || LOWORD(wParam) == 3))
-  {
-		PostMessage(hwStartMenuSelect,WM_USER+666,0,LOWORD(wParam));
-    return 0;
+    PostMessage(hwStartMenuSelect,WM_USER+666,wParam,0);
   }
   return CallWindowProc((long (__stdcall *)(struct HWND__ *,unsigned int,unsigned int,long))lpWndProcOld,hwnd,message,wParam,lParam);
 }
@@ -238,7 +216,7 @@ BOOL CALLBACK dlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
         temp_r.bottom - temp_r.top
       );
 
-      SendMessage(hwLocation, WM_SETTEXT, 0, (LPARAM) progname);
+      SendMessage(hwLocation, WM_SETTEXT, 0, (LPARAM) (*lastused ? lastused : progname));
 
       ProgressiveSetWindowPos(
         hwDirList,
@@ -268,20 +246,12 @@ BOOL CALLBACK dlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
     break;
     case WM_USER+666:
       g_done = 1;
-      switch (lParam) {
-      	case IDOK:
-          SendMessage(hwLocation, WM_GETTEXT, MAX_PATH, (LPARAM) buf);
-          pushstring(buf);
-          break;
-        case IDCANCEL:
-          if (*cancelconfirm && MessageBox(hwStartMenuSelect, cancelconfirm, cancelconfirmcaption, MB_YESNO|cancelconfirmflags) == IDNO)
-            g_done = 0;
-          else
-            pushstring("cancel");
-          break;
-        case 3:
-          pushstring("back");
-          break;
+      if (wParam == 0xD1E)
+        pushstring("cancel");
+      else
+      {
+        SendMessage(hwLocation, WM_GETTEXT, MAX_PATH, (LPARAM) buf);
+        pushstring(buf);
       }
     break;
   }
diff --git a/Contrib/StartMenu/StartMenu.dsp b/Contrib/StartMenu/StartMenu.dsp
index f197cb10..82f0c009 100644
--- a/Contrib/StartMenu/StartMenu.dsp
+++ b/Contrib/StartMenu/StartMenu.dsp
@@ -101,7 +101,7 @@ SOURCE=.\StartMenu.c
 # PROP Default_Filter "h;hpp;hxx;hm;inl"
 # Begin Source File
 
-SOURCE=.\ExDLL.h
+SOURCE=..\ExDLL\exdll.h
 # End Source File
 # End Group
 # Begin Group "Resource Files"
diff --git a/Contrib/StartMenu/exdll.h b/Contrib/StartMenu/exdll.h
deleted file mode 100644
index a64a2ed3..00000000
--- a/Contrib/StartMenu/exdll.h
+++ /dev/null
@@ -1,93 +0,0 @@
-#ifndef _EXDLL_H_
-#define _EXDLL_H_
-
-// only include this file from one place in your DLL.
-// (it is all static, if you use it in two places it will fail)
-
-#define EXDLL_INIT()           {  \
-        g_stringsize=string_size; \
-        g_stacktop=stacktop;      \
-        g_variables=variables; }
-
-
-typedef struct _stack_t {
-  struct _stack_t *next;
-  char text[1]; // this should be the length of string_size
-} stack_t;
-
-
-static int g_stringsize;
-static stack_t **g_stacktop;
-static char *g_variables;
-
-static int popstring(char *str); // 0 on success, 1 on empty stack
-static void pushstring(char *str);
-
-enum
-{
-INST_0,         // $0
-INST_1,         // $1
-INST_2,         // $2
-INST_3,         // $3
-INST_4,         // $4
-INST_5,         // $5
-INST_6,         // $6
-INST_7,         // $7
-INST_8,         // $8
-INST_9,         // $9
-INST_R0,        // $R0
-INST_R1,        // $R1
-INST_R2,        // $R2
-INST_R3,        // $R3
-INST_R4,        // $R4
-INST_R5,        // $R5
-INST_R6,        // $R6
-INST_R7,        // $R7
-INST_R8,        // $R8
-INST_R9,        // $R9
-INST_CMDLINE,   // $CMDLINE
-INST_INSTDIR,   // $INSTDIR
-INST_OUTDIR,    // $OUTDIR
-INST_EXEDIR,    // $EXEDIR
-INST_LANG,      // $LANGUAGE
-__INST_LAST
-};
-
-
-// utility functions (not required but often useful)
-static int popstring(char *str)
-{
-  stack_t *th;
-  if (!g_stacktop || !*g_stacktop) return 1;
-  th=(*g_stacktop);
-  lstrcpy(str,th->text);
-  *g_stacktop = th->next;
-  GlobalFree((HGLOBAL)th);
-  return 0;
-}
-
-static void pushstring(char *str)
-{
-  stack_t *th;
-  if (!g_stacktop) return;
-  th=(stack_t*)GlobalAlloc(GPTR,sizeof(stack_t)+g_stringsize);
-  lstrcpyn(th->text,str,g_stringsize);
-  th->next=*g_stacktop;
-  *g_stacktop=th;
-}
-
-static char *getuservariable(int varnum)
-{
-  if (varnum < 0 || varnum >= __INST_LAST) return NULL;
-  return g_variables+varnum*g_stringsize;
-}
-
-static void setuservariable(int varnum, char *var)
-{
-	if (var != NULL && varnum >= 0 && varnum < __INST_LAST) 
-		lstrcpy(g_variables + varnum*g_stringsize, var);
-}
-
-
-
-#endif//_EXDLL_H_
\ No newline at end of file
diff --git a/Docs/src/pages.but b/Docs/src/pages.but
index 68cc3f1e..18be93d9 100644
--- a/Docs/src/pages.but
+++ b/Docs/src/pages.but
@@ -25,11 +25,7 @@ Each built-in page has two callback functions. The pre-function and the post-cre
 
 A custom page has only one callback function that creates it but unlike the built-in pages this function is mandatory.
 
-Abort (see \K{abort}) has special usage from pages' callback functions.
-
-\b Use Abort from a built-in pre-function to skip the page
-
-\b Use Abort from a custom page creator function to go to the previous page
+Use Abort (see \K{abort}) from a built-in page pre-function to to skip the page.
 
 Examples:
 
@@ -47,14 +43,12 @@ Examples:
 \c    GetTempFileName $R0
 \c    File /oname=$R0 customPage.ini
 \c    InstallOptions::dialog $R0
-\c    Delete $R0
 \c    Pop $R1
-\c    StrCmp $R1 "cancel" "" nocancel
-\c      Quit
-\c    nocancel:
-\c    StrCmp $R1 "back" "" noback
-\c      Abort
-\c    noback:
+\c    StrCmp $R1 "cancel" done
+\c    StrCmp $R1 "back" done
+\c    StrCmp $R1 "sucess" done
+\c    error: MessageBox MB_OK|MB_ICONSTOP "InstallOptions error:$\r$\n$R1"
+\c    done:
 \c  FunctionEnd
 
 \S{page} Page
diff --git a/Plugins/InstallOptions.dll b/Plugins/InstallOptions.dll
index 1b4631b56949bfa24fbfbef477c5e59be33d4a95..1e9e57e4be1543d3a3e117f164f96f3ba76c78b9 100644
GIT binary patch
delta 4756
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

delta 5397
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
Ad;kCd

delta 3108
zcmc&$|5H@g6~7Mw7g*dEWDx}gbTt}L-`8CYtggT+O!%_0>?-3|is*Aol`*@pl0}^X_|*;)v8$%3SYuR;+t>$(PrzRGyha)tP^Rzx0Lm%x9oKym$D_RnV+!
zwFZ6e+iHW>?`u}5Pj^vn_mHXRWfvja7_B==Oor-scTrx}%3#akAWXh*!h;3UwHwR=`^XGT
z3xQ-{7BFqN2yw04-4tws?DT9rIDpz^X)BWoc)DT|kONE`F6wo#rS(8FA?FwLTP&|Sm%`(GlR(0(
zBGENO%`Hi-~
zVKCWtss!^!%>AQY`czOncGNzTkm$uQ+goZR`8+hS{>I?U$YPplB4JDWc3s!SZ{qnA
zOS_Kb{7S?@Yr$a?x=c%Bauq)bnJEJL|X^IA{y
z+PP!<*679jfgai&{#bu-naaf;1Q&H~NcQMKn>k(%HIu5tYO243(XBSDA@=VW09*r6
zCsmQ)njYG7{%F6+6L9HP*2u$X!+SK25zm?nsj-quI#P{E2e)HDZLpcnK7*5rK4L>N
z14-&o<5;pRl@nnMGRFD~=Jj|sg=>d~F>D2!s+(-ZX
zMAsYdJi_Z5e~*-8q!Gx}<#q(ot!?o1kA1GX**(tj8J5_mF#K>73_~p8*u{jK>ZFF^
z7k;l-IfekbtkB~h@hBbBxHa?Xdlbx3=NH3T>Bsth{fg1%p#A^}m?zgAxw8+URXHBj
z>kaU_Os@xhxWjGkbl*b{?iLr)1X~eFbt-tq#fH^Lr+We>r^>baGfTq}x|5IzE8WGm
zds}H{20Kn!W1o}_Fug|7A#;GE`r!bh8*|wRFvS`HrdT7u6l=s7?x9x<-i^h9z1nX~
zxoPnbkZMDwxz8HhNW@7m91>y`1(h&vpLlzBx^E-y8X`OXR^
z9#3^YrvCSryUjF2&i}-SAMX3xcHQ=2yDpgHO`hMA4}rhK
z{bf&~p!w3}tn1h<($THSaE$e%@3fQY8c4dkZ(^=)rJn^{
zEzd+Rnab5m(X}M>mDs;?$JPP0;;+eL5Bw@Fh|Qv|UK*PpS$iZjC$fal%ZD9(3%7J*
z#zf<#)FYi6m<z}rTKw6`tg;mi2qa1fjYb%CA+Ed)IY3M0}5
zN`HNh7?dGx1~rjg2E~6DrF4nOQB$_F!o8u)*U(T`D?m1#=i_{R)yB#OY7X5_ue)JG
zUA=o_eVwniVp7;p=c%dl!UP6Y<#n}Q2om#6KDW1_s;)M{SJlG3X1yUw$lP1XtJlY6
z+7pXCv$<)1b4zRUf&F{-9sHi=WH)NZ*xjk$X=?s1A$@mQ8`F0xDVNb^WtAj*2ze8K
zk$tbA#Mx+%4`d_aDy0&*cmGReUL5##i#S{C2*X-^U;1
z5A#R)7=N69jql~(;rsYM@PFd3^8et8kSfd)vW0oV3PBW}7ixq(LaXqS@QU!N@C%_w
z_?_^c@PRNxOcUpei^MJBe({iaRD4BL#cuIu;_Kqu;`y-niTJ7bt@uz(ljcYT(z8;r
zBuQmbowQX7NNv&~DIy)0PD<}dA4{K0qtbmTL!KuulUK{@7{ww>t_KWsw_FMK8ht;vbvDoo~gKKc?
wcf92Ik>e+hUdOK;pE$mDJaFW#rhmr9?>T4UST2_<RUzeback=2; // 2 - enabled, 1 - disabled, 0 - invisible
+        if (i) p->back=SW_SHOWNA|2; // 2 - enabled, SW_SHOWNA - visible, 0 - invisible (or'ed)
         else p->back=0;
 
         p->next=LANG_BTN_NEXT;
@@ -1367,7 +1367,7 @@ int CEXEBuild::write_output(void)
           p->next=LANG_BTN_LICENSE;
         #endif
         if (p->id==NSIS_PAGE_INSTFILES || p->id==NSIS_PAGE_COMPLETED)
-          p->back=1;
+          p->back&=~2;
       }
       (--p)->next=LANG_BTN_CLOSE;
       if (p->id==NSIS_PAGE_COMPLETED) (--p)->next=LANG_BTN_CLOSE;
diff --git a/Source/exehead/Ui.c b/Source/exehead/Ui.c
index 5d3dfdba..004bbd49 100644
--- a/Source/exehead/Ui.c
+++ b/Source/exehead/Ui.c
@@ -75,8 +75,13 @@ static int num_sections;
 
 #define WM_TREEVIEW_KEYHACK (WM_USER+0x13)
 
-static void NSISCALL outernotify(char num) {
-  SendMessage(g_hwnd,WM_NOTIFY_OUTER_NEXT,(WPARAM)num,0);
+static int m_page,m_abort,m_retcode,m_delta;
+
+static void NSISCALL outernotify(int num) {
+  if (num==0xD1E)
+    g_quit_flag=1;
+  m_delta=num;
+  SendMessage(g_hwnd,WM_NOTIFY_OUTER_NEXT,(WPARAM)num,0); // it sends num again for plugins - DON'T REMOVE!
 }
 
 #ifdef NSIS_CONFIG_VISIBLE_SUPPORT
@@ -102,7 +107,6 @@ page *g_inst_page;
 section *g_inst_section;
 entry *g_inst_entry;
 
-static int m_page=-1,m_abort;
 static HWND m_curwnd, m_bgwnd, m_hwndOK, m_hwndCancel;
 static int m_whichcfg;
 
@@ -442,7 +446,7 @@ BOOL CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
   if (uMsg == WM_INITDIALOG || uMsg == WM_NOTIFY_OUTER_NEXT)
   {
-    #define delta wParam
+    page *this_page;
     static struct
     {
       char *id;
@@ -479,10 +483,18 @@ BOOL CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
       ShowWindow(hwndDlg,SW_SHOW);
     }
 
+    // initial m_page is zero, m_pages grows and checked after this line so no memory misread
+    this_page=g_inst_page+m_page;
+
+    // if the last page was a custom page, wait for it to finish by itself.
+    // if it doesn't, it's a bad plugin.
+    // plugins should react to WM_NOTIFY_OUTER_NEXT.
+    if (this_page->id<0) return 0;
+
 nextPage:
 
-    if (m_page<0) delta=1;
-    m_page+=delta;
+    m_page+=m_delta;
+    this_page+=m_delta;
 
 #ifdef NSIS_SUPPORT_CODECALLBACKS
     if (m_page==g_inst_cmnheader->num_pages) ExecuteCodeSegment(g_inst_cmnheader->code_onInstSuccess,NULL);
@@ -491,69 +503,57 @@ nextPage:
     if (g_quit_flag || m_page < 0 || m_page == g_inst_cmnheader->num_pages)
     {
       DestroyWindow(m_curwnd);
-      EndDialog(hwndDlg,0);
+      EndDialog(hwndDlg,m_retcode);
     }
     else
     {
       HWND hwndtmp;
-      int page_id=g_inst_page[m_page].id;
 
-      SetDlgItemTextFromLang(hwndDlg,IDOK,g_inst_page[m_page].next);
+      SetDlgItemTextFromLang(hwndDlg,IDOK,this_page->next);
       
       hwndtmp=GetDlgItem(hwndDlg,IDC_BACK);
-      ShowWindow(hwndtmp,g_inst_page[m_page].back?SW_SHOWNA:SW_HIDE);
-      EnableWindow(hwndtmp, g_inst_page[m_page].back&2);
+      ShowWindow(hwndtmp,this_page->back&SW_SHOWNA);// SW_HIDE = 0
+      EnableWindow(hwndtmp,this_page->back&2);
 
-      if (page_id!=NSIS_PAGE_COMPLETED) DestroyWindow(m_curwnd);
+      if (this_page->id!=NSIS_PAGE_COMPLETED) DestroyWindow(m_curwnd);
       else if (g_autoclose) goto nextPage;
 
-      if (page_id>=0) // NSIS page
-      {
 #ifdef NSIS_SUPPORT_CODECALLBACKS
-        if (ExecuteCodeSegment(g_inst_page[m_page].prefunc,NULL))
-          goto nextPage;
-        else
-#endif //NSIS_SUPPORT_CODECALLBACKS
-        {
-          mystrcpy(g_tmp,g_caption);
-          process_string_fromtab(
-            g_tmp+mystrlen(g_tmp),
-            LANG_SUBCAPTION(page_id-(g_is_uninstaller?NSIS_PAGE_INSTFILES:0))
-          );
-
-          SetWindowText(hwndDlg,g_tmp);
-
-          gDontFookWithFocus = 0;
-          m_curwnd=CreateDialog(g_hInstance,windows[page_id].id,hwndDlg,windows[page_id].proc);
-          if (m_curwnd)
-          {
-            RECT r;
-            GetWindowRect(GetDlgItem(hwndDlg,IDC_CHILDRECT),&r);
-            ScreenToClient(hwndDlg,(LPPOINT)&r);
-            SetWindowPos(m_curwnd,0,r.left,r.top,0,0,SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOZORDER);
-            SendMessage(m_curwnd, WM_NOTIFY_START, 0, 0);
-            ShowWindow(m_curwnd,SW_SHOWNA);
-          }
-
-          //XGE 5th September 2002 - Do *not* move the focus to the OK button if we are
-          //on the license page, instead we want the focus left alone because in
-          //WM_INITDIALOG it is given to the richedit control.
-          if (!gDontFookWithFocus)
-              SetFocus(m_hwndOK);
-          //XGE End
-        }
-      }
-#ifdef NSIS_SUPPORT_CODECALLBACKS
-      else // User custom page
-      {
-        if (ExecuteCodeSegment(g_inst_page[m_page].prefunc,NULL))
-          delta=-1;
-        else
-          delta=1;
+      if (ExecuteCodeSegment(this_page->prefunc,NULL) || this_page->id<0)
         goto nextPage;
+#endif //NSIS_SUPPORT_CODECALLBACKS
+      if (this_page->id>=0) // NSIS page
+      {
+        mystrcpy(g_tmp,g_caption);
+        process_string_fromtab(
+          g_tmp+mystrlen(g_tmp),
+          LANG_SUBCAPTION(this_page->id-(g_is_uninstaller?NSIS_PAGE_INSTFILES:0))
+        );
+
+        SetWindowText(hwndDlg,g_tmp);
+
+        gDontFookWithFocus = 0;
+        m_curwnd=CreateDialog(g_hInstance,windows[this_page->id].id,hwndDlg,windows[this_page->id].proc);
+        if (m_curwnd)
+        {
+          RECT r;
+          GetWindowRect(GetDlgItem(hwndDlg,IDC_CHILDRECT),&r);
+          ScreenToClient(hwndDlg,(LPPOINT)&r);
+          SetWindowPos(m_curwnd,0,r.left,r.top,0,0,SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOZORDER);
+          SendMessage(m_curwnd, WM_NOTIFY_START, 0, 0);
+          ShowWindow(m_curwnd,SW_SHOWNA);
+        }
+
+        //XGE 5th September 2002 - Do *not* move the focus to the OK button if we are
+        //on the license page, instead we want the focus left alone because in
+        //WM_INITDIALOG it is given to the richedit control.
+        if (!gDontFookWithFocus)
+            SetFocus(m_hwndOK);
+        //XGE End
       }
 
-      ExecuteCodeSegment(g_inst_page[m_page].postfunc,NULL);
+#ifdef NSIS_SUPPORT_CODECALLBACKS
+      ExecuteCodeSegment(this_page->postfunc,NULL);
 #endif //NSIS_SUPPORT_CODECALLBACKS
     }
   }
@@ -580,7 +580,8 @@ nextPage:
 #ifdef NSIS_SUPPORT_CODECALLBACKS
         ExecuteCodeSegment(g_inst_cmnheader->code_onInstFailed,NULL);
 #endif//NSIS_SUPPORT_CODECALLBACKS
-        EndDialog(hwndDlg,2);
+        m_retcode=2;
+        outernotify(0xD1E);
       }
       else
       {
@@ -588,7 +589,8 @@ nextPage:
         if (!ExecuteCodeSegment(g_inst_cmnheader->code_onUserAbort,NULL))
 #endif//NSIS_SUPPORT_CODECALLBACKS
         {
-          EndDialog(hwndDlg,1);
+          m_retcode=1;
+          outernotify(0xD1E);
         }
       }
     }
@@ -1362,7 +1364,10 @@ static BOOL CALLBACK InstProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa
   if (uMsg == WM_NOTIFY_INSTPROC_DONE)
   {
     if (g_quit_flag)
-        EndDialog(g_hwnd,1);
+    {
+      m_retcode=1;
+      outernotify(0xD1E);
+    }
     else if (!wParam)
     {
       HWND h=m_hwndOK;