added background, extra 'finished' window
[swftools.git] / installer / installer.c
1 /* installer.c
2
3    Part of the swftools installer (Main program).
4    
5    Copyright (c) 2004 Matthias Kramm <kramm@quiss.org> 
6  
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
20
21 #include <windows.h>
22 #include <commctrl.h>
23 #include <commdlg.h>
24 #include <shlobj.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27
28 #include "depack.h"
29
30 #include "../config.h" //for swftools version
31 #include "../lib/os.h" //for registry functions
32
33 extern char*crndata;
34
35 static char*install_path = "c:\\swftools\\";
36 static char pathBuf[1024];
37 static int do_abort = 0;
38
39 static HWND wnd_params = 0;
40 static HWND wnd_progress = 0;
41 static HWND wnd_finish = 0;
42
43 static HBITMAP logo;
44
45 #define USER_SETMESSAGE 0x7f01
46
47 struct progress_data {
48     int width,height;
49     int bar_width;
50     int bar_height;
51     int bar_posx;
52     int bar_posy;
53     int pos,step,range;
54     char*text1;
55     char*text2;
56     char*text3;
57     HWND hwndButton;
58     HWND wnd_text3;
59 };
60 struct params_data {
61     int width,height;
62     int ok;
63     HWND installButton;
64     HWND edit;
65     HWND explore;
66 };
67 struct finish_data {
68     int width,height;
69     int ok;
70     HWND installButton;
71 };
72
73 LRESULT CALLBACK WindowFunc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
74 {
75     //printf("%08x, %d %08x %08x\n", hwnd, message, wParam, lParam);
76    
77     /* in order for the delegation below to also work for
78        WM_CREATE, we need to assign our window pointers *before* the
79        CreateWindow returns, because that's when the WM_CREATE event 
80        is sent  */
81     if(message == WM_CREATE) {
82         CREATESTRUCT*cs = ((LPCREATESTRUCT)lParam);
83         if(cs->lpCreateParams && !strcmp((char*)cs->lpCreateParams, "params")) {
84             wnd_params = hwnd;
85         }
86         if(cs->lpCreateParams && !strcmp((char*)cs->lpCreateParams, "progress")) {
87             wnd_progress = hwnd;
88         }
89         if(cs->lpCreateParams && !strcmp((char*)cs->lpCreateParams, "finish")) {
90             wnd_finish = hwnd;
91         }
92     }
93
94     if(hwnd == 0) {
95         return DefWindowProc(hwnd, message, wParam, lParam);
96     } else if(hwnd == wnd_progress) {
97         static struct progress_data data;
98
99         switch(message)
100         {
101             case USER_SETMESSAGE:
102                 data.text3 = (char*)wParam;
103                 SendMessage(data.wnd_text3, WM_SETTEXT, 0, (LPARAM)data.text3);
104                 return 0;
105             case WM_CREATE: {
106                 memset(&data, 0, sizeof(data));
107                 data.text1 = "Installing SWFTools";
108                 data.text2 = (char*)malloc(strlen(install_path)+250);
109                 sprintf(data.text2, "to %s", install_path);
110                 data.pos = 0;
111                 data.step = 1;
112
113                 CREATESTRUCT*cs = ((LPCREATESTRUCT)lParam);
114                 RECT rc;
115                 GetClientRect (hwnd, &rc);
116                 data.width = rc.right - rc.left;
117                 data.height = rc.bottom - rc.top;
118                 data.bar_width = cs->cx - 17;
119                 data.bar_height= 16;
120                 data.bar_posx = (data.width -data.bar_width)/2;
121                 data.bar_posy = 56;
122                 data.range = 50;
123
124                 data.hwndButton = CreateWindow (
125                         PROGRESS_CLASS,
126                         "Progress",
127                         WS_CHILD | WS_VISIBLE,
128                         data.bar_posx,
129                         data.bar_posy,
130                         data.bar_width, 
131                         data.bar_height,
132                         hwnd,  /* Parent */
133                         (HMENU)1,
134                         cs->hInstance,
135                         NULL
136                         );
137
138                 data.wnd_text3 = CreateWindow (
139                         WC_STATIC,
140                         "text3",
141                         WS_CHILD | WS_VISIBLE,
142                         data.bar_posx,
143                         72,
144                         (rc.right - rc.left - data.bar_posx*2), 
145                         20,
146                         hwnd,  /* Parent */
147                         (HMENU)1,
148                         cs->hInstance,
149                         NULL
150                         );
151                 SendMessage(data.wnd_text3, WM_SETTEXT, 0, (LPARAM)"");
152
153                 SendMessage(data.hwndButton, PBM_SETRANGE, 0, (LPARAM) MAKELONG(0,data.range));
154                 SendMessage(data.hwndButton, PBM_SETSTEP, (WPARAM) data.step, 0);
155                 return 0;
156             }   
157             case PBM_STEPIT: {
158                 if(data.pos+data.step < data.range) {
159                     data.pos += data.step;
160                     SendMessage(data.hwndButton, PBM_STEPIT, wParam, lParam);
161                 }
162             }
163             case WM_PAINT: {
164                 TEXTMETRIC    tm;
165                 HDC           hdc;             /* A device context used for drawing */
166                 PAINTSTRUCT   ps;              /* Also used during window drawing */
167                 RECT          rc;              /* A rectangle used during drawing */
168                 
169                 hdc = GetDC(hwnd);
170                 SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));
171                 GetTextMetrics(hdc, &tm);
172                 ReleaseDC(hwnd, hdc);
173
174                 hdc = BeginPaint (hwnd, &ps);
175
176                 /*
177                 // draw logo 
178                 HDC memDc=CreateCompatibleDC(hdc);
179                 SelectObject(memDc,logo);
180                 BitBlt(hdc,0,0,406,93,memDc,0,0,SRCCOPY);
181                 DeleteDC(memDc);
182                 // /
183                 */
184
185                 SetBkMode(hdc, TRANSPARENT);
186                 
187                 rc.top = 8; rc.left= 0; rc.right = data.width; rc.bottom = 24;
188                 DrawText(hdc, data.text1, -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
189
190                 char buf[256];
191                 char*text = data.text2;
192                 if(tm.tmAveCharWidth * strlen(text) > data.width) {
193                     int chars = (data.width / tm.tmAveCharWidth)-8;
194                     if(chars>240) chars=240;
195                     strncpy(buf, text, chars);
196                     strcpy(&buf[chars],"...");
197                     text = buf;
198                 }
199
200                 rc.top = 32; rc.left= 0; rc.right = data.width; rc.bottom = 48;
201                 DrawText(hdc, text, -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
202
203                 EndPaint (hwnd, &ps);
204                 return 0;
205             }
206             case WM_DESTROY:
207                 wnd_progress = 0;
208                 return DefWindowProc(hwnd, message, wParam, lParam);
209             default:
210                 return DefWindowProc(hwnd, message, wParam, lParam);
211         }
212     } else if(hwnd == wnd_params) {
213         static struct params_data data;
214         switch(message)
215         {
216             case WM_CREATE: {
217                 memset(&data, 0, sizeof(data));
218                 CREATESTRUCT*cs = ((LPCREATESTRUCT)lParam);
219                 RECT rc;
220                 GetClientRect (hwnd, &rc);
221                 data.width = rc.right - rc.left;
222                 data.height = rc.bottom - rc.top;
223
224                 //EDITTEXT IDD_EDIT,68,8,72,12, ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER  | WS_TABSTOP
225                 HWND text = CreateWindow(
226                         WC_STATIC,
227                         "Select Installation Directory:",
228                         WS_CHILD | WS_VISIBLE,
229                         32, 
230                         16,
231                         data.width-32*2, 
232                         20,
233                         hwnd,  /* Parent */
234                         0,
235                         cs->hInstance,
236                         NULL
237                         );
238
239                 data.edit = CreateWindow (
240                         WC_EDIT,
241                         "EditPath",
242                         WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | ES_AUTOHSCROLL,
243                         32, 
244                         48,
245                         (data.width-64)-32*2, 
246                         20,
247                         hwnd,  /* Parent */
248                         (HMENU)0x1234,
249                         cs->hInstance,
250                         NULL
251                         );
252                 
253                 data.explore = CreateWindow (
254                         WC_BUTTON,
255                         "Browse",
256                         WS_CHILD | WS_VISIBLE | WS_TABSTOP,
257                         data.width-32-64,
258                         48,
259                         64, 
260                         20,
261                         hwnd,  /* Parent */
262                         (HMENU)0x9999,
263                         cs->hInstance,
264                         NULL
265                         );
266                 
267                 data.installButton = CreateWindow (
268                         WC_BUTTON,
269                         "Install",
270                         WS_CHILD | WS_VISIBLE | WS_TABSTOP,
271                         (data.width - 80)/2,
272                         data.height - 32*2,
273                         80, 
274                         32,
275                         hwnd,  /* Parent */
276                         (HMENU)0xabcd,
277                         cs->hInstance,
278                         NULL
279                         );
280                 
281                 SendMessage(data.edit, WM_SETTEXT, 0, (LPARAM)install_path);
282                 return 0;
283             }   
284             case USER_SETMESSAGE: {
285                 //install_path = (char*)lParam;
286                 SendMessage(data.edit, WM_SETTEXT, 0, (LPARAM)install_path);
287                 printf("Setting path to %s\n", install_path);
288                 return 0;
289             }
290             case WM_PAINT: {
291                 return DefWindowProc(hwnd, message, wParam, lParam);
292             }
293             case WM_COMMAND: {
294                 if((wParam&0xffff) == 0x9999) {
295                     BROWSEINFOA browse;
296                     memset(&browse, 0, sizeof(browse));
297                     browse.ulFlags = BIF_EDITBOX | BIF_NEWDIALOGSTYLE | BIF_USENEWUI;// | BIF_RETURNONLYFSDIRS; //BIF_VALIDATE
298                     browse.pszDisplayName = (CHAR*)malloc(MAX_PATH);
299                     memset(browse.pszDisplayName, 0, MAX_PATH);
300                     browse.lpszTitle = "Select installation directory";
301                     /*browse.pidlRoot = (ITEMIDLIST*)malloc(sizeof(ITEMIDLIST)*200);
302                     memset((void*)browse.pidlRoot, 0, sizeof(ITEMIDLIST)*200);*/
303                     printf("Start browsing %s\n", browse.pszDisplayName);
304                     //SHGetDesktopFolder
305                     //ParseDisplayName(install_path,0,&browse.pidlRoot,0,0);
306                     //SHParseDisplayName(install_path,0,&browse.pidlRoot,0,0);
307                     //SHBrowseForFolderA(&browse);
308                     browse.pidlRoot = SHBrowseForFolder(&browse);
309                     printf("Browsing returns %s / %08x\n", browse.pszDisplayName, browse.pidlRoot);
310                     if(browse.pszDisplayName) {
311                         if(SHGetPathFromIDList(browse.pidlRoot, browse.pszDisplayName)) {
312                             printf("Path is %s\n", browse.pszDisplayName);
313                             install_path = browse.pszDisplayName;
314                         }
315                     }
316                     SendMessage(data.edit, WM_SETTEXT, 0, (LPARAM)install_path);
317                     return 0;
318                 } else if((wParam&0xffff) == 0xabcd) {
319                     data.ok = 1;
320                     DestroyWindow(wnd_params);
321                     return 0;
322                 } else if((wParam&0xffff) == 0x1234) {
323                     SendMessage(data.edit, WM_GETTEXT, sizeof(pathBuf), (LPARAM)&(pathBuf[0]));
324                     if(pathBuf[0]) {
325                         install_path = pathBuf;
326                         printf("Path edited: now \"%s\"\n", install_path);
327                     }
328                     return 0;
329                 }
330                 return DefWindowProc(hwnd, message, wParam, lParam);
331             }
332             case WM_KEYDOWN: {
333                 if(wParam == 0x49) {
334                     DestroyWindow(wnd_params);
335                 }
336                 return 0;
337             }
338             case WM_DESTROY:
339                 if(!data.ok) {
340                     do_abort = 1;
341                     PostQuitMessage (0);
342                 }
343                 wnd_params = 0;
344                 return DefWindowProc(hwnd, message, wParam, lParam);
345             default:
346                 return DefWindowProc(hwnd, message, wParam, lParam);
347         }
348     } else if(hwnd == wnd_finish) {
349         static struct finish_data data;
350         switch(message)
351         {
352             case WM_CREATE: {
353
354                 /* TODO:
355
356                    "swftools has been installed into directory %s
357                    successfully"
358
359                    [x] Create Desktop Shortcut
360                    [x] Create Start Menu Entry
361
362                 */
363
364                 RECT rc;
365                 CREATESTRUCT*cs = ((LPCREATESTRUCT)lParam);
366                 GetClientRect (hwnd, &rc);
367                 data.width = rc.right - rc.left;
368                 data.height = rc.bottom - rc.top;
369                 
370                 data.installButton = CreateWindow (
371                         WC_BUTTON,
372                         "Finish",
373                         WS_CHILD | WS_VISIBLE | WS_TABSTOP,
374                         (data.width - 80)/2,
375                         data.height - 40,
376                         80, 
377                         32,
378                         hwnd,  /* Parent */
379                         (HMENU)0xabcd,
380                         cs->hInstance,
381                         NULL
382                         );
383             }
384         }
385     }
386     return DefWindowProc(hwnd, message, wParam, lParam);
387 }
388
389 void processMessages()
390 {
391     MSG msg;
392     while(PeekMessage(&msg,NULL,0,0,0))
393     {
394         GetMessage(&msg, NULL, 0, 0);
395         TranslateMessage(&msg);
396         DispatchMessage(&msg);
397     }
398 }
399
400 static char*lastmessage = 0;
401 void myarchivestatus(int type, char*text)
402 {
403     if(text && text[0]=='[')
404         return;
405     //printf("%s\n", text);
406                         
407     SendMessage(wnd_progress, USER_SETMESSAGE, (WPARAM)strdup(text), 0);
408     SendMessage(wnd_progress, WM_PAINT, 0, 0);
409     int t;
410     for(t=0;t<9;t++) {
411         SendMessage(wnd_progress, PBM_STEPIT, 0, 0);
412         /* while we're here, we might also make ourselves useful */
413         processMessages();
414         /* we want the user to see what we're writing, right? */
415         Sleep(30);
416     }
417
418     if(type<0) {
419         while(1) {
420             int ret = MessageBox(0, text, "Error", MB_RETRYCANCEL|MB_ICONERROR);
421             
422             /* there is no MB_CANCEL, so, *sigh*, we have to display
423                the "retry" button. So pretend it's doing anything... */
424             if(ret==IDRETRY)
425                 continue;
426             else
427                 break;
428         }
429     }
430 }
431
432 int addRegistryEntries(char*install_dir)
433 {
434     int ret;
435     ret = setRegistryEntry("Software\\quiss.org\\swftools\\InstallPath", install_dir);
436     if(!ret) return 0;
437     return 1;
438 }
439
440 int WINAPI WinMain(HINSTANCE me,HINSTANCE hPrevInst,LPSTR lpszArgs, int nWinMode)
441 {
442     WNDCLASSEX wcl;
443     wcl.hInstance    = me;
444     wcl.lpfnWndProc  = WindowFunc;
445     wcl.lpszClassName= "SWFTools-Install";
446     wcl.style        = CS_HREDRAW | CS_VREDRAW;
447     wcl.hIcon        = LoadIcon(NULL, IDI_APPLICATION);
448     wcl.hIconSm      = LoadIcon(NULL, IDI_APPLICATION);
449     wcl.hCursor      = LoadCursor(NULL, IDC_ARROW);
450     wcl.lpszMenuName = NULL; //no menu
451     wcl.cbClsExtra   = 0;
452     wcl.cbWndExtra   = 0;
453     wcl.hbrBackground= (HBRUSH) GetStockObject(LTGRAY_BRUSH);
454     wcl.cbSize       = sizeof(WNDCLASSEX);
455
456     WNDCLASSEX wcl_background;
457     memcpy(&wcl_background, &wcl, sizeof(WNDCLASSEX));
458     wcl_background.lpszClassName= "SWFTools Installer";
459     wcl_background.hbrBackground= CreateSolidBrush(RGB(0, 0, 128));
460
461     if(!RegisterClassEx(&wcl)) {
462         MessageBox(0, "Could not register window class", "Install.exe", MB_OK);
463         return 1;
464     }
465     if(!RegisterClassEx(&wcl_background)) {
466         MessageBox(0, "Could not register window class 2", "Install.exe", MB_OK);
467         return 1;
468     }
469
470     HWND background = CreateWindow(wcl_background.lpszClassName, "Setup SWFTools",
471                          0, 0, 0, 
472                          GetSystemMetrics(SM_CXFULLSCREEN),
473                          GetSystemMetrics(SM_CYFULLSCREEN),
474                          NULL, NULL, me, NULL);
475     
476     if(!background) {
477         MessageBox(0, "Could not create installation background window", "Install.exe", MB_OK);
478         return 1;
479     }
480
481     ShowWindow(background, SW_SHOWMAXIMIZED);
482     UpdateWindow(background);
483
484     RECT r = {0,0,0,0};
485     GetWindowRect(background, &r);
486     int xx = 320, yy = 200;
487     if(r.right - r.left > 320)
488         xx = r.right - r.left;
489     if(r.right - r.left > 200)
490         yy = r.bottom - r.top;
491     
492     logo = LoadBitmap(me, "SWFTOOLS");
493     
494     install_path = getRegistryEntry("Software\\quiss.org\\swftools\\InstallPath");
495     if(!install_path || !install_path[0])
496         install_path = "c:\\swftools\\";
497
498     CoInitialize(0);
499     InitCommonControls();
500    
501     HWND installpath_window = CreateWindow(
502             wcl.lpszClassName,          /* Class name */
503             "SWFTools Installer",       /* Caption */
504             WS_CHILD | WS_CAPTION,
505             (xx-320)/2,                 /* Initial x  */
506             (yy-200)/2,                 /* Initial y  */
507             320,                        /* Initial x size */
508             200,                        /* Initial y size */
509             background,                       /* No parent window */
510             NULL,                       /* No menu */
511             me,                         /* This program instance */
512             (void*)"params"             /* Creation parameters */
513             );
514
515     if(!installpath_window) {
516         MessageBox(0, "Could not create installation window", "Install.exe", MB_OK);
517         return 1;
518     }
519
520     ShowWindow (wnd_params, nWinMode);
521     UpdateWindow (wnd_params);
522    
523     MSG msg;
524     while(wnd_params)
525     {
526         GetMessage(&msg,NULL,0,0);
527         TranslateMessage(&msg);
528         DispatchMessage(&msg);
529     }
530
531     if(do_abort)
532         return 1;
533    
534     /*char buf[1024];
535     sprintf(buf, "Do you want me to install SWFTools into the directory %s now?", install_path);
536     int ret = MessageBox(0, buf, "SWFTools Install", MB_YESNO|MB_ICONQUESTION);
537     if(ret == IDNO)
538         return 0;*/
539     
540     CreateWindow (
541             wcl.lpszClassName,          /* Class name */
542             "Installing...",            /* Caption */
543             WS_CHILD | WS_CAPTION,
544             //WS_OVERLAPPEDWINDOW&(~WS_SIZEBOX),        /* Style */
545             (xx-260)/2, (yy-128)/2,
546             260,                        /* Initial x size */
547             128,                        /* Initial y size */
548             background,                 /* No parent window */
549             NULL,                       /* No menu */
550             me,                         /* This program instance */
551             (void*)"progress"           /* Creation parameters */
552             );
553     ShowWindow (wnd_progress, nWinMode);
554     UpdateWindow (wnd_progress);
555     
556     int success = unpack_archive(crndata, install_path, myarchivestatus);
557    
558     DestroyWindow(wnd_progress);
559
560     while(wnd_progress)
561         processMessages();
562
563     CreateWindow (
564             wcl.lpszClassName,          /* Class name */
565             "Finished",                 /* Caption */
566             WS_CHILD | WS_CAPTION,
567             //WS_OVERLAPPEDWINDOW&(~WS_SIZEBOX),        /* Style */
568             (xx-320)/2, (yy-160)/2,
569             320,                        /* Initial x size */
570             160,                        /* Initial y size */
571             background,                 /* No parent window */
572             NULL,                       /* No menu */
573             me,                         /* This program instance */
574             (void*)"finish"             /* Creation parameters */
575             );
576     ShowWindow(wnd_finish, nWinMode);
577     UpdateWindow(wnd_finish);
578
579     while(wnd_finish)
580         processMessages();
581
582
583     if(!addRegistryEntries(install_path)) {
584         success = 0;
585         MessageBox(0, "Couldn't create Registry Entries", "SWFTools Install", MB_OK|MB_ICONERROR);
586     }
587
588     if(success) {
589         char buf[1024];
590         sprintf(buf, "SWFTools Version %s has been installed into %s successfully", VERSION, install_path);
591         MessageBox(0, buf, "SWFTools Install", MB_OK|MB_ICONINFORMATION);
592     } else {
593         /* error will already have been notified by either myarchivestatus or some other
594            routine */
595         /*sprintf(buf, "Installation failed\nLast message: %s", lastmessage);
596         ret = MessageBox(0, buf, "SWFTools Install", MB_OK|MB_ICONERROR);*/
597     }
598     exit(0);
599 }
600
601
602