1 ///////////////////////////////////////////////////////////////////////////////
\r
6 #include "../registry.h"
\r
7 #include "../stringtool.h"
\r
8 #include "../windowstool.h"
\r
9 #include "installer.h"
\r
12 #include <sys/types.h>
\r
13 #include <sys/stat.h>
\r
18 using namespace std;
\r
21 /////////////////////////////////////////////////////////////////////////////
\r
22 // Utility Functions
\r
25 uses the shell's IShellLink and IPersistFile interfaces to
\r
26 create and store a shortcut to the specified object.
\r
28 the result of calling the member functions of the interfaces.
\r
30 address of a buffer containing the path of the object.
\r
32 address of a buffer containing the path where the
\r
33 shell link is to be stored.
\r
35 address of a buffer containing the description of the
\r
38 HRESULT createLink(LPCTSTR i_pathObj, LPCTSTR i_pathLink, LPCTSTR i_desc,
\r
39 LPCTSTR i_workingDirectory)
\r
41 // Get a pointer to the IShellLink interface.
\r
44 CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
\r
45 IID_IShellLink, (void **)&psl);
\r
46 if (SUCCEEDED(hres)) {
\r
47 // Set the path to the shortcut target and add the description.
\r
48 psl->SetPath(i_pathObj);
\r
49 psl->SetDescription(i_desc);
\r
50 if (i_workingDirectory)
\r
51 psl->SetWorkingDirectory(i_workingDirectory);
\r
53 // Query IShellLink for the IPersistFile interface for saving the
\r
54 // shortcut in persistent storage.
\r
56 hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf);
\r
58 if (SUCCEEDED(hres)) {
\r
60 // Save the link by calling IPersistFile::Save.
\r
61 hres = ppf->Save(i_pathLink, TRUE);
\r
63 wchar_t wsz[MAX_PATH];
\r
64 // Ensure that the string is ANSI.
\r
65 MultiByteToWideChar(CP_ACP, 0, i_pathLink, -1, wsz, MAX_PATH);
\r
66 // Save the link by calling IPersistFile::Save.
\r
67 hres = ppf->Save(wsz, TRUE);
\r
77 // create file extension information
\r
78 void createFileExtension(const tstringi &i_ext, const tstring &i_contentType,
\r
79 const tstringi &i_fileType,
\r
80 const tstring &i_fileTypeName,
\r
81 const tstringi &i_iconPath,
\r
82 const tstring &i_command)
\r
86 Registry regExt(HKEY_CLASSES_ROOT, i_ext);
\r
87 if (! regExt.read (_T(""), &dummy))
\r
88 CHECK_TRUE( regExt.write(_T(""), i_fileType) );
\r
89 if (! regExt.read (_T("Content Type"), &dummy))
\r
90 CHECK_TRUE( regExt.write(_T("Content Type"), i_contentType) );
\r
92 Registry regFileType(HKEY_CLASSES_ROOT, i_fileType);
\r
93 if (! regFileType.read (_T(""), &dummy))
\r
94 CHECK_TRUE( regFileType.write(_T(""), i_fileTypeName) );
\r
96 Registry regFileTypeIcon(HKEY_CLASSES_ROOT,
\r
97 i_fileType + _T("\\DefaultIcon"));
\r
98 if (! regFileTypeIcon.read (_T(""), &dummy))
\r
99 CHECK_TRUE( regFileTypeIcon.write(_T(""), i_iconPath) );
\r
101 Registry regFileTypeComand(HKEY_CLASSES_ROOT,
\r
102 i_fileType + _T("\\shell\\open\\command"));
\r
103 if (! regFileTypeComand.read (_T(""), &dummy))
\r
104 CHECK_TRUE( regFileTypeComand.write(_T(""), i_command) );
\r
108 // remove file extension information
\r
109 void removeFileExtension(const tstringi &i_ext, const tstringi &i_fileType)
\r
111 Registry::remove(HKEY_CLASSES_ROOT, i_ext);
\r
112 Registry::remove(HKEY_CLASSES_ROOT,
\r
113 i_fileType + _T("\\shell\\open\\command"));
\r
114 Registry::remove(HKEY_CLASSES_ROOT, i_fileType + _T("\\shell\\open"));
\r
115 Registry::remove(HKEY_CLASSES_ROOT, i_fileType + _T("\\shell"));
\r
116 Registry::remove(HKEY_CLASSES_ROOT, i_fileType);
\r
120 // create uninstallation information
\r
121 void createUninstallInformation(const tstringi &i_name,
\r
122 const tstring &i_displayName,
\r
123 const tstring &i_commandLine)
\r
126 HKEY_LOCAL_MACHINE,
\r
127 _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\")
\r
130 CHECK_TRUE( reg.write(_T("DisplayName"), i_displayName) );
\r
131 CHECK_TRUE( reg.write(_T("UninstallString"), i_commandLine) );
\r
135 // remove uninstallation information
\r
136 void removeUninstallInformation(const tstringi &i_name)
\r
139 remove(HKEY_LOCAL_MACHINE,
\r
140 _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\")
\r
146 tstringi normalizePath(tstringi i_path)
\r
148 tregex regSlash(_T("^(.*)/(.*)$"));
\r
150 while (boost::regex_search(i_path, what, regSlash))
\r
151 i_path = what.str(1) + _T("\\") + what.str(2);
\r
153 tregex regTailBackSlash(_T("^(.*)\\\\$"));
\r
154 while (boost::regex_search(i_path, what, regTailBackSlash))
\r
155 i_path = what.str(1);
\r
161 // create deep directory
\r
162 bool createDirectories(const _TCHAR *i_folder)
\r
164 const _TCHAR *s = _tcschr(i_folder, _T('\\')); // TODO: '/'
\r
165 if (s && s - i_folder == 2 && i_folder[1] == _T(':'))
\r
166 s = _tcschr(s + 1, _T('\\'));
\r
170 tstringi f(i_folder, 0, s - i_folder);
\r
171 if (_tstat(f.c_str(), &sbuf) < 0)
\r
172 if (!CreateDirectory(f.c_str(), NULL))
\r
174 s = _tcschr(s + 1, _T('\\'));
\r
176 if (_tstat(i_folder, &sbuf) < 0)
\r
177 if (!CreateDirectory(i_folder, NULL))
\r
183 // get driver directory
\r
184 tstringi getDriverDirectory()
\r
186 _TCHAR buf[GANA_MAX_PATH];
\r
187 CHECK_TRUE( GetSystemDirectory(buf, NUMBER_OF(buf)) );
\r
188 return tstringi(buf) + _T("\\drivers");
\r
192 // get current directory
\r
193 tstringi getModuleDirectory()
\r
195 _TCHAR buf[GANA_MAX_PATH];
\r
196 CHECK_TRUE( GetModuleFileName(g_hInst, buf, NUMBER_OF(buf)) );
\r
197 tregex reg(_T("^(.*)\\\\[^\\\\]*$"));
\r
199 tstringi path(buf);
\r
200 if (boost::regex_search(path, what, reg))
\r
201 return what.str(1);
\r
207 // get start menu name
\r
208 tstringi getStartMenuName(const tstringi &i_shortcutName)
\r
211 char programDir[GANA_MAX_PATH];
\r
212 if (SUCCEEDED(SHGetSpecialFolderPath(NULL, programDir,
\r
213 CSIDL_COMMON_PROGRAMS, FALSE)))
\r
214 return tstringi(programDir) + "\\" + shortcutName + ".lnk";
\r
216 tstringi programDir;
\r
217 if (Registry::read(HKEY_LOCAL_MACHINE,
\r
218 _T("Software\\Microsoft\\Windows\\CurrentVersion\\")
\r
219 _T("Explorer\\Shell Folders"), _T("Common Programs"),
\r
221 return programDir + _T("\\") + i_shortcutName + _T(".lnk");
\r
227 // get start up name
\r
228 tstringi getStartUpName(const tstringi &i_shortcutName)
\r
230 tstringi startupDir;
\r
231 if (Registry::read(HKEY_CURRENT_USER,
\r
232 _T("Software\\Microsoft\\Windows\\CurrentVersion\\")
\r
233 _T("Explorer\\Shell Folders"), _T("Startup"),
\r
235 return startupDir + _T("\\") + i_shortcutName + _T(".lnk");
\r
240 #if defined(_WINNT)
\r
242 # define MAYUD_FILTER_KEY _T("System\\CurrentControlSet\\Control\\Class\\{4D36E96B-E325-11CE-BFC1-08002BE10318}")
\r
244 // create driver service
\r
245 DWORD createDriverService(const tstringi &i_serviceName,
\r
246 const tstring &i_serviceDescription,
\r
247 const tstringi &i_driverPath,
\r
248 const _TCHAR *i_preloadedGroups,
\r
252 OpenSCManager(NULL, NULL,
\r
253 SC_MANAGER_CREATE_SERVICE | SC_MANAGER_CONNECT);
\r
258 CreateService(hscm, i_serviceName.c_str(), i_serviceDescription.c_str(),
\r
259 SERVICE_START | SERVICE_STOP, SERVICE_KERNEL_DRIVER,
\r
260 forUsb == true ? SERVICE_DEMAND_START : SERVICE_AUTO_START,
\r
261 SERVICE_ERROR_IGNORE,
\r
262 i_driverPath.c_str(), NULL, NULL,
\r
263 i_preloadedGroups, NULL, NULL);
\r
264 DWORD err = GetLastError();
\r
267 case ERROR_SERVICE_EXISTS: {
\r
269 hs = OpenService(hscm, i_serviceName.c_str(), SERVICE_CHANGE_CONFIG);
\r
271 CloseServiceHandle(hscm);
\r
272 return GetLastError();
\r
274 if (!ChangeServiceConfig(
\r
275 hscm, SERVICE_KERNEL_DRIVER,
\r
276 forUsb == true ? SERVICE_DEMAND_START : SERVICE_AUTO_START,
\r
277 SERVICE_ERROR_IGNORE,
\r
278 i_driverPath.c_str(), NULL, NULL,
\r
279 i_preloadedGroups, NULL, NULL,
\r
280 i_serviceDescription.c_str())) {
\r
281 CloseServiceHandle(hs);
\r
282 CloseServiceHandle(hscm);
\r
283 return GetLastError(); // ERROR_IO_PENDING!
\r
284 // this code always reaches here. why?
\r
287 Registry reg(HKEY_LOCAL_MACHINE,
\r
288 _T("SYSTEM\\CurrentControlSet\\Services\\mayud"));
\r
289 reg.write(_T("Start"),
\r
290 forUsb ? SERVICE_DEMAND_START : SERVICE_AUTO_START);
\r
295 CloseServiceHandle(hscm);
\r
300 CloseServiceHandle(hs);
\r
301 CloseServiceHandle(hscm);
\r
303 if (forUsb == true) {
\r
304 Registry reg(HKEY_LOCAL_MACHINE, MAYUD_FILTER_KEY);
\r
305 typedef std::list<tstring> Filters;
\r
307 if (!reg.read(_T("UpperFilters"), &filters))
\r
309 for (Filters::iterator i = filters.begin(); i != filters.end(); ) {
\r
310 Filters::iterator next = i;
\r
312 if (*i == _T("mayud")) {
\r
317 filters.push_back(_T("mayud"));
\r
318 if (!reg.write(_T("UpperFilters"), filters))
\r
322 return ERROR_SUCCESS;
\r
327 #if defined(_WINNT)
\r
328 // remove driver service
\r
329 DWORD removeDriverService(const tstringi &i_serviceName)
\r
331 DWORD err = ERROR_SUCCESS;
\r
333 Registry reg(HKEY_LOCAL_MACHINE, MAYUD_FILTER_KEY);
\r
334 std::list<tstring> filters;
\r
335 if (reg.read(_T("UpperFilters"), &filters)) {
\r
336 filters.remove(_T("mayud"));
\r
337 reg.write(_T("UpperFilters"), filters);
\r
340 SC_HANDLE hscm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
\r
342 OpenService(hscm, i_serviceName.c_str(),
\r
343 SERVICE_START | SERVICE_STOP | DELETE);
\r
345 err = GetLastError();
\r
350 ControlService(hs, SERVICE_CONTROL_STOP, &ss);
\r
352 if (!DeleteService(hs)) {
\r
353 err = GetLastError();
\r
357 CloseServiceHandle(hs);
\r
358 CloseServiceHandle(hscm);
\r
364 // check operating system
\r
365 bool checkOs(SetupFile::OS os)
\r
368 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
\r
369 GetVersionEx(&ver);
\r
373 case SetupFile::ALL:
\r
375 case SetupFile::W9x:
\r
376 return (ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS &&
\r
377 4 <= ver.dwMajorVersion);
\r
378 case SetupFile::NT :
\r
379 return (ver.dwPlatformId == VER_PLATFORM_WIN32_NT &&
\r
380 4 <= ver.dwMajorVersion);
\r
381 case SetupFile::NT4:
\r
382 return (ver.dwPlatformId == VER_PLATFORM_WIN32_NT &&
\r
383 ver.dwMajorVersion == 4);
\r
384 case SetupFile::W2k: // W2k, XP, ...
\r
385 return (ver.dwPlatformId == VER_PLATFORM_WIN32_NT &&
\r
386 5 <= ver.dwMajorVersion);
\r
392 bool installFiles(const SetupFile::Data *i_setupFiles,
\r
393 size_t i_setupFilesSize, u_int32 i_flags,
\r
394 const tstringi &i_srcDir, const tstringi &i_destDir)
\r
397 tstringi destDriverDir = getDriverDirectory();
\r
399 for (size_t i = 0; i < i_setupFilesSize; ++ i) {
\r
400 const SetupFile::Data &s = i_setupFiles[i];
\r
401 const tstringi &fromDir = i_srcDir;
\r
402 const tstringi &toDir =
\r
403 (s.m_destination == SetupFile::ToDriver) ? destDriverDir : i_destDir;
\r
406 continue; // remove only
\r
408 if (fromDir == toDir)
\r
409 continue; // same directory
\r
411 if (!checkOs(s.m_os)) // check operating system
\r
414 if ((s.m_flags & i_flags) != i_flags) // check flags
\r
418 switch (s.m_kind) {
\r
419 case SetupFile::Dll: {
\r
421 tstringi from_ = toDir + _T("\\") + s.m_to;
\r
422 tstringi to_ = toDir + _T("\\deleted.") + s.m_to;
\r
423 DeleteFile(to_.c_str());
\r
424 MoveFile(from_.c_str(), to_.c_str());
\r
425 DeleteFile(to_.c_str());
\r
429 case SetupFile::File: {
\r
430 from += fromDir + _T('\\') + s.m_from + _T('\0');
\r
431 to += toDir + _T('\\') + s.m_to + _T('\0');
\r
434 case SetupFile::Dir: {
\r
435 createDirectories((toDir + _T('\\') + s.m_to).c_str());
\r
442 tstringi to_(to), from_(from);
\r
443 for (size_t i = 0; i < to_.size(); ++ i)
\r
446 for (size_t i = 0; i < from_.size(); ++ i)
\r
449 MessageBox(NULL, to_.c_str(), from_.c_str(), MB_OK);
\r
454 ::ZeroMemory(&fo, sizeof(fo));
\r
455 fo.wFunc = FO_COPY;
\r
456 fo.fFlags = FOF_MULTIDESTFILES;
\r
457 fo.pFrom = from.c_str();
\r
458 fo.pTo = to.c_str();
\r
459 if (SHFileOperation(&fo) || fo.fAnyOperationsAborted)
\r
465 // remove files from src
\r
466 bool removeSrcFiles(const SetupFile::Data *i_setupFiles,
\r
467 size_t i_setupFilesSize, u_int32 i_flags,
\r
468 const tstringi &i_srcDir)
\r
470 tstringi destDriverDir = getDriverDirectory();
\r
472 for (size_t i = 0; i < i_setupFilesSize; ++ i) {
\r
473 const SetupFile::Data &s = i_setupFiles[i_setupFilesSize - i - 1];
\r
474 const tstringi &fromDir = i_srcDir;
\r
477 continue; // remove only
\r
479 if (!checkOs(s.m_os)) // check operating system
\r
482 if ((s.m_flags & i_flags) != i_flags) // check flags
\r
486 switch (s.m_kind) {
\r
488 case SetupFile::Dll:
\r
489 case SetupFile::File:
\r
490 DeleteFile((fromDir + _T('\\') + s.m_from).c_str());
\r
492 case SetupFile::Dir:
\r
493 RemoveDirectory((fromDir + _T('\\') + s.m_from).c_str());
\r
497 RemoveDirectory(i_srcDir.c_str());
\r
503 void removeFiles(const SetupFile::Data *i_setupFiles,
\r
504 size_t i_setupFilesSize, u_int32 i_flags,
\r
505 const tstringi &i_destDir)
\r
507 tstringi destDriverDir = getDriverDirectory();
\r
509 for (size_t i = 0; i < i_setupFilesSize; ++ i) {
\r
510 const SetupFile::Data &s = i_setupFiles[i_setupFilesSize - i - 1];
\r
511 const tstringi &toDir =
\r
512 (s.m_destination == SetupFile::ToDriver) ? destDriverDir : i_destDir;
\r
514 if (!checkOs(s.m_os)) // check operating system
\r
517 if ((s.m_flags & i_flags) != i_flags) // check flags
\r
521 switch (s.m_kind) {
\r
522 case SetupFile::Dll:
\r
523 DeleteFile((toDir + _T("\\deleted.") + s.m_to).c_str());
\r
526 case SetupFile::File:
\r
527 DeleteFile((toDir + _T('\\') + s.m_to).c_str());
\r
529 case SetupFile::Dir:
\r
530 RemoveDirectory((toDir + _T('\\') + s.m_to).c_str());
\r
534 RemoveDirectory(i_destDir.c_str());
\r
539 int uninstallStep1(const _TCHAR *i_uninstallOption)
\r
541 // copy this EXEcutable image into the user's temp directory
\r
542 _TCHAR setup_exe[GANA_MAX_PATH], tmp_setup_exe[GANA_MAX_PATH];
\r
543 GetModuleFileName(NULL, setup_exe, NUMBER_OF(setup_exe));
\r
544 GetTempPath(NUMBER_OF(tmp_setup_exe), tmp_setup_exe);
\r
545 GetTempFileName(tmp_setup_exe, _T("del"), 0, tmp_setup_exe);
\r
546 CopyFile(setup_exe, tmp_setup_exe, FALSE);
\r
548 // open the clone EXE using FILE_FLAG_DELETE_ON_CLOSE
\r
549 HANDLE hfile = CreateFile(tmp_setup_exe, 0, FILE_SHARE_READ, NULL,
\r
550 OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL);
\r
552 // spawn the clone EXE passing it our EXE's process handle
\r
553 // and the full path name to the original EXE file.
\r
554 _TCHAR commandLine[512];
\r
555 HANDLE hProcessOrig =
\r
556 OpenProcess(SYNCHRONIZE, TRUE, GetCurrentProcessId());
\r
557 _sntprintf(commandLine, NUMBER_OF(commandLine), _T("%s %s %d"),
\r
558 tmp_setup_exe, i_uninstallOption, hProcessOrig);
\r
560 ::ZeroMemory(&si, sizeof(si));
\r
561 si.cb = sizeof(si);
\r
562 PROCESS_INFORMATION pi;
\r
563 CreateProcess(NULL, commandLine, NULL, NULL, TRUE, 0, NULL, NULL, &si,&pi);
\r
564 Sleep(2000); // important
\r
565 CloseHandle(hProcessOrig);
\r
566 CloseHandle(hfile);
\r
572 // (after this function, we cannot use any resource)
\r
573 void uninstallStep2(const _TCHAR *argByStep1)
\r
575 // clone EXE: When original EXE terminates, delete it
\r
576 HANDLE hProcessOrig = (HANDLE)_ttoi(argByStep1);
\r
577 WaitForSingleObject(hProcessOrig, INFINITE);
\r
578 CloseHandle(hProcessOrig);
\r
582 /////////////////////////////////////////////////////////////////////////////
\r
583 // Locale / StringResource
\r
587 Resource::Resource(const StringResource *i_stringResources)
\r
588 : m_stringResources(i_stringResources),
\r
591 struct LocaleInformaton {
\r
592 const _TCHAR *m_localeString;
\r
596 // set locale information
\r
597 const _TCHAR *localeString = ::_tsetlocale(LC_ALL, _T(""));
\r
599 static const LocaleInformaton locales[] = {
\r
600 { _T("Japanese_Japan.932"), LOCALE_Japanese_Japan_932 },
\r
603 for (size_t i = 0; i < NUMBER_OF(locales); ++ i)
\r
604 if (_tcsicmp(localeString, locales[i].m_localeString) == 0) {
\r
605 m_locale = locales[i].m_locale;
\r
611 // get resource string
\r
612 const _TCHAR *Resource::loadString(UINT i_id)
\r
614 int n = static_cast<int>(m_locale);
\r
616 for (int i = 0; m_stringResources[i].m_str; ++ i)
\r
617 if (m_stringResources[i].m_id == i_id) {
\r
619 return m_stringResources[i].m_str;
\r
624 return m_stringResources[index].m_str;
\r