samples/audio; Installer: Added SineTone sample
[sdk] / installer / src / installer.ec
index a514647..5da1a82 100644 (file)
@@ -1,8 +1,7 @@
-#ifdef NOMINGW
-static define buildString = $"Ecere SDK v0.44.08 (Without MinGW) -- built on August 9, 2013 ";
-#else
-static define buildString = $"Ecere SDK v0.44.08 -- built on August 9, 2013 ";
-#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
@@ -19,12 +18,41 @@ import "createLink"
 import "licensing"
 import "CheckListBox"
 
+static void SetBuildString(Label label)
+{
+   static const String addMinGW = "";
+   String s;
+
+#ifdef NOMINGW
+   addMinGW = withoutMinGW;
+#endif
+
+   s = PrintString(versionString, addMinGW, " -- ", builtOnString, dateString);
+   label.caption = s;
+   delete s;
+}
+
+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)
+   {
+      if(!CheckTokenMembership(NULL, AdministratorsGroup, &b))
+         b = FALSE;
+       FreeSid(AdministratorsGroup);
+   }
+   return b == TRUE;
+}
+
 struct CheckItem
 {
-   char * name;
+   const char * name;
    void * data;
    bool add32Bit;
-   char * OnGetString(char * tempString, void * fieldData, bool * needClass)
+   const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
    {
       if(add32Bit)
       {
@@ -46,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);
@@ -116,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);
@@ -154,9 +182,9 @@ 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;
@@ -175,7 +203,7 @@ struct Component
       if(this != null && parent)
          parent->GetFullPath(path, is32bit || (arch == bits32 && osIS64bit));
       else
-         strcpy(path, (is32bit || (arch == bits32 && osIS64bit)) ? installDir32 : installDir);
+         strcpy(path, (this && (is32bit || (arch == bits32 && osIS64bit))) ? installDir32 : installDir);
 
       if(this != null)
          PathCat(path, installPath);
@@ -216,10 +244,7 @@ struct Component
                PathCat(path, name);
             }
             if(requiredSize)
