added progress bar, dialog box.
[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 <stdio.h>
24 #include <stdlib.h>
25
26 #include "depack.h"
27
28 #include "../config.h" //for swftools version
29
30 extern char*crndata;
31
32 static char*install_path = "c:\\swftools\\";
33
34 static HWND wnd_progress = 0;
35 static HWND wnd_params = 0;
36
37 #define USER_SETMESSAGE 0x7fff0001
38
39 struct progress_data {
40     int width,height;
41     int bar_width;
42     int bar_height;
43     int bar_posx;
44     int bar_posy;
45     int pos,step,range;
46     char*text1;
47     char*text2;
48     char*text3;
49     HWND hwndButton;
50     HWND wnd_text3;
51 };
52 struct params_data {
53     int width,height;
54     int ok;
55     HWND installButton;
56     HWND edit;
57 };
58
59         
60 LRESULT CALLBACK WindowFunc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
61 {
62     printf("%08x, %d %08x %08x\n", hwnd, message, wParam, lParam);
63    
64     /* in order for the delegation below to also work for
65        WM_CREATE, we need to assign our window pointers *before* the
66        CreateWindow returns, because that's when the WM_CREATE event 
67        is sent  */
68     if(message == WM_CREATE) {
69         CREATESTRUCT*cs = ((LPCREATESTRUCT)lParam);
70         if(cs->lpCreateParams && !strcmp((char*)cs->lpCreateParams, "params")) {
71             wnd_params = hwnd;
72         }
73         if(cs->lpCreateParams && !strcmp((char*)cs->lpCreateParams, "progress")) {
74             wnd_progress = hwnd;
75         }
76     }
77
78     if(hwnd == 0) {
79         return DefWindowProc(hwnd, message, wParam, lParam);
80     } else if(hwnd == wnd_progress) {
81         static struct progress_data data;
82
83         switch(message)
84         {
85             case USER_SETMESSAGE:
86                 data.text3 = (char*)wParam;
87                 SendMessage(data.wnd_text3, WM_SETTEXT, 0, data.text3);
88                 return 0;
89             case WM_CREATE: {
90                 memset(&data, 0, sizeof(data));
91                 data.text1 = "Installing SWFTools";
92                 data.text2 = (char*)malloc(strlen(install_path)+250);
93                 sprintf(data.text2, "to %s", install_path);
94                 data.pos = 0;
95                 data.step = 1;
96
97                 CREATESTRUCT*cs = ((LPCREATESTRUCT)lParam);
98                 RECT rc;
99                 GetClientRect (hwnd, &rc);
100                 data.width = rc.right - rc.left;
101                 data.height = rc.bottom - rc.top;
102                 data.bar_width = cs->cx - 17;
103                 data.bar_height= 16;
104                 data.bar_posx = (data.width -data.bar_width)/2;
105                 data.bar_posy = 56;
106                 data.range = 50;
107                 data.hwndButton = CreateWindow (
108                         PROGRESS_CLASS,
109                         "Progress",
110                         WS_CHILD | WS_VISIBLE,
111                         data.bar_posx,
112                         data.bar_posy,
113                         data.bar_width, 
114                         data.bar_height,
115                         hwnd,  /* Parent */
116                         (HMENU)1,
117                         cs->hInstance,
118                         NULL
119                         );
120
121                 data.wnd_text3 = CreateWindow (
122                         WC_EDIT,
123                         "text3",
124                         WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER,
125                         data.bar_posx,
126                         72,
127                         (rc.right - rc.left - data.bar_posx*2), 
128                         20,
129                         hwnd,  /* Parent */
130                         (HMENU)1,
131                         cs->hInstance,
132                         NULL
133                         );
134                 SendMessage(data.hwndButton, PBM_SETRANGE, 0, (LPARAM) MAKELONG(0,data.range));
135                 SendMessage(data.hwndButton, PBM_SETSTEP, (WPARAM) data.step, 0);
136                 //ShowWindow(hwndButton, SW_SHOW);
137                 return 0;
138             }   
139             case PBM_STEPIT: {
140                 if(data.pos+data.step < data.range) {
141                     data.pos += data.step;
142                     SendMessage(data.hwndButton, PBM_STEPIT, wParam, lParam);
143                 }
144             }
145             case WM_PAINT: {
146                 TEXTMETRIC    tm;
147                 HDC           hdc;             /* A device context used for drawing */
148                 PAINTSTRUCT   ps;              /* Also used during window drawing */
149                 RECT          rc;              /* A rectangle used during drawing */
150                 
151                 hdc = GetDC(hwnd);
152                 SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));
153                 GetTextMetrics(hdc, &tm);
154                 ReleaseDC(hwnd, hdc);
155
156                 hdc = BeginPaint (hwnd, &ps);
157                 
158                 rc.top = 8; rc.left= 0; rc.right = data.width; rc.bottom = 24;
159                 DrawText(hdc, data.text1, -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
160
161                 /*if(data.text3) {
162                     rc.top = 112; rc.left= 0; rc.right = data.width; rc.bottom = 128;
163                     InvalidateRect(hwnd,&rc,1);
164                     DrawText(hdc, data.text3, -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
165                 }*/
166
167                 char buf[256];
168                 char*text = data.text2;
169                 if(tm.tmAveCharWidth * strlen(text) > data.width) {
170                     int chars = (data.width / tm.tmAveCharWidth)-8;
171                     if(chars>240) chars=240;
172                     strncpy(buf, text, chars);
173                     strcpy(&buf[chars],"...");
174                     text = buf;
175                 }
176
177                 rc.top = 32; rc.left= 0; rc.right = data.width; rc.bottom = 48;
178                 DrawText(hdc, text, -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
179
180                 EndPaint (hwnd, &ps);
181                 return 0;
182             }
183             case WM_DESTROY:
184                 wnd_progress = 0;
185                 return DefWindowProc(hwnd, message, wParam, lParam);
186             default:
187                 return DefWindowProc(hwnd, message, wParam, lParam);
188         }
189     } else if(hwnd == wnd_params) {
190         static struct params_data data;
191         switch(message)
192         {
193             case WM_CREATE: {
194                 memset(&data, 0, sizeof(data));
195                 CREATESTRUCT*cs = ((LPCREATESTRUCT)lParam);
196                 RECT rc;
197                 GetClientRect (hwnd, &rc);
198                 data.width = rc.right - rc.left;
199                 data.height = rc.bottom - rc.top;
200
201                 //EDITTEXT IDD_EDIT,68,8,72,12, ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER  | WS_TABSTOP
202                 HWND text = CreateWindow(
203                         WC_STATIC,
204                         "Select Installation Directory:",
205                         WS_CHILD | WS_VISIBLE,
206                         32, 
207                         0,
208                         data.width-32*2, 
209                         20,
210                         hwnd,  /* Parent */
211                         (HMENU)1,
212                         cs->hInstance,
213                         NULL
214                         );
215
216                 SendMessage(text, WM_SETTEXT, "test1", "test2");
217
218                 data.edit = CreateWindow (
219                         WC_EDIT,
220                         "EditPath",
221                         WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | ES_AUTOHSCROLL,
222                         32, 
223                         32,
224                         data.width-32*2, 
225                         20,
226                         hwnd,  /* Parent */
227                         (HMENU)1,
228                         cs->hInstance,
229                         NULL
230                         );
231  
232                 data.installButton = CreateWindow (
233                         WC_BUTTON,
234                         "Install",
235                         WS_CHILD | WS_VISIBLE | WS_TABSTOP,
236                         (data.width - 80)/2,
237                         data.height - 32*2,
238                         80, 
239                         32,
240                         hwnd,  /* Parent */
241                         (HMENU)1,
242                         cs->hInstance,
243                         NULL
244                         );
245                 return 0;
246             }   
247             case WM_PAINT: {
248                 return DefWindowProc(hwnd, message, wParam, lParam);
249             }
250             case WM_COMMAND: {
251                 data.ok = 1;
252                 DestroyWindow(wnd_params);
253                 return;
254             }
255             case WM_KEYDOWN: {
256                 if(wParam == 0x49) {
257                     DestroyWindow(wnd_params);
258                 }
259                 return 0;
260             }
261             case WM_DESTROY:
262                 if(!data.ok)
263                     PostQuitMessage (0);
264                 wnd_params = 0;
265                 return DefWindowProc(hwnd, message, wParam, lParam);
266             default:
267                 return DefWindowProc(hwnd, message, wParam, lParam);
268         }
269     }
270     return DefWindowProc(hwnd, message, wParam, lParam);
271 }
272
273 void processMessages()
274 {
275     MSG msg;
276     while(PeekMessage(&msg,NULL,0,0,0))
277     {
278         GetMessage(&msg, NULL, 0, 0);
279         TranslateMessage(&msg);
280         DispatchMessage(&msg);
281     }
282 }
283
284 static char*lastmessage = 0;
285 void myarchivestatus(int type, char*text)
286 {
287     if(text && text[0]=='[')
288         return;
289     //printf("%s\n", text);
290                         
291     SendMessage(wnd_progress, USER_SETMESSAGE, (WPARAM)strdup(text), 0);
292     SendMessage(wnd_progress, WM_PAINT, 0, 0);
293     int t;
294     for(t=0;t<9;t++) {
295         SendMessage(wnd_progress, PBM_STEPIT, 0, 0);
296         /* while we're here, we might also make ourselves useful */
297         processMessages();
298         /* we want the user to see what we're writing, right? */
299         Sleep(20);
300     }
301
302     if(type<0) {
303         while(1) {
304             int ret = MessageBox(0, text, "Error", MB_RETRYCANCEL|MB_ICONERROR);
305             
306             /* there is no MB_CANCEL, so, *sigh*, we have to display
307                the "retry" button. So pretend it's doing anything... */
308             if(ret==IDRETRY)
309                 continue;
310             else
311                 break;
312         }
313     }
314 }
315
316 static int regEnter(char*key,char*value)
317 {
318     HKEY hkey;
319     int ret = 0;
320     ret = RegCreateKey(HKEY_LOCAL_MACHINE, key, &hkey);
321     if(ret != ERROR_SUCCESS) {
322         fprintf(stderr, "registry: CreateKey %s failed\n", key);
323         return 0;
324     }
325     ret = RegSetValue(hkey, NULL, REG_SZ, value, strlen(value)+1);
326     if(ret != ERROR_SUCCESS) {
327         fprintf(stderr, "registry: SetValue %s failed\n", key);
328         return 0;
329     }
330     return 1;
331 }
332
333 int addRegistryEntries(char*install_dir)
334 {
335     int ret;
336     ret = regEnter("Software\\quiss.org\\swftools\\InstallPath", install_dir);
337     if(!ret) return 0;
338     return 1;
339 }
340
341 int WINAPI WinMain(HINSTANCE me,HINSTANCE hPrevInst,LPSTR lpszArgs, int nWinMode)
342 {
343     WNDCLASSEX wcl;
344     char*install_dir = "C:\\swftools\\";
345
346     wcl.hInstance    = me;
347     wcl.lpszClassName= "SWFTools-Installer";
348     wcl.lpfnWndProc  = WindowFunc;
349     wcl.style        = CS_HREDRAW | CS_VREDRAW;
350     wcl.hIcon        = LoadIcon(NULL, IDI_APPLICATION);
351     wcl.hIconSm      = LoadIcon(NULL, IDI_APPLICATION);
352     wcl.hCursor      = LoadCursor(NULL, IDC_ARROW);
353     wcl.lpszMenuName = NULL; //no menu
354     wcl.cbClsExtra   = 0;
355     wcl.cbWndExtra   = 0;
356     //wcl.hbrBackground= (HBRUSH) GetStockObject(DKGRAY_BRUSH);
357     wcl.hbrBackground= (HBRUSH) GetStockObject (WHITE_BRUSH);
358     wcl.cbSize       = sizeof(WNDCLASSEX);
359
360     if(!RegisterClassEx (&wcl)) {
361         return 0;
362     }
363
364     InitCommonControls();
365    
366     CreateWindow (
367             wcl.lpszClassName,          /* Class name */
368             "SWFTools Installer",            /* Caption */
369             WS_OVERLAPPEDWINDOW&(~WS_SIZEBOX),        /* Style */
370             CW_USEDEFAULT,              /* Initial x (use default) */
371             CW_USEDEFAULT,              /* Initial y (use default) */
372             320,                        /* Initial x size */
373             200,                        /* Initial y size */
374             NULL,                       /* No parent window */
375             NULL,                       /* No menu */
376             me,                         /* This program instance */
377             (void*)"params"             /* Creation parameters */
378             );
379     ShowWindow (wnd_params, nWinMode);
380     UpdateWindow (wnd_params);
381    
382     MSG msg;
383     while(wnd_params)
384     {
385         GetMessage(&msg,NULL,0,0);
386         TranslateMessage(&msg);
387         DispatchMessage(&msg);
388     }
389    
390     char buf[1024];
391     sprintf(buf, "Do you want me to install SWFTools into the directory %s now?", install_dir);
392     int ret = MessageBox(0, buf, "SWFTools Install", MB_YESNO|MB_ICONQUESTION);
393
394     if(ret == IDNO)
395         return 0;
396     
397     CreateWindow (
398             wcl.lpszClassName,          /* Class name */
399             "Installing...",            /* Caption */
400             WS_OVERLAPPEDWINDOW&(~WS_SIZEBOX),        /* Style */
401             CW_USEDEFAULT,              /* Initial x (use default) */
402             CW_USEDEFAULT,              /* Initial y (use default) */
403             260,                        /* Initial x size */
404             128,                        /* Initial y size */
405             NULL,                       /* No parent window */
406             NULL,                       /* No menu */
407             me,                         /* This program instance */
408             (void*)"progress"           /* Creation parameters */
409             );
410     ShowWindow (wnd_progress, nWinMode);
411     UpdateWindow (wnd_progress);
412     
413     int success = unpack_archive(crndata, "C:\\swftools\\", myarchivestatus);
414    
415     DestroyWindow(wnd_progress);
416
417     while(wnd_progress)
418         processMessages();
419
420     if(!addRegistryEntries(install_dir)) {
421         success = 0;
422         ret = MessageBox(0, "Couldn't create Registry Entries", "SWFTools Install", MB_OK|MB_ICONERROR);
423     }
424
425     if(success) {
426         sprintf(buf, "SWFTools Version %s has been installed into %s successfully", VERSION, install_dir);
427         ret = MessageBox(0, buf, "SWFTools Install", MB_OK|MB_ICONINFORMATION);
428     } else {
429         /* error will already have been notified by either myarchivestatus or some other
430            routine */
431         /*sprintf(buf, "Installation failed\nLast message: %s", lastmessage);
432         ret = MessageBox(0, buf, "SWFTools Install", MB_OK|MB_ICONERROR);*/
433     }
434     exit(0);
435 }
436
437
438