samples/audio; Installer: Added SineTone sample
[sdk] / installer / src / installer.ec
index 7f7e9b2..5da1a82 100644 (file)
@@ -1,8 +1,7 @@
-#ifdef NOMINGW
-static define buildString = $"Ecere SDK v0.44 (Without MinGW) -- built on March 7, 2012 ";
-#else
-static define buildString = $"Ecere SDK v0.44 -- built on March 7, 2012 ";
-#endif
+static define versionString = "Ecere SDK v0.44.10 (pr2)";
+static define dateString = $"August 7th, 2014";
+static define builtOnString = $"built on ";
+static define withoutMinGW = $" (Without MinGW)";
 
 #define WIN32_LEAN_AND_MEAN
 #define GetFreeSpace _GetFreeSpace
@@ -16,164 +15,51 @@ import "ecere"
 #endif
 import "IDESettings"
 import "createLink"
-// import "licenseBox"
 import "licensing"
+import "CheckListBox"
 
-class CheckListBox : ListBox
+static void SetBuildString(Label label)
 {
-   fullRowSelect = false, collapseControl = true, treeBranches = true, rootCollapseButton = true, 
-   noDragging = true;
-   rowHeight = 18;
-
-   void ToggleCheck(DataRow row)
-   {
-      Button checkBox = (Button)row.tag;
-      DataRow parent;
-      bool checked = !(checkBox.checked) || checkBox.buttonState == down;
-      if(!checkBox.disabled)
-      {
-         SetCheck(row, checked);
-         checkBox.buttonState = up;
-
-         for(parent = row; parent; parent = parent.parent)
-         {
-            for(row = parent.firstRow; row; row = row.next)
-            {
-               checkBox = (Button)row.tag;
-               if(checkBox.checked != checked)
-                  break;
-            }
-            checkBox = (Button)parent.tag;
-            if(row)
-            {
-               checkBox.checked = true;
-               NotifyChecked(master, this, parent);
-               checkBox.buttonState = down;
-               checked = true;
-            }
-            else
-            {
-               checkBox.checked = checked;
-               NotifyChecked(master, this, parent);
-               checkBox.buttonState = up;
-            }
-         }
-      }
-   }
-
-   void SetCheck(DataRow row, bool checked)
-   {
-      Button checkBox = (Button)row.tag;
-      DataRow subRow;
-      if(!checkBox.disabled && (checkBox.checked != checked || checkBox.buttonState == down))
-      {
-         checkBox.checked = checked;
-         for(subRow = row.firstRow; subRow; subRow = subRow.next)
-            SetCheck(subRow, checked);
-         NotifyChecked(master, this, row);
-      }
-   }
-   
-   DataRow AddRow(DataRow parentRow)
-   {      
-      DataRow row = parentRow ? parentRow.AddRow() : ListBox::AddRow();
-      int c;
-      DataRow parent;
-      int indent = 20;
-      for(parent = row.parent; parent; parent = parent.parent)
-         indent += 20;
-      row.tag = (int)Button
-      {
-         this, isCheckbox = true, inactive = true, checked = true,
-         position = { 2 + indent, 1+(row.index + hasHeader) * rowHeight }, size = { 12, 12 }; 
-         id = (int)row;
+   static const String addMinGW = "";
+   String s;
 
-         bool NotifyPushed(Button button, int x, int y, Modifiers mods)
-         {
-            currentRow = (DataRow)button.id;
-            ToggleCheck(currentRow);
-            return false;
-         }
-
-         bool NotifyReleased(Button button, int x, int y, Modifiers mods)
-         {
-            return false;
-         }
-
-         bool OnMouseOver(int x, int y, Modifiers mods)
-         {
-
-            return true;
-         }
-
-         bool OnMouseLeave(Modifiers mods)
-         {
-
-            return true;
-         }
-      };
-      return row;
-   }      
-
-   bool NotifyKeyDown(CheckListBox listBox, DataRow row, Key key, unichar ch)
-   {
-      if(key == space)
-      {
-         listBox.ToggleCheck(row);
-         return false;
-      }
-      return true;
-   }
-
-   bool OnKeyHit(Key key, unichar ch)
-   {
-      if(key == space)
-         return false;
-      return ListBox::OnKeyHit(key, ch);
-   }
-
-   bool NotifyDoubleClick(CheckListBox listBox, int x, int y, Modifiers mods)
-   {
-      listBox.OnLeftButtonDown(x, y, mods);
-      return false;
-   }
+#ifdef NOMINGW
+   addMinGW = withoutMinGW;
+#endif
 
-   bool NotifyReclick(CheckListBox listBox, DataRow row, Modifiers mods)
-   {
-      listBox.ToggleCheck(row);
-      return true;
-   }
+   s = PrintString(versionString, addMinGW, " -- ", builtOnString, dateString);
+   label.caption = s;
+   delete s;
+}
 
-   bool NotifyCollapse(ListBox listBox, DataRow row, bool collapsed)
+static bool IsAdministrator()
+{
+   BOOL b;
+   SID_IDENTIFIER_AUTHORITY NtAuthority = { SECURITY_NT_AUTHORITY };
+   PSID AdministratorsGroup;
+   b = AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &AdministratorsGroup);
+   if(b)
    {
-      DataRow r;
-      for(r = row.firstRow; r && r != row; )
-      {
-         Button checkBox = (Button)r.tag;
-         checkBox.visible = !collapsed;
-         if(r.firstRow && !r.collapsed) 
-            row = r.firstRow;
-         else 
-            for(; r != row; r = r.parent)
-               if(r.next) { r = r.next; break; }
-      }
-      for(r = row.GetNextRow(); r; r = r.GetNextRow())
-      {
-         Button checkBox = (Button)r.tag;
-         checkBox.position.y = 1 + (r.index + listBox.hasHeader) * listBox.rowHeight;
-      }
-      return true;
+      if(!CheckTokenMembership(NULL, AdministratorsGroup, &b))
+         b = FALSE;
+       FreeSid(AdministratorsGroup);
    }
