1 /* Installer.cpp: Merge7z plugin installer
2 * Copyright (c) 2005 Jochen Tucht
4 * License: This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 * Remarks: Bundles plugins for all supported versions of 7-Zip in a single
19 * installer. Also includes essential components from latest 7-Zip
20 * stable release for optional standalone operation.
21 * Files to be installed are embedded as resources (see Files.rc2).
22 * The resulting exe must be run through UPX (upx.sourceforge.net)
25 Please mind 2. a) of the GNU General Public License, and log your changes below.
27 DATE: BY: DESCRIPTION:
28 ========== ================== ================================================
29 2005-01-15 Jochen Tucht Created
30 2005-02-28 Jochen Tucht Initialize filename in Open dialog to "*.exe"
31 2005-04-26 Jochen Tucht No default assumption on program directory
32 Double-click option for in-place extraction
33 Fix empty path issue with GetFileTitle()
34 Accept extraction folder on command line
35 Batch options: /standalone, /select, /commit
36 2005-05-30 Jochen Tucht Standalone option now based on 7z420
37 2005-06-28 Jochen Tucht Standalone option now based on 7z423
38 2005-12-04 Jochen Tucht Standalone option now based on 7z431
39 2005-12-09 Jochen Tucht Standalone option now based on 7z432
40 2006-06-28 Jochen Neubeck Standalone option now based on 7z442
41 2007-12-22 Jochen Neubeck Standalone option now based on 7z457
46 #define VERSION7Z 4.57
48 #pragma intrinsic(memset) // do not depend on CRT
51 #define SHARPEN2(X) SHARPEN(X)
53 // Compute dwBuild from revision.txt
54 static const DWORD dwBuild =
57 # define VERSION(MAJOR,MINOR)
58 # include "../Merge7z/revision.txt"
62 static SYSTEMTIME st = {0,0,0,0,0,0,0,0};
64 LPTSTR NTAPI ArgLower(LPTSTR lpCmdLine)
66 while (*lpCmdLine == VK_SPACE)
71 LPTSTR NTAPI ArgUpper(LPTSTR lpCmdLine)
73 TCHAR cSpace = VK_SPACE;
74 while (*lpCmdLine && *lpCmdLine != cSpace)
76 if (*lpCmdLine == '"')
85 int NTAPI PathGetTailLength(LPCTSTR path)
87 //GetFileTitle() returns garbage when passed in empty path...
88 return *path ? GetFileTitle(path, 0, 0) : 0;
91 void InstallFile(HWND hWnd, LPTSTR lpName, LPCTSTR lpType, LPTSTR path, int cchPath)
93 HMODULE hModule = GetModuleHandle(0);
94 HRSRC hResource = FindResource(hModule, lpName, lpType);
95 DWORD dwSize = SizeofResource(hModule, hResource);
96 LPVOID pResource = LoadResource(hModule, hResource);
97 LPTSTR name = path + cchPath;
100 lstrcpy(name, lpName);
102 int cchName = lstrlen(name);
104 for (i = 0 ; i < cchName ; ++i)
109 CreateDirectory(path, 0);
113 HANDLE hFile = CreateFile(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
114 if (hFile != INVALID_HANDLE_VALUE)
116 DWORD dwNumberOfBytesWritten;
117 BOOL bSuccess = WriteFile(hFile, pResource, dwSize, &dwNumberOfBytesWritten, 0);
119 if (SystemTimeToFileTime(&st, &ft))
121 SetFileTime(hFile, &ft, &ft, &ft);
124 if (!bSuccess || dwNumberOfBytesWritten != dwSize)
126 hFile = INVALID_HANDLE_VALUE;
129 if (hFile == INVALID_HANDLE_VALUE)
131 LONG error = GetLastError();
132 name[cchName++] = '\n';
135 FORMAT_MESSAGE_FROM_SYSTEM,
137 MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT),
138 name + cchName, MAX_PATH, NULL
140 int response = MessageBox(hWnd, path, 0, MB_ICONSTOP|MB_OKCANCEL);
141 if (response == IDCANCEL)
148 BOOL CALLBACK fnPopulateList(HMODULE hModule, LPCTSTR lpType, LPTSTR lpName, LONG lParam)
150 TCHAR acName[MAX_PATH];
151 if (ATOM aName = FindAtom(lpName))
153 GetAtomName(aName, lpName = acName, sizeof acName);
155 SendDlgItemMessage((HWND)lParam, 100, LB_ADDSTRING, 0, (LPARAM)lpName);
159 BOOL CALLBACK fnInstallFiles(HMODULE hModule, LPCTSTR lpType, LPTSTR lpName, LONG lParam)
161 HWND hWnd = (HWND)lParam;
162 TCHAR path[8 * MAX_PATH];
163 int cchPath = GetDlgItemText(hWnd, 203, path, 5 * MAX_PATH);
164 int cchName = PathGetTailLength(path);
165 if (cchName < cchPath)
169 if (cchPath != 3 || path[1] != ':')
171 path[cchPath++] = '\\';
173 TCHAR acName[MAX_PATH];
174 if (ATOM aName = FindAtom(lpName))
176 GetAtomName(aName, lpName = acName, sizeof acName);
178 InstallFile(hWnd, lpName, lpType, path, cchPath);
182 BOOL CALLBACK DlgMain_InitDialog(HWND hWnd, LPARAM lParam)
184 char date[] = __DATE__; // Compilation date "MMM DD YYYY"
186 TCHAR path[5 * MAX_PATH];
187 wsprintf(path + GetWindowText(hWnd, path, MAX_PATH),
188 " (dllbuild %04lu, %s)", dwBuild, date);
189 SetWindowText(hWnd, path);
192 GetDlgItemText(hWnd, 205, fmt, MAX_PATH);
193 wsprintf(path, fmt, SHARPEN2(VERSION7Z));
194 SetDlgItemText(hWnd, 205, path);
197 st.wYear = FindAtom(&date[6]);
200 st.wDay = FindAtom(&date[3]);
203 const char *month = "Jan\0Feb\0Mar\0Apr\0May\0Jun\0Jul\0Aug\0Sep\0Oct\0Nov\0Dec";
204 while (lstrcmpi(month, date))
211 EnumResourceNames(GetModuleHandle(0), "Merge7z", fnPopulateList, (LONG)hWnd);
212 LONG lCount = SendDlgItemMessage(hWnd, 100, LB_GETCOUNT , 0, 0);
213 SendDlgItemMessage(hWnd, 100, LB_SELITEMRANGEEX, 0, lCount - 1);
214 CheckRadioButton(hWnd, 201, 202, 201);
215 BOOL bCommit = FALSE;
216 BOOL bSelect = FALSE;
217 LPTSTR lpCmdLine = GetCommandLine();
218 LPTSTR lpArgLower = ArgLower(lpCmdLine);
219 LPTSTR lpArgUpper = ArgUpper(lpArgLower);
220 while (*(lpArgLower = ArgLower(lpArgUpper)))
222 TCHAR cAhead = *(lpArgUpper = ArgUpper(lpArgLower));
224 if (0 == lstrcmpi(lpArgLower, "/standalone"))
226 CheckRadioButton(hWnd, 201, 202, 202);
227 SendMessage(hWnd, WM_COMMAND, 202, 0);
228 CheckDlgButton(hWnd, 205, 1);
229 SendMessage(hWnd, WM_COMMAND, 205, 0);
231 else if (0 == lstrcmpi(lpArgLower, "/select"))
235 *lpArgUpper = cAhead;
236 if (*(lpArgLower = ArgLower(lpArgUpper)))
238 cAhead = *(lpArgUpper = ArgUpper(lpArgLower));
240 lower = SendDlgItemMessage(hWnd, 100, LB_FINDSTRING, -1, (LPARAM)lpArgLower);
243 MessageBox(hWnd, lpArgLower, "No match", MB_ICONSTOP);
246 *lpArgUpper = cAhead;
247 if (*(lpArgLower = ArgLower(lpArgUpper)))
249 cAhead = *(lpArgUpper = ArgUpper(lpArgLower));
252 while ((ahead = SendDlgItemMessage(hWnd, 100, LB_FINDSTRING, ahead, (LPARAM)lpArgLower)) > upper)
258 MessageBox(hWnd, lpArgLower, "No match", MB_ICONSTOP);
261 if (lower >= 0 && upper >= 0)
265 SendDlgItemMessage(hWnd, 100, LB_SETSEL, 0, -1);
268 SendDlgItemMessage(hWnd, 100, LB_SELITEMRANGEEX, lower, upper);
271 else if (0 == lstrcmpi(lpArgLower, "/commit"))
276 else if (0 == lstrcmpi(lpArgLower, "\"ping pong\""))
278 MessageBox(hWnd, "", lpArgLower, 0);
282 DWORD dwAttributes = GetFileAttributes(lpArgLower);
283 if (dwAttributes != 0xFFFFFFFF && dwAttributes & FILE_ATTRIBUTE_DIRECTORY)
285 lstrcpy(path, lpArgLower);
286 if (PathGetTailLength(path) > 1)
290 lstrcat(path, "*.exe");
291 CheckRadioButton(hWnd, 201, 202, 202);
292 SendMessage(hWnd, WM_COMMAND, 202, 0);
293 SetDlgItemText(hWnd, 203, path);
297 MessageBox(hWnd, lpArgLower, "Not a directory", MB_ICONSTOP);
300 *lpArgUpper = cAhead;
304 SendMessage(hWnd, WM_COMMAND, IDOK, 0);
309 BOOL CALLBACK DlgMain_BrowseExe(HWND hWnd)
314 TCHAR buffer[5 * MAX_PATH];
316 ZeroMemory(&path, sizeof path);
317 path.ofn.lStructSize = sizeof path.ofn;
318 path.ofn.hwndOwner = hWnd;
319 path.ofn.lpstrFile = path.buffer;
320 path.ofn.nMaxFile = sizeof path.buffer;
321 path.ofn.lpstrFilter = "*.exe\0*.exe\0";
322 path.ofn.lpstrTitle = "Browse for application ...";
323 path.ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_LONGNAMES | OFN_PATHMUSTEXIST;
324 int cchPath = GetDlgItemText(hWnd, 203, path.buffer, sizeof path.buffer);
325 int cchName = PathGetTailLength(path.buffer);
326 if (cchName < cchPath)
328 lstrcpy(path.buffer + cchPath - cchName, "\\*.exe");
330 if (GetOpenFileName(&path.ofn))
332 SetDlgItemText(hWnd, 203, path.buffer);
337 BOOL CALLBACK DlgMain_InstallFiles(HWND hWnd)
339 HCURSOR hCursor = SetCursor(LoadCursor(0, IDC_WAIT));
340 HINSTANCE hModule = GetModuleHandle(0);
341 int count = SendDlgItemMessage(hWnd, 100, LB_GETCOUNT , 0, 0);
343 TCHAR path[8 * MAX_PATH];
345 if (IsDlgButtonChecked(hWnd, 201))
347 cchPath = GetSystemDirectory(path, 4 * MAX_PATH);
351 cchPath = GetDlgItemText(hWnd, 203, path, 5 * MAX_PATH);
352 int cchName = PathGetTailLength(path);
353 if (cchName < cchPath)
358 if (cchPath != 3 || path[1] != ':')
360 path[cchPath++] = '\\';
362 LPTSTR name = path + cchPath;
363 while (index < count)
365 if (SendDlgItemMessage(hWnd, 100, LB_GETSEL, index, 0))
367 int cchName = SendDlgItemMessage(hWnd, 100, LB_GETTEXT, index, (LPARAM)name);
368 InstallFile(hWnd, name, "Merge7z", path, cchPath);
372 if (IsDlgButtonChecked(hWnd, 205))
374 EnumResourceNames(GetModuleHandle(0), "7-ZIP", fnInstallFiles, (LONG)hWnd);
380 BOOL CALLBACK DlgMain_EnableStandalone(HWND hWnd)
382 if (IsDlgButtonChecked(hWnd, 205))
385 const UINT major = UINT(VERSION7Z);
386 const UINT minor = UINT(VERSION7Z * 100) % 100;
387 wsprintf(buffer, "Merge7z%u%02u.dll", major, minor);
388 int lower = SendDlgItemMessage(hWnd, 100, LB_FINDSTRINGEXACT, -1, (LPARAM)buffer);
389 wsprintf(buffer, "Merge7z%u%02uU.dll", major, minor);
390 int upper = SendDlgItemMessage(hWnd, 100, LB_FINDSTRINGEXACT, -1, (LPARAM)buffer);
391 SendDlgItemMessage(hWnd, 100, LB_SELITEMRANGEEX, lower, upper);
392 if (GetFocus() == GetDlgItem(hWnd, 205))
394 SendDlgItemMessage(hWnd, 100, LB_SETTOPINDEX, lower, 0);
400 BOOL CALLBACK DlgMain(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
402 TCHAR path[8 * MAX_PATH];
406 return DlgMain_InitDialog(hWnd, lParam);
411 CheckDlgButton(hWnd, 205, 0);
414 EnableWindow(GetDlgItem(hWnd, 203), wParam == 202);
415 EnableWindow(GetDlgItem(hWnd, 204), wParam == 202);
416 EnableWindow(GetDlgItem(hWnd, 205), wParam == 202);
417 SetDlgItemText(hWnd, 203, "");
419 case MAKELONG(202, BN_DOUBLECLICKED):
420 GetModuleFileName(0, path, sizeof path);
421 SetDlgItemText(hWnd, 203, path);
423 case MAKELONG(203, EN_CHANGE):
424 EnableWindow(GetDlgItem(hWnd, IDOK), GetWindowTextLength((HWND)lParam) || IsDlgButtonChecked(hWnd, 201));
427 return DlgMain_BrowseExe(hWnd);
429 if (IsDlgButtonChecked(hWnd, 205) && GetKeyState(VK_SHIFT) >= 0)
430 SendDlgItemMessage(hWnd, 100, LB_SETSEL, 0, -1);
432 case MAKELONG(100, LBN_SELCHANGE):
433 return DlgMain_EnableStandalone(hWnd);
434 case IDOK: if (DlgMain_InstallFiles(hWnd)) case IDCANCEL:
435 EndDialog(hWnd, wParam);
443 void WinMainCRTStartup(void)
445 InitAtomTable(0x3001);
446 HINSTANCE hModule = GetModuleHandle(0);
447 HRSRC hResource = FindResource(hModule, "Files.rc2", RT_RCDATA);
448 char *q = (char *)LoadResource(hModule, hResource);
449 DWORD n = SizeofResource(hModule, hResource);
450 char directive[MAX_PATH];
451 char arguments[MAX_PATH];
462 if (*directive == '\n')
477 DialogBoxParam(hModule, MAKEINTRESOURCE(100), 0, DlgMain, 0);