[RAPPS]
[reactos.git] / reactos / base / applications / rapps / misc.cpp
1 /*
2 * PROJECT: ReactOS Applications Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/applications/rapps/misc.cpp
5 * PURPOSE: Misc functions
6 * PROGRAMMERS: Dmitry Chapyshev (dmitry@reactos.org)
7 * Ismael Ferreras Morezuelas (swyterzone+ros@gmail.com)
8 */
9
10 #include "rapps.h"
11 #include <atlsimpcoll.h>
12 #include <atlstr.h>
13
14 /* SESSION Operation */
15 #define EXTRACT_FILLFILELIST 0x00000001
16 #define EXTRACT_EXTRACTFILES 0x00000002
17
18 static HANDLE hLog = NULL;
19 WCHAR szCachedINISectionLocale[MAX_PATH] = L"Section.";
20 WCHAR szCachedINISectionLocaleNeutral[MAX_PATH] = {0};
21 BYTE bCachedSectionStatus = FALSE;
22
23 typedef struct
24 {
25 int erfOper;
26 int erfType;
27 BOOL fError;
28 } ERF, *PERF;
29
30 struct FILELIST
31 {
32 LPSTR FileName;
33 struct FILELIST *next;
34 BOOL DoExtract;
35 };
36
37 typedef struct
38 {
39 INT FileSize;
40 ERF Error;
41 struct FILELIST *FileList;
42 INT FileCount;
43 INT Operation;
44 CHAR Destination[MAX_PATH];
45 CHAR CurrentFile[MAX_PATH];
46 CHAR Reserved[MAX_PATH];
47 struct FILELIST *FilterList;
48 } SESSION;
49
50 typedef HRESULT(WINAPI *fnExtract)(SESSION *dest, LPCSTR szCabName);
51 fnExtract pfnExtract;
52
53
54 INT
55 GetSystemColorDepth(VOID)
56 {
57 DEVMODE pDevMode;
58 INT ColorDepth;
59
60 pDevMode.dmSize = sizeof(pDevMode);
61 pDevMode.dmDriverExtra = 0;
62
63 if (!EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &pDevMode))
64 {
65 /* TODO: Error message */
66 return ILC_COLOR;
67 }
68
69 switch (pDevMode.dmBitsPerPel)
70 {
71 case 32: ColorDepth = ILC_COLOR32; break;
72 case 24: ColorDepth = ILC_COLOR24; break;
73 case 16: ColorDepth = ILC_COLOR16; break;
74 case 8: ColorDepth = ILC_COLOR8; break;
75 case 4: ColorDepth = ILC_COLOR4; break;
76 default: ColorDepth = ILC_COLOR; break;
77 }
78
79 return ColorDepth;
80 }
81
82 int
83 GetWindowWidth(HWND hwnd)
84 {
85 RECT Rect;
86
87 GetWindowRect(hwnd, &Rect);
88 return (Rect.right - Rect.left);
89 }
90
91 int
92 GetWindowHeight(HWND hwnd)
93 {
94 RECT Rect;
95
96 GetWindowRect(hwnd, &Rect);
97 return (Rect.bottom - Rect.top);
98 }
99
100 int
101 GetClientWindowWidth(HWND hwnd)
102 {
103 RECT Rect;
104
105 GetClientRect(hwnd, &Rect);
106 return (Rect.right - Rect.left);
107 }
108
109 int
110 GetClientWindowHeight(HWND hwnd)
111 {
112 RECT Rect;
113
114 GetClientRect(hwnd, &Rect);
115 return (Rect.bottom - Rect.top);
116 }
117
118 VOID
119 CopyTextToClipboard(LPCWSTR lpszText)
120 {
121 HRESULT hr;
122
123 if (OpenClipboard(NULL))
124 {
125 HGLOBAL ClipBuffer;
126 WCHAR *Buffer;
127 DWORD cchBuffer;
128
129 EmptyClipboard();
130 cchBuffer = wcslen(lpszText) + 1;
131 ClipBuffer = GlobalAlloc(GMEM_DDESHARE, cchBuffer * sizeof(WCHAR));
132 Buffer = (PWCHAR)GlobalLock(ClipBuffer);
133 hr = StringCchCopyW(Buffer, cchBuffer, lpszText);
134 GlobalUnlock(ClipBuffer);
135
136 if (SUCCEEDED(hr))
137 SetClipboardData(CF_UNICODETEXT, ClipBuffer);
138
139 CloseClipboard();
140 }
141 }
142
143 VOID
144 SetWelcomeText(VOID)
145 {
146 WCHAR szText[MAX_STR_LEN*3];
147
148 LoadStringW(hInst, IDS_WELCOME_TITLE, szText, _countof(szText));
149 NewRichEditText(szText, CFE_BOLD);
150
151 LoadStringW(hInst, IDS_WELCOME_TEXT, szText, _countof(szText));
152 InsertRichEditText(szText, 0);
153
154 LoadStringW(hInst, IDS_WELCOME_URL, szText, _countof(szText));
155 InsertRichEditText(szText, CFM_LINK);
156 }
157
158 VOID
159 ShowPopupMenu(HWND hwnd, UINT MenuID, UINT DefaultItem)
160 {
161 HMENU hMenu = NULL;
162 HMENU hPopupMenu;
163 MENUITEMINFO mii;
164 POINT pt;
165
166 if (MenuID)
167 {
168 hMenu = LoadMenuW(hInst, MAKEINTRESOURCEW(MenuID));
169 hPopupMenu = GetSubMenu(hMenu, 0);
170 }
171 else
172 hPopupMenu = GetMenu(hwnd);
173
174 ZeroMemory(&mii, sizeof(mii));
175 mii.cbSize = sizeof(mii);
176 mii.fMask = MIIM_STATE;
177 GetMenuItemInfo(hPopupMenu, DefaultItem, FALSE, &mii);
178
179 if (!(mii.fState & MFS_GRAYED))
180 SetMenuDefaultItem(hPopupMenu, DefaultItem, FALSE);
181
182 GetCursorPos(&pt);
183
184 SetForegroundWindow(hwnd);
185 TrackPopupMenu(hPopupMenu, 0, pt.x, pt.y, 0, hMainWnd, NULL);
186
187 if (hMenu)
188 DestroyMenu(hMenu);
189 }
190
191 BOOL
192 StartProcess(LPWSTR lpPath, BOOL Wait)
193 {
194 PROCESS_INFORMATION pi;
195 STARTUPINFOW si;
196 DWORD dwRet;
197 MSG msg;
198
199 ZeroMemory(&si, sizeof(si));
200 si.cb = sizeof(si);
201 si.dwFlags = STARTF_USESHOWWINDOW;
202 si.wShowWindow = SW_SHOW;
203
204 if (!CreateProcessW(NULL, lpPath, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
205 {
206 return FALSE;
207 }
208
209 CloseHandle(pi.hThread);
210 if (Wait) EnableWindow(hMainWnd, FALSE);
211
212 while (Wait)
213 {
214 dwRet = MsgWaitForMultipleObjects(1, &pi.hProcess, FALSE, INFINITE, QS_ALLEVENTS);
215 if (dwRet == WAIT_OBJECT_0 + 1)
216 {
217 while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
218 {
219 TranslateMessage(&msg);
220 DispatchMessage(&msg);
221 }
222 }
223 else
224 {
225 if (dwRet == WAIT_OBJECT_0 || dwRet == WAIT_FAILED)
226 break;
227 }
228 }
229
230 CloseHandle(pi.hProcess);
231
232 if (Wait)
233 {
234 EnableWindow(hMainWnd, TRUE);
235 SetForegroundWindow(hMainWnd);
236 SetFocus(hMainWnd);
237 }
238
239 return TRUE;
240 }
241
242 BOOL
243 GetStorageDirectory(PWCHAR lpDirectory, DWORD cch)
244 {
245 if (cch < MAX_PATH)
246 return FALSE;
247
248 if (!SHGetSpecialFolderPathW(NULL, lpDirectory, CSIDL_LOCAL_APPDATA, TRUE))
249 return FALSE;
250
251 if (FAILED(StringCchCatW(lpDirectory, cch, L"\\rapps")))
252 return FALSE;
253
254 if (!CreateDirectoryW(lpDirectory, NULL) &&
255 GetLastError() != ERROR_ALREADY_EXISTS)
256 {
257 return FALSE;
258 }
259
260 return TRUE;
261 }
262
263 BOOL
264 ExtractFilesFromCab(LPWSTR lpCabName, LPWSTR lpOutputPath)
265 {
266 HINSTANCE hCabinetDll;
267 CHAR szCabName[MAX_PATH];
268 SESSION Dest;
269 HRESULT Result;
270
271 hCabinetDll = LoadLibraryW(L"cabinet.dll");
272 if (hCabinetDll)
273 {
274 pfnExtract = (fnExtract) GetProcAddress(hCabinetDll, "Extract");
275 if (pfnExtract)
276 {
277 ZeroMemory(&Dest, sizeof(Dest));
278
279 WideCharToMultiByte(CP_ACP, 0, lpOutputPath, -1, Dest.Destination, MAX_PATH, NULL, NULL);
280 WideCharToMultiByte(CP_ACP, 0, lpCabName, -1, szCabName, MAX_PATH, NULL, NULL);
281 Dest.Operation = EXTRACT_FILLFILELIST;
282
283 Result = pfnExtract(&Dest, szCabName);
284 if (Result == S_OK)
285 {
286 Dest.Operation = EXTRACT_EXTRACTFILES;
287 Result = pfnExtract(&Dest, szCabName);
288 if (Result == S_OK)
289 {
290 FreeLibrary(hCabinetDll);
291 return TRUE;
292 }
293 }
294 }
295 FreeLibrary(hCabinetDll);
296 }
297
298 return FALSE;
299 }
300
301 VOID
302 InitLogs(VOID)
303 {
304 WCHAR szBuf[MAX_PATH] = L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\ReactOS Application Manager";
305 WCHAR szPath[MAX_PATH];
306 DWORD dwCategoryNum = 1;
307 DWORD dwDisp, dwData;
308 HKEY hKey;
309
310 if (!SettingsInfo.bLogEnabled) return;
311
312 if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,
313 szBuf, 0, NULL,
314 REG_OPTION_NON_VOLATILE,
315 KEY_WRITE, NULL, &hKey, &dwDisp) != ERROR_SUCCESS)
316 {
317 return;
318 }
319
320 if (!GetModuleFileNameW(NULL, szPath, _countof(szPath)))
321 return;
322
323 if (RegSetValueExW(hKey,
324 L"EventMessageFile",
325 0,
326 REG_EXPAND_SZ,
327 (LPBYTE)szPath,
328 (DWORD)(wcslen(szPath) + 1) * sizeof(WCHAR)) != ERROR_SUCCESS)
329 {
330 RegCloseKey(hKey);
331 return;
332 }
333
334 dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE |
335 EVENTLOG_INFORMATION_TYPE;
336
337 if (RegSetValueExW(hKey,
338 L"TypesSupported",
339 0,
340 REG_DWORD,
341 (LPBYTE)&dwData,
342 sizeof(DWORD)) != ERROR_SUCCESS)
343 {
344 RegCloseKey(hKey);
345 return;
346 }
347
348 if (RegSetValueExW(hKey,
349 L"CategoryMessageFile",
350 0,
351 REG_EXPAND_SZ,
352 (LPBYTE)szPath,
353 (DWORD)(wcslen(szPath) + 1) * sizeof(WCHAR)) != ERROR_SUCCESS)
354 {
355 RegCloseKey(hKey);
356 return;
357 }
358
359 if (RegSetValueExW(hKey,
360 L"CategoryCount",
361 0,
362 REG_DWORD,
363 (LPBYTE)&dwCategoryNum,
364 sizeof(DWORD)) != ERROR_SUCCESS)
365 {
366 RegCloseKey(hKey);
367 return;
368 }
369
370 RegCloseKey(hKey);
371
372 hLog = RegisterEventSourceW(NULL, L"ReactOS Application Manager");
373 }
374
375
376 VOID
377 FreeLogs(VOID)
378 {
379 if (hLog) DeregisterEventSource(hLog);
380 }
381
382
383 BOOL
384 WriteLogMessage(WORD wType, DWORD dwEventID, LPWSTR lpMsg)
385 {
386 if (!SettingsInfo.bLogEnabled) return TRUE;
387
388 if (!ReportEventW(hLog,
389 wType,
390 0,
391 dwEventID,
392 NULL,
393 1,
394 0,
395 (LPCWSTR*)&lpMsg,
396 NULL))
397 {
398 return FALSE;
399 }
400
401 return TRUE;
402 }
403
404
405 LPWSTR GetINIFullPath(LPCWSTR lpFileName)
406 {
407 WCHAR szDir[MAX_PATH];
408 static WCHAR szBuffer[MAX_PATH];
409
410 GetStorageDirectory(szDir, _countof(szDir));
411 StringCbPrintfW(szBuffer, sizeof(szBuffer), L"%ls\\rapps\\%ls", szDir, lpFileName);
412
413 return szBuffer;
414 }
415
416
417 UINT ParserGetString(LPCWSTR lpKeyName, LPWSTR lpReturnedString, UINT nSize, LPCWSTR lpFileName)
418 {
419 PWSTR lpFullFileName = GetINIFullPath(lpFileName);
420 DWORD dwResult;
421
422 /* we don't have cached section strings for the current system language, create them */
423 if(bCachedSectionStatus == FALSE)
424 {
425 WCHAR szLocale[4 + 1];
426 DWORD len;
427
428 /* find out what is the current system lang code (e.g. "0a") and append it to SectionLocale */
429 GetLocaleInfoW(GetUserDefaultLCID(), LOCALE_ILANGUAGE,
430 szLocale, _countof(szLocale));
431
432 StringCbCatW(szCachedINISectionLocale, sizeof(szCachedINISectionLocale), szLocale);
433
434 /* copy the locale-dependent string into the buffer of the future neutral one */
435 StringCbCopyW(szCachedINISectionLocaleNeutral,
436 sizeof(szCachedINISectionLocaleNeutral),
437 szCachedINISectionLocale);
438
439 /* turn "Section.0c0a" into "Section.0a", keeping just the neutral lang part */
440 len = wcslen(szCachedINISectionLocale);
441
442 memmove((szCachedINISectionLocaleNeutral + len) - 4,
443 (szCachedINISectionLocaleNeutral + len) - 2,
444 (2 * sizeof(WCHAR)) + sizeof(UNICODE_NULL));
445
446 /* finally, mark us as cache-friendly for the next time */
447 bCachedSectionStatus = TRUE;
448 }
449
450 /* 1st - find localized strings (e.g. "Section.0c0a") */
451 dwResult = GetPrivateProfileStringW(szCachedINISectionLocale,
452 lpKeyName,
453 NULL,
454 lpReturnedString,
455 nSize,
456 lpFullFileName);
457
458 if (dwResult != 0)
459 return TRUE;
460
461 /* 2nd - if they weren't present check for neutral sub-langs/ generic translations (e.g. "Section.0a") */
462 dwResult = GetPrivateProfileStringW(szCachedINISectionLocaleNeutral,
463 lpKeyName,
464 NULL,
465 lpReturnedString,
466 nSize,
467 lpFullFileName);
468
469 if (dwResult != 0)
470 return TRUE;
471
472 /* 3rd - if they weren't present fallback to standard english strings (just "Section") */
473 dwResult = GetPrivateProfileStringW(L"Section",
474 lpKeyName,
475 NULL,
476 lpReturnedString,
477 nSize,
478 lpFullFileName);
479
480 return (dwResult != 0 ? TRUE : FALSE);
481 }
482
483 UINT ParserGetInt(LPCWSTR lpKeyName, LPCWSTR lpFileName)
484 {
485 WCHAR Buffer[30];
486 UNICODE_STRING BufferW;
487 ULONG Result;
488
489 /* grab the text version of our entry */
490 if (!ParserGetString(lpKeyName, Buffer, _countof(Buffer), lpFileName))
491 return FALSE;
492
493 if (!Buffer[0])
494 return FALSE;
495
496 /* convert it to an actual integer */
497 RtlInitUnicodeString(&BufferW, Buffer);
498 RtlUnicodeStringToInteger(&BufferW, 0, &Result);
499
500 return (UINT)Result;
501 }
502
503 //Parses version string that can be formatted as 1.2.3.4-5
504 //Returns int buffer and it's size
505 BOOL
506 ParseVersion(_In_z_ LPCWSTR szVersion, _Outptr_ INT* parrVersion, _Out_opt_ UINT iVersionSize)
507 {
508 ATL::CSimpleArray<int> arrVersionResult;
509 ATL::CStringW szVersionSingleInt = L"";
510 ATL::CStringW sDelimiters = L".-";
511 BOOL bHasParsed = TRUE;
512 INT iVersionCharCount = 0;
513 //INT iVersionSingleCharCount = 0;
514 INT iIntResult;
515 iVersionSize = 0;
516 while(szVersion[iVersionCharCount] != L'\0')
517 {
518 for (;!sDelimiters.Find(szVersion[iVersionCharCount]); ++iVersionCharCount)
519 {
520 szVersionSingleInt += szVersion[iVersionCharCount];
521 }
522 szVersionSingleInt += L'\0';
523 iIntResult = StrToIntW(szVersionSingleInt.GetBuffer());
524 if (iIntResult)
525 {
526 arrVersionResult.Add(iIntResult);
527 iVersionSize++;
528 }
529 else
530 {
531 bHasParsed = FALSE;
532 }
533 ++iVersionCharCount;
534 }
535 parrVersion = arrVersionResult.GetData();
536 return bHasParsed;
537 }
538
539 //Compares versions
540 //In: Zero terminated strings of versions
541 //Out: TRUE if first is bigger than second, FALSE if else
542 BOOL
543 CompareVersionsBigger(_In_z_ LPCWSTR sczVersion1, _In_z_ LPCWSTR sczVersion2, _Out_ BOOL bResult)
544 {
545 UINT iVersionSize1 = 0;
546 UINT iVersionSize2 = 0;
547 INT *parrVersion1 = NULL, *parrVersion2 = NULL;
548 bResult = FALSE;
549
550 if (!ParseVersion(sczVersion1, parrVersion1, iVersionSize1)
551 || !ParseVersion(sczVersion2, parrVersion2, iVersionSize2))
552 {
553 return FALSE;
554 }
555
556 for (INT i = 0; i < iVersionSize1 && i < iVersionSize2; ++i)
557 {
558 if (parrVersion1[i] > parrVersion2[i])
559 {
560 bResult = TRUE;
561 return TRUE;
562 }
563 }
564
565 return TRUE;
566 }