1 /*
2  * Copyright 2003, 2004, 2005 Martin Fuchs
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library 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 GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18 
19 
20  //
21  // Explorer clone
22  //
23  // utility.cpp
24  //
25  // Martin Fuchs, 23.07.2003
26  //
27 
28 
29 #include <precomp.h>
30 
31 //#include <shellapi.h>
32 
33 #include <time.h>
34 #include <sstream>
35 
36 
37 DWORD WINAPI Thread::ThreadProc(void* para)
38 {
39 	Thread* pThis = (Thread*) para;
40 
41 	int ret = pThis->Run();
42 
43 	pThis->_alive = false;
44 
45 	return ret;
46 }
47 
48 
49 void CenterWindow(HWND hwnd)
50 {
51 	RECT rt, prt;
52 	GetWindowRect(hwnd, &rt);
53 
54 	DWORD style;
55 	HWND owner = 0;
56 
57 	for(HWND wh=hwnd; (wh=GetWindow(wh,GW_OWNER))!=0; )
58 		if (((style=GetWindowStyle(wh))&WS_VISIBLE) && !(style&WS_MINIMIZE))
59 			{owner=wh; break;}
60 
61 	if (owner)
62 		GetWindowRect(owner, &prt);
63 	else
64 		SystemParametersInfo(SPI_GETWORKAREA, 0, &prt, 0);	//@@ GetDesktopWindow() w�re auch hilfreich.
65 
66 	SetWindowPos(hwnd, 0, (prt.left+prt.right+rt.left-rt.right)/2,
67 					   (prt.top+prt.bottom+rt.top-rt.bottom)/2, 0,0, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOZORDER);
68 
69 	MoveVisible(hwnd);
70 }
71 
72 void MoveVisible(HWND hwnd)
73 {
74 	RECT rc;
75 	GetWindowRect(hwnd, &rc);
76 	int left=rc.left, top=rc.top;
77 
78 	int xmax = GetSystemMetrics(SM_CXSCREEN);
79 	int ymax = GetSystemMetrics(SM_CYSCREEN);
80 
81 	if (rc.left < 0)
82 		rc.left = 0;
83 	else if (rc.right > xmax)
84 		if ((rc.left-=rc.right-xmax) < 0)
85 			rc.left = 0;
86 
87 	if (rc.top < 0)
88 		rc.top = 0;
89 	else if (rc.bottom > ymax)
90 		if ((rc.top-=rc.bottom-ymax) < 0)
91 			rc.top = 0;
92 
93 	if (rc.left!=left || rc.top!=top)
94 		SetWindowPos(hwnd, 0, rc.left,rc.top, 0,0, SWP_NOZORDER|SWP_NOSIZE|SWP_NOACTIVATE);
95 }
96 
97 
98 void display_error(HWND hwnd, DWORD error)	//@@ CONTEXT mit ausgeben -> display_error(HWND hwnd, const Exception& e)
99 {
100 	PTSTR msg;
101 
102 	if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
103 		0, error, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), (PTSTR)&msg, 0, NULL)) {
104 		LOG(FmtString(TEXT("display_error(%#x): %s"), error, msg));
105 
106 		SetLastError(0);
107 		MessageBox(hwnd, msg, TEXT("ROS Explorer"), MB_OK);
108 
109 		if (GetLastError() == ERROR_INVALID_WINDOW_HANDLE)
110 			MessageBox(0, msg, TEXT("ROS Explorer"), MB_OK);
111 	} else {
112 		LOG(FmtString(TEXT("Unknown Error %#x"), error));
113 
114 		FmtString msg(TEXT("Unknown Error %#x"), error);
115 
116 		SetLastError(0);
117 		MessageBox(hwnd, msg, TEXT("ROS Explorer"), MB_OK);
118 
119 		if (GetLastError() == ERROR_INVALID_WINDOW_HANDLE)
120 			MessageBox(0, msg, TEXT("ROS Explorer"), MB_OK);
121 	}
122 
123 	LocalFree(msg);
124 }
125 
126 
127 Context Context::s_main("-NO-CONTEXT-");
128 Context* Context::s_current = &Context::s_main;
129 
130 String Context::toString() const
131 {
132 	String str = _ctx;
133 
134 	if (!_obj.empty())
135 		str.appendf(TEXT("\nObject: %s"), (LPCTSTR)_obj);
136 
137 	return str;
138 }
139 
140 String Context::getStackTrace() const
141 {
142 	ostringstream str;
143 
144 	str << "Context Trace:\n";
145 
146 	for(const Context*p=this; p && p!=&s_main; p=p->_last) {
147 		str << "- " << p->_ctx;
148 
149 		if (!p->_obj.empty())
150 			str << " obj=" << ANS(p->_obj);
151 
152 		str << '\n';
153 	}
154 
155 	return str.str();
156 }
157 
158 
159 BOOL time_to_filetime(const time_t* t, FILETIME* ftime)
160 {
161 #if defined(__STDC_WANT_SECURE_LIB__) && defined(_MS_VER)
162 	SYSTEMTIME stime;
163 	struct tm tm_;
164 	struct tm* tm = &tm_;
165 
166 	if (gmtime_s(tm, t) != 0)
167 		return FALSE;
168 #else
169 	struct tm* tm = gmtime(t);
170 	SYSTEMTIME stime;
171 
172 	if (!tm)
173 		return FALSE;
174 #endif
175 
176 	stime.wYear = tm->tm_year+1900;
177 	stime.wMonth = tm->tm_mon+1;
178 	stime.wDayOfWeek = (WORD)-1;
179 	stime.wDay = tm->tm_mday;
180 	stime.wHour = tm->tm_hour;
181 	stime.wMinute = tm->tm_min;
182 	stime.wSecond = tm->tm_sec;
183 	stime.wMilliseconds = 0;
184 
185 	return SystemTimeToFileTime(&stime, ftime);
186 }
187 
188 
189 BOOL launch_file(HWND hwnd, LPCTSTR cmd, UINT nCmdShow, LPCTSTR parameters)
190 {
191 	CONTEXT("launch_file()");
192 
193 	HINSTANCE hinst = ShellExecute(hwnd, NULL/*operation*/, cmd, parameters, NULL/*dir*/, nCmdShow);
194 
195 	if ((INT_PTR)hinst <= 32) {
196 		display_error(hwnd, GetLastError());
197 		return FALSE;
198 	}
199 
200 	return TRUE;
201 }
202 
203 #ifdef UNICODE
204 BOOL launch_fileA(HWND hwnd, LPSTR cmd, UINT nCmdShow, LPCSTR parameters)
205 {
206 	HINSTANCE hinst = ShellExecuteA(hwnd, NULL/*operation*/, cmd, parameters, NULL/*dir*/, nCmdShow);
207 
208 	if ((INT_PTR)hinst <= 32) {
209 		display_error(hwnd, GetLastError());
210 		return FALSE;
211 	}
212 
213 	return TRUE;
214 }
215 #endif
216 
217 
218 /* search for already running instance */
219 
220 static int g_foundPrevInstance = 0;
221 
222 static BOOL CALLBACK EnumWndProc(HWND hwnd, LPARAM lparam)
223 {
224 	TCHAR cls[128];
225 
226 	GetClassName(hwnd, cls, 128);
227 
228 	if (!lstrcmp(cls, (LPCTSTR)lparam)) {
229 		g_foundPrevInstance++;
230 		return FALSE;
231 	}
232 
233 	return TRUE;
234 }
235 
236 /* search for window of given class name to allow only one running instance */
237 int find_window_class(LPCTSTR classname)
238 {
239 	EnumWindows(EnumWndProc, (LPARAM)classname);
240 
241 	if (g_foundPrevInstance)
242 		return 1;
243 
244 	return 0;
245 }
246 
247 
248 String get_windows_version_str()
249 {
250 	OSVERSIONINFOEX osvi = {sizeof(OSVERSIONINFOEX)};
251 	BOOL osvie_val;
252 	String str;
253 
254 	if (!(osvie_val = GetVersionEx((OSVERSIONINFO*)&osvi))) {
255 		osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
256 
257 		if (!GetVersionEx((OSVERSIONINFO*)&osvi))
258 			return TEXT("???");
259 	}
260 
261 	switch(osvi.dwPlatformId) {
262 	  case VER_PLATFORM_WIN32_NT:
263 #ifdef __REACTOS__	// This work around can be removed if ReactOS gets a unique version number.
264 		str = TEXT("ReactOS");
265 #else
266 		if (osvi.dwMajorVersion <= 4)
267 			str = TEXT("Microsoft Windows NT");
268 		else if (osvi.dwMajorVersion==5 && osvi.dwMinorVersion==0)
269 			str = TEXT("Microsoft Windows 2000");
270 		else if (osvi.dwMajorVersion==5 && osvi.dwMinorVersion==1)
271 			str = TEXT("Microsoft Windows XP");
272 #endif
273 
274 		if (osvie_val) {
275 			if (osvi.wProductType == VER_NT_WORKSTATION) {
276 			   if (osvi.wSuiteMask & VER_SUITE_PERSONAL)
277 				  str += TEXT(" Personal");
278 			   else
279 				  str += TEXT(" Professional");
280 			} else if (osvi.wProductType == VER_NT_SERVER) {
281 			   if (osvi.wSuiteMask & VER_SUITE_DATACENTER)
282 				  str += TEXT(" DataCenter Server");
283 			   else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE)
284 				  str += TEXT(" Advanced Server");
285 			   else
286 				  str += TEXT(" Server");
287 			} else if (osvi.wProductType == VER_NT_DOMAIN_CONTROLLER) {
288 				str += TEXT(" Domain Controller");
289 			}
290 		} else {
291 			TCHAR type[80];
292 			DWORD dwBufLen;
293 			HKEY hkey;
294 
295 			if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Control\\ProductOptions"), 0, KEY_QUERY_VALUE, &hkey)) {
296 				RegQueryValueEx(hkey, TEXT("ProductType"), NULL, NULL, (LPBYTE)type, &dwBufLen);
297 				RegCloseKey(hkey);
298 
299 				if (!_tcsicmp(TEXT("WINNT"), type))
300 				   str += TEXT(" Workstation");
301 				else if (!_tcsicmp(TEXT("LANMANNT"), type))
302 				   str += TEXT(" Server");
303 				else if (!_tcsicmp(TEXT("SERVERNT"), type))
304 					str += TEXT(" Advanced Server");
305 			}
306 		}
307 		break;
308 
309 	  case VER_PLATFORM_WIN32_WINDOWS:
310 		if (osvi.dwMajorVersion>4 ||
311 			(osvi.dwMajorVersion==4 && osvi.dwMinorVersion>0)) {
312 			if (osvi.dwMinorVersion == 90)
313 				str = TEXT("Microsoft Windows ME");
314 			else
315 				str = TEXT("Microsoft Windows 98");
316 
317             if (osvi.szCSDVersion[1] == 'A')
318 				str += TEXT(" SE");
319 		} else {
320 			str = TEXT("Microsoft Windows 95");
321 
322             if (osvi.szCSDVersion[1]=='B' || osvi.szCSDVersion[1]=='C')
323 				str += TEXT(" OSR2");
324 		}
325 		break;
326 
327 	  case VER_PLATFORM_WIN32s:
328 		str = TEXT("Microsoft Win32s");
329 
330 	  default:
331 		return TEXT("???");
332 	}
333 
334 	String vstr;
335 
336 	if (osvi.dwMajorVersion <= 4)
337 		vstr.printf(TEXT(" Version %d.%d %s Build %d"),
338 						osvi.dwMajorVersion, osvi.dwMinorVersion,
339 						osvi.szCSDVersion, osvi.dwBuildNumber&0xFFFF);
340 	else
341 		vstr.printf(TEXT(" %s (Build %d)"), osvi.szCSDVersion, osvi.dwBuildNumber&0xFFFF);
342 
343 	return str + vstr;
344 }
345 
346 
347 typedef void (WINAPI*RUNDLLPROC)(HWND hwnd, HINSTANCE hinst, LPCTSTR cmdline, DWORD nCmdShow);
348 
349 BOOL RunDLL(HWND hwnd, LPCTSTR dllname, LPCSTR procname, LPCTSTR cmdline, UINT nCmdShow)
350 {
351 	HMODULE hmod = LoadLibrary(dllname);
352 	if (!hmod)
353 		return FALSE;
354 
355 /*TODO
356 	<Windows NT/2000>
357 	It is possible to create a Unicode version of the function.
358 	Rundll32 first tries to find a function named EntryPointW.
359 	If it cannot find this function, it tries EntryPointA, then EntryPoint.
360 	To create a DLL that supports ANSI on Windows 95/98/Me and Unicode otherwise,
361 	export two functions: EntryPointW and EntryPoint.
362 */
363 	RUNDLLPROC proc = (RUNDLLPROC)GetProcAddress(hmod, procname);
364 	if (!proc) {
365 		FreeLibrary(hmod);
366 		return FALSE;
367 	}
368 
369 	proc(hwnd, hmod, cmdline, nCmdShow);
370 
371 	FreeLibrary(hmod);
372 
373 	return TRUE;
374 }
375 
376 
377 #ifdef UNICODE
378 #define CONTROL_RUNDLL "Control_RunDLLW"
379 #else
380 #define CONTROL_RUNDLL "Control_RunDLLA"
381 #endif
382 
383 BOOL launch_cpanel(HWND hwnd, LPCTSTR applet)
384 {
385 	TCHAR parameters[MAX_PATH];
386 
387 	_tcscpy(parameters, TEXT("shell32.dll,Control_RunDLL "));
388 	_tcscat(parameters, applet);
389 
390 	return ((INT_PTR)ShellExecute(hwnd, TEXT("open"), TEXT("rundll32.exe"), parameters, NULL, SW_SHOWDEFAULT) > 32);
391 }
392 
393 
394 BOOL RecursiveCreateDirectory(LPCTSTR path_in)
395 {
396 	TCHAR path[MAX_PATH], hole_path[MAX_PATH];
397 
398 	_tcscpy(hole_path, path_in);
399 
400 	int drv_len = 0;
401 	LPCTSTR d;
402 
403 	for(d=hole_path; *d && *d!='/' && *d!='\\'; ++d) {
404 		++drv_len;
405 
406 		if (*d == ':')
407 			break;
408 	}
409 
410 	LPTSTR dir = hole_path + drv_len;
411 
412 	int l;
413 	LPTSTR p = hole_path + (l=_tcslen(hole_path));
414 
415 	while(--p>=hole_path && (*p=='/' || *p=='\\'))
416 		*p = '\0';
417 
418 	WIN32_FIND_DATA w32fd;
419 
420 	HANDLE hFind = FindFirstFile(hole_path, &w32fd);
421 
422 	if (hFind == INVALID_HANDLE_VALUE) {
423 		_tcsncpy(path, hole_path, drv_len);
424 		int i = drv_len;
425 
426 		for(p=dir; *p=='/'||*p=='\\'; p++)
427 			path[i++] = *p++;
428 
429 		for(; i<l; i++) {
430 			memcpy(path, hole_path, i*sizeof(TCHAR));
431 
432 			for(; hole_path[i] && hole_path[i]!='/' && hole_path[i]!='\\'; i++)
433 				path[i] = hole_path[i];
434 
435 			path[i] = '\0';
436 
437 			hFind = FindFirstFile(path, &w32fd);
438 
439 			if (hFind != INVALID_HANDLE_VALUE)
440 				FindClose(hFind);
441 			else {
442 				LOG(FmtString(TEXT("CreateDirectory(\"%s\")"), path));
443 
444 				if (!CreateDirectory(path, 0))
445 					return FALSE;
446 			}
447 		}
448 	} else
449 		FindClose(hFind);
450 
451 	return TRUE;
452 }
453 
454 
455 DWORD RegGetDWORDValue(HKEY root, LPCTSTR path, LPCTSTR valueName, DWORD def)
456 {
457 	HKEY hkey;
458 	DWORD ret;
459 
460 	if (!RegOpenKey(root, path, &hkey)) {
461 		DWORD len = sizeof(ret);
462 
463 		if (RegQueryValueEx(hkey, valueName, 0, NULL, (LPBYTE)&ret, &len))
464 			ret = def;
465 
466 		RegCloseKey(hkey);
467 
468 		return ret;
469 	} else
470 		return def;
471 }
472 
473 
474 BOOL RegSetDWORDValue(HKEY root, LPCTSTR path, LPCTSTR valueName, DWORD value)
475 {
476 	HKEY hkey;
477 	BOOL ret = FALSE;
478 
479 	if (!RegOpenKey(root, path, &hkey)) {
480 		ret = RegSetValueEx(hkey, valueName, 0, REG_DWORD, (LPBYTE)&value, sizeof(value));
481 
482 		RegCloseKey(hkey);
483 	}
484 
485 	return ret;
486 }
487 
488 
489 BOOL exists_path(LPCTSTR path)
490 {
491 	WIN32_FIND_DATA fd;
492 
493 	HANDLE hfind = FindFirstFile(path, &fd);
494 
495 	if (hfind != INVALID_HANDLE_VALUE) {
496 		FindClose(hfind);
497 
498 		return TRUE;
499 	} else
500 		return FALSE;
501 }
502 
503 
504 bool SplitFileSysURL(LPCTSTR url, String& dir_out, String& fname_out)
505 {
506 	if (!_tcsnicmp(url, TEXT("file://"), 7)) {
507 		url += 7;
508 
509 		 // remove third slash in front of drive characters
510 		if (*url == '/')
511 			++url;
512 	}
513 
514 	if (exists_path(url)) {
515 		TCHAR path[_MAX_PATH];
516 
517 		 // convert slashes to back slashes
518 		GetFullPathName(url, COUNTOF(path), path, NULL);
519 
520 		if (GetFileAttributes(path) & FILE_ATTRIBUTE_DIRECTORY)
521 			fname_out.erase();
522 		else {
523 			TCHAR drv[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
524 
525 			_tsplitpath_s(path, drv, COUNTOF(drv), dir, COUNTOF(dir), fname, COUNTOF(fname), ext, COUNTOF(ext));
526 			_stprintf(path, TEXT("%s%s"), drv, dir);
527 
528 			fname_out.printf(TEXT("%s%s"), fname, ext);
529 		}
530 
531 		dir_out = path;
532 
533 		return true;
534 	} else
535 		return false;
536 }
537