-            {
-               uint p = installProgress.progressBar.progress;
-               ExtractFileFromArchive(installProgress.progressBar, source, path); 
-            }
+               ExtractFileFromArchive(installProgress.progressBar, source, path);
          }
          if(subComponents)
          {
@@ -236,65 +261,64 @@ define minGWIncluded = true;
 define minGWIncluded = false;
 #endif
 
-Component samples[] =
-{
-   { "Ecere Chess",     "samples/chess",     "chess",       null, false, true, true, none },
-   { "Ecere Fractals",  "samples/fractals",  "fractals",    null, false, true, true, none },
+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 },
+   { $"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 }
+   { $"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, ide32, runtime, runtime32, ec, ec32,
-   gcc, gdb, gdb32, mingw, binutils, make,
+   gcc, gdb, mingw, binutils, make,
    none
 };
 
-Component coreSDK[CoreSDKID] =
-{
+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, bits64 },
-   { "GNU Debugger",    "tdm/gdb32",      "tdm", null, true, true, minGWIncluded, bits32 },
-   { "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 },
+   { $"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 }
-};
+};
 
 public enum AdditionalID
 {
-   eda, eda32, vanilla, vanilla32, extras, upx, gnurx, gnurx32, /*pthreads, */cpp, /*w32api, gcci18n, gdbi18n, makei18n, binutilsi18n, */none
+   eda, eda32, audio, audio32, vanilla, vanilla32, extras, upx, gnurx, gnurx32, /*pthreads, */cpp, /*w32api, gcci18n, gdbi18n, makei18n, binutilsi18n, */none
 };
 
-Component additional[AdditionalID] =
-{
-   { "Data Access",     "ecere-sdk/eda",                 "bin",      null, false, true, true, bits64 },
-   { "Data Access",     "ecere-sdk32/eda",               "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 },
+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 },
+   { $"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 },
+   { $"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 },
@@ -302,31 +326,29 @@ Component additional[AdditionalID] =
    { "Binutils I18n",   "mingw/locale/binutils",         "tdm",    null, false, false, minGWIncluded, none },
 */
    { null }
-};
+};
 
 public enum DocumentationID
 {
-   ecereBook, apiRef, tutorials, coursework,
+   ecereBook, apiRef, coursework,
    gccDoc, gppDocs, gdbDocs, makeDocs, binDocs, mingwDocs, gnurxDocs, upxDocs,
    none
 };
 
-Component documentation[DocumentationID] =
-{
-   { "Ecere Book",         "ecere-sdk/book",       "doc",            null, false, true, true, none },
-   { "API Reference",      "ecere-sdk/doc",        "doc",            null, false, true, true, none },
-   { "Ecere Tutorials",    "ecere-sdk/tutorials",  "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 },
-   { "MinGW Docs",         "tdm/doc/mingwrt",      "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 },
+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
 {
@@ -337,20 +359,20 @@ public enum ComponentID
    none
 };
 
-Component components[ComponentID] =
-{
-   { "Core SDK Files", null, null, coreSDK, true, true, true, none },
-   { "Additional Support", null, null, additional, false, true, true, none },
-   { "Documentation", null /*"doc"*/, null /*"doc"*/, documentation, false, true, true, none },
-   { "Samples", null, "samples", samples, false, true, true, none },
+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;
@@ -368,46 +390,47 @@ 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, AddMinGWPaths
 };
 
-InstallOption pathOptions[] =
-{
-   { "Add Ecere binaries location to the user environment path", null, true, true },
-   { "Add MinGW to the user environment path", null, true, minGWIncluded }
+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, true },
-   { "Desktop Icon", null, true, true },
-   { "Quicklaunch Icon", null, true, true },
-   { "Associate the Ecere IDE with Supported File Types", associateOptions, true, true },
-   { "Add binaries location to the user environment paths", pathOptions, true, minGWIncluded },
+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];
@@ -416,32 +439,37 @@ bool osIS64bit;
 
 class Installer : Window
 {
-   text = $"Ecere Software Development Kit Setup - v0.44.08 \"Ryōan-ji\" 64 Bit Edition";
-   background = activeBorder;
+   background = formColor;
    borderStyle = fixed;
    hasMinimize = true;
    hasClose = true;
    tabCycle = true;
-   clientSize = { 636, 456 };
-   // clientSize = { 796, 576 };
+   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, 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, false);
-         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)
          {
@@ -456,7 +484,9 @@ class Installer : Window
    CheckListBox componentsBox
    {
       this, size = { 460, 112 }, position = { 160, 160 }, hasHeader = true;
-      fullRowSelect = false, collapseControl = true, treeBranches = true, rootCollapseButton = true, 
+      fullRowSelect = false, collapseControl = true, treeBranches = true, rootCollapseButton = true,
+      hasHorzScroll = true;
+      resizable = true,
       noDragging = true;
       rowHeight = 18;
       selectionColor = { 145, 150, 140 };
@@ -484,7 +514,10 @@ class Installer : Window
          if(newPath)
          {
             PathCat(fullPath, newPath);
-            MakePathRelative(fullPath, path, relative);
+            if(IsPathInsideOf(fullPath, path))
+               MakePathRelative(fullPath, path, relative);
+            else
+               strcpy(relative, fullPath);
          }
          listBox.SetData(locationField, relative);
          strcpy(component->installPath, relative);
@@ -534,7 +567,7 @@ class Installer : Window
          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;
@@ -546,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)
@@ -572,10 +605,11 @@ 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 };
-      fullRowSelect = false, collapseControl = true, treeBranches = true, rootCollapseButton = true, 
+      this, size = { 460, 114 }, position = { 160, 284 };
+      fullRowSelect = false, collapseControl = true, treeBranches = true, rootCollapseButton = true,
       noDragging = true;
       rowHeight = 18;
       opacity = 0;
@@ -585,11 +619,65 @@ class Installer : Window
          CheckItem * item = row.GetData(optionField);
          InstallOption * option = item->data;
          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)
       {
@@ -600,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;
@@ -662,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"
@@ -670,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)
@@ -695,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 } };
+   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 = 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;
@@ -724,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);
@@ -744,7 +864,7 @@ class Installer : Window
       return size;
    }
 
-   void AddComponent(Component component, Component parent, char * parentPath)
+   void AddComponent(Component component, Component parent, const char * parentPath)
    {
       DataRow row = (parent != null) ? parent.row.AddRow() : componentsBox.AddRow();
       FileSize size = 0;
@@ -756,7 +876,7 @@ class Installer : Window
       if(component.defInstallPath)
          PathCat(path, component.defInstallPath);
       component.parent = parent;
-         
+
       row.SetData(null, CheckItem { component.name, component, (component.arch == bits32 && osIS64bit) } );
 
       if(component.defInstallPath)
@@ -807,7 +927,7 @@ class Installer : Window
 
       while(!FileExists(path) && path[0])
          StripLastDirectory(path, path);
-      
+
       if(path[0])
          GetFreeSpace(path, &avSize);
       else
@@ -839,11 +959,50 @@ class Installer : Window
       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);
