- Implement ProtocolResetComplete
[reactos.git] / base / shell / explorer / utility / utility.cpp
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 #ifdef __STDC_WANT_SECURE_LIB__
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)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)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 //launch_file(_hwnd, applet, SW_SHOWNORMAL); // This would be enough, but we want the to use the most direct and fastest call.
386 //launch_file(_hwnd, String(TEXT("rundll32.exe /d shell32.dll,Control_RunDLL "))+applet, SW_SHOWNORMAL);
387
388 return RunDLL(hwnd, TEXT("shell32"), CONTROL_RUNDLL, applet, SW_SHOWNORMAL);
389 }
390
391
392 BOOL RecursiveCreateDirectory(LPCTSTR path_in)
393 {
394 TCHAR path[MAX_PATH], hole_path[MAX_PATH];
395
396 _tcscpy(hole_path, path_in);
397
398 int drv_len = 0;
399 LPCTSTR d;
400
401 for(d=hole_path; *d && *d!='/' && *d!='\\'; ++d) {
402 ++drv_len;
403
404 if (*d == ':')
405 break;
406 }
407
408 LPTSTR dir = hole_path + drv_len;
409
410 int l;
411 LPTSTR p = hole_path + (l=_tcslen(hole_path));
412
413 while(--p>=hole_path && (*p=='/' || *p=='\\'))
414 *p = '\0';
415
416 WIN32_FIND_DATA w32fd;
417
418 HANDLE hFind = FindFirstFile(hole_path, &w32fd);
419
420 if (hFind == INVALID_HANDLE_VALUE) {
421 _tcsncpy(path, hole_path, drv_len);
422 int i = drv_len;
423
424 for(p=dir; *p=='/'||*p=='\\'; p++)
425 path[i++] = *p++;
426
427 for(; i<l; i++) {
428 memcpy(path, hole_path, i*sizeof(TCHAR));
429
430 for(; hole_path[i] && hole_path[i]!='/' && hole_path[i]!='\\'; i++)
431 path[i] = hole_path[i];
432
433 path[i] = '\0';
434
435 hFind = FindFirstFile(path, &w32fd);
436
437 if (hFind != INVALID_HANDLE_VALUE)
438 FindClose(hFind);
439 else {
440 LOG(FmtString(TEXT("CreateDirectory(\"%s\")"), path));
441
442 if (!CreateDirectory(path, 0))
443 return FALSE;
444 }
445 }
446 } else
447 FindClose(hFind);
448
449 return TRUE;
450 }
451
452
453 DWORD RegGetDWORDValue(HKEY root, LPCTSTR path, LPCTSTR valueName, DWORD def)
454 {
455 HKEY hkey;
456 DWORD ret;
457
458 if (!RegOpenKey(root, path, &hkey)) {
459 DWORD len = sizeof(ret);
460
461 if (RegQueryValueEx(hkey, valueName, 0, NULL, (LPBYTE)&ret, &len))
462 ret = def;
463
464 RegCloseKey(hkey);
465
466 return ret;
467 } else
468 return def;
469 }
470
471
472 BOOL RegSetDWORDValue(HKEY root, LPCTSTR path, LPCTSTR valueName, DWORD value)
473 {
474 HKEY hkey;
475 BOOL ret = FALSE;
476
477 if (!RegOpenKey(root, path, &hkey)) {
478 ret = RegSetValueEx(hkey, valueName, 0, REG_DWORD, (LPBYTE)&value, sizeof(value));
479
480 RegCloseKey(hkey);
481 }
482
483 return ret;
484 }
485
486
487 BOOL exists_path(LPCTSTR path)
488 {
489 WIN32_FIND_DATA fd;
490
491 HANDLE hfind = FindFirstFile(path, &fd);
492
493 if (hfind != INVALID_HANDLE_VALUE) {
494 FindClose(hfind);
495
496 return TRUE;
497 } else
498 return FALSE;
499 }
500
501
502 bool SplitFileSysURL(LPCTSTR url, String& dir_out, String& fname_out)
503 {
504 if (!_tcsnicmp(url, TEXT("file://"), 7)) {
505 url += 7;
506
507 // remove third slash in front of drive characters
508 if (*url == '/')
509 ++url;
510 }
511
512 if (exists_path(url)) {
513 TCHAR path[_MAX_PATH];
514
515 // convert slashes to back slashes
516 GetFullPathName(url, COUNTOF(path), path, NULL);
517
518 if (GetFileAttributes(path) & FILE_ATTRIBUTE_DIRECTORY)
519 fname_out.erase();
520 else {
521 TCHAR drv[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
522
523 _tsplitpath_s(path, drv, COUNTOF(drv), dir, COUNTOF(dir), fname, COUNTOF(fname), ext, COUNTOF(ext));
524 _stprintf(path, TEXT("%s%s"), drv, dir);
525
526 fname_out.printf(TEXT("%s%s"), fname, ext);
527 }
528
529 dir_out = path;
530
531 return true;
532 } else
533 return false;
534 }