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