1 #include "CtrlLib.h"
2 
3 namespace Upp {
4 
5 #ifdef GUI_WIN
6 #ifndef PLATFORM_WINCE
7 
8 #define LLOG(x)
9 
10 static String s_updatedir;
11 static String s_updater;
12 
UpdateSetDir(const char * path)13 void UpdateSetDir(const char *path)
14 {
15 	s_updatedir = path;
16 }
17 
UpdateSetUpdater(const char * exename)18 void UpdateSetUpdater(const char *exename)
19 {
20 	s_updater = exename;
21 }
22 
UpdateGetDir()23 String UpdateGetDir()
24 {
25 	return Nvl(s_updatedir, GetIniKey("UPDATE"));
26 }
27 
FileTimeToTime(const FILETIME & time)28 Time FileTimeToTime(const FILETIME& time) {
29 	SYSTEMTIME t;
30 	FileTimeToSystemTime(&time, &t);
31 	return Time(t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond);
32 }
33 
NoUpdate(const char * dsf,const char * srf,int & len)34 bool NoUpdate(const char *dsf, const char *srf, int& len) {
35 	FindFile dst(dsf);
36 	FindFile src(srf);
37 	if(!src) return true;
38 	len = (int)src.GetLength();
39 	if(!dst) return false;
40 	return abs(FileTimeToTime(dst.GetLastWriteTime()) - FileTimeToTime(src.GetLastWriteTime()))
41 		    < 100 && len == dst.GetLength();
42 }
43 
UpdateFile(String dst,String src)44 void UpdateFile(String dst, String src)
45 {
46 	if(src.IsEmpty()) return;
47 	String filename = GetFileName(dst);
48 	int len;
49 	if(NoUpdate(dst, src, len)) return;
50 	String tmp = dst + ".tmp";
51 	Progress pi;
52 	pi.Title((t_("Updating ") + filename).ToWString());
53 	pi.SetText(t_("Updating ") + filename);
54 //	pi.Open();
55 	FileIn in(src);
56 	if(!in)
57 	{
58 		Exclamation(Format(t_("Error opening file [* \1%s\1]."), src));
59 		return;
60 	}
61 	FileDelete(tmp);
62 	FileOut out(tmp);
63 	dword n = 0;
64 	char buffer[2048];
65 	if(!out)
66 	{
67 		Exclamation(Format(t_("Error creating file [* \1%s\1]."), tmp));
68 		return;
69 	}
70 	for(;;)
71 	{
72 		dword i = in.Get(buffer, 2048);
73 		if(i == 0) break;
74 		out.Put(buffer, i);
75 		n += i;
76 		pi.Set(n, len);
77 		if(pi.Canceled() && PromptYesNo(t_("Aborting update is likely to cause trouble when running the application for the next time.\nContinue?")))
78 		{
79 			out.Close();
80 			FileDelete(tmp);
81 			return;
82 		}
83 	}
84 	out.SetTime(in.GetTime());
85 	out.Close();
86 	if(out.IsError())
87 	{
88 		Exclamation(Format(t_("Error writing file [* \1%s\1]."), tmp));
89 		FileDelete(tmp);
90 		return;
91 	}
92 	String old = dst + ".old";
93 	pi.SetText(Format(t_("Overwriting %s"), dst));
94 	pi.SetTotal(10000);
95 	int start = msecs();
96 	for(;;)
97 	{
98 		SetFileAttributes(dst, 0);
99 		FileDelete(old);
100 		FileMove(dst, old);
101 		if(FileMove(tmp, dst))
102 			return;
103 		if(pi.SetPosCanceled(msecs(start) % 10000) && PromptYesNo(t_("Aborting update is likely to cause trouble when running the application for the next time.\nContinue?")))
104 			return;
105 		Sleep(500);
106 	}
107 }
108 
UpdateFile(const char * filename)109 void UpdateFile(const char *filename)
110 {
111 	String dst = GetExeDirFile(filename);
112 	String src = UpdateGetDir();
113 	if(IsNull(src))
114 		return;
115 	UpdateFile(dst, AppendFileName(src, filename));
116 }
117 
FixArg(String s)118 static String FixArg(String s)
119 {
120 	if(s.Find(' ') < 0 && s.Find('\"') < 0)
121 		return s;
122 	String ucmd;
123 	ucmd << '\"';
124 	for(const char *p = s; *p; p++)
125 		if(*p == '\"')
126 			ucmd << "\"\"";
127 		else
128 			ucmd << *p;
129 	ucmd << '\"';
130 	return ucmd;
131 }
132 
SelfUpdate()133 void SelfUpdate() {
134 	char dst[512];
135 	UpdateFile(Nvl(s_updater, String("UPDATER.EXE")));
136 	::GetModuleFileName(NULL, dst, 512);
137 	{
138 		String src = UpdateGetDir();
139 		if(src.IsEmpty()) return;
140 		src = AppendFileName(src, GetFileNamePos(dst));
141 		int dummy;
142 		if(NoUpdate(dst, src, dummy)) return;
143 		String commandline;
144 		const Vector<String>& cmd = CommandLine();
145 		for(int i = 0; i < cmd.GetCount(); i++) {
146 			commandline += ' ';
147 			commandline += FixArg(cmd[i]);
148 		}
149 		if(WinExec(GetExeDirFile("updater.exe") + " " + GetFileName(dst) + commandline, SW_SHOWNORMAL) <= 31)
150 			return;
151 	}
152 	exit(0);
153 }
154 
SelfUpdateSelf()155 bool SelfUpdateSelf()
156 {
157 	const Vector<String>& cmdline = CommandLine();
158 	String exe = GetExeFilePath();
159 
160 	if(cmdline.GetCount() >= 2 && cmdline[0] == "-update")
161 	{ // updater
162 		String exec = FixArg(cmdline[1]);
163 		UpdateFile(exec, exe);
164 		for(int i = 2; i < cmdline.GetCount(); i++)
165 			exec << ' ' << FixArg(cmdline[i]);
166 		WinExec(exec, SW_SHOWNORMAL);
167 		return true;
168 	}
169 
170 	String src = UpdateGetDir();
171 	if(src.IsEmpty()) return false;
172 	src = AppendFileName(src, GetFileNamePos(exe));
173 	int dummy;
174 	if(NoUpdate(exe, src, dummy)) return false;
175 
176 	String commandline;
177 	commandline << src << " -update " << FixArg(exe);
178 	for(int i = 0; i < cmdline.GetCount(); i++)
179 		commandline << ' ' << FixArg(cmdline[i]);
180 	LLOG("SelfUpdateSelf (running updater): " << commandline);
181 	return WinExec(commandline, SW_SHOWNORMAL) >= 32;
182 }
183 
184 #endif
185 #endif
186 
187 }
188