@@ -851,15 +1010,22 @@ class Installer : Window
 
       optionsBox.AddField(optionField);
 
+      languageBox.AddField(languageField);
+
+      programFilesDir[0] = 0;
       if(GetEnvironment("ProgramFiles", programFilesDir, MAX_LOCATION))
       {
-         char * x86 = strstr(programFilesDir, " (x86)");
+         x86 = strstr(programFilesDir, " (x86)");
+         if(x86)
+            osIS64bit = true;
+      }
+
+      if(isAdministrator && programFilesDir[0])
+      {
          if(x86)
          {
             strcpy(installDir32, programFilesDir);
             PathCat(installDir32, "Ecere SDK");
-            osIS64bit = true;
-
             *x86 = 0;
             strcpy(installDir, programFilesDir);
             PathCat(installDir, "Ecere SDK");
@@ -868,34 +1034,43 @@ class Installer : Window
          {
             strcpy(installDir, programFilesDir);
             PathCat(installDir, "Ecere SDK");
+            strcpy(installDir32, installDir);
          }
       }
-      else if(homeDrive && homeDrive[0])
+      else if(homeDrive[0])
       {
          strcpy(installDir, homeDrive);
          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");
+         strcpy(installDir32, installDir);
+         strcat(installDir32, " (32)");
       }
       else
+      {
          strcpy(installDir, "C:\\Ecere SDK");
-      
-      if(appData && appData[0])
+         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;
+         components[ComponentID::samples].defInstallPath = defSamplesPath;
 
          strcpy(defExtrasPath, appData);
          PathCat(defExtrasPath, "Ecere SDK\\extras");
-         additional[extras].defInstallPath = defExtrasPath;
+         additional[AdditionalID::extras].defInstallPath = defExtrasPath;
       }
-         
+
       destBox.path = installDir;
 
       {
@@ -914,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;
    }
@@ -930,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 };
@@ -944,29 +1194,34 @@ class Installer : Window
 
 class InstallProgress : Window
 {
-   text = $"Ecere Software Development Kit Setup - v0.44.08 \"Ryōan-ji\" 64 Bit Edition";
+   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 };
-   clientSize = { 636, 456 };
+   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)
       {
@@ -980,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 };
@@ -992,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);
    }
 
@@ -1035,7 +1290,7 @@ static void AddPath(char * sysPaths[200], int sysCount, char * paths[200], int *
    if(!found)
    {
       char * start;
-      if(*count) 
+      if(*count)
       {
          strcat(userPath, ";");
          start = paths[(*count)-1] + strlen(paths[(*count)-1])+1;
@@ -1055,17 +1310,24 @@ static void AddPath(char * sysPaths[200], int sysCount, char * paths[200], int *
 void ModifyPath(char * systemPath, char * userPath)
 {
    char oldPath[8192], * paths[200], * sysPaths[200];
-   int count, sysCount;
+   int count, sysCount = 0;
 
-   strcpy(oldPath, userPath);
-   count = TokenizeWith(oldPath, sizeof(paths) / sizeof(char *), paths, ";", false);
-   sysCount = TokenizeWith(systemPath, sizeof(sysPaths) / sizeof(char *), sysPaths, ";", false);
+   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++)
       {
-         bool found = false;
          char path[MAX_LOCATION];
          if(!coreSDK[c].selected) continue;
          coreSDK[c].GetFullPath(path, false);
@@ -1078,7 +1340,7 @@ void ModifyPath(char * systemPath, char * userPath)
          }
          else if(!pathOptions[PathOptions::AddECEREPaths].selected) continue;
 
-         AddPath(sysPaths, sysCount, paths, &count, oldPath, userPath, path);
+         AddPath(sysPaths, sysCount, paths, &count, oldPath, userPath ? userPath : systemPath, path);
       }
    }
    {
@@ -1086,45 +1348,44 @@ void ModifyPath(char * systemPath, char * userPath)
       // Up to C++
       for(c = 0; c <= cpp; c++)
       {
-         bool found = false;
          char path[MAX_LOCATION];
          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)
+         if(c != eda && c != eda32 && c != upx && c != audio && c != audio32)
             PathCat(path, "bin");
-         AddPath(sysPaths, sysCount, paths, &count, oldPath, userPath, path);
+         AddPath(sysPaths, sysCount, paths, &count, oldPath, userPath ? userPath : systemPath, path);
       }
    }
 }
 
-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, (uint)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, (uint)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, (uint)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\"");
    {
@@ -1142,18 +1403,22 @@ 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, 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
@@ -1169,9 +1434,10 @@ class InstallThread : Thread
             driver = "JSON";
             dataOwner = &settings;
             dataClass = class(IDESettings);
+            allUsers = options[0].selected;
          };
          CompilerConfig compiler;
