added .gitignore for all to enjoy
[installer] / installer.ec
1 #ifdef NOMINGW
2 static const char * buildString = "ECERE SDK v0.43 (Without MinGW) -- built on September 3, 2008 ";
3 #else
4 static const char * buildString = "ECERE SDK v0.43 -- built on September 3, 2008 ";
5 #endif
6
7 #define WIN32_LEAN_AND_MEAN
8 #define GetFreeSpace _GetFreeSpace
9 #include <windows.h>
10 #undef GetFreeSpace
11
12 #ifdef ECERE_STATIC
13 import static "ecere"
14 #else
15 import "ecere"
16 #endif
17 import "Settings"
18 import "createLink"
19 import "licenseBox"
20
21 class CheckListBox : ListBox
22 {
23    fullRowSelect = false, collapseControl = true, treeBranches = true, rootCollapseButton = true, 
24    noDragging = true;
25    rowHeight = 18;
26
27    void ToggleCheck(DataRow row)
28    {
29       Button checkBox = (Button)row.tag;
30       DataRow parent;
31       bool checked = !(checkBox.checked) || checkBox.buttonState == down;
32       if(!checkBox.disabled)
33       {
34          SetCheck(row, checked);
35          checkBox.buttonState = up;
36
37          for(parent = row; parent; parent = parent.parent)
38          {
39             for(row = parent.firstRow; row; row = row.next)
40             {
41                checkBox = (Button)row.tag;
42                if(checkBox.checked != checked)
43                   break;
44             }
45             checkBox = (Button)parent.tag;
46             if(row)
47             {
48                checkBox.checked = true;
49                NotifyChecked(master, this, parent);
50                checkBox.buttonState = down;
51                checked = true;
52             }
53             else
54             {
55                checkBox.checked = checked;
56                NotifyChecked(master, this, parent);
57                checkBox.buttonState = up;
58             }
59          }
60       }
61    }
62
63    void SetCheck(DataRow row, bool checked)
64    {
65       Button checkBox = (Button)row.tag;
66       DataRow subRow;
67       if(!checkBox.disabled && (checkBox.checked != checked || checkBox.buttonState == down))
68       {
69          checkBox.checked = checked;
70          for(subRow = row.firstRow; subRow; subRow = subRow.next)
71             SetCheck(subRow, checked);
72          NotifyChecked(master, this, row);
73       }
74    }
75    
76    DataRow AddRow(DataRow parentRow)
77    {      
78       DataRow row = parentRow ? parentRow.AddRow() : ListBox::AddRow();
79       int c;
80       DataRow parent;
81       int indent = 20;
82       for(parent = row.parent; parent; parent = parent.parent)
83          indent += 20;
84       row.tag = (int)Button
85       {
86          this, isCheckbox = true, inactive = true, checked = true,
87          position = { 2 + indent, 1+(row.index + hasHeader) * rowHeight }, size = { 12, 12 }; 
88          id = (int)row;
89
90          bool NotifyPushed(Button button, int x, int y, Modifiers mods)
91          {
92             currentRow = (DataRow)button.id;
93             ToggleCheck(currentRow);
94             return false;
95          }
96
97          bool NotifyReleased(Button button, int x, int y, Modifiers mods)
98          {
99             return false;
100          }
101
102          bool OnMouseOver(int x, int y, Modifiers mods)
103          {
104
105             return true;
106          }
107
108          bool OnMouseLeave(Modifiers mods)
109          {
110
111             return true;
112          }
113       };
114       return row;
115    }      
116
117    bool NotifyKeyDown(CheckListBox listBox, DataRow row, Key key, unichar ch)
118    {
119       if(key == space)
120       {
121          listBox.ToggleCheck(row);
122          return false;
123       }
124       return true;
125    }
126
127    bool OnKeyHit(Key key, unichar ch)
128    {
129       if(key == space)
130          return false;
131       return ListBox::OnKeyHit(key, ch);
132    }
133
134    bool NotifyDoubleClick(CheckListBox listBox, int x, int y, Modifiers mods)
135    {
136       listBox.OnLeftButtonDown(x, y, mods);
137       return false;
138    }
139
140    bool NotifyReclick(CheckListBox listBox, DataRow row, Modifiers mods)
141    {
142       listBox.ToggleCheck(row);
143       return true;
144    }
145
146    bool NotifyCollapse(ListBox listBox, DataRow row, bool collapsed)
147    {
148       DataRow r;
149       for(r = row.firstRow; r && r != row; )
150       {
151          Button checkBox = (Button)r.tag;
152          checkBox.visible = !collapsed;
153          if(r.firstRow && !r.collapsed) 
154             row = r.firstRow;
155          else 
156             for(; r != row; r = r.parent)
157                if(r.next) { r = r.next; break; }
158       }
159       for(r = row.GetNextRow(); r; r = r.GetNextRow())
160       {
161          Button checkBox = (Button)r.tag;
162          checkBox.position.y = 1 + (r.index + listBox.hasHeader) * listBox.rowHeight;
163       }
164       return true;
165    }
166
167    virtual void Window::NotifyChecked(CheckListBox listBox, DataRow row);
168 };
169
170 struct CheckItem
171 {
172    char * name;
173    void * data;
174    char * OnGetString(char * tempString, void * fieldData, bool * needClass)
175    {
176       return name;
177    }
178
179    void OnDisplay(Surface surface, int x, int y, int width, void * fieldData, Alignment alignment, DataDisplayFlags displayFlags)
180    {
181       if(!displayFlags.active) displayFlags.current = false;
182       class::OnDisplay(surface, x + 22, y, width - 22, fieldData, alignment, displayFlags);
183    }
184 };
185
186 //#define BUFFERSIZE 0x10000
187 #define BUFFERSIZE 0x1000
188 bool abortInstall = false;
189
190 void ExtractFileFromArchive(ProgressBar progressBar, char * path, char * outputFile)
191 {
192    char fileName[MAX_LOCATION];
193    FileAttribs exists = FileExists(path);
194    bool setTime = false;
195    FileStats stats;
196
197    if(exists.isDirectory)
198    {
199       FileListing listing { path };
200
201       if(outputFile[0])
202       {
203          if(MakeDir(outputFile))
204          {
205             setTime = true;
206             FileGetStats(path, &stats);
207          }
208       }
209
210       while(listing.Find() && !abortInstall)
211       {
212          strcpy(fileName, outputFile);
213
214          // Tweak file name if out
215          if(outputFile[0])
216          {
217             if(!strcmp(fileName, ".")) fileName[0] = '\0';
218             if(listing.name[0] == '/' || listing.name[0] == '\\')
219             {
220                char * afterSlash, rest[MAX_LOCATION];
221                for(afterSlash = fileName; *afterSlash == '/' || *afterSlash == '\\'; afterSlash++);
222                strcpy(rest, afterSlash);
223                PathCat(fileName, "_root");
224                PathCat(fileName, rest);
225             }
226             else if(listing.name[1] == ':')
227             {
228                char letter[10];
229                sprintf(letter, "_%cdrive", toupper(listing.name[0]));
230                PathCat(fileName, letter);
231                PathCat(fileName, listing.name[2] ? (listing.name + 3) : (listing.name + 2));
232             }
233             else
234                PathCat(fileName, listing.name);
235          }
236          else
237             PathCat(fileName, listing.name);
238          if(!strcmp(fileName, "/") || !strcmp(fileName, "\\"))
239             strcpy(fileName, DIR_SEPS);
240          ExtractFileFromArchive(progressBar, listing.path, fileName);
241       }
242       listing.Stop();
243    }
244    else if(exists)
245    {
246       File input = FileOpen(path, read);
247       if(input)
248       {
249          File output = FileOpen(outputFile, write);
250          if(output)
251          {
252             char fileName[MAX_FILENAME];
253             uint position = progressBar.progress;
254             FileSize dataSize;
255             int c;
256             byte buffer[BUFFERSIZE];
257
258             FileGetSize(path, &dataSize);
259             GetLastDirectory(outputFile, fileName);
260             
261             ((GuiApplication)__thisModule).SignalEvent();
262             //((GuiApplication)__thisModule).ProcessInput();
263             //((GuiApplication)__thisModule).UpdateDisplay();
264             
265             for(c = 0; c<dataSize && !abortInstall; c += BUFFERSIZE)
266             {
267                uint size = (dataSize > c + BUFFERSIZE) ? BUFFERSIZE : (dataSize - c);
268
269                ((GuiApplication)__thisModule).Unlock();
270
271                input.Read(buffer, 1, size);
272                output.Write(buffer, 1, size);
273
274                ((GuiApplication)__thisModule).Lock();
275
276                progressBar.progress = position + c + size;
277                ((GuiApplication)__thisModule).SignalEvent();
278
279                //((GuiApplication)__thisModule).ProcessInput();
280                //((GuiApplication)__thisModule).UpdateDisplay();
281             }
282
283             delete output;
284             setTime = true;
285             FileGetStats(path, &stats);
286          }
287          delete input;
288       }
289    }
290    if(setTime)
291       FileSetTime(outputFile, stats.created, 0, stats.modified);
292 }
293
294 struct Component
295 {
296    char * name;
297    char * dataPath;
298    char * defInstallPath;
299    Component * subComponents;
300    bool mandatory;
301    bool selected;
302    Component * parent;
303
304    uint requiredSize;
305    uint size;
306    char installPath[MAX_LOCATION];
307    DataRow row;
308
309    void GetFullPath(char * path)
310    {
311       if(this != null && parent)
312          parent->GetFullPath(path);
313       else
314          strcpy(path, installDir);
315
316       if(this != null)
317          PathCat(path, installPath);
318    }
319
320    void Install(char * parentPath)
321    {
322       int c;
323       if(selected)
324       {
325          char path[MAX_LOCATION];
326          strcpy(path, parentPath);
327          PathCat(path, installPath);
328
329          installProgress.installing.SetText("Installing %s...", name);
330          ((GuiApplication)__thisModule).UpdateDisplay();
331
332          if(dataPath)
333          {
334             char source[MAX_LOCATION];
335             strcpy(source, ":");
336             strcat(source, dataPath);
337
338             MakeDir(path);
339
340             if(FileExists(source).isFile)
341             {
342                char name[MAX_FILENAME];
343                GetLastDirectory(source, name);
344                PathCat(path, name);
345             }
346             ExtractFileFromArchive(installProgress.progressBar, source, path); 
347          }
348          if(subComponents)
349          {
350             for(c = 0; subComponents[c].name; c++)
351                subComponents[c].Install(path);
352          }
353       }
354    }
355 };
356 Component samples[] =
357 {
358    { "Hello World", "samples/HelloWorld", "HelloWorld", null, false, true },
359    { "Hello Form", "samples/HelloForm", "HelloForm", null, false, true },
360    { "Test3D", "samples/Test3D", "Test3D", null, false, true },
361    { "Blank", "samples/Blank", "Blank", null, false, true },
362    { "Start", "samples/Start", "Start", null, false, true },
363    { "Animate3DS", "samples/Animate3DS", "Animate3DS", null, false, true },
364    { "Balls", "samples/Balls", "Balls", null, false, true },
365    { "Chess", "samples/Chess", "Chess", null, false, true },
366    { "Clock", "samples/Clock", "Clock", null, false, true },
367    { "Othello", "samples/Othello", "Othello", null, false, true },
368    { "eCom", "samples/eCom", "eCom", null, false, true },
369    { "ModelViewer", "samples/ModelViewer", "ModelViewer", null, false, true },
370    { "HTTPServer", "samples/HTTPServer", "HTTPServer", null, false, true },
371    { "Fractals", "samples/Fractals", "Fractals", null, false, true },
372    { "ColorSpheres", "samples/ColorSpheres", "ColorSpheres", null, false, true },
373    { "HiraganaCube", "samples/HiraganaCube", "HiraganaCube", null, false, true },
374    { "MedDB", "samples/MedDB", "MedDB", null, false, true },
375    { "EDATest", "samples/EDATest", "EDATest", null, false, true },
376    { "DCOMSample", "samples/DCOMSample", "DCOMSample", null, false, true },
377    { "ContainersTest", "samples/ContainersTest", "ContainersTest", null, false, true },
378
379 /*
380    { "Find", "samples/Find", "Find", null, false, true },
381    { "Notepad", "samples/Notepad", "Notepad", null, false, true },
382
383    { "Bomb", "samples/Bomb", "Bomb", null, false, true },
384    { "TongIts", "samples/TongIts", "TongIts", null, false, true },
385    { "War2", "samples/War2", "War2", null, false, true },
386    { "Poker", "samples/Poker", "Poker", null, false, true },
387    { "Ruff", "samples/Ruff", "Ruff", null, false, true },
388    { "Scrabble", "samples/Scrabble", "Scrabble", null, false, true },
389
390    { "ICQ", "samples/ICQ", "ICQ", null, false, true },
391    { "Browser", "samples/Browser", "Browser", null, false, true },
392
393    { "Replace", "samples/Replace", "Replace", null, false, true },
394    { "FliPlay", "samples/FliPlay", "FliPlay", null, false, true },
395    { "SlideShow", "samples/SlideShow", "SlideShow", null, false, true },
396 */
397    { null }
398 };
399
400 public enum CoreSDKID
401 {
402    ide, runtime, eda, ec,
403 #ifndef NOMINGW
404    gcc, gdb, mingw, binutils, make, upx,
405 #endif
406    none
407 };
408
409 Component coreSDK[CoreSDKID] =
410 {
411    { "ECERE IDE", "ecere_bin/ide", "bin", null, true, true },
412    { "Runtime Library", "ecere_bin/ecere.dll", "bin", null, true, true },
413    { "Data Access", "ecere_bin/EDA.dll", "bin", null, true, true },
414    { "eC Compiler", "ecere_bin/compiler", "bin", null, true, true },
415 #ifndef NOMINGW
416    { "GNU C Compiler", "mingw/gcc", "mingw", null, true, true },
417    { "GNU Debugger", "mingw/gdb", "mingw", null, true, true },
418    { "MinGW Runtime", "mingw/MinGW", "mingw", null, true, true },
419    { "Binary Utils", "mingw/binutils", "mingw", null, true, true },
420    { "GNU Make", "mingw/make", "mingw", null, true, true },
421    { "UPX", "upx/upx.exe", "mingw/bin", null, true, true },
422 #endif
423    { null }
424 };
425
426 #ifndef NOMINGW
427 Component additional[] =
428 {
429    { "C++ Compiler", "mingw/g++", "mingw", null, false, true },
430    { "Win32 APIs", "mingw/win32", "mingw", null, false, true },
431    { "GCC I18n", "mingw/i18n", "mingw", null, false, true },
432    { null }
433 };
434 #endif
435
436 public enum DocumentationID
437 {
438 #ifndef NOMINGW
439    gccDoc, gppDocs, gdbDocs, makeDocs, binDocs, mingwDocs, upxDocs,
440 #endif
441    ecereBook, none
442 };
443
444 Component documentation[DocumentationID] =
445 {
446 #ifndef NOMINGW
447    { "GCC Docs", "mingw/doc/gcc", "mingw", null, false, true },
448    { "G++ Docs", "mingw/doc/g++", "mingw", null, false, true },
449    { "GDB Docs", "mingw/doc/gdb", "mingw", null, false, true },
450    { "Make Docs", "mingw/doc/make", "mingw", null, false, true },
451    { "Binutils Docs", "mingw/doc/binutils", "mingw", null, false, true },
452    { "MinGW Docs", "mingw/doc/mingw", "mingw", null, false, true },
453    { "UPX Docs", "upx/doc", "mingw/doc/upx", null, false, true },
454 #endif
455    { "Ecere Book", "ecere_bin/book", "doc", null, false, true },
456    { null }
457 };
458
459 public enum ComponentID
460 {
461    coreSDK,
462 #ifndef NOMINGW
463    additional,
464 #endif
465    documentation,
466    samples,
467    none
468 };
469
470 Component components[ComponentID] =
471 {
472    { "Core SDK Files", null, null, coreSDK, true, true },
473 #ifndef NOMINGW
474    { "Additional Support", null, null, additional, false, true },
475 #endif
476    { "Documentation", null /*"doc"*/, null /*"doc"*/, documentation, false, true },
477    { "Samples", null, "samples", samples, false, true },
478    { null }
479 };
480 FileSize totalSize;
481 FileSize totalInstalled;
482
483 struct InstallOption
484 {
485    char * name;
486    InstallOption * subOptions;
487    bool selected;
488    DataRow row;
489 };
490
491 enum AssociateOptions
492 {
493    AssociateEPJ,
494    AssociateEC,
495    AssociateC,
496    AssociateCPP,
497    AssociateTXT,
498    Associate3DS,
499    AssociateIMG
500 };
501
502 InstallOption associateOptions[] =
503 {
504    { "Associate with ECERE Project Files (*.epj)", null, true },
505    { "Associate with eC Files (*.ec, *.eh)", null, true },
506    { "Associate with C files (*.c, *.h)", null, false },
507    { "Associate with C++ Files (*.cpp, *.hpp, *.cc, *.hh, *.cxx, *.hxx)", null, false },
508    { "Associate with text files (*.txt)", null, false },
509    { "Associate with 3D Studio Model Files (*.3ds)", null, true },
510    { "Associate with Image Files (*.png, *.jpg, *.pcx, *.bmp, *.gif)", null, false },
511    { null }
512 };
513
514 enum PathOptions
515 {
516    AddECEREPaths
517 #ifndef NOMINGW
518    , AddMinGWPaths
519 #endif
520 };
521
522 InstallOption pathOptions[] =
523 {
524    { "Add ECERE binaries location to the system path", null, true },
525    { "Add MinGW to the system path", null, true }
526    { null }
527 };
528
529 enum IconOptions
530 {
531    StartMenuIcon,
532    DesktopIcon,
533    QuickLaunchIcon
534 };
535
536 InstallOption options[] =
537 {
538    { "Start Menu Group", null, true },
539    { "Desktop Icon", null, true },
540    { "Quicklaunch Icon", null, true },
541    { "Associate the ECERE IDE with Supported File Types", associateOptions, true },
542 #ifndef NOMINGW
543    { "Add binaries location to the system paths", pathOptions, true },
544 #endif
545    { null }
546 };
547
548 char sourceDir[MAX_LOCATION] = ":";
549 char installDir[MAX_LOCATION];
550
551 class Installer : Window
552 {
553    text = "ECERE Software Development Kit Setup";
554    background = activeBorder;
555    borderStyle = fixed;
556    hasMinimize = true;
557    hasClose = true;
558    tabCycle = true;
559    size = { 640, 480 };
560
561    FileDialog fileDialog
562    {
563       master = this, type = selectDir,
564       text = "Select a new location"
565    };
566    Button browse
567    {
568       master = this, autoCreate = false, inactive = true, /*hotKey = F2,*/ text = "...";
569       
570       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
571       {
572          DataRow row = componentsBox.currentRow;
573          Component * component = ((CheckItem *)row.GetData(componentField))->data;
574          component->GetFullPath(fileDialog.filePath);
575          StripLastDirectory(fileDialog.filePath, fileDialog.currentDirectory);
576
577          if(fileDialog.Modal() == ok)
578          {
579             componentsBox.StopEditing(false);
580             row.SetData(locationField, fileDialog.filePath);
581             componentsBox.NotifyChanged(this, componentsBox, row);
582             componentsBox.currentField = componentsBox.currentField;
583          }
584          return true;
585       }
586    };
587    CheckListBox componentsBox
588    {
589       this, size = { 460, 112 }, position = { 160, 160 }, hasHeader = true;
590       alwaysEdit = true;
591
592       bool NotifyChanged(ListBox listBox, DataRow row)
593       {
594          Component * component = ((CheckItem *)listBox.GetData(componentField))->data;
595          char path[MAX_LOCATION], relative[MAX_LOCATION] = "", ** newPath;
596          char fullPath[MAX_LOCATION];
597
598          component->parent->GetFullPath(path);
599          strcpy(fullPath, path);
600
601          newPath = (char **)row.GetData(locationField);
602          if(newPath && *newPath)
603          {
604             PathCat(fullPath, *newPath);
605             MakePathRelative(fullPath, path, relative);
606          }
607          listBox.SetData(locationField, relative);
608          strcpy(component->installPath, relative);
609
610          //SetAvailableSpace(component, path);
611          {
612             ComponentID c;
613             install.disabled = false;
614             for(c = 0; components[c].name; c++)
615             {
616                SetAvailableSpace(components[c], installDir);
617             }
618          }
619          return true;
620       }
621
622       bool NotifyEditDone(ListBox listBox, DataRow row)
623       {
624          browse.Destroy(0);
625          return true;
626       }
627
628       bool NotifyEdited(ListBox listBox, DataRow row)
629       {
630          browse.parent = listBox;
631          browse.position = { componentField.width + locationField.width + 18, (listBox.currentIndex+1) * listBox.rowHeight - 2 };
632          browse.size = { 30, listBox.rowHeight + 3 };
633
634          browse.Create();
635          return true;
636       }
637
638       void NotifyChecked(CheckListBox listBox, DataRow row)
639       {
640          Component * component = ((CheckItem *)row.GetData(componentField))->data;
641          int c;
642          Button checkBox = (Button)row.tag;
643          component->selected = checkBox.checked;
644
645          if(!component->parent) totalSize -= component->requiredSize;
646          component->requiredSize = 0;
647          if(component->selected)
648          {
649             component->requiredSize += component->size; 
650             if(component->subComponents)
651                for(c = 0; component->subComponents[c].name; c++)
652                   component->requiredSize += component->subComponents[c].requiredSize;
653          }
654          if(component->requiredSize)
655             row.SetData(reqField, (void *)component->requiredSize);
656          else
657             row.UnsetData(reqField);
658          if(!component->parent) 
659          {
660             totalSize += component->requiredSize;
661             {
662                char sizeString[100];
663                PrintSize(sizeString, totalSize, 2);
664                totalSpaceValue.text = sizeString;
665             }
666          }
667       }
668    };
669    Label agreementLbl { parent = this, text = "By installing the ECERE SDK, you agree to the terms and conditions.", anchor = Anchor { left = 24, top = 424 } };
670    Button licenseButton
671    {
672       this, inactive = true, offset = false, bevel = false, foreground = blue, font = { "Tahoma", 8.25f, underline = true },
673       text = "terms and conditions", anchor = Anchor { left = 241, top = 421 };
674       cursor = ((GuiApplication)__thisModule).GetCursor(hand);
675
676       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
677       {
678          LicenseBox { master = this, sourceFile = ":LICENSE" }.Modal();
679          return true;
680       }
681    };
682    CheckListBox optionsBox
683    {
684       this, size = { 460, 94 }, position = { 160, 284 };
685
686       void NotifyChecked(CheckListBox listBox, DataRow row)
687       {
688          CheckItem * item = row.GetData(optionField);
689          InstallOption * option = item->data;
690          int c;
691          Button checkBox = (Button)row.tag;
692          option->selected = checkBox.checked;
693       }
694    };
695    Button install
696    {
697       parent = this, text = "Install", isDefault = true, size = { 75, 23 }, position = { 432, 416 };
698
699       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
700       {
701          installProgress.Create();
702          Destroy(0);
703          // installProgress.thread.Main();
704          installProgress.thread.Create();
705          return true;
706       }
707    };
708    Button button3 { parent = this, text = "Cancel", hotKey = altX, size = Size { 75, 23 }, anchor = Anchor { left = 544, top = 416 }, NotifyClicked = ButtonCloseDialog };
709    Label label1 { labeledWindow = destBox, tabCycle = true, isGroupBox = true, parent = this, inactive = false, size = Size { 458, 50 }, anchor = Anchor { left = 160, top = 96 } };
710    EditBox destBox
711    {
712       parent = label1, master = this, text = " Destination Folder", size = Size { 336, 19 }, anchor = Anchor { left = 12, top = 20 };
713
714       bool NotifyModified(EditBox editBox)
715       {
716          ComponentID c;
717          strcpy(installDir, destBox.contents);
718          install.disabled = false;
719          for(c = 0; components[c].name; c++)
720          {
721             SetAvailableSpace(components[c], installDir);
722          }
723          return true;
724       }
725    };
726    Button button1
727    {
728       label1, this, "Browse", altB, size = { 83, 24 }, position = { 360, 16 };
729
730       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
731       {
732          strcpy(fileDialog.filePath, installDir);
733          StripLastDirectory(installDir, fileDialog.currentDirectory);
734          if(fileDialog.Modal())
735          {
736             strcpy(installDir, fileDialog.filePath);
737             destBox.contents = installDir;
738             // TOCHECK: Should setting contents call NotifyModified?
739             destBox.NotifyModified(destBox.master, destBox);
740          }
741          return true;
742       }
743    };
744    EditBox label5
745    {
746       this, multiLine = true,
747       opacity = 0, borderStyle = none, inactive = true, size = { 136, 53 }, position = { 14, 96 }, noSelect = true,
748       contents = "Select the default root\n"
749          "folder where to install\n"
750          "all components:"
751    };
752    EditBox label6
753    {
754       this, opacity = 0, borderStyle = none, inactive = true, size = { 136, 132 }, position = { 14, 152 }, noSelect = true,
755       multiLine = true, 
756       contents = "Select the optional\n"
757          "components you wish\n"
758          "to install:\n\n"
759          "You may customize the\n"
760          "install location for each\n"
761          "of them, or use the default\n"
762          "based on the main\n"
763          "destination folder."
764    };
765    EditBox label7
766    {
767       this, opacity = 0, borderStyle = none, inactive = true, size = { 136, 53 }, position = { 14, 280 }, noSelect = true, 
768       multiLine = true, 
769       contents = "Select icons to install, file\n"
770       "associations, and system\n"
771       "environment modifications:"
772    };
773    Label totalSpaceLabel
774    {
775       this, position = { 18, 352 }, text = "Space Required: "
776    };
777    Label totalSpaceValue
778    {
779       this, position = { 100, 352 }, text = "0 mb"
780    };
781    EditBox editBox1
782    {
783       inactive = true, noSelect = true,
784       multiLine = true, parent = label3, text = "editBox1", opacity = 0, borderStyle = none, size = Size { 350, 35 }, anchor = Anchor { horz = 111, vert = 13 },
785       contents = "Choose in which folder to install the ECERE SDK, which features\n"
786          "of the SDK to install, as well as where to install program icons."
787    };
788    Label label2 { parent = this, text = buildString, position = { 16, 392 }, disabled = true, opacity = 1, background = activeBorder };
789    Picture picture1 { image = BitmapResource { ":ecere.bmp", transparent = true }, filter = true, parent = label3, text = "picture1", anchor = Anchor { left = 16, top = 4 } };
790    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 } };
791    DataField componentField { "CheckItem", width = 140, header = "Component" };
792    DataField locationField { "char *", width = 108, header = "Destination Folder", editable = true };
793    DataField reqField { "FileSize", width = 80, header = "Req. Space", alignment = right };
794    DataField avField { "FileSize", width = 80, header = "Avail. Space", alignment = right };
795    DataField optionField { "CheckItem" };
796
797    void SetAvailableSpace(Component component, char * parentPath)
798    {
799       char path[MAX_LOCATION];
800       int c;
801       FileSize size = 0;
802
803       strcpy(path, parentPath);
804       PathCat(path, component.installPath);
805
806       if(component.subComponents)
807          for(c = 0; component.subComponents[c].name; c++)
808             SetAvailableSpace(component.subComponents[c], path);
809
810       while(!FileExists(path) && path[0])
811          StripLastDirectory(path, path);
812
813       if(path[0])
814          GetFreeSpace(path, &size);
815       component.row.SetData(avField, (void *)size);
816       if(!size) install.disabled = true;
817    }
818
819    FileSize ComputeSize(char * path)
820    {
821       FileSize size = 0;
822       FileAttribs attribs = FileExists(path);
823       if(attribs.isDirectory)
824       {
825          FileListing listing { path };
826          while(listing.Find())
827          {
828             if(listing.stats.attribs.isDirectory)
829                size += ComputeSize(listing.path);
830             else
831                size += listing.stats.size;
832          }
833       }
834       else
835          FileGetSize(path, &size);
836       return size;
837    }
838
839    void AddComponent(Component component, Component parent, char * parentPath)
840    {
841       DataRow row = component.row = componentsBox.AddRow((parent != null) ? parent.row : null);
842       Button checkBox = (Button) row.tag;
843       FileSize size = 0;
844       char path[MAX_LOCATION];
845       strcpy(path, parentPath);
846       if(component.defInstallPath)
847          PathCat(path, component.defInstallPath);
848       component.parent = parent;
849          
850       row.SetData(null, CheckItem { component.name, component } );
851
852       if(component.defInstallPath)
853       {
854          strcpy(component.installPath, component.defInstallPath);
855          ChangeCh(component.installPath, '/', DIR_SEP);
856          row.SetData(locationField, component.installPath);
857       }
858
859       if(component.mandatory) checkBox.disabled = true;
860       if(!component.selected) componentsBox.ToggleCheck(row);
861       if(component.dataPath)
862       {
863          char path[MAX_LOCATION];
864          strcpy(path, ":");
865          PathCat(path, component.dataPath);
866          component.size = ComputeSize(path);
867       }
868       if(component.subComponents)
869       {
870          int c;
871          for(c = 0; component.subComponents[c].name; c++)
872          {
873             AddComponent(component.subComponents[c], component, path);
874             size += component.subComponents[c].requiredSize;
875          }
876       }
877
878       component.requiredSize = component.selected ? (size + component.size) : 0;
879       if(component.requiredSize)
880          row.SetData(reqField, (void *)component.requiredSize);
881
882       while(!FileExists(path) && path[0])
883          StripLastDirectory(path, path);
884       
885       if(path[0])
886          GetFreeSpace(path, &size);
887       else
888          size = 0;
889       row.SetData(avField, (void *)size);
890       row.collapsed = true;
891    }
892
893    void AddOption(InstallOption option, InstallOption parent)
894    {
895       DataRow row = option.row = optionsBox.AddRow((parent != null) ? parent.row : null);
896       row.SetData(null, CheckItem { option.name, option } );
897       if(!option.selected)
898          optionsBox.ToggleCheck(row);
899       if(option.subOptions)
900       {
901          int c;
902          for(c = 0; option.subOptions[c].name; c++)
903          {
904             AddOption(option.subOptions[c], option);
905          }
906       }
907       row.collapsed = true;
908    }
909
910    Installer()
911    {
912       int c;
913       char programFilesDir[MAX_LOCATION];
914       char appData[MAX_LOCATION]; // = getenv("APPDATA");
915       char homeDrive[MAX_LOCATION]; //= getenv("HOMEDRIVE");
916       char winDir[MAX_LOCATION]; //= getenv("windir");
917
918       GetEnvironment("APPDATA", appData, sizeof(appData));
919       GetEnvironment("HOMEDRIVE", homeDrive, sizeof(homeDrive));
920       GetEnvironment("windir", winDir, sizeof(winDir));
921       
922       componentsBox.AddField(componentField);
923       componentsBox.AddField(locationField);
924       componentsBox.AddField(reqField);
925       componentsBox.AddField(avField);
926
927       optionsBox.AddField(optionField);
928
929       if(GetEnvironment("ProgramFiles", programFilesDir, MAX_LOCATION))
930       {
931          strcpy(installDir, programFilesDir);
932          PathCat(installDir, "ECERE SDK");
933       }
934       else if(homeDrive && homeDrive[0])
935       {
936          strcpy(installDir, homeDrive);
937          PathCat(installDir, "ECERE SDK");
938       }
939       else if(winDir && winDir[0])
940       {
941          strcpy(installDir, winDir);
942          PathCat(installDir, "..\\ECERE SDK");
943       }
944       else
945          strcpy(installDir, "C:\\ECERE SDK");
946       
947       if(appData && appData[0])
948       {
949          static char defSamplesPath[MAX_LOCATION];
950          strcpy(defSamplesPath, appData);
951          PathCat(defSamplesPath, "ECERE SDK\\Samples");
952          components[samples].defInstallPath = defSamplesPath;
953       }
954          
955       destBox.contents = installDir;
956
957       totalSize = 0;
958       {
959          ComponentID c;
960          for(c = 0; components[c].name; c++)
961          {
962             AddComponent(components[c], null, installDir);
963             totalSize += components[c].requiredSize;
964          }
965       }
966       {
967          char sizeString[100];
968          PrintSize(sizeString, totalSize, 2);
969          totalSpaceValue.text = sizeString;
970       }
971       for(c = 0; options[c].name; c++)
972          AddOption(options[c], null);
973    }
974
975    bool OnCreate()
976    {
977       destBox.Activate();
978       return true;
979    }
980
981    void OnRedraw(Surface surface)
982    {
983       ColorKey keys[2] =
984       {
985          { blue, 0 },
986          { darkBlue, 1 }
987       };
988       //surface.Gradient(keys, sizeof(keys)/sizeof(ColorKey), 1.0f, Vertical, 0,0, clientSize.w, clientSize.h);
989       surface.SetForeground(Color { 128, 128, 128 });
990       surface.HLine(160, 620, 400);
991       surface.SetForeground(white);
992       surface.HLine(160, 621, 401);
993       surface.PutPixel(621, 400);
994    }
995    Label label3
996    {
997       parent = this, opacity = 1, borderStyle = deep, size = Size { 644, 93 }, anchor = Anchor { left = -8, top = -8 };
998
999       void OnRedraw(Surface surface)
1000       {
1001          ColorKey keys[] =
1002          {
1003             { white, 0 },
1004             { activeBorder, 1 }
1005          };
1006          surface.Gradient(keys, sizeof(keys)/sizeof(ColorKey), 0, horizontal, 220,0, clientSize.w, clientSize.h);
1007
1008          Label::OnRedraw(surface);
1009       }
1010    };
1011 }
1012
1013 class InstallProgress : Window
1014 {
1015    text = "ECERE Software Development Kit Setup";
1016    background = activeBorder;
1017    borderStyle = fixed;
1018    hasMinimize = true;
1019    hasClose = true;
1020    tabCycle = true;
1021    size = Size { 640, 480 };
1022
1023    Label installing { this, position = { 32, 160 } };
1024    ProgressBar progressBar { parent = this, text = "progressBar1", size = Size { 588, 24 }, anchor = Anchor { left = 24, top = 184 } };
1025    Button finish
1026    {
1027       parent = this, text = "Install", disabled = true, isDefault = true, size = Size { 75, 23 }, anchor = Anchor { left = 432, top = 416 };
1028
1029       NotifyClicked = ButtonCloseDialog
1030    };
1031    Button cancel
1032    {
1033       this, text = "Cancel", hotKey = altX, size = Size { 75, 23 }, anchor = Anchor { left = 544, top = 416 };
1034
1035       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1036       {
1037          abortInstall = true;
1038          return true;
1039       }
1040    };
1041    EditBox titleInfo
1042    {
1043       inactive = true, noSelect = true,
1044       multiLine = true, parent = label3, text = "editBox1", opacity = 0, borderStyle = none, size = Size { 350, 35 }, anchor = Anchor { horz = 111, vert = 13 },
1045       contents = "Please wait while the Ecere Software Development Kit is being installed."
1046    };
1047    Label label2 { parent = this, text = buildString, position = { 16, 392 }, disabled = true, opacity = 1, background = activeBorder };
1048    Picture picture1 { image = BitmapResource { ":ecere.bmp", transparent = true }, filter = true, parent = label3, text = "picture1", anchor = Anchor { left = 16, top = 4 } };
1049    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 } };
1050
1051    void OnRedraw(Surface surface)
1052    {
1053       ColorKey keys[2] =
1054       {
1055          { blue, 0 },
1056          { darkBlue, 1 }
1057       };
1058       //surface.Gradient(keys, sizeof(keys)/sizeof(ColorKey), 1.0f, Vertical, 0,0, clientSize.w, clientSize.h);
1059       surface.SetForeground(Color { 128, 128, 128 });
1060       surface.HLine(160, 620, 400);
1061       surface.SetForeground(white);
1062       surface.HLine(160, 621, 401);
1063       surface.PutPixel(621, 400);
1064    }
1065    Label label3
1066    {
1067       parent = this, opacity = 1, borderStyle = deep, size = Size { 644, 93 }, anchor = Anchor { left = -8, top = -8 };
1068
1069       void OnRedraw(Surface surface)
1070       {
1071          ColorKey keys[] =
1072          {
1073             { white, 0 },
1074             { activeBorder, 1 }
1075          };
1076          surface.Gradient(keys, sizeof(keys)/sizeof(ColorKey), 0, horizontal, 220,0, clientSize.w, clientSize.h);
1077
1078          Label::OnRedraw(surface);
1079       }
1080    };
1081    InstallThread thread
1082    {
1083    };
1084 }
1085
1086 Installer installer {};
1087 InstallProgress installProgress { autoCreate = false };
1088
1089 void ModifyPath(char * newPath)
1090 {
1091    char * paths[100];
1092    int p, count;
1093    char oldPath[4096];
1094    CoreSDKID c;
1095
1096    strcpy(oldPath, newPath);
1097    count = TokenizeWith(oldPath, sizeof(paths) / sizeof(char *), paths, ";", false);
1098
1099    for(c = 0; coreSDK[c].name; c++)
1100    {
1101       char path[MAX_LOCATION];
1102       coreSDK[c].GetFullPath(path);
1103       if(c != ide && c != runtime && c != eda && c != ec
1104 #ifndef NOMINGW
1105             && c != upx
1106 #endif
1107          )
1108       {
1109 #ifndef NOMINGW
1110          if(!pathOptions[PathOptions::AddMinGWPaths].selected)
1111 #endif
1112          continue;
1113          PathCat(path, "bin");
1114       }
1115       else if(!pathOptions[PathOptions::AddECEREPaths].selected) continue;
1116
1117       for(p = 0; p<count; p++)
1118          if(!fstrcmp(paths[p], path))
1119             break;
1120       if(p == count)
1121       {
1122          char * start;
1123          if(count) 
1124          {
1125             strcat(newPath, ";");
1126             start = oldPath + strlen(paths[count-1])+1;
1127          }
1128          else
1129             start = oldPath;
1130          
1131          strcpy(start, path);
1132          *(start + strlen(path)) = '\0';
1133          paths[count++] = start;
1134
1135          strcat(newPath, path);
1136       }
1137    }
1138 #ifndef NOMINGW
1139    if(pathOptions[PathOptions::AddMinGWPaths].selected)
1140    {
1141       int c;
1142       for(c = 0; additional[c].name; c++)
1143       {
1144          char path[MAX_LOCATION];
1145          NamedItem item;
1146          additional[c].GetFullPath(path);
1147          PathCat(path, "bin");
1148          for(p = 0; p<count; p++)
1149             if(!fstrcmp(paths[p], path))
1150                break;
1151
1152          if(p == count)
1153          {
1154             char * start;
1155             if(count) 
1156             {
1157                strcat(newPath, ";");
1158                start = oldPath + strlen(paths[count-1])+1;
1159             }
1160             else
1161                start = oldPath;
1162             
1163             strcpy(start, path);
1164             *(start + strlen(path)) = '\0';
1165             paths[count++] = start;
1166
1167             strcat(newPath, path);
1168          }
1169       }
1170    }
1171 #endif
1172 }
1173
1174 void AssociateExtension(char * extension, char * description, char *name, char * action, char * path)
1175 {
1176    HKEY key;
1177    uint status, size;
1178    char keyName[1024];
1179
1180    RegCreateKeyEx(HKEY_CLASSES_ROOT, extension, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
1181    RegSetValueEx(key, null, 0, REG_SZ, name, strlen(name)+1);
1182    RegCloseKey(key);
1183
1184    RegCreateKeyEx(HKEY_CLASSES_ROOT, name, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
1185    RegSetValueEx(key, null, 0, REG_SZ, description, strlen(description)+1);
1186    RegCloseKey(key);
1187
1188    sprintf(keyName, "%s\\shell", extension);
1189    RegCreateKeyEx(HKEY_CLASSES_ROOT, keyName, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
1190    RegSetValueEx(key, null, 0, REG_SZ, action, strlen(action)+1);
1191    RegCloseKey(key);
1192
1193    sprintf(keyName, "%s\\shell\\%s", name, action);
1194    RegCreateKeyEx(HKEY_CLASSES_ROOT, keyName, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
1195    RegCloseKey(key);
1196
1197    sprintf(keyName, "%s\\shell\\%s\\command", name, action);
1198    RegCreateKeyEx(HKEY_CLASSES_ROOT, keyName, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
1199    
1200    sprintf(keyName, path);
1201    strcat(keyName, " \"%L\"");
1202    {
1203       uint16 wKeyName[2048];
1204       UTF8toUTF16Buffer(keyName, wKeyName, sizeof(wKeyName) / sizeof(uint16));
1205       RegSetValueExW(key, null, 0, REG_SZ, (byte *)wKeyName, (wcslen(wKeyName) + 1)*sizeof(uint16));
1206    }
1207    RegCloseKey(key);
1208 }
1209
1210 class InstallThread : Thread
1211 {
1212    unsigned int Main()
1213    {
1214       ComponentID c;
1215       ((GuiApplication)__thisModule).Lock();
1216       installProgress.progressBar.range = totalSize;
1217       for(c = 0; components[c].name && !abortInstall; c++)
1218          components[c].Install(installDir);
1219       if(abortInstall)
1220       {
1221          installProgress.progressBar.range = 0;
1222          installProgress.finish.Destroy(0);
1223          installProgress.cancel.text = "Close";
1224          installProgress.cancel.isDefault = true;
1225          installProgress.cancel.disabled = false;
1226          installProgress.cancel.NotifyClicked = Window::ButtonCloseDialog;
1227          installProgress.installing.text = "Installation Cancelled.";
1228          installProgress.title.text = "Installation Cancelled";
1229          installProgress.titleInfo.contents = "The installation was not completed.";
1230       }
1231       else
1232       {
1233          CoreSDKID c;
1234          char idePath[MAX_LOCATION];
1235          char userProfile[MAX_LOCATION];
1236
1237          // Configure IDE
1238          GlobalSettings settings
1239          {
1240             
1241          };
1242          installProgress.installing.text = "Configuring ECERE IDE...";
1243          ((GuiApplication)__thisModule).Unlock();
1244          ((GuiApplication)__thisModule).SignalEvent();
1245
1246          settings.Load();
1247          for(c = 0; coreSDK[c].name; c++)
1248          {
1249             char path[MAX_LOCATION];
1250             NamedItem item;
1251             coreSDK[c].GetFullPath(path);
1252             if(c != ide && c != runtime && c != eda && c != ec
1253 #ifndef NOMINGW
1254                && c != upx
1255 #endif
1256                )
1257                PathCat(path, "bin");
1258             if(c == ide)
1259             {
1260                coreSDK[c].GetFullPath(idePath);
1261                PathCat(idePath, "IDE.exe");
1262             }
1263
1264             // TODO: Update This!
1265             /*
1266             for(item = settings.systemDirs[executables].first; item; item = item.next)
1267                if(!fstrcmp(item.name, path))
1268                   break;
1269             if(!item)
1270             {
1271                settings.systemDirs[executables].Add(NamedItem { name = CopyString(path); });
1272             }
1273
1274             if(c == runtime)
1275             {
1276                for(item = settings.systemDirs[libraries].first; item; item = item.next)
1277                   if(!fstrcmp(item.name, path))
1278                      break;
1279                if(!item)
1280                {
1281                   settings.systemDirs[libraries].Add(NamedItem { name = CopyString(path); });
1282                }
1283             }
1284             */
1285          }
1286 #ifndef NOMINGW
1287          /*
1288          for(c = 0; additional[c].name; c++)
1289          {
1290             char path[MAX_LOCATION];
1291             NamedItem item;
1292             additional[c].GetFullPath(path);
1293             PathCat(path, "bin");
1294             for(item = settings.systemDirs[executables].first; item; item = item.next)
1295                if(!fstrcmp(item.name, path))
1296                   break;
1297             if(!item)
1298             {
1299                settings.systemDirs[executables].Add(NamedItem { name = CopyString(path); });
1300             }
1301          }
1302          */
1303 #endif
1304          
1305          {
1306             char path[MAX_LOCATION] = "";
1307             if(components[samples].selected)
1308                components[samples].GetFullPath(path);
1309             else
1310                components[coreSDK].GetFullPath(path);
1311             /* TODO: Update This!
1312             if(!settings.ideProjectFileDialogLocation)
1313                settings.ideProjectFileDialogLocation = path;
1314             if(!settings.ideFileDialogLocation)
1315                settings.ideFileDialogLocation = path;
1316             */
1317          }
1318
1319          settings.Save();
1320          delete settings;
1321
1322          // Set up Uninstaller
1323          ((GuiApplication)__thisModule).Lock();
1324          installProgress.installing.text = "Registering uninstaller...";
1325          ((GuiApplication)__thisModule).Unlock();
1326          ((GuiApplication)__thisModule).SignalEvent();
1327
1328          {
1329             HKEY key;
1330             uint status, size;
1331             char * displayName = "ECERE SDK 0.43";
1332             char uninstaller[MAX_LOCATION];
1333             bool nomodify = true;
1334
1335             strcpy(uninstaller, installDir);
1336             PathCat(uninstaller, "uninstall_ecere.exe");
1337
1338             RegCreateKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ECERE SDK", 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
1339
1340             RegSetValueEx(key, "DisplayName", 0, REG_SZ, displayName, strlen(displayName)+1);
1341             RegSetValueEx(key, "UninstallString", 0, REG_SZ, uninstaller, strlen(uninstaller)+1);
1342             RegSetValueEx(key, "DisplayIcon", 0, REG_SZ, idePath, strlen(idePath)+1);
1343             //RegSetValueEx(key, "NoModify", 0, REG_DWORD, (byte *)&nomodify, sizeof(nomodify));
1344             //RegSetValueEx(key, "NoRepair", 0, REG_DWORD, (byte *)&nomodify, sizeof(nomodify));
1345             RegCloseKey(key);
1346          }
1347
1348          // Add paths
1349          if(pathOptions[PathOptions::AddECEREPaths].selected 
1350 #ifndef NOMINGW
1351             || pathOptions[PathOptions::AddMinGWPaths].selected
1352 #endif
1353             )
1354          {
1355             HKEY key;
1356             uint status, size;
1357             char path[2048] = "";
1358             uint16 wPath[2048];
1359
1360             ((GuiApplication)__thisModule).Lock();
1361             installProgress.installing.text = "Registering paths...";
1362             ((GuiApplication)__thisModule).Unlock();
1363             ((GuiApplication)__thisModule).SignalEvent();
1364                         
1365             // if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Environment", 0, KEY_ALL_ACCESS, &key) == ERROR_SUCCESS)
1366             
1367             RegCreateKeyEx(HKEY_CURRENT_USER, "Environment", 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
1368             // RegCreateKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &key, &status);
1369             if(status == REG_OPENED_EXISTING_KEY)
1370             {
1371                size = sizeof(wPath);
1372                RegQueryValueExW(key, L"path", null, null, (byte *)wPath, &size);
1373                UTF16toUTF8Buffer(wPath, path, sizeof(path));
1374             }
1375             ModifyPath(path);
1376             UTF8toUTF16Buffer(path, wPath, sizeof(wPath) / sizeof(uint16));
1377             RegSetValueExW(key, L"path", 0, REG_EXPAND_SZ, (byte *)wPath, (wcslen(wPath)+1) * 2);
1378             RegCloseKey(key);
1379
1380             SendMessageTimeout (HWND_BROADCAST, WM_SETTINGCHANGE, 0, (int)"Environment", SMTO_NORMAL, 1000, NULL);
1381          }
1382
1383          // Install Program Group Icons
1384          // userProfile = getenv("USERPROFILE");
1385          GetEnvironment("USERPROFILE", userProfile, sizeof(userProfile));
1386
1387          if(options[IconOptions::StartMenuIcon].selected)
1388          {
1389             char destPath[MAX_LOCATION];
1390             char startMenuPath[MAX_LOCATION] = "";
1391             HKEY key;
1392
1393             ((GuiApplication)__thisModule).Lock();
1394             installProgress.installing.text = "Installing Start Menu Icons...";
1395             ((GuiApplication)__thisModule).Unlock();
1396             ((GuiApplication)__thisModule).SignalEvent();
1397
1398             strcpy(destPath, userProfile);
1399
1400             if(RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", 0, KEY_ALL_ACCESS, &key) == ERROR_SUCCESS)
1401             {
1402                uint16 wStartMenuPath[2048];
1403                uint size = sizeof(wStartMenuPath);
1404                // RegQueryValueEx(key, "Start Menu", null, null, startMenuPath, &size);
1405                RegQueryValueExW(key, L"Programs", null, null, (byte *)wStartMenuPath, &size);
1406                UTF16toUTF8Buffer(wStartMenuPath, startMenuPath, sizeof(startMenuPath));
1407                RegCloseKey(key);
1408             }
1409             if(!startMenuPath[0] && userProfile && userProfile[0])
1410             {
1411                strcpy(startMenuPath, userProfile);
1412                PathCat(startMenuPath, "Start Menu\\Programs");
1413             }
1414
1415             if(startMenuPath[0])
1416             {
1417                strcpy(destPath, startMenuPath);
1418                PathCat(destPath, "ECERE SDK");
1419                MakeDir(destPath);
1420
1421                strcpy(destPath, startMenuPath);
1422                PathCat(destPath, "ECERE SDK\\ECERE IDE.lnk");
1423                CreateLink(idePath, destPath, null); //"ECERE IDE");
1424                if(components[samples].selected)
1425                {
1426                   char samplesPath[MAX_LOCATION] = "";
1427                   components[samples].GetFullPath(samplesPath);
1428
1429                   strcpy(destPath, startMenuPath);
1430                   PathCat(destPath, "ECERE SDK\\Sample Projects.lnk");
1431                   CreateLink(samplesPath, destPath, null);//"Sample Projects");
1432                }
1433                if(components[documentation].selected && documentation[ecereBook].selected)
1434                {
1435                   char docPath[MAX_LOCATION] = "";
1436                   documentation[ecereBook].GetFullPath(docPath);
1437                   PathCat(docPath, "Ecere Tao of Programming [work in progress].pdf");
1438
1439                   strcpy(destPath, startMenuPath);
1440                   PathCat(destPath, "ECERE SDK\\The Ecere Tao of Programming.lnk");
1441                   CreateLink(docPath, destPath, null);
1442                }
1443             }
1444          }
1445
1446          // Install Desktop Icon
1447          if(options[IconOptions::DesktopIcon].selected)
1448          {
1449             HKEY key;
1450             char desktopPath[MAX_LOCATION];
1451
1452             if(RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", 0, KEY_ALL_ACCESS, &key) == ERROR_SUCCESS)
1453             {
1454                uint16 wDesktopPath[MAX_LOCATION];
1455                uint size = sizeof(wDesktopPath);
1456                RegQueryValueExW(key, L"Desktop", null, null, (byte *)wDesktopPath, &size);
1457                UTF16toUTF8Buffer(wDesktopPath, desktopPath, sizeof(desktopPath));
1458                RegCloseKey(key);
1459             }
1460             if(!desktopPath[0] && userProfile && userProfile[0])
1461             {
1462                strcpy(desktopPath, userProfile);
1463                PathCat(desktopPath, "Desktop");
1464             }
1465
1466             if(desktopPath[0])
1467             {
1468                PathCat(desktopPath, "ECERE IDE.lnk");
1469
1470                ((GuiApplication)__thisModule).Lock();
1471                installProgress.installing.text = "Installing Desktop Icon...";
1472                ((GuiApplication)__thisModule).Unlock();
1473                ((GuiApplication)__thisModule).SignalEvent();
1474
1475                CreateLink(idePath, desktopPath, null);//"ECERE IDE");
1476             }
1477          }
1478
1479          // Install QuickLaunch Icon
1480          if(options[IconOptions::QuickLaunchIcon].selected)
1481          {
1482             char appData[MAX_LOCATION]; // = getenv("APPDATA");
1483             GetEnvironment("APPDATA", appData, sizeof(appData));
1484
1485             if(appData && appData[0])
1486             {
1487                char destPath[MAX_LOCATION];
1488
1489                ((GuiApplication)__thisModule).Lock();
1490                installProgress.installing.text = "Installing Quicklaunch Icon...";
1491                ((GuiApplication)__thisModule).Unlock();
1492                ((GuiApplication)__thisModule).SignalEvent();
1493
1494                strcpy(destPath, appData);
1495                PathCat(destPath, "Microsoft\\Internet Explorer\\Quick Launch\\ECERE IDE.lnk");
1496
1497                CreateLink(idePath, destPath, null);//"ECERE IDE");
1498             }
1499          }
1500
1501          // Register File Types
1502          if(associateOptions[AssociateOptions::AssociateEPJ].selected ||
1503             associateOptions[AssociateOptions::AssociateEC].selected ||
1504             associateOptions[AssociateOptions::AssociateC].selected ||
1505             associateOptions[AssociateOptions::AssociateCPP].selected ||
1506             associateOptions[AssociateOptions::AssociateTXT].selected ||
1507             associateOptions[AssociateOptions::Associate3DS].selected ||
1508             associateOptions[AssociateOptions::AssociateIMG].selected)
1509          {
1510             ((GuiApplication)__thisModule).Lock();
1511             installProgress.installing.text = "Resgistering File Types...";
1512             ((GuiApplication)__thisModule).Unlock();
1513             ((GuiApplication)__thisModule).SignalEvent();
1514             
1515             if(associateOptions[AssociateOptions::AssociateEPJ].selected)
1516             {
1517                AssociateExtension(".epj", "ECERE IDE Project", "epj_file", "Open", idePath);
1518             }
1519             if(associateOptions[AssociateOptions::AssociateEC].selected)
1520             {
1521                AssociateExtension(".ec", "eC Source File", "ec_file", "Open", idePath);
1522                AssociateExtension(".eh", "eC Header File", "eh_file", "Open", idePath);
1523             }
1524             if(associateOptions[AssociateOptions::AssociateC].selected)
1525             {
1526                AssociateExtension(".c", "C Source File", "c_file", "Open", idePath);
1527                AssociateExtension(".h", "C Header File", "h_file", "Open", idePath);
1528             }
1529             if(associateOptions[AssociateOptions::AssociateCPP].selected)
1530             {
1531                AssociateExtension(".cpp", "C++ Source File", "cpp_file", "Open", idePath);
1532                AssociateExtension(".cc", "C++ Source File", "cpp_file", "Open", idePath);
1533                AssociateExtension(".cxx", "C++ Source File", "cpp_file", "Open", idePath);
1534                AssociateExtension(".chh", "C++ Header File", "chh_file", "Open", idePath);
1535                AssociateExtension(".hh", "C++ Header File", "chh_file", "Open", idePath);
1536                AssociateExtension(".hxx", "C++ Header File", "chh_file", "Open", idePath);
1537             }
1538             if(associateOptions[AssociateOptions::AssociateTXT].selected)
1539             {
1540                AssociateExtension(".txt", "Text File", "txt_file", "Open", idePath);
1541             }
1542             if(associateOptions[AssociateOptions::Associate3DS].selected)
1543             {
1544                AssociateExtension(".3ds", "3D Studio Model", "3ds_file", "View", idePath);
1545             }
1546             if(associateOptions[AssociateOptions::AssociateIMG].selected)
1547             {
1548                AssociateExtension(".bmp", "BMP Image", "bmp_file", "View", idePath);
1549                AssociateExtension(".pcx", "PCX Image", "pcx_file", "View", idePath);
1550                AssociateExtension(".png", "PNG Image", "png_file", "View", idePath);
1551                AssociateExtension(".jpg", "JPEG Image", "jpg_file", "View", idePath);
1552                AssociateExtension(".jpeg", "JPEG Image", "jpg_file", "View", idePath);
1553                AssociateExtension(".gif", "GIF Image", "gif_file", "View", idePath);
1554             }
1555          }
1556          ((GuiApplication)__thisModule).Lock();
1557
1558          installProgress.cancel.Destroy(0);
1559          installProgress.finish.text = "Finish";
1560          installProgress.finish.disabled = false;
1561          installProgress.finish.Activate();
1562          installProgress.installing.text = "Installation Complete.";
1563          installProgress.title.text = "Installation Complete";
1564          installProgress.titleInfo.contents = "Thank you for using the ECERE SDK.";
1565       }
1566       ((GuiApplication)__thisModule).Unlock();
1567       return 0;
1568    }
1569 }