3 Part of the rfx installer (Main program).
5 Copyright (c) 2004-2008 Matthias Kramm <kramm@quiss.org>
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.
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.
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 */
28 #include "installer.h"
34 static int config_forAllUsers
= 0;
35 static int config_createLinks
= 0;
36 static int config_createStartmenu
= 1;
37 static int config_createDesktop
= 1;
38 static int config_deleteextra
= 1;
40 static char path_startmenu
[MAX_PATH
] = "\0";
41 static char path_desktop
[MAX_PATH
] = "\0";
42 static char path_programfiles
[MAX_PATH
] = "\0";
44 static char pathBuf
[MAX_PATH
];
45 static int do_abort
= 0;
47 static char* pdf2swf_dir
;
48 static char* pdf2swf_path
;
50 static char registry_path
[1024];
52 static char elevated
= 0;
54 static char*install_path
= "c:\\swftools\\";
55 #define SOFTWARE_DOMAIN "quiss.org"
56 #define SOFTWARE_NAME "SWFTools"
57 #define INSTALLER_NAME "SWFTools Installer"
59 static HBITMAP logo
= 0;
63 #define USER_SETMESSAGE 0x7f01
67 extern int crndata_len
;
68 extern int crn_decompressed_size
;
69 extern char*license_text
;
71 #include "background.c"
74 typedef struct _filelist
77 struct _filelist
*next
;
81 static filelist_t
* registerFile(filelist_t
*next
, const char*filename
, char type
)
83 filelist_t
*file
= malloc(sizeof(filelist_t
));
84 file
->filename
= strdup(filename
);
90 static filelist_t
* readFileList(char*filename
)
92 FILE*fi
= fopen(filename
, "rb");
96 fseek(fi
, 0, SEEK_END
);
98 fseek(fi
, 0, SEEK_SET
);
99 char*data
= malloc(len
+1);
100 fread(data
, len
, 1, fi
);
104 filelist_t
*list
= 0,*lpos
=0;;
106 if(data
[t
]=='\r' || data
[t
]=='\n') {
108 if(strchr("DFI", line
[0]) && line
[1]==' ' && line
[2]!=' ') {
109 filelist_t
*f
= malloc(sizeof(filelist_t
));
111 f
->filename
=strdup(line
+2);
120 // skip line- this usually only happens if somebody tampered
123 while(t
<len
&& (data
[t
]=='\0' || data
[t
]=='\r' || data
[t
]=='\n'))
133 static void writeFileList(filelist_t
*file
, const char*filename
)
135 FILE*fi
= fopen(filename
, "wb");
136 fprintf(fi
, "[%s installed files]\r\n", SOFTWARE_NAME
);
139 sprintf(buf
, "Couldn't write file %s", filename
);
140 MessageBox(0, buf
, INSTALLER_NAME
, MB_OK
|MB_ICONERROR
);
145 fprintf(fi
, "%c %s\r\n", file
->type
, file
->filename
);
151 static filelist_t
*installedFiles
= 0;
153 static void addFile(const char*filename
)
155 installedFiles
= registerFile(installedFiles
, filename
, 'F');
157 static void addDir(const char*filename
)
159 installedFiles
= registerFile(installedFiles
, filename
, 'D');
162 static void handleTemplateFile(const char*filename
)
164 FILE*fi
= fopen(filename
, "rb");
165 fseek(fi
, 0, SEEK_END
);
167 fseek(fi
, 0, SEEK_SET
);
168 char*file
= malloc(len
+1);
169 fread(file
, len
, 1, fi
);
171 int l
= strlen(install_path
);
172 fi
= fopen(filename
, "wb");
176 pos
= strstr(pos
, "%%PATH%%");
182 fwrite(lastpos
, pos
-lastpos
, 1, fi
);
183 fwrite(install_path
, l
, 1, fi
);
184 pos
+=8; // length of "%%PATH%%"
187 fwrite(lastpos
, pos
-lastpos
, 1, fi
);
192 static int setRegistryEntry(char*key
,char*value
)
196 int ret1
= -1, ret2
= -1;
197 ret1
= RegCreateKey(HKEY_CURRENT_USER
, key
, &hkey1
);
198 if(config_forAllUsers
) {
199 ret2
= RegCreateKey(HKEY_LOCAL_MACHINE
, key
, &hkey2
);
203 fprintf(stderr
, "registry: CreateKey %s failed\n", key
);
207 installedFiles
= registerFile(installedFiles
, key
, 'k');
210 installedFiles
= registerFile(installedFiles
, key
, 'K');
214 ret1
= RegSetValue(hkey1
, NULL
, REG_SZ
, value
, strlen(value
)+1);
216 ret2
= RegSetValue(hkey2
, NULL
, REG_SZ
, value
, strlen(value
)+1);
218 fprintf(stderr
, "registry: SetValue %s failed\n", key
);
225 static char* getRegistryEntry(char*path
)
233 rc
= RegOpenKeyEx(HKEY_LOCAL_MACHINE
, path
, 0, KEY_ALL_ACCESS
/* KEY_READ*/, &key
);
234 if (rc
!= ERROR_SUCCESS
) {
235 fprintf(stderr
, "RegOpenKeyEx failed\n");
238 rc
= RegQueryValueEx(key
, NULL
, 0, 0, 0, (LPDWORD
)&size
) ;
239 if(rc
!= ERROR_SUCCESS
) {
240 fprintf(stderr
, "RegQueryValueEx(1) failed: %d\n", rc
);
243 buf
= (char*)malloc(size
+1);
244 rc
= RegQueryValueEx(key
, NULL
, 0, &type
, (BYTE
*)buf
, (LPDWORD
)&size
);
245 if(rc
!= ERROR_SUCCESS
) {
246 fprintf(stderr
, "RegQueryValueEx(2) failed: %d\n", rc
);
249 if(type
== REG_SZ
|| type
== REG_EXPAND_SZ
) {
250 while(size
&& buf
[size
-1] == '\0')
255 } else if(type
== REG_BINARY
) {
260 static int has_full_access
= 0;
261 static char hasFullAccess()
263 /* find out whether we can write keys in HKEY_LOCAL_MACHINE */
265 int ret
= RegOpenKeyEx(HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall", 0,
266 KEY_CREATE_SUB_KEY
, &hKey
);
275 void processMessages()
278 while(PeekMessage(&msg
,NULL
,0,0,0))
280 GetMessage(&msg
, NULL
, 0, 0);
281 TranslateMessage(&msg
);
282 DispatchMessage(&msg
);
286 int addRegistryEntries(char*install_dir
)
289 ret
= setRegistryEntry(registry_path
, install_dir
);
294 int CreateShortcut(char*path
, char*description
, char*filename
, char*arguments
, int iconindex
, char*iconpath
, char*workdir
)
296 printf("Creating %s -> %s\n", filename
, path
);
297 WCHAR wszFilename
[MAX_PATH
];
298 IShellLink
*ps1
= NULL
;
299 IPersistFile
*pPf
= NULL
;
301 hr
= CoCreateInstance(&CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IShellLink
, (void*)&ps1
);
302 if(FAILED(hr
)) return 0;
303 hr
= ps1
->lpVtbl
->QueryInterface(ps1
, &IID_IPersistFile
, (void **)&pPf
);
304 if(FAILED(hr
)) return 0;
305 hr
= ps1
->lpVtbl
->SetPath(ps1
, path
);
306 if(FAILED(hr
)) return 0;
307 hr
= ps1
->lpVtbl
->SetDescription(ps1
, description
);
310 hr
= ps1
->lpVtbl
->SetArguments(ps1
, arguments
);
311 if(FAILED(hr
)) return 0;
314 hr
= ps1
->lpVtbl
->SetIconLocation(ps1
, iconpath
, iconindex
);
315 if (FAILED(hr
)) return 0;
318 hr
= ps1
->lpVtbl
->SetWorkingDirectory(ps1
, workdir
);
319 if (FAILED(hr
)) return 0;
321 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, wszFilename
, MAX_PATH
);
322 hr
= pPf
->lpVtbl
->Save(pPf
, wszFilename
, TRUE
);
326 pPf
->lpVtbl
->Release(pPf
);
327 ps1
->lpVtbl
->Release(ps1
);
332 static int CreateURL(const char*url
, const char*path
)
334 FILE*fi
= fopen(path
, "wb");
337 fprintf(fi
, "[InternetShortcut]\r\n");
338 fprintf(fi
, "URL=http://localhost:8081/\r\n");
345 BOOL CALLBACK
PropertySheetFuncCommon(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
, int buttons
)
349 HWND dialog
= GetParent(hwnd
);
351 if(message
== WM_INITDIALOG
) {
353 SendDlgItemMessage(hwnd
, IDC_BITMAP
, STM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
)logo
);
356 GetWindowRect(dialog
, &rc
);
357 int width
= rc
.right
- rc
.left
;
358 int height
= rc
.bottom
- rc
.top
;
359 MoveWindow(dialog
, (GetSystemMetrics(SM_CXSCREEN
) - width
)/2, (GetSystemMetrics(SM_CYSCREEN
) - height
)/2, width
, height
, FALSE
);
363 if(message
== WM_NOTIFY
&& (((LPNMHDR
)lParam
)->code
== PSN_SETACTIVE
)) {
364 PropSheet_SetWizButtons(dialog
, buttons
);
371 BOOL CALLBACK
PropertySheetFunc1(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
) {
372 if(message
== WM_INITDIALOG
) {
373 SetDlgItemText(hwnd
, IDC_LICENSE
, license_text
);
375 return PropertySheetFuncCommon(hwnd
, message
, wParam
, lParam
, PSWIZB_NEXT
);
377 BOOL CALLBACK
PropertySheetFunc2(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
) {
378 if(message
== WM_INITDIALOG
) {
379 SetDlgItemText(hwnd
, IDC_INSTALL_PATH
, install_path
);
381 SendDlgItemMessage(hwnd
, IDC_ALLUSERS
, BM_SETCHECK
, config_forAllUsers
, 0);
382 SendDlgItemMessage(hwnd
, IDC_CURRENTUSER
, BM_SETCHECK
, config_forAllUsers
^1, 0);
384 if(message
== WM_COMMAND
) {
385 if((wParam
&0xffff) == IDC_BROWSE
) {
387 memset(&browse
, 0, sizeof(browse
));
388 browse
.ulFlags
= BIF_EDITBOX
| BIF_NEWDIALOGSTYLE
| BIF_USENEWUI
;// | BIF_RETURNONLYFSDIRS; //BIF_VALIDATE
389 browse
.pszDisplayName
= (CHAR
*)malloc(MAX_PATH
);
390 memset(browse
.pszDisplayName
, 0, MAX_PATH
);
391 browse
.lpszTitle
= "Select installation directory";
392 browse
.pidlRoot
= SHBrowseForFolder(&browse
);
393 if(browse
.pszDisplayName
) {
394 if(SHGetPathFromIDList(browse
.pidlRoot
, browse
.pszDisplayName
)) {
395 install_path
= browse
.pszDisplayName
;
396 int l
= strlen(install_path
);
397 while(l
&& install_path
[l
-1]=='\\') {
402 SendDlgItemMessage(hwnd
, IDC_INSTALL_PATH
, WM_SETTEXT
, 0, (LPARAM
)install_path
);
406 else if((wParam
&0xffff) == IDC_ALLUSERS
) {
407 config_forAllUsers
= 1;
408 SendDlgItemMessage(hwnd
, IDC_ALLUSERS
, BM_SETCHECK
, config_forAllUsers
, 0);
409 SendDlgItemMessage(hwnd
, IDC_CURRENTUSER
, BM_SETCHECK
, config_forAllUsers
^1, 0);
411 else if((wParam
&0xffff) == IDC_CURRENTUSER
) {
412 config_forAllUsers
= 0;
413 SendDlgItemMessage(hwnd
, IDC_ALLUSERS
, BM_SETCHECK
, config_forAllUsers
, 0);
414 SendDlgItemMessage(hwnd
, IDC_CURRENTUSER
, BM_SETCHECK
, config_forAllUsers
^1, 0);
416 else if((wParam
&0xffff) == IDC_INSTALL_PATH
) {
417 SendDlgItemMessage(hwnd
, IDC_INSTALL_PATH
, WM_GETTEXT
, sizeof(pathBuf
), (LPARAM
)&(pathBuf
[0]));
419 install_path
= pathBuf
;
420 int l
= strlen(install_path
);
421 while(l
&& install_path
[l
-1]=='\\') {
428 if(message
== WM_NOTIFY
&& (((LPNMHDR
)lParam
)->code
== PSN_SETACTIVE
)) {
429 if(!elevated
&& !has_full_access
) {
430 OSVERSIONINFO winverinfo
;
431 memset(&winverinfo
, 0, sizeof(OSVERSIONINFO
));
432 winverinfo
.dwOSVersionInfoSize
= sizeof(winverinfo
);
433 if (GetVersionEx(&winverinfo
) && winverinfo
.dwMajorVersion
>= 5) {
434 /* we're on Vista, were asked to install for all users, but don't have
435 priviledges to do so. Ask to spawn the process elevated. */
436 char exename
[MAX_PATH
];
437 GetModuleFileName(NULL
, exename
, sizeof(exename
));
438 if((int)ShellExecute(0, "runas", exename
, "elevated", NULL
, SW_SHOWNORMAL
)>32) {
439 /* that worked- the second process will do the work */
445 return PropertySheetFuncCommon(hwnd
, message
, wParam
, lParam
, PSWIZB_BACK
|PSWIZB_NEXT
);
448 static int progress_pos
= 0;
450 void PropertyArchiveError(char*text
)
453 int ret
= MessageBox(0, text
, "Error", MB_RETRYCANCEL
|MB_ICONERROR
);
454 if(ret
==IDRETRY
) continue;
459 void PropertyArchive_NewFile(char*filename
)
464 void PropertyArchive_NewDirectory(char*filename
)
470 static int lastlen
= 0;
471 void PropertyArchiveStatus(int pos
, int len
)
474 SendDlgItemMessage(statuswnd
, IDC_PROGRESS
, PBM_SETRANGE
, 0, (LPARAM
)MAKELONG(0,len
));
477 SendDlgItemMessage(statuswnd
, IDC_PROGRESS
, PBM_SETPOS
, pos
, 0);
481 void PropertyArchiveMessage(char*text
)
483 if(text
&& text
[0]=='[') {
486 SetDlgItemText(statuswnd
, IDC_INFO
, strdup(text
));
490 void print_space(char*dest
, char*msg
, ULONGLONG size
)
493 sprintf(dest
, "%s%d Bytes", msg
, size
);
494 else if(size
< 1048576l)
495 sprintf(dest
, "%s%.2f Kb", msg
, size
/1024.0);
496 else if(size
< 1073741824l)
497 sprintf(dest
, "%s%.2f Mb", msg
, size
/1048576.0);
498 else if(size
< 1099511627776ll)
499 sprintf(dest
, "%s%.2f Gb", msg
, size
/1073741824.0);
501 sprintf(dest
, "%s%.2f Tb", msg
, size
/1125899906842624.0);
504 BOOL CALLBACK
PropertySheetFunc3(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
) {
505 HWND dialog
= GetParent(hwnd
);
506 if(message
== WM_INITDIALOG
) {
507 SetDlgItemText(hwnd
, IDC_INFO
, "Ready to install");
510 print_space(buf
, "Space required: ", crn_decompressed_size
);
511 SetDlgItemText(hwnd
, IDC_SPACE1
, buf
);
512 ULARGE_INTEGER available
,total
,totalfree
;
513 available
.QuadPart
=0;
515 totalfree
.QuadPart
=0;
516 if(GetDiskFreeSpaceEx(install_path
, &available
, &total
, &totalfree
)) {
517 print_space(buf
, "Space available: ", available
.QuadPart
);
519 sprintf(buf
, "Space available: [Error %d]", GetLastError());
520 if((GetLastError() == ERROR_FILE_NOT_FOUND
|| GetLastError() == ERROR_PATH_NOT_FOUND
)
521 && install_path
[0] && install_path
[1]==':') {
522 /* installation directory does not yet exist */
523 char path
[3]={'c',':',0};
524 path
[0] = install_path
[0];
525 if(GetDiskFreeSpaceEx(path
, &available
, &total
, &totalfree
)) {
526 print_space(buf
, "Space available: ", available
.QuadPart
);
530 SetDlgItemText(hwnd
, IDC_SPACE2
, buf
);
532 if(message
== WM_NOTIFY
&& (((LPNMHDR
)lParam
)->code
== PSN_WIZNEXT
)) {
533 SetDlgItemText(hwnd
, IDC_SPACE1
, "");
534 SetDlgItemText(hwnd
, IDC_SPACE2
, "");
535 PropSheet_SetWizButtons(dialog
, 0);
536 SendMessage(dialog
, PSM_CANCELTOCLOSE
, 0, 0); //makes wine display a warning
537 SetDlgItemText(hwnd
, IDC_TITLE
, "Installing...");
540 status
.status
= PropertyArchiveStatus
;
541 status
.message
= PropertyArchiveMessage
;
542 status
.error
= PropertyArchiveError
;
543 status
.new_file
= PropertyArchive_NewFile
;
544 status
.new_directory
= PropertyArchive_NewDirectory
;
545 int success
= unpack_archive(crndata
, crndata_len
, install_path
, &status
);
546 memset(&status
, 0, sizeof(status_t
));
548 MessageBox(0, "Couldn't extract all installation files", INSTALLER_NAME
, MB_OK
|MB_ICONERROR
);
554 return PropertySheetFuncCommon(hwnd
, message
, wParam
, lParam
, PSWIZB_BACK
|PSWIZB_NEXT
);
557 static HRESULT (WINAPI
*f_SHGetSpecialFolderPath
)(HWND hwnd
, LPTSTR lpszPath
, int nFolder
, BOOL fCreate
);
559 BOOL CALLBACK
PropertySheetFunc4(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
) {
560 if(message
== WM_INITDIALOG
) {
561 pdf2swf_dir
= install_path
; //concatPaths(install_path, "gpdf2swf");
562 pdf2swf_path
= concatPaths(pdf2swf_dir
, "gpdf2swf.exe");
563 FILE*fi
= fopen(pdf2swf_path
, "rb");
565 printf("a GUI program exists, creating desktop/startmenu links\n");
566 config_createLinks
= 1;
569 config_createLinks
= 0;
570 config_createStartmenu
= 0;
571 config_createDesktop
= 0;
573 if(!config_createLinks
) {
574 SendDlgItemMessage(hwnd
, IDC_STARTMENU
, BN_DISABLE
, 0, 0);
575 SendDlgItemMessage(hwnd
, IDC_DESKTOP
, BN_DISABLE
, 0, 0);
578 SendDlgItemMessage(hwnd
, IDC_STARTMENU
, BM_SETCHECK
, config_createStartmenu
, 0);
579 SendDlgItemMessage(hwnd
, IDC_DESKTOP
, BM_SETCHECK
, config_createDesktop
, 0);
581 if(message
== WM_COMMAND
) {
582 if((wParam
&0xffff) == IDC_STARTMENU
) {
583 config_createStartmenu
= SendDlgItemMessage(hwnd
, IDC_STARTMENU
, BM_GETCHECK
, 0, 0);
584 if(config_createLinks
) {
585 config_createStartmenu
^=1;
587 SendDlgItemMessage(hwnd
, IDC_STARTMENU
, BM_SETCHECK
, config_createStartmenu
, 0);
590 if((wParam
&0xffff) == IDC_DESKTOP
) {
591 config_createDesktop
= SendDlgItemMessage(hwnd
, IDC_DESKTOP
, BM_GETCHECK
, 0, 0);
592 if(config_createLinks
) {
593 config_createDesktop
^=1;
595 SendDlgItemMessage(hwnd
, IDC_DESKTOP
, BM_SETCHECK
, config_createDesktop
, 0);
600 if(message
== WM_NOTIFY
&& (((LPNMHDR
)lParam
)->code
== PSN_WIZFINISH
)) {
601 if(!addRegistryEntries(install_path
)) {
602 MessageBox(0, "Couldn't create Registry Entries", INSTALLER_NAME
, MB_OK
|MB_ICONERROR
);
606 char mypath
[MAX_PATH
];
607 path_startmenu
[0] = 0;
609 if(config_forAllUsers
) {
610 f_SHGetSpecialFolderPath(NULL
, path_desktop
, CSIDL_COMMON_DESKTOPDIRECTORY
, 0);
611 f_SHGetSpecialFolderPath(NULL
, path_startmenu
, CSIDL_COMMON_PROGRAMS
, 0);
613 /* get local program/desktop directory- this is both for forAllUsers=0 as well
614 as a fallback if the above didn't return any paths */
615 if(!path_startmenu
[0]) {
616 f_SHGetSpecialFolderPath(NULL
, path_startmenu
, CSIDL_PROGRAMS
, 0);
618 if(!path_desktop
[0]) {
619 f_SHGetSpecialFolderPath(NULL
, path_desktop
, CSIDL_DESKTOPDIRECTORY
, 0);
622 char*uninstall_path
= concatPaths(install_path
, "uninstall.exe");
624 if(config_createLinks
) {
625 if(config_createDesktop
&& path_desktop
[0]) {
626 char* linkName
= concatPaths(path_desktop
, "pdf2swf.lnk");
627 printf("Creating desktop link %s -> %s\n", linkName
, pdf2swf_path
);
628 if(!CreateShortcut(pdf2swf_path
, "pdf2swf", linkName
, 0, 0, 0, pdf2swf_dir
)) {
629 MessageBox(0, "Couldn't create desktop shortcut", INSTALLER_NAME
, MB_OK
);
633 if(config_createStartmenu
&& path_startmenu
[0]) {
634 char* group
= concatPaths(path_startmenu
, "pdf2swf");
635 CreateDirectory(group
, 0);
637 char* linkName
= concatPaths(group
, "pdf2swf.lnk");
638 if(!CreateShortcut(pdf2swf_path
, "pdf2swf", concatPaths(group
, "pdf2swf.lnk"), 0, 0, 0, pdf2swf_dir
) ||
639 !CreateShortcut(uninstall_path
, "uninstall", concatPaths(group
, "uninstall.lnk"), 0, 0, 0, install_path
)) {
640 MessageBox(0, "Couldn't create start menu entry", INSTALLER_NAME
, MB_OK
);
645 printf("not creating desktop/startmenu links\n");
648 char*uninstall_ini
= concatPaths(install_path
, "uninstall.ini");
649 addFile(uninstall_ini
);
650 writeFileList(installedFiles
, uninstall_ini
);
652 return PropertySheetFuncCommon(hwnd
, message
, wParam
, lParam
, PSWIZB_FINISH
);
658 void findfiles(char*path
, int*pos
, char*data
, int len
, char del
)
660 WIN32_FIND_DATA findFileData
;
661 HANDLE hFind
= FindFirstFile(concatPaths(path
, "*"), &findFileData
);
662 if(hFind
== INVALID_HANDLE_VALUE
)
665 if(findFileData
.cFileName
[0] == '.' &&
666 (findFileData
.cFileName
[0] == '.' || findFileData
.cFileName
== '\0'))
668 char*f
= concatPaths(path
, findFileData
.cFileName
);
669 if(findFileData
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) {
670 findfiles(f
, pos
, data
, len
, del
);
671 /* always try to remove directories- if they are empty, this
672 will work, and they won't prevent superdirectory deletion later */
677 /* don't list the uninstaller as file- it's going to be removed *after*
678 everything else is done */
679 char*uninstaller
="uninstall.exe";
680 int ll
= strlen(uninstaller
);
682 if(!strcasecmp(&f
[l
-ll
],uninstaller
)) {
689 memcpy(&data
[*pos
], f
, l
);(*pos
)+=l
;
690 data
[(*pos
)++] = '\r';
691 data
[(*pos
)++] = '\n';
701 } while(FindNextFile(hFind
, &findFileData
));
705 static char*extrafiles
= 0;
707 BOOL CALLBACK
PropertySheetFunc5(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
) {
708 HWND dialog
= GetParent(hwnd
);
709 if(message
== WM_INITDIALOG
) {
710 SetDlgItemText(hwnd
, IDC_INFO
, "Ready to uninstall");
712 if(message
== WM_NOTIFY
&& (((LPNMHDR
)lParam
)->code
== PSN_WIZNEXT
)) {
714 filelist_t
* list
= readFileList("uninstall.ini");
716 list
= readFileList(concatPaths(install_path
, "uninstall.ini"));
718 //Don't abort. If there's still something there, it'll be catched by the "extra files"
719 //functionality later
720 //MessageBox(0, "Couldn't determine installed files list- did you run uninstall twice?", INSTALLER_NAME, MB_OK);
724 filelist_t
* l
= list
;
726 while(l
) {num
++;l
=l
->next
;}
728 PropSheet_SetWizButtons(dialog
, 0);
729 SendMessage(dialog
, PSM_CANCELTOCLOSE
, 0, 0);
730 SetDlgItemText(hwnd
, IDC_TITLE
, "Uninstalling files...");
731 SendDlgItemMessage(hwnd
, IDC_PROGRESS
, PBM_SETRANGE
, 0, (LPARAM
)MAKELONG(0,num
));
735 SendDlgItemMessage(hwnd
, IDC_PROGRESS
, PBM_SETPOS
, num
, 0);
737 DeleteFile(l
->filename
);
738 else if(l
->type
=='D')
739 RemoveDirectory(l
->filename
);
740 else if(l
->type
=='I')
741 /* skip- we will remove ourselves later */;
746 findfiles(install_path
, &len
, 0, 0, 0);
748 extrafiles
= malloc(len
);
750 findfiles(install_path
, &pos
, extrafiles
, len
, 0);
752 PropSheet_RemovePage(dialog
, 1, 0);
756 return PropertySheetFuncCommon(hwnd
, message
, wParam
, lParam
, PSWIZB_BACK
|PSWIZB_NEXT
);
759 BOOL CALLBACK
PropertySheetFunc6(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
) {
760 if(message
== WM_INITDIALOG
) {
761 SendDlgItemMessage(hwnd
, IDC_DELETEEXTRA
, BM_SETCHECK
, config_deleteextra
, 0);
763 SetDlgItemText(hwnd
, IDC_FILELIST
, extrafiles
);
766 if(message
== WM_COMMAND
) {
767 if((wParam
&0xffff) == IDC_DELETEEXTRA
) {
768 config_deleteextra
= SendDlgItemMessage(hwnd
, IDC_DELETEEXTRA
, BM_GETCHECK
, 0, 0);
769 config_deleteextra
^=1;
770 SendDlgItemMessage(hwnd
, IDC_DELETEEXTRA
, BM_SETCHECK
, config_deleteextra
, 0);
774 if(message
== WM_NOTIFY
&& (((LPNMHDR
)lParam
)->code
== PSN_WIZNEXT
)) {
775 if(config_deleteextra
) {
777 findfiles(install_path
, &pos
, 0, 0, 1);
780 return PropertySheetFuncCommon(hwnd
, message
, wParam
, lParam
, PSWIZB_NEXT
);
783 BOOL CALLBACK
PropertySheetFunc7(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
) {
784 if(message
== WM_INITDIALOG
) {
787 return PropertySheetFuncCommon(hwnd
, message
, wParam
, lParam
, PSWIZB_FINISH
);
791 #ifndef PSP_HIDEHEADER
792 #define PSP_HIDEHEADER 2048
795 typedef struct _wizardpage
{
800 void runPropertySheet(HWND parent
)
802 PROPSHEETHEADER sheet
;
804 wizardpage_t wpage
[5] = {
806 {PropertySheetFunc1
, IDD_LICENSE
},
807 {PropertySheetFunc2
, IDD_INSTALLDIR
},
808 {PropertySheetFunc3
, IDD_PROGRESS
},
809 {PropertySheetFunc4
, IDD_FINISH
},
811 {PropertySheetFunc5
, IDD_SURE
},
812 {PropertySheetFunc6
, IDD_EXTRAFILES
},
813 {PropertySheetFunc7
, IDD_DEINSTALLED
},
817 int num
= sizeof(wpage
)/sizeof(wpage
[0]);
822 TODO: remove installdir querying, too (pass installdir
823 to second process) */
826 wpage
[t
-1] = wpage
[t
];
832 HPROPSHEETPAGE pages
[num
];
836 memset(&page
, 0, sizeof(PROPSHEETPAGE
));
837 page
.dwSize
= sizeof(PROPSHEETPAGE
);
838 page
.dwFlags
= PSP_DEFAULT
|PSP_HIDEHEADER
;
840 page
.pfnDlgProc
= wpage
[t
].function
;
841 page
.pszTemplate
= MAKEINTRESOURCE(wpage
[t
].resource
);
842 pages
[t
] = CreatePropertySheetPage(&page
);
845 memset(&sheet
, 0, sizeof(PROPSHEETHEADER
));
846 sheet
.dwSize
= sizeof(PROPSHEETHEADER
);
847 sheet
.hInstance
= me
;
848 sheet
.hwndParent
= parent
;
849 sheet
.phpage
= pages
;
850 sheet
.dwFlags
= PSH_WIZARD
;
852 PropertySheet(&sheet
);
857 static void remove_self()
859 char exename
[MAX_PATH
];
860 char batdir
[MAX_PATH
];
861 char batfile
[MAX_PATH
];
865 memset(batdir
, 0, sizeof(batdir
));
867 GetModuleFileName(NULL
, exename
, sizeof(exename
));
868 GetTempPath(MAX_PATH
, batdir
);
869 sprintf(batfile
, "%08x.bat", rand());
871 batname
= concatPaths(batdir
, batfile
);
873 fp
= fopen(batname
, "w");
878 fprintf(fp
, ":Repeat\n");
879 fprintf(fp
, "del \"%s\"\n", exename
);
880 fprintf(fp
, "if exist \"%s\" goto Repeat\n", exename
);
881 fprintf(fp
, "rmdir \"%s\"\n", install_path
);
882 fprintf(fp
, "del \"%s\"\n", batname
);
886 PROCESS_INFORMATION pi
;
887 memset(&si
, 0, sizeof(si
));
888 si
.dwFlags
= STARTF_USESHOWWINDOW
;
889 si
.wShowWindow
= SW_HIDE
;
891 if (CreateProcess(NULL
, batname
, NULL
, NULL
, FALSE
,
892 CREATE_SUSPENDED
| IDLE_PRIORITY_CLASS
,
893 NULL
, "\\", &si
, &pi
)) {
894 SetThreadPriority(pi
.hThread
, THREAD_PRIORITY_IDLE
);
895 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL
);
896 SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS
);
897 CloseHandle(pi
.hProcess
);
898 ResumeThread(pi
.hThread
);
899 CloseHandle(pi
.hThread
);
904 int WINAPI
WinMain(HINSTANCE _me
,HINSTANCE hPrevInst
,LPSTR lpszArgs
, int nWinMode
)
907 sprintf(registry_path
, "Software\\%s\\%s\\InstallPath", SOFTWARE_DOMAIN
, SOFTWARE_NAME
);
910 logo
= LoadBitmap(me
, "LOGO");
912 install_path
= getRegistryEntry(registry_path
);
913 if(!install_path
|| !install_path
[0]) {
914 MessageBox(0, "Couldn't find software installation directory- did you run the uninstallation twice?", INSTALLER_NAME
, MB_OK
);
919 InitCommonControls();
921 runPropertySheet(background
);
927 int WINAPI
WinMain(HINSTANCE _me
,HINSTANCE hPrevInst
,LPSTR lpszArgs
, int nWinMode
)
930 WNDCLASSEX wcl_background
;
931 wcl_background
.hInstance
= me
;
932 wcl_background
.lpfnWndProc
= WindowFunc
;
933 wcl_background
.lpszClassName
= INSTALLER_NAME
;
934 wcl_background
.style
= CS_HREDRAW
| CS_VREDRAW
;
935 wcl_background
.hIcon
= LoadIcon(NULL
, IDI_APPLICATION
);
936 wcl_background
.hIconSm
= LoadIcon(NULL
, IDI_APPLICATION
);
937 wcl_background
.hCursor
= LoadCursor(NULL
, IDC_ARROW
);
938 wcl_background
.lpszMenuName
= NULL
; //no menu
939 wcl_background
.cbClsExtra
= 0;
940 wcl_background
.cbWndExtra
= 0;
941 wcl_background
.hbrBackground
= CreateSolidBrush(RGB(0, 0, 128));
942 wcl_background
.cbSize
= sizeof(WNDCLASSEX
);
944 sprintf(registry_path
, "Software\\%s\\%s\\InstallPath", SOFTWARE_DOMAIN
, SOFTWARE_NAME
);
946 if(lpszArgs
&& strstr(lpszArgs
, "elevated")) {
949 has_full_access
= hasFullAccess();
950 config_forAllUsers
= has_full_access
;
952 HINSTANCE shell32
= LoadLibrary("shell32.dll");
954 MessageBox(0, "Could not load shell32.dll", INSTALLER_NAME
, MB_OK
);
957 f_SHGetSpecialFolderPath
= (HRESULT (WINAPI
*)(HWND
,LPTSTR
,int,BOOL
))GetProcAddress(shell32
, "SHGetSpecialFolderPathA");
958 if(!f_SHGetSpecialFolderPath
) {
959 MessageBox(0, "Could not load shell32.dll", INSTALLER_NAME
, MB_OK
);
963 HRESULT coret
= CoInitialize(NULL
);
965 MessageBox(0, "Could not initialize COM interface", INSTALLER_NAME
, MB_OK
);
969 path_programfiles
[0] = 0;
970 f_SHGetSpecialFolderPath(NULL
, path_programfiles
, CSIDL_PROGRAM_FILES
, 0);
972 if(!RegisterClassEx(&wcl_background
)) {
973 MessageBox(0, "Could not register window background class", INSTALLER_NAME
, MB_OK
);
977 HWND background
= CreateWindow(wcl_background
.lpszClassName
, INSTALLER_NAME
,
979 GetSystemMetrics(SM_CXFULLSCREEN
),
980 GetSystemMetrics(SM_CYFULLSCREEN
),
982 (void*)"background");
985 MessageBox(0, "Could not create installation background window", INSTALLER_NAME
, MB_OK
);
989 ShowWindow(background
, SW_SHOWMAXIMIZED
);
990 SetForegroundWindow(background
);
991 UpdateWindow(background
);
993 logo
= LoadBitmap(me
, "LOGO");
995 install_path
= getRegistryEntry(registry_path
);
996 if(!install_path
|| !install_path
[0]) {
997 if(path_programfiles
[0]) {
998 install_path
= concatPaths(path_programfiles
, SOFTWARE_NAME
);
1000 install_path
= concatPaths("c:\\", SOFTWARE_NAME
);
1004 InitCommonControls();
1006 runPropertySheet(background
);