-         installProgress.installing.text = $"Configuring Ecere IDE...";
+         installProgress.installing.caption = $"Configuring Ecere IDE...";
          ((GuiApplication)__thisModule).Unlock();
          ((GuiApplication)__thisModule).SignalEvent();
 
@@ -1232,63 +1498,83 @@ class InstallThread : Thread
          {
             char path[MAX_LOCATION] = "";
 
-            if(components[samples].selected)
-               components[samples].GetFullPath(path, false);
-            else
-               components[coreSDK].GetFullPath(path, false);
+            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[apiRef].selected)
+            if(documentation[DocumentationID::apiRef].selected)
             {
-               documentation[apiRef].GetFullPath(path, false);
+               documentation[DocumentationID::apiRef].GetFullPath(path, false);
                if(!settings.docDir[0])
                   settings.docDir = path;
             }
          }
 
+         settings.language = GetLanguageString();
+
+         // Set LANGUAGE environment variable
+         {
+            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
+               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);
+            }
+         }
+
          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, (uint)strlen(displayName)+1);
-            RegSetValueEx(key, "UninstallString", 0, REG_SZ, uninstaller, (uint)strlen(uninstaller)+1);
-            RegSetValueEx(key, "DisplayIcon", 0, REG_SZ, idePath, (uint)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 userKey = null, systemKey = null;
-            uint status, size;
+            DWORD status, size;
             char userPath[8192] = "";
             char systemPath[8192] = "";
             uint16 wUserPath[8192];
@@ -1298,35 +1584,51 @@ class InstallThread : Thread
             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, "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", 0, KEY_QUERY_VALUE, &systemKey) == ERROR_SUCCESS)
+
+            if(options[0].selected)
             {
-               size = sizeof(wSystemPath);
-               RegQueryValueExW(systemKey, L"path", null, null, (byte *)wSystemPath, &size);
-               UTF16toUTF8Buffer(wSystemPath, systemPath, sizeof(systemPath));
+               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);
+               }
             }
-            
-            RegCreateKeyEx(HKEY_CURRENT_USER, "Environment", 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &userKey, &status);
-            if(status == REG_OPENED_EXISTING_KEY)
+            else
             {
-               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);
-            RegCloseKey(systemKey);
+               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
-         GetEnvironment("USERPROFILE", userProfile, sizeof(userProfile));
+         GetEnvironment(options[0].selected ? "ALLUSERSPROFILE" : "USERPROFILE", userProfile, sizeof(userProfile));
 
          if(options[IconOptions::StartMenuIcon].selected)
          {
@@ -1335,18 +1637,19 @@ 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);
             }
@@ -1365,24 +1668,24 @@ class InstallThread : Thread
                strcpy(destPath, startMenuPath);
                PathCat(destPath, "Ecere SDK\\Ecere IDE.lnk");
                CreateLink(idePath, destPath, null); //"Ecere IDE");
-               if(components[samples].selected)
+               if(components[ComponentID::samples].selected)
                {
                   char samplesPath[MAX_LOCATION] = "";
-                  components[samples].GetFullPath(samplesPath, false);
+                  components[ComponentID::samples].GetFullPath(samplesPath, false);
 
                   strcpy(destPath, startMenuPath);
                   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, false);
+                  documentation[DocumentationID::ecereBook].GetFullPath(docPath, false);
                   PathCat(docPath, "Ecere Tao of Programming [work in progress].pdf");
 
                   {
                      char tao[MAX_LOCATION] ;
-                     documentation[ecereBook].GetFullPath(tao, false);
+                     documentation[DocumentationID::ecereBook].GetFullPath(tao, false);
                      PathCat(tao, "tao.pdf");
                      RenameFile(tao, docPath);
                   }
@@ -1400,11 +1703,12 @@ 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);
             }
@@ -1419,7 +1723,7 @@ class InstallThread : Thread
                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();
 
@@ -1427,25 +1731,44 @@ class InstallThread : Thread
             }
          }
 
+         SendMessageTimeout (HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM)"Environment", SMTO_NORMAL, 1000, NULL);
+
          // Install QuickLaunch Icon
          if(options[IconOptions::QuickLaunchIcon].selected)
          {
             char appData[MAX_LOCATION];
             GetEnvironment("APPDATA", appData, sizeof(appData));
-
             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");
+               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);
+               */
             }
          }
 
@@ -1459,10 +1782,10 @@ 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);
@@ -1507,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();