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