-
-   virtual void Window::NotifyChecked(CheckListBox listBox, DataRow row);
-};
+   return b == TRUE;
+}
 
 struct CheckItem
 {
-   char * name;
+   const char * name;
    void * data;
-   char * OnGetString(char * tempString, void * fieldData, bool * needClass)
+   bool add32Bit;
+   const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
    {
+      if(add32Bit)
+      {
+         strcpy(tempString, name);
+         strcat(tempString, " (32)");
+         return tempString;
+      }
       return name;
    }
 
@@ -188,7 +74,7 @@ struct CheckItem
 #define BUFFERSIZE 0x1000
 bool abortInstall = false;
 
-void ExtractFileFromArchive(ProgressBar progressBar, char * path, char * outputFile)
+void ExtractFileFromArchive(ProgressBar progressBar, const char * path, const char * outputFile)
 {
    char fileName[MAX_LOCATION];
    FileAttribs exists = FileExists(path);
@@ -258,11 +144,11 @@ void ExtractFileFromArchive(ProgressBar progressBar, char * path, char * outputF
 
             FileGetSize(path, &dataSize);
             GetLastDirectory(outputFile, fileName);
-            
+
             ((GuiApplication)__thisModule).SignalEvent();
             //((GuiApplication)__thisModule).ProcessInput();
             //((GuiApplication)__thisModule).UpdateDisplay();
-            
+
             for(c = 0; c<dataSize && !abortInstall; c += BUFFERSIZE)
             {
                uint size = (dataSize > c + BUFFERSIZE) ? BUFFERSIZE : (dataSize - c);
@@ -292,14 +178,19 @@ void ExtractFileFromArchive(ProgressBar progressBar, char * path, char * outputF
       FileSetTime(outputFile, stats.created, 0, stats.modified);
 }
 
+public enum BitArch { none, bits32, bits64 };
+
 struct Component
 {
-   char * name;
-   char * dataPath;
-   char * defInstallPath;
+   const char * name;
+   const char * dataPath;
+   const char * defInstallPath;
    Component * subComponents;
    bool mandatory;
    bool selected;
+   bool available;
+   BitArch arch;
+
    Component * parent;
 
    uint requiredSize;
@@ -307,35 +198,43 @@ struct Component
    char installPath[MAX_LOCATION];
    DataRow row;
 
-   void GetFullPath(char * path)
+   void GetFullPath(char * path, bool is32bit)
    {
       if(this != null && parent)
-         parent->GetFullPath(path);
+         parent->GetFullPath(path, is32bit || (arch == bits32 && osIS64bit));
       else
-         strcpy(path, installDir);
+         strcpy(path, (this && (is32bit || (arch == bits32 && osIS64bit))) ? installDir32 : installDir);
 
       if(this != null)
          PathCat(path, installPath);
    }
 
-   void Install(char * parentPath)
+   void Install(char * parentPath, char * parentPath32)
    {
       int c;
-      if(selected)
+      if(selected && (arch == none || arch == bits32 || osIS64bit))
       {
-         char path[MAX_LOCATION];
-         strcpy(path, parentPath);
-         PathCat(path, installPath);
+         char path64[MAX_LOCATION];
+         char path32[MAX_LOCATION];
+         strcpy(path64, parentPath);
+         PathCat(path64, installPath);
+
+         strcpy(path32, parentPath32);
+         PathCat(path32, installPath);
 
          installProgress.installing.SetText($"Installing %s...", name);
          ((GuiApplication)__thisModule).UpdateDisplay();
 
          if(dataPath)
          {
+            char * path = path64;
             char source[MAX_LOCATION];
             strcpy(source, ":");
             strcat(source, dataPath);
 
+            if(arch == bits32)
+               path = path32;
+
             MakeDir(path);
 
             if(FileExists(source).isFile)
@@ -345,136 +244,138 @@ struct Component
                PathCat(path, name);
             }
             if(requiredSize)
-            {
-               uint p = installProgress.progressBar.progress;
-               ExtractFileFromArchive(installProgress.progressBar, source, path); 
-            }
+               ExtractFileFromArchive(installProgress.progressBar, source, path);
          }
          if(subComponents)
          {
             for(c = 0; subComponents[c].name; c++)
-               subComponents[c].Install(path);
+               subComponents[c].Install(path64, path32);
          }
       }
    }
 };
-Component samples[] =
-{
-   { "Ecere Chess",     "samples/chess",     "chess",       null, false, true },
-   { "Ecere Fractals",  "samples/fractals",  "fractals",    null, false, true },
-   { "3D",              "samples/3D",        "3D",          null, false, true },
-   { "Audio",           "samples/audio",     "audio",       null, false, true },
-   { "Database",        "samples/db",        "db",          null, false, true },
-   { "eC",              "samples/eC",        "eC",          null, false, true },
-   { "Games",           "samples/games",     "games",       null, false, true },
-   { "GUI & Graphics",  "samples/guiAndGfx", "guiAndGfx",   null, false, true },
-   { "Miscellaneous",   "samples/misc",      "misc",        null, false, true },
-   { "Networking",      "samples/net",       "net",         null, false, true },
-   { "WIA Scanning",    "samples/scanning",  "scanning",    null, false, true },
-   { "Threading",       "samples/threads",   "threads",     null, false, true }
+
+#ifndef NOMINGW
+define minGWIncluded = true;
+#else
+define minGWIncluded = false;
+#endif
+
+Array<Component> samples
+{ [
+   { "3D",              "samples/3D",        "3D",          null, false, true, true, none },
+   { "Android",         "samples/android",   "android",          null, false, true, true, none },
+   { $"Audio",           "samples/audio",     "audio",       null, false, true, true, none },
+   { $"Database",        "samples/db",        "db",          null, false, true, true, none },
+   { "eC",              "samples/eC",        "eC",          null, false, true, true, none },
+   { $"Games",           "samples/games",     "games",       null, false, true, true, none },
+   { $"GUI & Graphics",  "samples/guiAndGfx", "guiAndGfx",   null, false, true, true, none },
+   { $"Miscellaneous",   "samples/misc",      "misc",        null, false, true, true, none },
+   { $"Networking",      "samples/net",       "net",         null, false, true, true, none },
+   { $"WIA Scanning",    "samples/scanning",  "scanning",    null, false, true, true, none },
+   { $"Threading",       "samples/threads",   "threads",     null, false, true, true, none },
    { null }
-};
+};
 
 public enum CoreSDKID
 {
-   ide, runtime, ec, eda, vanilla, extras,
-#ifndef NOMINGW
+   ide, ide32, runtime, runtime32, ec, ec32,
    gcc, gdb, mingw, binutils, make,
-#endif
    none
 };
 
-Component coreSDK[CoreSDKID] =
-{
-   { "Ecere IDE",       "ecere-sdk/ide",                 "bin",      null, true,  true },
-   { "Runtime Library", "ecere-sdk/ecere.dll",           "bin",      null, true,  true },
-   { "eC Compiler",     "ecere-sdk/compiler",            "bin",      null, true,  true },
-   { "Data Access",     "ecere-sdk/eda",                 "bin",      null, false, true },
-   { "Ecere Vanilla",   "ecere-sdk/libecereVanilla.a",   "lib",      null, false, true },
-   { "Ecere Extras",    "extras",                        "extras",   null, false, true },
-#ifndef NOMINGW
-   { "GNU C Compiler",  "mingw/gcc/core",   "mingw", null, true, true },
-   { "GNU Debugger",    "mingw/gdb",        "mingw", null, true, true },
-   { "MinGW Runtime",   "mingw/mingwrt",    "mingw", null, true, true },
-   { "Binary Utils",    "mingw/binutils",   "mingw", null, true, true },
-   { "GNU Make",        "mingw/make",       "mingw", null, true, true },
-#endif
+Array<Component> coreSDK
+{ [
+   { "Ecere IDE",       "ecere-sdk/ide",                 "bin",      null, true,  true, true, bits64 },
+   { "Ecere IDE",       "ecere-sdk32/ide",                 "bin",      null, true,  true, true, bits32 },
+   { $"Runtime Library", "ecere-sdk/ecere.dll",           "bin",      null, true,  true, true, bits64 },
+   { $"Runtime Library", "ecere-sdk32/ecere.dll",           "bin",      null, true,  true, true, bits32 },
+   { $"eC Compiler",     "ecere-sdk/compiler",            "bin",      null, true,  true, true, bits64 },
+   { $"eC Compiler",     "ecere-sdk32/compiler",            "bin",      null, true,  true, true, bits32 },
+   { $"GNU C Compiler",  "tdm/gcc/core",   "tdm", null, true, true, minGWIncluded, none },
+   { $"GNU Debugger",    "tdm/gdb",        "tdm", null, true, true, minGWIncluded, none },
+   { $"MinGW-w64 Runtime",   "tdm/mingwrt",    "tdm", null, true, true, minGWIncluded, none },
+   { $"Binary Utils",    "tdm/binutils",   "tdm", null, true, true, minGWIncluded, none },
+   { $"GNU Make",        "tdm/make",       "tdm", null, true, true, minGWIncluded, none },
    { null }
-};
+};
 
-#ifndef NOMINGW
-Component additional[] =
+public enum AdditionalID
 {
-   { "UPX",             "upx/bin",                 "mingw",    null, false, true },
-   { "GNU Regexp",      "mingw/gnurx",             "mingw",    null, false, true },
-   { "Win32 APIs",      "mingw/w32api",            "mingw",    null, false, true },
-   { "pthreads",        "mingw/pthreads",          "mingw",    null, false, true },
-   { "C++ Compiler",    "mingw/gcc/c++",           "mingw",    null, false, true },
-   { "GCC I18n",        "mingw/locale/gcc",        "mingw",    null, false, false },
-   { "GDB I18n",        "mingw/locale/gdb",        "mingw",    null, false, false },
-   { "Make I18n",       "mingw/locale/make",       "mingw",    null, false, false },
-   { "Binutils I18n",   "mingw/locale/binutils",   "mingw",    null, false, false },
-   { null }
+   eda, eda32, audio, audio32, vanilla, vanilla32, extras, upx, gnurx, gnurx32, /*pthreads, */cpp, /*w32api, gcci18n, gdbi18n, makei18n, binutilsi18n, */none
 };
-#endif
+
+Array<Component> additional
+{ [
+   { $"Data Access",     "ecere-sdk/eda",                 "bin",      null, false, true, true, bits64 },
+   { $"Data Access",     "ecere-sdk32/eda",               "bin",      null, false, true, true, bits32 },
+   { $"Ecere Audio",     "ecere-sdk/EcereAudio.dll",      "bin",      null, false, true, true, bits64 },
+   { $"Ecere Audio",     "ecere-sdk32/EcereAudio.dll",    "bin",      null, false, true, true, bits32 },
+   { $"Ecere Vanilla",   "ecere-sdk/libecereVanilla.a",   "lib",      null, false, true, true, bits64 },
+   { $"Ecere Vanilla",   "ecere-sdk32/libecereVanilla.a", "lib",      null, false, true, true, bits32 },
+   { $"Ecere Extras",    "extras",                        "extras",   null, false, true, true, none },
+   { "UPX",             "upx/bin",                       "upx/bin",      null, false, true, true, none },
+   { $"GNU Regexp",      "tdm/gnurx",                     "tdm",    null, false, true, true, bits64 },
+   { $"GNU Regexp",      "tdm/gnurx32",                   "tdm",    null, false, true, true, bits32 },
+//   { "pthreads",        "tdm/pthreads",                   "mingw",    null, false, true, minGWIncluded, none },
+   { $"C++ Compiler",    "tdm/gcc/c++",                   "tdm",    null, false, true, minGWIncluded, none },
+//   { "Win32 APIs",      "mingw/w32api",                  "mingw",    null, false, true, minGWIncluded, none },
+/*   { "GCC I18n",        "mingw/locale/gcc",              "tdm",    null, false, false, minGWIncluded, none },
+   { "GDB I18n",        "mingw/locale/gdb",              "tdm",    null, false, false, minGWIncluded, none },
+   { "Make I18n",       "mingw/locale/make",             "tdm",    null, false, false, minGWIncluded, none },
+   { "Binutils I18n",   "mingw/locale/binutils",         "tdm",    null, false, false, minGWIncluded, none },
+*/
+   { null }
+] };
 
 public enum DocumentationID
 {
-   ecereBook, apiRef, tutorials, coursework,
-#ifndef NOMINGW
+   ecereBook, apiRef, coursework,
    gccDoc, gppDocs, gdbDocs, makeDocs, binDocs, mingwDocs, gnurxDocs, upxDocs,
-#endif
    none
 };
 
-Component documentation[DocumentationID] =
-{
-   { "Ecere Book",         "ecere-sdk/book",       "doc",            null, false, true },
-   { "API Reference",      "ecere-sdk/doc",        "doc",            null, false, true },
-   { "Ecere Tutorials",    "ecere-sdk/tutorials",  "doc",            null, false, true },
-   { "Ecere Coursework",   "ecere-sdk/coursework", "doc",            null, false, true },
-#ifndef NOMINGW
-   { "GCC Docs",        "mingw/doc/gcc",        "mingw",          null, false, false },
-   { "G++ Docs",        "mingw/doc/g++",        "mingw",          null, false, false },
-   { "GDB Docs",        "mingw/doc/gdb",        "mingw",          null, false, false },
-   { "Make Docs",       "mingw/doc/make",       "mingw",          null, false, false },
-   { "Binutils Docs",   "mingw/doc/binutils",   "mingw",          null, false, false },
-   { "MinGW Docs",      "mingw/doc/mingwrt",    "mingw",          null, false, false },
-   { "gnurx Docs",      "mingw/doc/gnurx",      "mingw",          null, false, false },
-   { "UPX Docs",        "upx/doc",              "mingw/doc/upx",  null, false, false },
-#endif
+Array<Component> documentation
+{ [
+   { $"Ecere Book",         "ecere-sdk/book",       "doc",            null, false, true, true, none },
+   { $"API Reference",      "ecere-sdk/doc",        "doc",            null, false, true, true, none },
+   { $"Ecere Coursework",   "ecere-sdk/coursework", "doc",            null, false, true, true, none },
+   { $"GCC Docs",           "tdm/doc/gcc",          "tdm",          null, false, false, minGWIncluded, none },
+   { $"G++ Docs",           "tdm/doc/g++",          "tdm",          null, false, false, minGWIncluded, none },
+   { $"GDB Docs",           "tdm/doc/gdb",          "tdm",          null, false, false, minGWIncluded, none },
+   { $"Make Docs",          "tdm/doc/make",         "tdm",          null, false, false, minGWIncluded, none },
+   { $"Binutils Docs",      "tdm/doc/binutils",     "tdm",          null, false, false, minGWIncluded, none },
+   { $"gnurx Docs",         "tdm/doc/gnurx",        "tdm",          null, false, false, minGWIncluded, none },
+   { $"UPX Docs",           "upx/doc",              "upx/doc",  null, false, false, minGWIncluded, none },
    { null }
-};
+};
 
 public enum ComponentID
 {
    coreSDK,
-#ifndef NOMINGW
    additional,
-#endif
    documentation,
    samples,
    none
 };
 
-Component components[ComponentID] =
-{
-   { "Core SDK Files", null, null, coreSDK, true, true },
-#ifndef NOMINGW
-   { "Additional Support", null, null, additional, false, true },
-#endif
-   { "Documentation", null /*"doc"*/, null /*"doc"*/, documentation, false, true },
-   { "Samples", null, "samples", samples, false, true },
+Array<Component> components
+{ [
+   { $"Core SDK Files", null, null, coreSDK.array, true, true, true, none },
+   { $"Additional Support", null, null, additional.array, false, true, true, none },
+   { $"Documentation", null /*"doc"*/, null /*"doc"*/, documentation.array, false, true, true, none },
+   { $"Samples", null, "samples", samples.array, false, true, true, none },
    { null }
-};
+};
 FileSize totalSize;
 FileSize totalInstalled;
 
 struct InstallOption
 {
-   char * name;
+   const char * name;
    InstallOption * subOptions;
    bool selected;
+   bool available;
    DataRow row;
 };
 
@@ -489,82 +390,86 @@ enum AssociateOptions
    AssociateIMG
 };
 
-InstallOption associateOptions[] =
-{
-   { "Associate with Ecere Project Files (*.epj)", null, true },
-   { "Associate with eC Files (*.ec, *.eh)", null, true },
-   { "Associate with C files (*.c, *.h)", null, false },
-   { "Associate with C++ Files (*.cpp, *.hpp, *.cc, *.hh, *.cxx, *.hxx)", null, false },
-   { "Associate with text files (*.txt)", null, false },
-   { "Associate with 3D Studio Model Files (*.3ds)", null, true },
-   { "Associate with Image Files (*.png, *.jpg, *.pcx, *.bmp, *.gif)", null, false },
+Array<InstallOption> associateOptions
+{ [
+   { $"Associate with Ecere Project Files (*.epj)", null, true },
+   { $"Associate with eC Files (*.ec, *.eh)", null, true },
+   { $"Associate with C files (*.c, *.h)", null, false },
+   { $"Associate with C++ Files (*.cpp, *.hpp, *.cc, *.hh, *.cxx, *.hxx)", null, false },
+   { $"Associate with text files (*.txt)", null, false },
+   { $"Associate with 3D Studio Model Files (*.3ds)", null, true },
+   { $"Associate with Image Files (*.png, *.jpg, *.pcx, *.bmp, *.gif)", null, false },
    { null }
-};
+};
 
 enum PathOptions
 {
-   AddECEREPaths
-#ifndef NOMINGW
-   , AddMinGWPaths
-#endif
+   AddECEREPaths, AddMinGWPaths
 };
 
-InstallOption pathOptions[] =
-{
-   { "Add Ecere binaries location to the system path", null, true },
-   { "Add MinGW to the system path", null, true }
+Array<InstallOption> pathOptions
+{ [
+   { $"Add Ecere binaries location to the user environment path", null, true, true },
+   { $"Add MinGW to the user environment path", null, true, minGWIncluded },
    { null }
-};
+};
 
 enum IconOptions
 {
-   StartMenuIcon,
-   DesktopIcon,
-   QuickLaunchIcon
+   StartMenuIcon = 1,
+   DesktopIcon = 2,
+   QuickLaunchIcon = 3
 };
 
-InstallOption options[] =
-{
-   { "Start Menu Group", null, true },
-   { "Desktop Icon", null, true },
-   { "Quicklaunch Icon", null, true },
-   { "Associate the ECERE IDE with Supported File Types", associateOptions, true },
-#ifndef NOMINGW
-   { "Add binaries location to the system paths", pathOptions, true },
-#endif
+Array<InstallOption> options
+{ [
+   { $"Install for All Users", null, true, true },
+   { $"Start Menu Group", null, true, true },
+   { $"Desktop Icon", null, true, true },
+   { $"Quicklaunch Icon", null, true, true },
+   { $"Associate the Ecere IDE with Supported File Types", associateOptions.array, true, true },
+   { $"Add binaries location to the user environment paths", pathOptions.array, true, minGWIncluded },
    { null }
-};
+};
 
 char sourceDir[MAX_LOCATION] = ":";
 char installDir[MAX_LOCATION];
+char installDir32[MAX_LOCATION];
+bool osIS64bit;
 
 class Installer : Window
 {
-   text = $"Ecere Software Development Kit Setup - v0.44 \"Ryōan-ji\"";
-   background = activeBorder;
+   background = formColor;
    borderStyle = fixed;
    hasMinimize = true;
    hasClose = true;
    tabCycle = true;
-   clientSize = { 636, 456 };
+   clientSize = { 636, 476 };
    icon = { ":icon.png" };
+   caption = $"Ecere Software Development Kit Setup - v0.44.10 \"Ryōan-ji\" 64 Bit Edition";
+
+   // clientSize = { 796, 576 };
+   bool loaded;
 
    Picture back { image = BitmapResource { ":ryoanji.png" }, parent = this, position = { 0, 0 } };
    FileDialog fileDialog
    {
       master = this, type = selectDir,
-      text = $"Select a new location"
+      caption = $"Select a new location"
    };
    Button browse
    {
-      master = this, autoCreate = false, inactive = true, /*hotKey = F2,*/ text = "...";
-      
+      master = this, autoCreate = false, inactive = true, caption = "...";
+
       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
       {
          DataRow row = componentsBox.currentRow;
          Component * component = ((CheckItem *)row.GetData(componentField))->data;
-         component->GetFullPath(fileDialog.filePath);
-         StripLastDirectory(fileDialog.filePath, fileDialog.currentDirectory);
+         char filePath[MAX_LOCATION];
+         component->GetFullPath(filePath, false);
+         fileDialog.filePath = filePath;
+         StripLastDirectory(filePath, filePath);
+         fileDialog.currentDirectory = filePath;
 
          if(fileDialog.Modal() == ok)
          {
@@ -579,23 +484,40 @@ class Installer : Window
    CheckListBox componentsBox
    {
       this, size = { 460, 112 }, position = { 160, 160 }, hasHeader = true;
+      fullRowSelect = false, collapseControl = true, treeBranches = true, rootCollapseButton = true,
+      hasHorzScroll = true;
+      resizable = true,
+      noDragging = true;
+      rowHeight = 18;
+      selectionColor = { 145, 150, 140 };
+
       alwaysEdit = true;
       opacity = 0;
 
+      bool NotifyKeyDown(ListBox listBox, DataRow row, Key key, unichar ch)
+      {
+         if(key == f2 && browse.visible)
+            browse.NotifyClicked(this, browse, 0, 0, 0);
+         return true;
+      }
+
       bool NotifyChanged(ListBox listBox, DataRow row)
       {
          Component * component = ((CheckItem *)listBox.GetData(componentField))->data;
-         char path[MAX_LOCATION], relative[MAX_LOCATION] = "", ** newPath;
+         char path[MAX_LOCATION], relative[MAX_LOCATION] = "", * newPath;
          char fullPath[MAX_LOCATION];
 
-         component->parent->GetFullPath(path);
+         component->parent->GetFullPath(path, false);
          strcpy(fullPath, path);
 
-         newPath = (char **)row.GetData(locationField);
-         if(newPath && *newPath)
+         newPath = row.GetData(locationField);
+         if(newPath)
          {
-            PathCat(fullPath, *newPath);
-            MakePathRelative(fullPath, path, relative);
+            PathCat(fullPath, newPath);
+            if(IsPathInsideOf(fullPath, path))
+               MakePathRelative(fullPath, path, relative);
+            else
+               strcpy(relative, fullPath);
          }
          listBox.SetData(locationField, relative);
          strcpy(component->installPath, relative);
@@ -620,10 +542,17 @@ class Installer : Window
 
       bool NotifyEdited(ListBox listBox, DataRow row)
       {
+         Window e;
          browse.parent = listBox;
          browse.position = { componentField.width + locationField.width + 18, (listBox.currentIndex+1) * listBox.rowHeight - 2 };
          browse.size = { 30, listBox.rowHeight + 3 };
-
+         for(e = listBox.firstChild; e; e = e.next)
+         {
+            if(e._class == class(DataBox))
+               break;
+         }
+         if(e)
+            e.Activate();
          browse.Create();
          return true;
       }
@@ -632,14 +561,13 @@ class Installer : Window
       {
          Component * component = ((CheckItem *)row.GetData(componentField))->data;
          int c;
-         Button checkBox = (Button)row.tag;
-         component->selected = checkBox.checked;
+         component->selected = listBox.IsChecked(row);
 
          if(!component->parent) totalSize -= component->requiredSize;
          component->requiredSize = 0;
          if(component->selected)
          {
-            component->requiredSize += component->size; 
+            component->requiredSize += component->size;
             if(component->subComponents)
                for(c = 0; component->subComponents[c].name; c++)
                   component->requiredSize += component->subComponents[c].requiredSize;
@@ -651,23 +579,23 @@ class Installer : Window
          }
          else
             row.UnsetData(reqField);
-         if(!component->parent) 
+         if(!component->parent)
          {
             totalSize += component->requiredSize;
             {
                char sizeString[100];
                PrintSize(sizeString, totalSize, 2);
-               totalSpaceValue.text = sizeString;
+               totalSpaceValue.caption = sizeString;
             }
          }
       }
    };
-   Label agreementLbl { parent = this, text = $"By installing the Ecere SDK, you agree to the                                         .", font = { "Tahoma", 8.25f }, anchor = Anchor { left = 24, top = 424 } };
+   Label agreementLbl { parent = this, caption = $"By installing the Ecere SDK, you agree to the", font = { "Tahoma", 8.25f }, anchor = Anchor { right = 399, top = 448 } };
    Button licenseButton
    {
       this, inactive = true, offset = false, bevel = false, foreground = blue, font = { "Tahoma", 8.25f, underline = true, bold = true },
-      // text = $"terms and conditions", anchor = Anchor { left = 241, top = 421 };
-      text = $"terms and conditions", anchor = Anchor { left = 237, top = 421 };
+      // caption = $"terms and conditions", anchor = Anchor { left = 241, top = 421 };
+      caption = $"terms and conditions", anchor = Anchor { left = 235, top = 445 };
       cursor = ((GuiApplication)__thisModule).GetCursor(hand);
 
       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
@@ -677,23 +605,79 @@ class Installer : Window
          return true;
       }
    };
+   Label dotLbl { parent = this, caption = ".", font = { "Tahoma", 8.25f }, anchor = Anchor { left = 372, top = 448 } };
    CheckListBox optionsBox
    {
-      this, size = { 460, 94 }, position = { 160, 284 };
+      this, size = { 460, 114 }, position = { 160, 284 };
+      fullRowSelect = false, collapseControl = true, treeBranches = true, rootCollapseButton = true,
+      noDragging = true;
+      rowHeight = 18;
       opacity = 0;
 
       void NotifyChecked(CheckListBox listBox, DataRow row)
       {
          CheckItem * item = row.GetData(optionField);
          InstallOption * option = item->data;
-         int c;
-         Button checkBox = (Button)row.tag;
-         option->selected = checkBox.checked;
+         option->selected = listBox.IsChecked(row);
+         // Update default samples/extras path whether we're installing for All Users or not
+         if(option == &options[0])
+         {
+            char appData[MAX_LOCATION];
+
+            options[5].name = options[0].selected ? $"Add binaries location to the system environment paths" : $"Add binaries location to the user environment paths";
+            if(options[5].row)
+               ((CheckItem *)options[5].row.GetData(optionField))->name = options[5].name;
+
+            pathOptions[PathOptions::AddECEREPaths].name = options[0].selected ? $"Add Ecere binaries location to the system environment path" : $"Add Ecere binaries location to the user environment path";
+            if(pathOptions[PathOptions::AddECEREPaths].row)
+               ((CheckItem *)pathOptions[PathOptions::AddECEREPaths].row.GetData(optionField))->name = pathOptions[PathOptions::AddECEREPaths].name;
+
+            pathOptions[PathOptions::AddMinGWPaths].name = options[0].selected ? $"Add TDM-GCC/MinGW-w64 to the system environment path" : $"Add TDM-GCC/MinGW-w64 to the user environment path";
+            if(pathOptions[PathOptions::AddMinGWPaths].row)
+               ((CheckItem *)pathOptions[PathOptions::AddMinGWPaths].row.GetData(optionField))->name = pathOptions[PathOptions::AddMinGWPaths].name;
+
+            GetEnvironment(options[0].selected ? "ALLUSERSPROFILE" : "APPDATA", appData, sizeof(appData));
+            if(appData[0])
+            {
+               char defPath[MAX_LOCATION];
+
+               strcpy(defPath, installDir);
+               PathCat(defPath, components[ComponentID::samples].defInstallPath);
+               ChangeCh(defPath, '/', DIR_SEP);
+               if(!strcmp(defPath, components[ComponentID::samples].installPath))
+               {
+                  static char defSamplesPath[MAX_LOCATION];
+                  strcpy(defSamplesPath, appData);
+                  PathCat(defSamplesPath, "Ecere SDK\\Samples");
+                  components[ComponentID::samples].defInstallPath = defSamplesPath;
+
+                  strcpy(components[ComponentID::samples].installPath, components[ComponentID::samples].defInstallPath);
+                  ChangeCh(components[ComponentID::samples].installPath, '/', DIR_SEP);
+                  components[ComponentID::samples].row.SetData(locationField, components[ComponentID::samples].installPath);
+               }
+
+               strcpy(defPath, installDir);
+               PathCat(defPath, additional[AdditionalID::extras].defInstallPath);
+               ChangeCh(defPath, '/', DIR_SEP);
+               if(!strcmp(additional[AdditionalID::extras].installPath, additional[AdditionalID::extras].installPath))
+               {
+                  static char defExtrasPath[MAX_LOCATION];
+                  strcpy(defExtrasPath, appData);
+                  PathCat(defExtrasPath, "Ecere SDK\\extras");
+                  additional[AdditionalID::extras].defInstallPath = defExtrasPath;
+
+                  strcpy(additional[AdditionalID::extras].installPath, additional[AdditionalID::extras].defInstallPath);
+                  ChangeCh(additional[AdditionalID::extras].installPath, '/', DIR_SEP);
+                  additional[AdditionalID::extras].row.SetData(locationField, additional[AdditionalID::extras].installPath);
+               }
+            }
+            listBox.Update(null);
+         }
       }
    };
    Button install
    {
-      parent = this, text = $"Install", isDefault = true, size = { 75, 23 }, position = { 432, 416 };
+      parent = this, caption = $"Install", isDefault = true, size = { 75, 23 }, position = { 432, 440 };
 
       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
       {
@@ -704,11 +688,43 @@ class Installer : Window
          return true;
       }
    };
-   Button button3 { parent = this, text = $"Cancel", hotKey = altX, size = Size { 75, 23 }, anchor = Anchor { left = 544, top = 416 }, NotifyClicked = ButtonCloseDialog };
+   Button button3 { parent = this, caption = $"Cancel", hotKey = altX, size = Size { 75, 23 }, anchor = Anchor { left = 544, top = 440 }, NotifyClicked = ButtonCloseDialog };
+   DropBox languageBox
+   {
+      this, position = { 14, 374 }, size = { 142, 0 }, caption = "Language:";
+
+      bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
+      {
+         LanguageOption * option = row.GetData(null);
+         // If the language is already set, we need to override it
+         {
+            IDESettings settings = null;
+            IDESettingsContainer settingsContainer
+            {
+               driver = "JSON";
+               dataOwner = &settings;
+               dataClass = class(IDESettings);
+               allUsers = options[0].selected;
+            };
+            settingsContainer.Load();
+            if(settings.language)
+            {
+               settings.language = option->code;
+               settingsContainer.Save();
+            }
+            delete settingsContainer;
+            delete settings;
+         }
+         ((GuiApplication)__thisModule.application).desktop.Destroy(0);
+         LanguageRestart(option->code, __thisModule.application, null, null, null, null, false);
+         return true;
+      }
+   };
+   Label lblLanguageBox { this, position = { 14, 354 }, labeledWindow = languageBox };
    Label label1 { labeledWindow = destBox, tabCycle = true, isGroupBox = true, parent = this, inactive = false, size = Size { 458, 50 }, anchor = Anchor { left = 160, top = 96 } };
    PathBox destBox
    {
-      parent = label1, master = this, text = $" Destination Folder", size = Size { 336, 22 }, anchor = Anchor { left = 12, top = 20, right = 12 };
+      parent = label1, master = this, caption = $" Destination Folder", size = Size { 336, 22 }, anchor = Anchor { left = 12, top = 20, right = 12 };
       typeExpected = directory;
       browseDialog = fileDialog;
       opacity = 0;
@@ -766,7 +782,7 @@ class Installer : Window
    };
    EditBox label7
    {
-      this, opacity = 0, borderStyle = none, inactive = true, size = { 136, 53 }, position = { 14, 280 }, noSelect = true, 
+      this, opacity = 0, borderStyle = none, inactive = true, size = { 136, 83 }, position = { 14, 280 }, noSelect = true,
       multiLine = true,
       contents = $"Select icons to install, file\n"
       "associations, and system\n"
@@ -774,23 +790,21 @@ class Installer : Window
    };
    Label totalSpaceLabel
    {
-      this, position = { 18, 352 }, text = $"Space Required: "
+      this, anchor = { right = 72, top = 404 }, caption = $"Space Required: "
    };
    Label totalSpaceValue
    {
-      this, position = { 100, 352 }, text = "0 mb"
+      this, anchor = { right = 14, top = 404 }, caption = "0 mb"
    };
    EditBox editBox1
    {
-      inactive = true, noSelect = true,
-      multiLine = true, parent = label3, text = "editBox1", opacity = 0, borderStyle = none, size = Size { 350, 35 }, anchor = Anchor { horz = 111, vert = 13 },
-      contents = $"Choose in which folder to install the ECERE SDK, which features\n"
+      label3, caption = "editBox1", opacity = 0, borderStyle = none, inactive = true, size = { 350, 35 }, position = { 256, 40 }, multiLine = true, noSelect = true, contents = $"Choose in which folder to install the Ecere SDK, which features\n"
          "of the SDK to install, as well as where to install program icons."
    };
-   Label label2 { parent = this, text = buildString, position = { 16, 392 }, font = { "Tahoma", 10, true }, disabled = true, opacity = 0, background = activeBorder };
+   Label label2 { parent = this, position = { 16, 422 }, font = { "Tahoma", 10, true }, disabled = true, opacity = 0, background = activeBorder };
    Picture picture1
    {
-      image = BitmapResource { ":ecere.png", alphaBlend = true }, filter = true, parent = label3, text = "picture1", anchor = Anchor { left = 16, top = 4 };
+      image = BitmapResource { ":ecere.png", alphaBlend = true }, filter = true, parent = label3, caption = "picture1", anchor = Anchor { left = 16, top = 4 };
       cursor = ((GuiApplication)__thisModule).GetCursor(hand);
 
       bool OnLeftButtonDown(int x, int y, Modifiers mods)
@@ -799,14 +813,16 @@ class Installer : Window
          return true;
       }
    };
-   Label label4 { parent = label3, text = $"Choose Components, Locations and Install Options", font = FontResource { "Tahoma", 8.25f, bold = true }, size = Size { 326, 16 }, anchor = Anchor { horz = 91, vert = -12 } };
-   DataField componentField { "CheckItem", width = 140, header = $"Component" };
+   Label label4 { label3, font = { "Tahoma", 8.25f, bold = true }, /*size = { 326, 16 }, */position = { 248, 24 }, caption = $"Choose Components, Locations and Install Options" };
+   DataField componentField { "CheckItem", width = 160, header = $"Component" };
    DataField locationField { "char *", width = 108, header = $"Destination Folder", editable = true };
-   DataField reqField { "FileSize", width = 80, header = $"Req. Space", alignment = right };
-   DataField avField { "FileSize64", width = 80, header = $"Avail. Space", alignment = right };
+   DataField reqField { "FileSize", width = 70, header = $"Req. Space", alignment = right };
+   DataField avField { "FileSize64", width = 70, header = $"Avail. Space", alignment = right };
    DataField optionField { "CheckItem" };
 
-   void SetAvailableSpace(Component component, char * parentPath)
+   DataField languageField { class(LanguageOption) };
+
+   void SetAvailableSpace(Component component, const char * parentPath)
    {
       char path[MAX_LOCATION];
       int c;
@@ -828,7 +844,7 @@ class Installer : Window
       if(!size) install.disabled = true;
    }
 
-   FileSize ComputeSize(char * path)
+   FileSize ComputeSize(const char * path)
    {
       FileSize size = 0;
       FileAttribs attribs = FileExists(path);
@@ -848,19 +864,20 @@ class Installer : Window
       return size;
    }
 
-   void AddComponent(Component component, Component parent, char * parentPath)
+   void AddComponent(Component component, Component parent, const char * parentPath)
    {
-      DataRow row = component.row = componentsBox.AddRow((parent != null) ? parent.row : null);
-      Button checkBox = (Button) row.tag;
+      DataRow row = (parent != null) ? parent.row.AddRow() : componentsBox.AddRow();
       FileSize size = 0;
       FileSize64 avSize = 0;
       char path[MAX_LOCATION];
+
+      component.row = row;
       strcpy(path, parentPath);
       if(component.defInstallPath)
          PathCat(path, component.defInstallPath);
       component.parent = parent;
-         
-      row.SetData(null, CheckItem { component.name, component } );
+
+      row.SetData(null, CheckItem { component.name, component, (component.arch == bits32 && osIS64bit) } );
 
       if(component.defInstallPath)
       {
@@ -869,8 +886,18 @@ class Installer : Window
          row.SetData(locationField, component.installPath);
       }
 
-      if(component.mandatory) checkBox.disabled = true;
-      if(!component.selected) componentsBox.ToggleCheck(row);
+      if(component.mandatory)
+      {
+         if(component.arch != bits32 || !osIS64bit) // || component == &coreSDK[gdb32])
+            componentsBox.SetDisabled(row, true);
+         /*else
+            component.selected = false;*/
+      }
+      else if(component.arch == bits32 && osIS64bit)
+         ; //component.selected = false;
+
+      componentsBox.SetCheck(row, component.selected);
+
       if(component.dataPath)
       {
          char path[MAX_LOCATION];
@@ -883,8 +910,14 @@ class Installer : Window
          int c;
          for(c = 0; component.subComponents[c].name; c++)
          {
-            AddComponent(component.subComponents[c], component, path);
-            size += component.subComponents[c].requiredSize;
+            Component * sub = &component.subComponents[c];
+            if(sub->available && (osIS64bit || sub->arch == bits32 || sub->arch == none))
+            {
+               AddComponent(sub, component, path);
+               size += sub->requiredSize;
+            }
+            else
+               sub->selected = false;
          }
       }
 
@@ -894,7 +927,7 @@ class Installer : Window
 
       while(!FileExists(path) && path[0])
          StripLastDirectory(path, path);
-      
+
       if(path[0])
          GetFreeSpace(path, &avSize);
       else
@@ -905,10 +938,9 @@ class Installer : Window
 
    void AddOption(InstallOption option, InstallOption parent)
    {
-      DataRow row = option.row = optionsBox.AddRow((parent != null) ? parent.row : null);
+      DataRow row = option.row = (parent != null) ? parent.row.AddRow() : optionsBox.AddRow();
       row.SetData(null, CheckItem { option.name, option } );
-      if(!option.selected)
-         optionsBox.ToggleCheck(row);
+      optionsBox.SetCheck(row, option.selected);
       if(option.subOptions)
       {
          int c;
@@ -924,14 +956,53 @@ class Installer : Window
    {
       int c;
       char programFilesDir[MAX_LOCATION];
-      char appData[MAX_LOCATION]; // = getenv("APPDATA");
-      char homeDrive[MAX_LOCATION]; //= getenv("HOMEDRIVE");
-      char winDir[MAX_LOCATION]; //= getenv("windir");
+      char appData[MAX_LOCATION];
+      char homeDrive[MAX_LOCATION];
+      char winDir[MAX_LOCATION];
+      char * x86 = null;
+
+      bool isAdministrator = IsAdministrator();
+
+      SetBuildString(label2);
+
+      if(!isAdministrator)
+      {
+         options[0].available = false;
+         options[0].selected = false;
+      }
+
+      // If the SDK is already installed, use currently selected language
+      {
+         IDESettings settings = null;
+         IDESettingsContainer settingsContainer
+         {
+            driver = "JSON";
+            dataOwner = &settings;
+            dataClass = class(IDESettings);
+            allUsers = options[0].selected;
+         };
+
+         settingsContainer.Load();
+
+         if(settings.language)
+         {
+            const String language = GetLanguageString();
+            if(settings.language.OnCompare(language))
+            {
+               // Relaunch the installer with previously selected language
+               LanguageRestart(settings.language, __thisModule.application, null, null, null, null, false);
+               return false;
+            }
+         }
+         delete settingsContainer;
+         delete settings;
+      }
 
-      GetEnvironment("APPDATA", appData, sizeof(appData));
       GetEnvironment("HOMEDRIVE", homeDrive, sizeof(homeDrive));
       GetEnvironment("windir", winDir, sizeof(winDir));
-      
+
+      GetEnvironment(options[0].selected ? "ALLUSERSPROFILE" : "APPDATA", appData, sizeof(appData));
+
       componentsBox.AddField(componentField);
       componentsBox.AddField(locationField);
       componentsBox.AddField(reqField);
@@ -939,37 +1010,67 @@ class Installer : Window
 
       optionsBox.AddField(optionField);
 
+      languageBox.AddField(languageField);
+
+      programFilesDir[0] = 0;
       if(GetEnvironment("ProgramFiles", programFilesDir, MAX_LOCATION))
       {
-         strcpy(installDir, programFilesDir);
-         PathCat(installDir, "ECERE SDK");
+         x86 = strstr(programFilesDir, " (x86)");
+         if(x86)
+            osIS64bit = true;
       }
-      else if(homeDrive && homeDrive[0])
+
+      if(isAdministrator && programFilesDir[0])
+      {
+         if(x86)
+         {
+            strcpy(installDir32, programFilesDir);
+            PathCat(installDir32, "Ecere SDK");
+            *x86 = 0;
+            strcpy(installDir, programFilesDir);
+            PathCat(installDir, "Ecere SDK");
+         }
+         else
+         {
+            strcpy(installDir, programFilesDir);
+            PathCat(installDir, "Ecere SDK");
+            strcpy(installDir32, installDir);
+         }
+      }
+      else if(homeDrive[0])
       {
          strcpy(installDir, homeDrive);
-         PathCat(installDir, "ECERE SDK");
+         PathCat(installDir, "Ecere SDK");
+         strcpy(installDir32, installDir);
+         strcat(installDir32, " (32)");
       }
-      else if(winDir && winDir[0])
+      else if(winDir[0])
       {
          strcpy(installDir, winDir);
-         PathCat(installDir, "..\\ECERE SDK");
+         PathCat(installDir, "..\\Ecere SDK");
+         strcpy(installDir32, installDir);
+         strcat(installDir32, " (32)");
       }
       else
-         strcpy(installDir, "C:\\ECERE SDK");
-      
-      if(appData && appData[0])
+      {
+         strcpy(installDir, "C:\\Ecere SDK");
+         strcpy(installDir32, installDir);
+         strcat(installDir32, " (32)");
+      }
+
+      if(appData[0])
       {
          static char defSamplesPath[MAX_LOCATION];
          static char defExtrasPath[MAX_LOCATION];
          strcpy(defSamplesPath, appData);
-         PathCat(defSamplesPath, "ECERE SDK\\Samples");
-         components[samples].defInstallPath = defSamplesPath;
+         PathCat(defSamplesPath, "Ecere SDK\\Samples");
+         components[ComponentID::samples].defInstallPath = defSamplesPath;
 
          strcpy(defExtrasPath, appData);
-         PathCat(defExtrasPath, "ECERE SDK\\extras");
-         coreSDK[extras].defInstallPath = defExtrasPath;
+         PathCat(defExtrasPath, "Ecere SDK\\extras");
+         additional[AdditionalID::extras].defInstallPath = defExtrasPath;
       }
-         
+
       destBox.path = installDir;
 
       {
@@ -988,14 +1089,90 @@ class Installer : Window
       {
          char sizeString[100];
          PrintSize(sizeString, totalSize, 2);
-         totalSpaceValue.text = sizeString;
+         totalSpaceValue.caption = sizeString;
       }
       for(c = 0; options[c].name; c++)
-         AddOption(options[c], null);
+      {
+         if(options[c].available)
+            AddOption(options[c], null);
+      }
+   }
+
+   void OnDestroy()
+   {
+      for(l : languages)
+         delete l.res;
+   }
+
+   bool OnPostCreate()
+   {
+      dotLbl.position.x = licenseButton.position.x + licenseButton.size.w - 4;
+      return true;
    }
 
    bool OnCreate()
    {
+      // Constructor happens before Languages is instantiated...
+      for(l : languages)
+      {
+         l.res = { l.bitmap, window = this };
+         incref l.res;
+      }
+
+      if(!loaded)
+      {
+         const String language = GetLanguageString();
+         bool found = false;
+         DataRow row;
+
+         // Try to find country-specific language first
+         for(l : languages)
+         {
+            LanguageOption option = l;
+            row = languageBox.AddRow();
+            row.SetData(null, option); // TOFIX: l used directly here
+
+            if(!found && (!strcmpi(l.code, language) || (!row.GetPrevRow() && !strcmpi("en", language))))
+            {
+               languageBox.currentRow = row;
+               found = true;
+            }
+         }
+
+         // Try generalizing locale
+         if(!found)
+         {
+            char * under;
+            char genericLocale[256];
+            strncpy(genericLocale, language, sizeof(genericLocale));
+            genericLocale[sizeof(genericLocale)-1] = 0;
+
+            under = strchr(genericLocale, '_');
+            if(under)
+               *under = 0;
+            if(!strcmpi(genericLocale, "zh"))
+               strcpy(genericLocale, "zh_CN");
+            if(strcmp(genericLocale, language))
+            {
+               row = languageBox.firstRow;
+               for(l : languages)
+               {
+                  if(!strcmpi(l.code, genericLocale) || (!row.GetPrevRow() && !strcmpi("en", genericLocale)))
+                  {
+                     languageBox.currentRow = row;
+                     found = true;
+                     break;
+                  }
+                  row = row.GetNextRow();
+               }
+            }
+         }
+
+         if(!found)
+            languageBox.currentRow = languageBox.firstRow;
+         loaded = true;
+      }
+
       destBox.Activate();
       return true;
    }
@@ -1004,12 +1181,11 @@ class Installer : Window
    {
       int tw = label2.size.w;
       surface.SetForeground(Color { 128, 128, 128 });
-      surface.HLine(label2.position.x + tw + 6, 620, 400);
+      surface.HLine(label2.position.x + tw + 6, 620, 430);
       surface.SetForeground(white);
-      surface.HLine(label2.position.x + tw + 6, 621, 401);
+      surface.HLine(label2.position.x + tw + 6, 621, 431);
       surface.PutPixel(621, 400);
    }
-
    Label label3
    {
       parent = this, opacity = 0, borderStyle = deep, size = Size { 644, 93 }, anchor = Anchor { left = -8, top = -8 };
@@ -1018,27 +1194,34 @@ class Installer : Window
 
 class InstallProgress : Window
 {
-   text = $"Ecere Software Development Kit Setup - v0.44 \"Ryōan-ji\"";
+   caption = $"Ecere Software Development Kit Setup - v0.44.10 \"Ryōan-ji\" 64 Bit Edition";
    background = activeBorder;
    borderStyle = fixed;
    hasMinimize = true;
    hasClose = true;
    tabCycle = true;
-   size = Size { 640, 480 };
+   // size = Size { 640, 480 };
+   clientSize = { 636, 476 };
+   //clientSize = { 796, 576 };
    icon = { ":icon.png" };
 
+   InstallProgress()
+   {
+      SetBuildString(label2);
+   }
+
    Picture back { image = BitmapResource { ":ryoanji-progress.png" }, parent = this, position = { 0, 0 } };
    Label installing { this, position = { 32, 160 } };
    ProgressBar progressBar { parent = this, size = Size { 588, 24 }, anchor = Anchor { left = 24, top = 184 } };
    Button finish
    {
-      parent = this, text = $"Install", disabled = true, isDefault = true, size = Size { 75, 23 }, anchor = Anchor { left = 432, top = 416 };
+      parent = this, caption = $"Install", disabled = true, isDefault = true, size = Size { 75, 23 }, anchor = Anchor { left = 432, top = 440 };
 
       NotifyClicked = ButtonCloseDialog
    };
    Button cancel
    {
-      this, text = $"Cancel", hotKey = altX, size = Size { 75, 23 }, anchor = Anchor { left = 544, top = 416 };
+      this, caption = $"Cancel", hotKey = altX, size = Size { 75, 23 }, anchor = Anchor { left = 544, top = 440 };
 
       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
       {
@@ -1052,7 +1235,7 @@ class InstallProgress : Window
       multiLine = true, parent = label3, opacity = 0, borderStyle = none, size = Size { 350, 35 }, anchor = Anchor { horz = 111, vert = 13 },
       contents = $"Please wait while the Ecere Software Development Kit is being installed."
    };
-   Label label2 { parent = this, text = buildString, position = { 16, 392 }, font = { "Tahoma", 10, true }, disabled = true, opacity = 0, background = activeBorder };
+   Label label2 { parent = this, position = { 16, 422 }, font = { "Tahoma", 10, true }, disabled = true, opacity = 0, background = activeBorder };
    Picture picture1
    {
       image = BitmapResource { ":ecere.png", alphaBlend = true }, filter = true, parent = label3, anchor = Anchor { left = 16, top = 4 };
@@ -1064,15 +1247,15 @@ class InstallProgress : Window
          return true;
       }
    };
-   Label title { parent = label3, text = $"Installing the ECERE SDK", font = FontResource { "Tahoma", 8.25f, bold = true }, size = Size { 326, 16 }, anchor = Anchor { horz = 91, vert = -12 } };
+   Label title { parent = label3, caption = $"Installing the Ecere SDK", font = FontResource { "Tahoma", 8.25f, bold = true }, size = Size { 326, 16 }, anchor = Anchor { horz = 91, vert = -12 } };
 
    void OnDrawOverChildren(Surface surface)
    {
       int tw = label2.size.w;
       surface.SetForeground(Color { 128, 128, 128 });
-      surface.HLine(label2.position.x + tw + 6, 620, 400);
+      surface.HLine(label2.position.x + tw + 6, 620, 430);
       surface.SetForeground(white);
-      surface.HLine(label2.position.x + tw + 6, 621, 401);
+      surface.HLine(label2.position.x + tw + 6, 621, 431);
       surface.PutPixel(621, 400);
    }
 
@@ -1088,121 +1271,127 @@ class InstallProgress : Window
 Installer installer {};
 InstallProgress installProgress { autoCreate = false };
 
-void ModifyPath(char * newPath)
+static void AddPath(char * sysPaths[200], int sysCount, char * paths[200], int * count, char * oldPath, char * userPath, char * path)
 {
-   char * paths[100];
-   int p, count;
-   char oldPath[4096];
-   CoreSDKID c;
-
-   strcpy(oldPath, newPath);
-   count = TokenizeWith(oldPath, sizeof(paths) / sizeof(char *), paths, ";", false);
-
-   for(c = 0; coreSDK[c].name; c++)
+   int p;
+   bool found = false;
+   for(p = 0; p<sysCount; p++)
+      if(!fstrcmp(sysPaths[p], path))
+      {
+         found = true;
+         break;
+      }
+   for(p = 0; !found && p<*count; p++)
+      if(!fstrcmp(paths[p], path))
+      {
+         found = true;
+         break;
+      }
+   if(!found)
    {
-      char path[MAX_LOCATION];
-      if(c == extras || c == vanilla) continue;
-
-      coreSDK[c].GetFullPath(path);
-      if(c != ide && c != runtime && c != eda && c != ec)
+      char * start;
+      if(*count)
       {
-#ifndef NOMINGW
-         if(!pathOptions[PathOptions::AddMinGWPaths].selected)
-#endif
-         continue;
-         PathCat(path, "bin");
+         strcat(userPath, ";");
+         start = paths[(*count)-1] + strlen(paths[(*count)-1])+1;
       }
-      else if(!pathOptions[PathOptions::AddECEREPaths].selected) continue;
+      else
+         start = oldPath;
+
+      strcpy(start, path);
+      *(start + strlen(path)) = '\0';
+      paths[(*count)++] = start;
+
+      strcat(userPath, path);
+   }
+}
+
 
-      for(p = 0; p<count; p++)
-         if(!fstrcmp(paths[p], path))
-            break;
-      if(p == count)
+void ModifyPath(char * systemPath, char * userPath)
+{
+   char oldPath[8192], * paths[200], * sysPaths[200];
+   int count, sysCount = 0;
+
+   if(userPath)
+   {
+      strcpy(oldPath, userPath);
+      count = TokenizeWith(oldPath, sizeof(paths) / sizeof(char *), paths, ";", false);
+      sysCount = TokenizeWith(systemPath, sizeof(sysPaths) / sizeof(char *), sysPaths, ";", false);
+   }
+   else
+   {
+      strcpy(oldPath, systemPath);
+      count = TokenizeWith(oldPath, sizeof(paths) / sizeof(char *), paths, ";", false);
+   }
+
+   {
+      CoreSDKID c;
+      for(c = 0; coreSDK[c].name; c++)
       {
-         char * start;
-         if(count) 
+         char path[MAX_LOCATION];
+         if(!coreSDK[c].selected) continue;
+         coreSDK[c].GetFullPath(path, false);
+         if(c != ide && c != runtime && c != ec &&
+            c != ide32 && c != runtime32 && c != ec32)
          {
-            strcat(newPath, ";");
-            start = oldPath + strlen(paths[count-1])+1;
+            if(!pathOptions[PathOptions::AddMinGWPaths].available || !pathOptions[PathOptions::AddMinGWPaths].selected)
+               continue;
+            PathCat(path, "bin");
          }
-         else
-            start = oldPath;
-         
-         strcpy(start, path);
-         *(start + strlen(path)) = '\0';
-         paths[count++] = start;
+         else if(!pathOptions[PathOptions::AddECEREPaths].selected) continue;
 
-         strcat(newPath, path);
+         AddPath(sysPaths, sysCount, paths, &count, oldPath, userPath ? userPath : systemPath, path);
       }
    }
-#ifndef NOMINGW
-   if(pathOptions[PathOptions::AddMinGWPaths].selected)
    {
-      int c;
-      for(c = 0; additional[c].name; c++)
+      AdditionalID c;
+      // Up to C++
+      for(c = 0; c <= cpp; c++)
       {
          char path[MAX_LOCATION];
-         NamedItem item;
-         additional[c].GetFullPath(path);
-         PathCat(path, "bin");
-         for(p = 0; p<count; p++)
-            if(!fstrcmp(paths[p], path))
-               break;
-
-         if(p == count)
-         {
-            char * start;
-            if(count) 
-            {
-               strcat(newPath, ";");
-               start = oldPath + strlen(paths[count-1])+1;
-            }
-            else
-               start = oldPath;
-            
-            strcpy(start, path);
-            *(start + strlen(path)) = '\0';
-            paths[count++] = start;
-
-            strcat(newPath, path);
-         }
+         if(!additional[c].selected || c == vanilla || c == vanilla32 || c == extras) continue;
+         if((c != eda && c != eda32 && c != upx) && (!pathOptions[PathOptions::AddMinGWPaths].available || !pathOptions[PathOptions::AddMinGWPaths].selected))
+            continue;
+         additional[c].GetFullPath(path, false);
+         if(c != eda && c != eda32 && c != upx && c != audio && c != audio32)
+            PathCat(path, "bin");
+         AddPath(sysPaths, sysCount, paths, &count, oldPath, userPath ? userPath : systemPath, path);
       }
    }
-#endif
 }
 
-void AssociateExtension(char * extension, char * description, char *name, char * action, char * path)
+void AssociateExtension(const char * extension, const char * description, const char *name, const char * action, const char * path)
 {
    HKEY key;
-   uint status, size;
+   DWORD status;
    char keyName[1024];
 
-   RegCreateKeyEx(HKEY_CLASSES_ROOT, extension, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
-   RegSetValueEx(key, null, 0, REG_SZ, name, strlen(name)+1);
+   RegCreateKeyEx(HKEY_CLASSES_ROOT, extension, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
+   RegSetValueEx(key, null, 0, REG_SZ, (byte *)name, (uint)strlen(name)+1);
    RegCloseKey(key);
 
-   RegCreateKeyEx(HKEY_CLASSES_ROOT, name, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
-   RegSetValueEx(key, null, 0, REG_SZ, description, strlen(description)+1);
+   RegCreateKeyEx(HKEY_CLASSES_ROOT, name, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
+   RegSetValueEx(key, null, 0, REG_SZ, (byte *)description, (uint)strlen(description)+1);
    RegCloseKey(key);
 
    sprintf(keyName, "%s\\shell", extension);
-   RegCreateKeyEx(HKEY_CLASSES_ROOT, keyName, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
-   RegSetValueEx(key, null, 0, REG_SZ, action, strlen(action)+1);
+   RegCreateKeyEx(HKEY_CLASSES_ROOT, keyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
+   RegSetValueEx(key, null, 0, REG_SZ, (byte *)action, (uint)strlen(action)+1);
    RegCloseKey(key);
 
    sprintf(keyName, "%s\\shell\\%s", name, action);
-   RegCreateKeyEx(HKEY_CLASSES_ROOT, keyName, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
+   RegCreateKeyEx(HKEY_CLASSES_ROOT, keyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
    RegCloseKey(key);
 
    sprintf(keyName, "%s\\shell\\%s\\command", name, action);
-   RegCreateKeyEx(HKEY_CLASSES_ROOT, keyName, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
-   
+   RegCreateKeyEx(HKEY_CLASSES_ROOT, keyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
+
    sprintf(keyName, path);
    strcat(keyName, " \"%L\"");
    {
       uint16 wKeyName[2048];
       UTF8toUTF16Buffer(keyName, wKeyName, sizeof(wKeyName) / sizeof(uint16));
-      RegSetValueExW(key, null, 0, REG_SZ, (byte *)wKeyName, (wcslen(wKeyName) + 1)*sizeof(uint16));
+      RegSetValueExW(key, null, 0, REG_SZ, (byte *)wKeyName, (uint)(wcslen(wKeyName) + 1)*sizeof(uint16));
    }
    RegCloseKey(key);
 }
@@ -1214,171 +1403,232 @@ class InstallThread : Thread
       ComponentID c;
       ((GuiApplication)__thisModule).Lock();
       installProgress.progressBar.range = totalSize;
+
+      if(!osIS64bit)
+         strcpy(installDir32, installDir);
+
       for(c = 0; components[c].name && !abortInstall; c++)
-         components[c].Install(installDir);
+         components[c].Install(installDir, installDir32);
       if(abortInstall)
       {
          installProgress.progressBar.range = 0;
          installProgress.finish.Destroy(0);
-         installProgress.cancel.text = $"Close";
+         installProgress.cancel.caption = $"Close";
          installProgress.cancel.isDefault = true;
          installProgress.cancel.disabled = false;
          installProgress.cancel.NotifyClicked = Window::ButtonCloseDialog;
-         installProgress.installing.text = $"Installation Cancelled.";
-         installProgress.title.text = $"Installation Cancelled";
+         installProgress.installing.caption = $"Installation Cancelled.";
+         installProgress.title.caption = $"Installation Cancelled";
          installProgress.titleInfo.contents = $"The installation was not completed.";
       }
       else
       {
-         CoreSDKID c;
          char idePath[MAX_LOCATION];
          char userProfile[MAX_LOCATION];
 
          // Configure IDE
-         GlobalSettings settings
+         IDESettings settings = null; // Don't instantiate yet so we can pick up old settings
+
+         IDESettingsContainer settingsContainer
          {
-            
+            driver = "JSON";
+            dataOwner = &settings;
+            dataClass = class(IDESettings);
+            allUsers = options[0].selected;
          };
-         installProgress.installing.text = $"Configuring ECERE IDE...";
+         CompilerConfig compiler;
+         installProgress.installing.caption = $"Configuring Ecere IDE...";
          ((GuiApplication)__thisModule).Unlock();
          ((GuiApplication)__thisModule).SignalEvent();
 
-         settings.Load();
-         for(c = 0; coreSDK[c].name; c++)
+         settingsContainer.Load();
+         compiler = settings.GetCompilerConfig(defaultCompilerName);
+         if(compiler)
          {
-            char path[MAX_LOCATION];
-            NamedItem item;
-            coreSDK[c].GetFullPath(path);
-            if(c != ide && c != runtime && c != eda && c != ec)
-               PathCat(path, "bin");
-            if(c == ide)
             {
-               coreSDK[c].GetFullPath(idePath);
-               PathCat(idePath, "IDE.exe");
-            }
+               CoreSDKID c;
+               for(c = 0; coreSDK[c].name; c++)
+               {
+                  char path[MAX_LOCATION];
+                  if(!coreSDK[c].selected || !coreSDK[c].available) continue;
+
+                  coreSDK[c].GetFullPath(path, false);
+                  if(c != ide && c != runtime && c != ec &&
+                     c != ide32 && c != runtime32 && c != ec32)
+                     PathCat(path, "bin");
+                  MakeSlashPath(path);
+                  if((c == ide && osIS64bit) || (c == ide32 && !osIS64bit))
+                  {
+                     coreSDK[c].GetFullPath(idePath, false);
+                     PathCat(idePath, "ide.exe");
+                  }
 
-            // TODO: Update This!
-            /*
-            for(item = settings.systemDirs[executables].first; item; item = item.next)
-               if(!fstrcmp(item.name, path))
-                  break;
-            if(!item)
-            {
-               settings.systemDirs[executables].Add(NamedItem { name = CopyString(path); });
+                  if(c == runtime || c == runtime32)
+                  {
+                     if(!compiler.libraryDirs.Find(path))
+                        compiler.libraryDirs.Add(CopyString(path));
+                  }
+               }
             }
-
-            if(c == runtime)
             {
-               for(item = settings.systemDirs[libraries].first; item; item = item.next)
-                  if(!fstrcmp(item.name, path))
-                     break;
-               if(!item)
+               AdditionalID c;
+               // Up to C++
+               for(c = 0; c <= cpp; c++)
                {
-                  settings.systemDirs[libraries].Add(NamedItem { name = CopyString(path); });
+                  char path[MAX_LOCATION];
+                  if(c == extras || !additional[c].selected || !additional[c].available) continue;
+                  additional[c].GetFullPath(path, false);
+                  if(c != upx && c != eda && c != vanilla && c != eda32 && c != vanilla32)
+                     PathCat(path, "bin");
+                  MakeSlashPath(path);
+                  if(c == vanilla || c == vanilla32)
+                  {
+                     if(!compiler.libraryDirs.Find(path))
+                        compiler.libraryDirs.Add(CopyString(path));
+                  }
+                  else
+                  {
+                     if(!compiler.executableDirs.Find(path))
+                        compiler.executableDirs.Add(CopyString(path));
+                  }
                }
             }
-            */
          }
-#ifndef NOMINGW
-         /*
-         for(c = 0; additional[c].name; c++)
+
          {
-            char path[MAX_LOCATION];
-            NamedItem item;
-            additional[c].GetFullPath(path);
-            PathCat(path, "bin");
-            for(item = settings.systemDirs[executables].first; item; item = item.next)
-               if(!fstrcmp(item.name, path))
-                  break;
-            if(!item)
+            char path[MAX_LOCATION] = "";
+
+            if(components[ComponentID::samples].selected)
+               components[ComponentID::samples].GetFullPath(path, false);
+            // IDE will now default to HOME for the default project/files locations
+
+            if(!settings.ideProjectFileDialogLocation[0])
+               settings.ideProjectFileDialogLocation = path;
+            if(!settings.ideFileDialogLocation[0])
+               settings.ideFileDialogLocation = path;
+
+            if(documentation[DocumentationID::apiRef].selected)
             {
-               settings.systemDirs[executables].Add(NamedItem { name = CopyString(path); });
+               documentation[DocumentationID::apiRef].GetFullPath(path, false);
+               if(!settings.docDir[0])
+                  settings.docDir = path;
             }
          }
-         */
-#endif
-         
+
+         settings.language = GetLanguageString();
+
+         // Set LANGUAGE environment variable
          {
-            char path[MAX_LOCATION] = "";
-            if(components[samples].selected)
-               components[samples].GetFullPath(path);
+            HKEY key = null;
+            uint16 wLanguage[256];
+            DWORD status;
+            wLanguage[0] = 0;
+
+            if(options[0].selected)
+               RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", 0, KEY_ALL_ACCESS, &key);
             else
-               components[coreSDK].GetFullPath(path);
-            /* TODO: Update This!
-            if(!settings.ideProjectFileDialogLocation)
-               settings.ideProjectFileDialogLocation = path;
-            if(!settings.ideFileDialogLocation)
-               settings.ideFileDialogLocation = path;
-            */
+               RegCreateKeyEx(HKEY_CURRENT_USER, "Environment", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
+            if(key)
+            {
+               UTF8toUTF16Buffer(settings.language, wLanguage, sizeof(wLanguage) / sizeof(uint16));
+               RegSetValueExW(key, L"ECERE_LANGUAGE", 0, REG_EXPAND_SZ, (byte *)wLanguage, (uint)(wcslen(wLanguage)+1) * 2);
+               RegCloseKey(key);
+            }
          }
 
-         settings.Save();
+         settingsContainer.Save();
+         delete settingsContainer;
          delete settings;
 
          // Set up Uninstaller
          ((GuiApplication)__thisModule).Lock();
-         installProgress.installing.text = $"Registering uninstaller...";
+         installProgress.installing.caption = $"Registering uninstaller...";
          ((GuiApplication)__thisModule).Unlock();
          ((GuiApplication)__thisModule).SignalEvent();
 
          {
             HKEY key;
-            uint status, size;
-            char * displayName = "ECERE SDK 0.44";
+            DWORD status;
+            const char * displayName = "Ecere SDK 0.44";
             char uninstaller[MAX_LOCATION];
-            bool nomodify = true;
+            //bool nomodify = true;
 
             strcpy(uninstaller, installDir);
             PathCat(uninstaller, "uninstall_ecere.exe");
 
-            RegCreateKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ECERE SDK", 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
+            RegCreateKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Ecere SDK", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
 
-            RegSetValueEx(key, "DisplayName", 0, REG_SZ, displayName, strlen(displayName)+1);
-            RegSetValueEx(key, "UninstallString", 0, REG_SZ, uninstaller, strlen(uninstaller)+1);
-            RegSetValueEx(key, "DisplayIcon", 0, REG_SZ, idePath, strlen(idePath)+1);
+            RegSetValueEx(key, "DisplayName", 0, REG_SZ, (byte *)displayName, (uint)strlen(displayName)+1);
+            RegSetValueEx(key, "UninstallString", 0, REG_SZ, (byte *)uninstaller, (uint)strlen(uninstaller)+1);
+            RegSetValueEx(key, "DisplayIcon", 0, REG_SZ, (byte *)idePath, (uint)strlen(idePath)+1);
             //RegSetValueEx(key, "NoModify", 0, REG_DWORD, (byte *)&nomodify, sizeof(nomodify));
             //RegSetValueEx(key, "NoRepair", 0, REG_DWORD, (byte *)&nomodify, sizeof(nomodify));
             RegCloseKey(key);
          }
 
          // Add paths
-         if(pathOptions[PathOptions::AddECEREPaths].selected 
+         if(pathOptions[PathOptions::AddECEREPaths].selected
 #ifndef NOMINGW
             || pathOptions[PathOptions::AddMinGWPaths].selected
 #endif
             )
          {
-            HKEY key;
-            uint status, size;
-            char path[2048] = "";
-            uint16 wPath[2048];
+            HKEY userKey = null, systemKey = null;
+            DWORD status, size;
+            char userPath[8192] = "";
+            char systemPath[8192] = "";
+            uint16 wUserPath[8192];
+            uint16 wSystemPath[8192];
+
+            wUserPath[0] = 0;
+            wSystemPath[0] = 0;
 
             ((GuiApplication)__thisModule).Lock();
-            installProgress.installing.text = "Registering paths...";
+            installProgress.installing.caption = "Registering paths...";
             ((GuiApplication)__thisModule).Unlock();
             ((GuiApplication)__thisModule).SignalEvent();
-                        
-            // if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Environment", 0, KEY_ALL_ACCESS, &key) == ERROR_SUCCESS)
-            
-            RegCreateKeyEx(HKEY_CURRENT_USER, "Environment", 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
-            // RegCreateKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
-            if(status == REG_OPENED_EXISTING_KEY)
+
+            if(options[0].selected)
             {
-               size = sizeof(wPath);
-               RegQueryValueExW(key, L"path", null, null, (byte *)wPath, &size);
-               UTF16toUTF8Buffer(wPath, path, sizeof(path));
+               if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", 0, KEY_ALL_ACCESS, &systemKey) == ERROR_SUCCESS)
+               {
+                  size = sizeof(wSystemPath);
+                  RegQueryValueExW(systemKey, L"path", null, null, (byte *)wSystemPath, &size);
+                  UTF16toUTF8Buffer(wSystemPath, systemPath, sizeof(systemPath));
+                  ModifyPath(systemPath, null);
+
+                  UTF8toUTF16Buffer(systemPath, wSystemPath, sizeof(wSystemPath) / sizeof(uint16));
+                  RegSetValueExW(systemKey, L"path", 0, REG_EXPAND_SZ, (byte *)wSystemPath, (uint)(wcslen(wSystemPath)+1) * 2);
+                  RegCloseKey(systemKey);
+               }
             }
-            ModifyPath(path);
-            UTF8toUTF16Buffer(path, wPath, sizeof(wPath) / sizeof(uint16));
-            RegSetValueExW(key, L"path", 0, REG_EXPAND_SZ, (byte *)wPath, (wcslen(wPath)+1) * 2);
-            RegCloseKey(key);
+            else
+            {
+               if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", 0, KEY_QUERY_VALUE, &systemKey) == ERROR_SUCCESS)
+               {
+                  size = sizeof(wSystemPath);
+                  RegQueryValueExW(systemKey, L"path", null, null, (byte *)wSystemPath, &size);
+                  UTF16toUTF8Buffer(wSystemPath, systemPath, sizeof(systemPath));
+                  RegCloseKey(systemKey);
+               }
 
-            SendMessageTimeout (HWND_BROADCAST, WM_SETTINGCHANGE, 0, (int)"Environment", SMTO_NORMAL, 1000, NULL);
+               RegCreateKeyEx(HKEY_CURRENT_USER, "Environment", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &userKey, &status);
+               if(status == REG_OPENED_EXISTING_KEY)
+               {
+                  size = sizeof(wUserPath);
+                  RegQueryValueExW(userKey, L"path", null, null, (byte *)wUserPath, &size);
+                  UTF16toUTF8Buffer(wUserPath, userPath, sizeof(userPath));
+               }
+               ModifyPath(systemPath, userPath);
+               UTF8toUTF16Buffer(userPath, wUserPath, sizeof(wUserPath) / sizeof(uint16));
+               RegSetValueExW(userKey, L"path", 0, REG_EXPAND_SZ, (byte *)wUserPath, (uint)(wcslen(wUserPath)+1) * 2);
+               RegCloseKey(userKey);
+            }
+            // SendMessageTimeout (HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM)"Environment", SMTO_NORMAL, 1000, NULL);
          }
 
          // Install Program Group Icons
-         // userProfile = getenv("USERPROFILE");
-         GetEnvironment("USERPROFILE", userProfile, sizeof(userProfile));
+         GetEnvironment(options[0].selected ? "ALLUSERSPROFILE" : "USERPROFILE", userProfile, sizeof(userProfile));
 
          if(options[IconOptions::StartMenuIcon].selected)
          {
@@ -1387,22 +1637,23 @@ class InstallThread : Thread
             HKEY key;
 
             ((GuiApplication)__thisModule).Lock();
-            installProgress.installing.text = $"Installing Start Menu Icons...";
+            installProgress.installing.caption = $"Installing Start Menu Icons...";
             ((GuiApplication)__thisModule).Unlock();
             ((GuiApplication)__thisModule).SignalEvent();
 
             strcpy(destPath, userProfile);
 
-            if(RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", 0, KEY_ALL_ACCESS, &key) == ERROR_SUCCESS)
+            if(RegOpenKeyEx(options[0].selected ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
+               "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS)
             {
                uint16 wStartMenuPath[2048];
-               uint size = sizeof(wStartMenuPath);
+               DWORD size = sizeof(wStartMenuPath);
                // RegQueryValueEx(key, "Start Menu", null, null, startMenuPath, &size);
-               RegQueryValueExW(key, L"Programs", null, null, (byte *)wStartMenuPath, &size);
+               RegQueryValueExW(key, options[0].selected ? L"Common Programs" : L"Programs", null, null, (byte *)wStartMenuPath, &size);
                UTF16toUTF8Buffer(wStartMenuPath, startMenuPath, sizeof(startMenuPath));
                RegCloseKey(key);
             }
-            if(!startMenuPath[0] && userProfile && userProfile[0])
+            if(!startMenuPath[0] && userProfile[0])
             {
                strcpy(startMenuPath, userProfile);
                PathCat(startMenuPath, "Start Menu\\Programs");
@@ -1411,36 +1662,36 @@ class InstallThread : Thread
             if(startMenuPath[0])
             {
                strcpy(destPath, startMenuPath);
-               PathCat(destPath, "ECERE SDK");
+               PathCat(destPath, "Ecere SDK");
                MakeDir(destPath);
 
                strcpy(destPath, startMenuPath);
-               PathCat(destPath, "ECERE SDK\\ECERE IDE.lnk");
-               CreateLink(idePath, destPath, null); //"ECERE IDE");
-               if(components[samples].selected)
+               PathCat(destPath, "Ecere SDK\\Ecere IDE.lnk");
+               CreateLink(idePath, destPath, null); //"Ecere IDE");
+               if(components[ComponentID::samples].selected)
                {
                   char samplesPath[MAX_LOCATION] = "";
-                  components[samples].GetFullPath(samplesPath);
+                  components[ComponentID::samples].GetFullPath(samplesPath, false);
 
                   strcpy(destPath, startMenuPath);
-                  PathCat(destPath, "ECERE SDK\\Sample Projects.lnk");
+                  PathCat(destPath, "Ecere SDK\\Sample Projects.lnk");
                   CreateLink(samplesPath, destPath, null);//"Sample Projects");
                }
-               if(components[documentation].selected && documentation[ecereBook].selected)
+               if(components[ComponentID::documentation].selected && documentation[DocumentationID::ecereBook].selected)
                {
                   char docPath[MAX_LOCATION] = "";
-                  documentation[ecereBook].GetFullPath(docPath);
+                  documentation[DocumentationID::ecereBook].GetFullPath(docPath, false);
                   PathCat(docPath, "Ecere Tao of Programming [work in progress].pdf");
 
                   {
                      char tao[MAX_LOCATION] ;
-                     documentation[ecereBook].GetFullPath(tao);
+                     documentation[DocumentationID::ecereBook].GetFullPath(tao, false);
                      PathCat(tao, "tao.pdf");
                      RenameFile(tao, docPath);
                   }
 
                   strcpy(destPath, startMenuPath);
-                  PathCat(destPath, "ECERE SDK\\The Ecere Tao of Programming.lnk");
+                  PathCat(destPath, "Ecere SDK\\The Ecere Tao of Programming.lnk");
                   CreateLink(docPath, destPath, null);
                }
             }
@@ -1452,15 +1703,16 @@ class InstallThread : Thread
             HKEY key;
             char desktopPath[MAX_LOCATION];
 
-            if(RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", 0, KEY_ALL_ACCESS, &key) == ERROR_SUCCESS)
+            if(RegOpenKeyEx(options[0].selected ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
+               "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS)
             {
                uint16 wDesktopPath[MAX_LOCATION];
-               uint size = sizeof(wDesktopPath);
-               RegQueryValueExW(key, L"Desktop", null, null, (byte *)wDesktopPath, &size);
+               DWORD size = sizeof(wDesktopPath);
+               RegQueryValueExW(key, options[0].selected ? L"Common Desktop" : L"Desktop", null, null, (byte *)wDesktopPath, &size);
                UTF16toUTF8Buffer(wDesktopPath, desktopPath, sizeof(desktopPath));
                RegCloseKey(key);
             }
-            if(!desktopPath[0] && userProfile && userProfile[0])
+            if(!desktopPath[0] && userProfile[0])
             {
                strcpy(desktopPath, userProfile);
                PathCat(desktopPath, "Desktop");
@@ -1468,36 +1720,55 @@ class InstallThread : Thread
 
             if(desktopPath[0])
             {
-               PathCat(desktopPath, "ECERE IDE.lnk");
+               PathCat(desktopPath, "Ecere IDE.lnk");
 
                ((GuiApplication)__thisModule).Lock();
-               installProgress.installing.text = $"Installing Desktop Icon...";
+               installProgress.installing.caption = $"Installing Desktop Icon...";
                ((GuiApplication)__thisModule).Unlock();
                ((GuiApplication)__thisModule).SignalEvent();
 
-               CreateLink(idePath, desktopPath, null);//"ECERE IDE");
+               CreateLink(idePath, desktopPath, null);//"Ecere IDE");
             }
          }
 
+         SendMessageTimeout (HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM)"Environment", SMTO_NORMAL, 1000, NULL);
+
          // Install QuickLaunch Icon
          if(options[IconOptions::QuickLaunchIcon].selected)
          {
-            char appData[MAX_LOCATION]; // = getenv("APPDATA");
+            char appData[MAX_LOCATION];
             GetEnvironment("APPDATA", appData, sizeof(appData));
-
-            if(appData && appData[0])
+            if(appData[0])
             {
                char destPath[MAX_LOCATION];
 
+               if(appData[0] && options[0].selected)
+               {
+                  char dir[MAX_FILENAME];
+                  GetLastDirectory(appData, dir);
+                  if(!strcmpi(dir, "Roaming"))
+                     PathCat(appData, "../../../Default/AppData/Roaming");
+                  else
+                     PathCat(appData, "../Default");
+               }
+
                ((GuiApplication)__thisModule).Lock();
-               installProgress.installing.text = $"Installing Quicklaunch Icon...";
+               installProgress.installing.caption = $"Installing Quicklaunch Icon...";
                ((GuiApplication)__thisModule).Unlock();
                ((GuiApplication)__thisModule).SignalEvent();
 
                strcpy(destPath, appData);
-               PathCat(destPath, "Microsoft\\Internet Explorer\\Quick Launch\\ECERE IDE.lnk");
+               PathCat(destPath, "Microsoft\\Internet Explorer\\Quick Launch\\Ecere IDE.lnk");
+               CreateLink(idePath, destPath, null);
 
-               CreateLink(idePath, destPath, null);//"ECERE IDE");
+               // Set it up on the dock for Windows 7 -- not working
+               /*
+               StripLastDirectory(destPath, destPath);
+               PathCat(destPath, "User Pinned\\TaskBar");
+               MakeDir(destPath);
+               PathCat(destPath, "Ecere IDE.lnk");
+               CreateLink(idePath, destPath, null);
+               */
             }
          }
 
@@ -1511,13 +1782,13 @@ class InstallThread : Thread
             associateOptions[AssociateOptions::AssociateIMG].selected)
          {
             ((GuiApplication)__thisModule).Lock();
-            installProgress.installing.text = $"Resgistering File Types...";
+            installProgress.installing.caption = $"Registering File Types...";
             ((GuiApplication)__thisModule).Unlock();
             ((GuiApplication)__thisModule).SignalEvent();
-            
+
             if(associateOptions[AssociateOptions::AssociateEPJ].selected)
             {
-               AssociateExtension(".epj", "ECERE IDE Project", "epj_file", "Open", idePath);
+               AssociateExtension(".epj", "Ecere IDE Project", "epj_file", "Open", idePath);
             }
             if(associateOptions[AssociateOptions::AssociateEC].selected)
             {
@@ -1559,11 +1830,11 @@ class InstallThread : Thread
          ((GuiApplication)__thisModule).Lock();
 
          installProgress.cancel.Destroy(0);
-         installProgress.finish.text = $"Finish";
+         installProgress.finish.caption = $"Finish";
          installProgress.finish.disabled = false;
          installProgress.finish.Activate();
-         installProgress.installing.text = $"Installation Complete.";
-         installProgress.title.text = $"Installation Complete";
+         installProgress.installing.caption = $"Installation Complete.";
+         installProgress.title.caption = $"Installation Complete";
          installProgress.titleInfo.contents = $"Thank you for using the Ecere SDK.";
       }
       ((GuiApplication)__thisModule).Unlock();