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