313c12340abceb12173a3ef3f70aa30734ceba69
[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 Result = pfnExtract(&Dest, szCabName);
264 if (Result == S_OK)
265 {
266 FreeLibrary(hCabinetDll);
267 return TRUE;
268 }
269 }
270 }
271 FreeLibrary(hCabinetDll);
272 }
273
274 return FALSE;
275 }
276
277 VOID InitLogs()
278 {
279 if (!SettingsInfo.bLogEnabled)
280 {
281 return;
282 }
283
284 WCHAR szPath[MAX_PATH];
285 DWORD dwCategoryNum = 1;
286 DWORD dwDisp, dwData;
287 ATL::CRegKey key;
288
289 if (key.Create(HKEY_LOCAL_MACHINE,
290 L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\ReactOS Application Manager",
291 REG_NONE, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &dwDisp) != ERROR_SUCCESS)
292 {
293 return;
294 }
295
296 if (!GetModuleFileNameW(NULL, szPath, _countof(szPath)))
297 {
298 return;
299 }
300
301 dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE |
302 EVENTLOG_INFORMATION_TYPE;
303
304 if ((key.SetStringValue(L"EventMessageFile",
305 szPath,
306 REG_EXPAND_SZ) == ERROR_SUCCESS)
307 && (key.SetStringValue(L"CategoryMessageFile",
308 szPath,
309 REG_EXPAND_SZ) == ERROR_SUCCESS)
310 && (key.SetDWORDValue(L"TypesSupported",
311 dwData) == ERROR_SUCCESS)
312 && (key.SetDWORDValue(L"CategoryCount",
313 dwCategoryNum) == ERROR_SUCCESS))
314
315 {
316 hLog = RegisterEventSourceW(NULL, L"ReactOS Application Manager");
317 }
318
319 key.Close();
320 }
321
322
323 VOID FreeLogs()
324 {
325 if (hLog)
326 {
327 DeregisterEventSource(hLog);
328 }
329 }
330
331
332 BOOL WriteLogMessage(WORD wType, DWORD dwEventID, LPCWSTR lpMsg)
333 {
334 if (!SettingsInfo.bLogEnabled)
335 {
336 return TRUE;
337 }
338
339 if (!ReportEventW(hLog, wType, 0, dwEventID,
340 NULL, 1, 0, &lpMsg, NULL))
341 {
342 return FALSE;
343 }
344
345 return TRUE;
346 }
347
348 BOOL GetInstalledVersion_WowUser(ATL::CStringW* szVersionResult,
349 const ATL::CStringW& RegName,
350 BOOL IsUserKey,
351 REGSAM keyWow)
352 {
353 BOOL bHasSucceded = FALSE;
354 ATL::CRegKey key;
355 ATL::CStringW szVersion;
356 ATL::CStringW szPath = L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" + RegName;
357
358 if (key.Open(IsUserKey ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE,
359 szPath.GetString(),
360 keyWow | KEY_READ) != ERROR_SUCCESS)
361 {
362 return FALSE;
363 }
364
365 if (szVersionResult != NULL)
366 {
367 ULONG dwSize = MAX_PATH * sizeof(WCHAR);
368
369 if (key.QueryStringValue(L"DisplayVersion",
370 szVersion.GetBuffer(MAX_PATH),
371 &dwSize) == ERROR_SUCCESS)
372 {
373 szVersion.ReleaseBuffer();
374 *szVersionResult = szVersion;
375 bHasSucceded = TRUE;
376 }
377 else
378 {
379 szVersion.ReleaseBuffer();
380 }
381 }
382 else
383 {
384 bHasSucceded = TRUE;
385 szVersion.ReleaseBuffer();
386 }
387 key.Close();
388
389 return bHasSucceded;
390 }
391
392 BOOL GetInstalledVersion(ATL::CStringW *pszVersion, const ATL::CStringW &szRegName)
393 {
394 return (!szRegName.IsEmpty()
395 && (GetInstalledVersion_WowUser(pszVersion, szRegName, TRUE, KEY_WOW64_32KEY)
396 || GetInstalledVersion_WowUser(pszVersion, szRegName, FALSE, KEY_WOW64_32KEY)
397 || GetInstalledVersion_WowUser(pszVersion, szRegName, TRUE, KEY_WOW64_64KEY)
398 || GetInstalledVersion_WowUser(pszVersion, szRegName, FALSE, KEY_WOW64_64KEY)));
399 }
400
401 // CConfigParser
402 ATL::CStringW CConfigParser::m_szLocaleID;
403 ATL::CStringW CConfigParser::m_szCachedINISectionLocale;
404 ATL::CStringW CConfigParser::m_szCachedINISectionLocaleNeutral;
405
406 CConfigParser::CConfigParser(const ATL::CStringW& FileName) : szConfigPath(GetINIFullPath(FileName))
407 {
408 // we don't have cached section strings for the current system language, create them, lazy
409 CacheINILocaleLazy();
410 }
411
412 ATL::CStringW CConfigParser::GetINIFullPath(const ATL::CStringW& FileName)
413 {
414 ATL::CStringW szDir;
415 ATL::CStringW szBuffer;
416
417 GetStorageDirectory(szDir);
418 szBuffer.Format(L"%ls\\rapps\\%ls", szDir, FileName);
419
420 return szBuffer;
421 }
422
423 VOID CConfigParser::CacheINILocaleLazy()
424 {
425 if (m_szLocaleID.IsEmpty())
426 {
427 // TODO: Set default locale if call fails
428 // find out what is the current system lang code (e.g. "0a") and append it to SectionLocale
429 GetLocaleInfoW(GetUserDefaultLCID(), LOCALE_ILANGUAGE,
430 m_szLocaleID.GetBuffer(m_cchLocaleSize), m_cchLocaleSize);
431
432 m_szLocaleID.ReleaseBuffer();
433 m_szCachedINISectionLocale = L"Section." + m_szLocaleID;
434
435 // turn "Section.0c0a" into "Section.0a", keeping just the neutral lang part
436 m_szCachedINISectionLocaleNeutral = m_szCachedINISectionLocale + m_szLocaleID.Right(2);
437 }
438 }
439
440 const ATL::CStringW& CConfigParser::GetLocale()
441 {
442 CacheINILocaleLazy();
443 return m_szLocaleID;
444 }
445
446 INT CConfigParser::GetLocaleSize()
447 {
448 return m_cchLocaleSize;
449 }
450
451 UINT CConfigParser::GetString(const ATL::CStringW& KeyName, ATL::CStringW& ResultString)
452 {
453 DWORD dwResult;
454
455 LPWSTR ResultStringBuffer = ResultString.GetBuffer(MAX_PATH);
456 // 1st - find localized strings (e.g. "Section.0c0a")
457 dwResult = GetPrivateProfileStringW(m_szCachedINISectionLocale.GetString(),
458 KeyName.GetString(),
459 NULL,
460 ResultStringBuffer,
461 MAX_PATH,
462 szConfigPath.GetString());
463
464 if (!dwResult)
465 {
466 // 2nd - if they weren't present check for neutral sub-langs/ generic translations (e.g. "Section.0a")
467 dwResult = GetPrivateProfileStringW(m_szCachedINISectionLocaleNeutral.GetString(),
468 KeyName.GetString(),
469 NULL,
470 ResultStringBuffer,
471 MAX_PATH,
472 szConfigPath.GetString());
473 if (!dwResult)
474 {
475 // 3rd - if they weren't present fallback to standard english strings (just "Section")
476 dwResult = GetPrivateProfileStringW(L"Section",
477 KeyName.GetString(),
478 NULL,
479 ResultStringBuffer,
480 MAX_PATH,
481 szConfigPath.GetString());
482 }
483 }
484
485 ResultString.ReleaseBuffer();
486 return (dwResult != 0 ? TRUE : FALSE);
487 }
488
489 UINT CConfigParser::GetInt(const ATL::CStringW& KeyName)
490 {
491 ATL::CStringW Buffer;
492
493 // grab the text version of our entry
494 if (!GetString(KeyName, Buffer))
495 return FALSE;
496
497 if (Buffer.IsEmpty())
498 return FALSE;
499
500 // convert it to an actual integer
501 INT result = StrToIntW(Buffer.GetString());
502
503 return (UINT) (result <= 0) ? 0 : result;
504 }
505 // CConfigParser