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