1a9b1e059SJoachim Henze /*
2a9b1e059SJoachim Henze * PROJECT: ReactOS Applications Manager
3a9b1e059SJoachim Henze * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4a9b1e059SJoachim Henze * PURPOSE: Classes for working with available applications
5a9b1e059SJoachim Henze * COPYRIGHT: Copyright 2017 Alexander Shaposhnikov (sanchaez@reactos.org)
6a9b1e059SJoachim Henze * Copyright 2020 He Yang (1160386205@qq.com)
7a9b1e059SJoachim Henze * Copyright 2021-2023 Mark Jansen <mark.jansen@reactos.org>
8a9b1e059SJoachim Henze */
9a9b1e059SJoachim Henze
10a9b1e059SJoachim Henze #include "rapps.h"
11a9b1e059SJoachim Henze #include "appview.h"
12a9b1e059SJoachim Henze
CAppInfo(const CStringW & Identifier,AppsCategories Category)13a9b1e059SJoachim Henze CAppInfo::CAppInfo(const CStringW &Identifier, AppsCategories Category)
14a9b1e059SJoachim Henze : szIdentifier(Identifier), iCategory(Category)
15a9b1e059SJoachim Henze {
16a9b1e059SJoachim Henze }
17a9b1e059SJoachim Henze
~CAppInfo()18a9b1e059SJoachim Henze CAppInfo::~CAppInfo()
19a9b1e059SJoachim Henze {
20a9b1e059SJoachim Henze }
21a9b1e059SJoachim Henze
CAvailableApplicationInfo(CConfigParser * Parser,const CStringW & PkgName,AppsCategories Category,const CPathW & BasePath)22a9b1e059SJoachim Henze CAvailableApplicationInfo::CAvailableApplicationInfo(
23a9b1e059SJoachim Henze CConfigParser *Parser,
24a9b1e059SJoachim Henze const CStringW &PkgName,
25a9b1e059SJoachim Henze AppsCategories Category,
26a9b1e059SJoachim Henze const CPathW &BasePath)
27a9b1e059SJoachim Henze : CAppInfo(PkgName, Category), m_Parser(Parser), m_ScrnshotRetrieved(false), m_LanguagesLoaded(false)
28a9b1e059SJoachim Henze {
29a9b1e059SJoachim Henze m_Parser->GetString(L"Name", szDisplayName);
30a9b1e059SJoachim Henze m_Parser->GetString(L"Version", szDisplayVersion);
31a9b1e059SJoachim Henze m_Parser->GetString(L"URLDownload", m_szUrlDownload);
32a9b1e059SJoachim Henze m_Parser->GetString(L"Description", szComments);
33a9b1e059SJoachim Henze
34a9b1e059SJoachim Henze CPathW IconPath = BasePath;
35a9b1e059SJoachim Henze IconPath += L"icons";
36a9b1e059SJoachim Henze
37a9b1e059SJoachim Henze CStringW IconName;
38a9b1e059SJoachim Henze if (m_Parser->GetString(L"Icon", IconName))
39a9b1e059SJoachim Henze {
40a9b1e059SJoachim Henze IconPath += IconName;
41a9b1e059SJoachim Henze }
42a9b1e059SJoachim Henze else
43a9b1e059SJoachim Henze {
44a9b1e059SJoachim Henze // inifile.ico
45a9b1e059SJoachim Henze IconPath += (szIdentifier + L".ico");
46a9b1e059SJoachim Henze }
47a9b1e059SJoachim Henze
48a9b1e059SJoachim Henze if (PathFileExistsW(IconPath))
49a9b1e059SJoachim Henze {
50a9b1e059SJoachim Henze szDisplayIcon = (LPCWSTR)IconPath;
51a9b1e059SJoachim Henze }
52a9b1e059SJoachim Henze
53a9b1e059SJoachim Henze INT iSizeBytes;
54a9b1e059SJoachim Henze
55a9b1e059SJoachim Henze if (m_Parser->GetInt(L"SizeBytes", iSizeBytes))
56a9b1e059SJoachim Henze {
57a9b1e059SJoachim Henze StrFormatByteSizeW(iSizeBytes, m_szSize.GetBuffer(MAX_PATH), MAX_PATH);
58a9b1e059SJoachim Henze m_szSize.ReleaseBuffer();
59a9b1e059SJoachim Henze }
60a9b1e059SJoachim Henze
61a9b1e059SJoachim Henze m_Parser->GetString(L"URLSite", m_szUrlSite);
62a9b1e059SJoachim Henze }
63a9b1e059SJoachim Henze
~CAvailableApplicationInfo()64a9b1e059SJoachim Henze CAvailableApplicationInfo::~CAvailableApplicationInfo()
65a9b1e059SJoachim Henze {
66a9b1e059SJoachim Henze delete m_Parser;
67a9b1e059SJoachim Henze }
68a9b1e059SJoachim Henze
69a9b1e059SJoachim Henze VOID
ShowAppInfo(CAppRichEdit * RichEdit)70a9b1e059SJoachim Henze CAvailableApplicationInfo::ShowAppInfo(CAppRichEdit *RichEdit)
71a9b1e059SJoachim Henze {
72a9b1e059SJoachim Henze RichEdit->SetText(szDisplayName, CFE_BOLD);
73a9b1e059SJoachim Henze InsertVersionInfo(RichEdit);
74a9b1e059SJoachim Henze RichEdit->LoadAndInsertText(IDS_AINFO_LICENSE, LicenseString(), 0);
75a9b1e059SJoachim Henze InsertLanguageInfo(RichEdit);
76a9b1e059SJoachim Henze
77a9b1e059SJoachim Henze RichEdit->LoadAndInsertText(IDS_AINFO_SIZE, m_szSize, 0);
78a9b1e059SJoachim Henze RichEdit->LoadAndInsertText(IDS_AINFO_URLSITE, m_szUrlSite, CFE_LINK);
79a9b1e059SJoachim Henze RichEdit->LoadAndInsertText(IDS_AINFO_DESCRIPTION, szComments, 0);
80a9b1e059SJoachim Henze RichEdit->LoadAndInsertText(IDS_AINFO_URLDOWNLOAD, m_szUrlDownload, CFE_LINK);
81a9b1e059SJoachim Henze RichEdit->LoadAndInsertText(IDS_AINFO_PACKAGE_NAME, szIdentifier, 0);
82a9b1e059SJoachim Henze }
83a9b1e059SJoachim Henze
84a9b1e059SJoachim Henze int
CompareVersion(const CStringW & left,const CStringW & right)85a9b1e059SJoachim Henze CompareVersion(const CStringW &left, const CStringW &right)
86a9b1e059SJoachim Henze {
87a9b1e059SJoachim Henze int nLeft = 0, nRight = 0;
88a9b1e059SJoachim Henze
89a9b1e059SJoachim Henze while (true)
90a9b1e059SJoachim Henze {
91a9b1e059SJoachim Henze CStringW leftPart = left.Tokenize(L".", nLeft);
92a9b1e059SJoachim Henze CStringW rightPart = right.Tokenize(L".", nRight);
93a9b1e059SJoachim Henze
94a9b1e059SJoachim Henze if (leftPart.IsEmpty() && rightPart.IsEmpty())
95a9b1e059SJoachim Henze return 0;
96a9b1e059SJoachim Henze if (leftPart.IsEmpty())
97a9b1e059SJoachim Henze return -1;
98a9b1e059SJoachim Henze if (rightPart.IsEmpty())
99a9b1e059SJoachim Henze return 1;
100a9b1e059SJoachim Henze
101a9b1e059SJoachim Henze int leftVal, rightVal;
102a9b1e059SJoachim Henze
103a9b1e059SJoachim Henze if (!StrToIntExW(leftPart, STIF_DEFAULT, &leftVal))
104a9b1e059SJoachim Henze leftVal = 0;
105a9b1e059SJoachim Henze if (!StrToIntExW(rightPart, STIF_DEFAULT, &rightVal))
106a9b1e059SJoachim Henze rightVal = 0;
107a9b1e059SJoachim Henze
108a9b1e059SJoachim Henze if (leftVal > rightVal)
109a9b1e059SJoachim Henze return 1;
110a9b1e059SJoachim Henze if (rightVal < leftVal)
111a9b1e059SJoachim Henze return -1;
112a9b1e059SJoachim Henze }
113a9b1e059SJoachim Henze }
114a9b1e059SJoachim Henze
115a9b1e059SJoachim Henze VOID
InsertVersionInfo(CAppRichEdit * RichEdit)116a9b1e059SJoachim Henze CAvailableApplicationInfo::InsertVersionInfo(CAppRichEdit *RichEdit)
117a9b1e059SJoachim Henze {
118a9b1e059SJoachim Henze CStringW szRegName;
119*57b775efSWhindmar Saksit m_Parser->GetString(DB_REGNAME, szRegName);
120a9b1e059SJoachim Henze
121a9b1e059SJoachim Henze BOOL bIsInstalled = ::GetInstalledVersion(NULL, szRegName) || ::GetInstalledVersion(NULL, szDisplayName);
122a9b1e059SJoachim Henze if (bIsInstalled)
123a9b1e059SJoachim Henze {
124a9b1e059SJoachim Henze CStringW szInstalledVersion;
125a9b1e059SJoachim Henze CStringW szNameVersion = szDisplayName + L" " + szDisplayVersion;
126a9b1e059SJoachim Henze BOOL bHasInstalledVersion = ::GetInstalledVersion(&szInstalledVersion, szRegName) ||
127a9b1e059SJoachim Henze ::GetInstalledVersion(&szInstalledVersion, szDisplayName) ||
128a9b1e059SJoachim Henze ::GetInstalledVersion(&szInstalledVersion, szNameVersion);
129a9b1e059SJoachim Henze
130a9b1e059SJoachim Henze if (bHasInstalledVersion)
131a9b1e059SJoachim Henze {
132a9b1e059SJoachim Henze BOOL bHasUpdate = CompareVersion(szInstalledVersion, szDisplayVersion) < 0;
133a9b1e059SJoachim Henze if (bHasUpdate)
134*57b775efSWhindmar Saksit {
135a9b1e059SJoachim Henze RichEdit->LoadAndInsertText(IDS_STATUS_UPDATE_AVAILABLE, CFE_ITALIC);
136a9b1e059SJoachim Henze RichEdit->LoadAndInsertText(IDS_AINFO_VERSION, szInstalledVersion, 0);
137a9b1e059SJoachim Henze }
138a9b1e059SJoachim Henze else
139a9b1e059SJoachim Henze {
140a9b1e059SJoachim Henze RichEdit->LoadAndInsertText(IDS_STATUS_INSTALLED, CFE_ITALIC);
141a9b1e059SJoachim Henze }
142a9b1e059SJoachim Henze }
143a9b1e059SJoachim Henze else
144a9b1e059SJoachim Henze {
145*57b775efSWhindmar Saksit RichEdit->LoadAndInsertText(IDS_STATUS_INSTALLED, CFE_ITALIC);
146*57b775efSWhindmar Saksit }
147*57b775efSWhindmar Saksit }
148*57b775efSWhindmar Saksit else
149*57b775efSWhindmar Saksit {
150a9b1e059SJoachim Henze RichEdit->LoadAndInsertText(IDS_STATUS_NOTINSTALLED, CFE_ITALIC);
151a9b1e059SJoachim Henze }
152a9b1e059SJoachim Henze
153a9b1e059SJoachim Henze RichEdit->LoadAndInsertText(IDS_AINFO_AVAILABLEVERSION, szDisplayVersion, 0);
154a9b1e059SJoachim Henze }
155a9b1e059SJoachim Henze
156a9b1e059SJoachim Henze CStringW
LicenseString()157a9b1e059SJoachim Henze CAvailableApplicationInfo::LicenseString()
158a9b1e059SJoachim Henze {
159a9b1e059SJoachim Henze INT IntBuffer;
160a9b1e059SJoachim Henze m_Parser->GetInt(L"LicenseType", IntBuffer);
161a9b1e059SJoachim Henze CStringW szLicenseString;
162a9b1e059SJoachim Henze m_Parser->GetString(L"License", szLicenseString);
163a9b1e059SJoachim Henze LicenseType licenseType;
164a9b1e059SJoachim Henze
1654b039818SWhindmar Saksit if (IsKnownLicenseType(IntBuffer))
166a9b1e059SJoachim Henze {
167a9b1e059SJoachim Henze licenseType = static_cast<LicenseType>(IntBuffer);
168a9b1e059SJoachim Henze }
169a9b1e059SJoachim Henze else
170a9b1e059SJoachim Henze {
171a9b1e059SJoachim Henze licenseType = LICENSE_NONE;
1724b039818SWhindmar Saksit if (szLicenseString.CompareNoCase(L"Freeware") == 0)
1734b039818SWhindmar Saksit {
1744b039818SWhindmar Saksit licenseType = LICENSE_FREEWARE;
1754b039818SWhindmar Saksit szLicenseString = L"";
1764b039818SWhindmar Saksit }
177a9b1e059SJoachim Henze }
178a9b1e059SJoachim Henze
179a9b1e059SJoachim Henze CStringW szLicense;
180a9b1e059SJoachim Henze switch (licenseType)
181a9b1e059SJoachim Henze {
182a9b1e059SJoachim Henze case LICENSE_OPENSOURCE:
183a9b1e059SJoachim Henze szLicense.LoadStringW(IDS_LICENSE_OPENSOURCE);
184a9b1e059SJoachim Henze break;
185a9b1e059SJoachim Henze case LICENSE_FREEWARE:
186a9b1e059SJoachim Henze szLicense.LoadStringW(IDS_LICENSE_FREEWARE);
187a9b1e059SJoachim Henze break;
188a9b1e059SJoachim Henze case LICENSE_TRIAL:
189a9b1e059SJoachim Henze szLicense.LoadStringW(IDS_LICENSE_TRIAL);
190a9b1e059SJoachim Henze break;
191a9b1e059SJoachim Henze default:
192a9b1e059SJoachim Henze return szLicenseString;
193a9b1e059SJoachim Henze }
194a9b1e059SJoachim Henze
1954b039818SWhindmar Saksit if (!szLicenseString.IsEmpty())
1964b039818SWhindmar Saksit szLicense += L" (" + szLicenseString + L")";
1974b039818SWhindmar Saksit return szLicense;
198a9b1e059SJoachim Henze }
199a9b1e059SJoachim Henze
200a9b1e059SJoachim Henze VOID
InsertLanguageInfo(CAppRichEdit * RichEdit)201a9b1e059SJoachim Henze CAvailableApplicationInfo::InsertLanguageInfo(CAppRichEdit *RichEdit)
202a9b1e059SJoachim Henze {
203a9b1e059SJoachim Henze if (!m_LanguagesLoaded)
204a9b1e059SJoachim Henze {
205a9b1e059SJoachim Henze RetrieveLanguages();
206a9b1e059SJoachim Henze }
207a9b1e059SJoachim Henze
208a9b1e059SJoachim Henze if (m_LanguageLCIDs.GetSize() == 0)
209a9b1e059SJoachim Henze {
210a9b1e059SJoachim Henze return;
211a9b1e059SJoachim Henze }
212a9b1e059SJoachim Henze
213a9b1e059SJoachim Henze const INT nTranslations = m_LanguageLCIDs.GetSize();
214a9b1e059SJoachim Henze CStringW szLangInfo;
215a9b1e059SJoachim Henze CStringW szLoadedTextAvailability;
216a9b1e059SJoachim Henze CStringW szLoadedAInfoText;
217a9b1e059SJoachim Henze
218a9b1e059SJoachim Henze szLoadedAInfoText.LoadStringW(IDS_AINFO_LANGUAGES);
219a9b1e059SJoachim Henze
220a9b1e059SJoachim Henze const LCID lcEnglish = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), SORT_DEFAULT);
221a9b1e059SJoachim Henze if (m_LanguageLCIDs.Find(GetUserDefaultLCID()) >= 0)
222a9b1e059SJoachim Henze {
223a9b1e059SJoachim Henze szLoadedTextAvailability.LoadStringW(IDS_LANGUAGE_AVAILABLE_TRANSLATION);
224a9b1e059SJoachim Henze if (nTranslations > 1)
225a9b1e059SJoachim Henze {
226a9b1e059SJoachim Henze CStringW buf;
227a9b1e059SJoachim Henze buf.LoadStringW(IDS_LANGUAGE_MORE_PLACEHOLDER);
228a9b1e059SJoachim Henze szLangInfo.Format(buf, nTranslations - 1);
229a9b1e059SJoachim Henze }
230a9b1e059SJoachim Henze else
231a9b1e059SJoachim Henze {
232a9b1e059SJoachim Henze szLangInfo.LoadStringW(IDS_LANGUAGE_SINGLE);
233a9b1e059SJoachim Henze szLangInfo = L" (" + szLangInfo + L")";
234a9b1e059SJoachim Henze }
235a9b1e059SJoachim Henze }
236a9b1e059SJoachim Henze else if (m_LanguageLCIDs.Find(lcEnglish) >= 0)
237a9b1e059SJoachim Henze {
238a9b1e059SJoachim Henze szLoadedTextAvailability.LoadStringW(IDS_LANGUAGE_ENGLISH_TRANSLATION);
239a9b1e059SJoachim Henze if (nTranslations > 1)
240a9b1e059SJoachim Henze {
241a9b1e059SJoachim Henze CStringW buf;
242a9b1e059SJoachim Henze buf.LoadStringW(IDS_LANGUAGE_AVAILABLE_PLACEHOLDER);
243a9b1e059SJoachim Henze szLangInfo.Format(buf, nTranslations - 1);
244a9b1e059SJoachim Henze }
245a9b1e059SJoachim Henze else
246a9b1e059SJoachim Henze {
247a9b1e059SJoachim Henze szLangInfo.LoadStringW(IDS_LANGUAGE_SINGLE);
248a9b1e059SJoachim Henze szLangInfo = L" (" + szLangInfo + L")";
249a9b1e059SJoachim Henze }
250a9b1e059SJoachim Henze }
251a9b1e059SJoachim Henze else
252a9b1e059SJoachim Henze {
253a9b1e059SJoachim Henze szLoadedTextAvailability.LoadStringW(IDS_LANGUAGE_NO_TRANSLATION);
254a9b1e059SJoachim Henze }
255a9b1e059SJoachim Henze
256a9b1e059SJoachim Henze RichEdit->InsertText(szLoadedAInfoText, CFE_BOLD);
257a9b1e059SJoachim Henze RichEdit->InsertText(szLoadedTextAvailability, NULL);
258a9b1e059SJoachim Henze RichEdit->InsertText(szLangInfo, CFE_ITALIC);
259a9b1e059SJoachim Henze }
260a9b1e059SJoachim Henze
261a9b1e059SJoachim Henze VOID
RetrieveLanguages()262a9b1e059SJoachim Henze CAvailableApplicationInfo::RetrieveLanguages()
263a9b1e059SJoachim Henze {
264a9b1e059SJoachim Henze m_LanguagesLoaded = true;
265a9b1e059SJoachim Henze
266a9b1e059SJoachim Henze CStringW szBuffer;
267a9b1e059SJoachim Henze if (!m_Parser->GetString(L"Languages", szBuffer))
268a9b1e059SJoachim Henze {
269a9b1e059SJoachim Henze return;
270a9b1e059SJoachim Henze }
271a9b1e059SJoachim Henze
272a9b1e059SJoachim Henze // Parse parameter string
273a9b1e059SJoachim Henze int iIndex = 0;
274a9b1e059SJoachim Henze while (true)
275a9b1e059SJoachim Henze {
276a9b1e059SJoachim Henze CStringW szLocale = szBuffer.Tokenize(L"|", iIndex);
277a9b1e059SJoachim Henze if (szLocale.IsEmpty())
278a9b1e059SJoachim Henze break;
279a9b1e059SJoachim Henze
280a9b1e059SJoachim Henze szLocale = L"0x" + szLocale;
281a9b1e059SJoachim Henze
282a9b1e059SJoachim Henze INT iLCID;
283a9b1e059SJoachim Henze if (StrToIntExW(szLocale, STIF_SUPPORT_HEX, &iLCID))
284a9b1e059SJoachim Henze {
285a9b1e059SJoachim Henze m_LanguageLCIDs.Add(static_cast<LCID>(iLCID));
286a9b1e059SJoachim Henze }
287a9b1e059SJoachim Henze }
288a9b1e059SJoachim Henze }
289a9b1e059SJoachim Henze
290a9b1e059SJoachim Henze BOOL
Valid() const291a9b1e059SJoachim Henze CAvailableApplicationInfo::Valid() const
292a9b1e059SJoachim Henze {
293a9b1e059SJoachim Henze return !szDisplayName.IsEmpty() && !m_szUrlDownload.IsEmpty();
294a9b1e059SJoachim Henze }
295a9b1e059SJoachim Henze
296a9b1e059SJoachim Henze BOOL
CanModify()297a9b1e059SJoachim Henze CAvailableApplicationInfo::CanModify()
298a9b1e059SJoachim Henze {
299a9b1e059SJoachim Henze return FALSE;
300a9b1e059SJoachim Henze }
301a9b1e059SJoachim Henze
302a9b1e059SJoachim Henze BOOL
RetrieveIcon(CStringW & Path) const303a9b1e059SJoachim Henze CAvailableApplicationInfo::RetrieveIcon(CStringW &Path) const
304a9b1e059SJoachim Henze {
305a9b1e059SJoachim Henze Path = szDisplayIcon;
306a9b1e059SJoachim Henze return !Path.IsEmpty();
307a9b1e059SJoachim Henze }
308a9b1e059SJoachim Henze
309a9b1e059SJoachim Henze #define MAX_SCRNSHOT_NUM 16
310a9b1e059SJoachim Henze BOOL
RetrieveScreenshot(CStringW & Path)311a9b1e059SJoachim Henze CAvailableApplicationInfo::RetrieveScreenshot(CStringW &Path)
312a9b1e059SJoachim Henze {
313a9b1e059SJoachim Henze if (!m_ScrnshotRetrieved)
314a9b1e059SJoachim Henze {
315a9b1e059SJoachim Henze static_assert(MAX_SCRNSHOT_NUM < 10000, "MAX_SCRNSHOT_NUM is too big");
316a9b1e059SJoachim Henze for (int i = 0; i < MAX_SCRNSHOT_NUM; i++)
317a9b1e059SJoachim Henze {
318a9b1e059SJoachim Henze CStringW ScrnshotField;
319a9b1e059SJoachim Henze ScrnshotField.Format(L"Screenshot%d", i + 1);
320a9b1e059SJoachim Henze CStringW ScrnshotLocation;
321a9b1e059SJoachim Henze if (!m_Parser->GetString(ScrnshotField, ScrnshotLocation))
322a9b1e059SJoachim Henze {
323a9b1e059SJoachim Henze // We stop at the first screenshot not found,
324a9b1e059SJoachim Henze // so screenshots _have_ to be consecutive
325a9b1e059SJoachim Henze break;
326a9b1e059SJoachim Henze }
327a9b1e059SJoachim Henze
328a9b1e059SJoachim Henze if (PathIsURLW(ScrnshotLocation.GetString()))
329a9b1e059SJoachim Henze {
330a9b1e059SJoachim Henze m_szScrnshotLocation.Add(ScrnshotLocation);
331a9b1e059SJoachim Henze }
332a9b1e059SJoachim Henze }
333a9b1e059SJoachim Henze m_ScrnshotRetrieved = true;
334a9b1e059SJoachim Henze }
335a9b1e059SJoachim Henze
336a9b1e059SJoachim Henze if (m_szScrnshotLocation.GetSize() > 0)
337a9b1e059SJoachim Henze {
338a9b1e059SJoachim Henze Path = m_szScrnshotLocation[0];
339a9b1e059SJoachim Henze }
340a9b1e059SJoachim Henze
341a9b1e059SJoachim Henze return !Path.IsEmpty();
342a9b1e059SJoachim Henze }
343a9b1e059SJoachim Henze
344a9b1e059SJoachim Henze VOID
GetDownloadInfo(CStringW & Url,CStringW & Sha1,ULONG & SizeInBytes) const345a9b1e059SJoachim Henze CAvailableApplicationInfo::GetDownloadInfo(CStringW &Url, CStringW &Sha1, ULONG &SizeInBytes) const
346a9b1e059SJoachim Henze {
347a9b1e059SJoachim Henze Url = m_szUrlDownload;
348a9b1e059SJoachim Henze m_Parser->GetString(L"SHA1", Sha1);
349a9b1e059SJoachim Henze INT iSizeBytes;
350a9b1e059SJoachim Henze
351a9b1e059SJoachim Henze if (m_Parser->GetInt(L"SizeBytes", iSizeBytes))
352a9b1e059SJoachim Henze {
353a9b1e059SJoachim Henze SizeInBytes = (ULONG)iSizeBytes;
354a9b1e059SJoachim Henze }
355a9b1e059SJoachim Henze else
356a9b1e059SJoachim Henze {
357a9b1e059SJoachim Henze SizeInBytes = 0;
358a9b1e059SJoachim Henze }
359a9b1e059SJoachim Henze }
360a9b1e059SJoachim Henze
361a9b1e059SJoachim Henze VOID
GetDisplayInfo(CStringW & License,CStringW & Size,CStringW & UrlSite,CStringW & UrlDownload)362a9b1e059SJoachim Henze CAvailableApplicationInfo::GetDisplayInfo(CStringW &License, CStringW &Size, CStringW &UrlSite, CStringW &UrlDownload)
363a9b1e059SJoachim Henze {
364a9b1e059SJoachim Henze License = LicenseString();
365a9b1e059SJoachim Henze Size = m_szSize;
366a9b1e059SJoachim Henze UrlSite = m_szUrlSite;
367a9b1e059SJoachim Henze UrlDownload = m_szUrlDownload;
368a9b1e059SJoachim Henze }
369a9b1e059SJoachim Henze
370*57b775efSWhindmar Saksit InstallerType
GetInstallerType() const371*57b775efSWhindmar Saksit CAvailableApplicationInfo::GetInstallerType() const
372*57b775efSWhindmar Saksit {
373*57b775efSWhindmar Saksit CStringW str;
374*57b775efSWhindmar Saksit m_Parser->GetString(DB_INSTALLER, str);
375*57b775efSWhindmar Saksit if (str.CompareNoCase(DB_GENINSTSECTION) == 0)
376*57b775efSWhindmar Saksit return INSTALLER_GENERATE;
377*57b775efSWhindmar Saksit else
378*57b775efSWhindmar Saksit return INSTALLER_UNKNOWN;
379*57b775efSWhindmar Saksit }
380*57b775efSWhindmar Saksit
381a9b1e059SJoachim Henze BOOL
UninstallApplication(UninstallCommandFlags Flags)382*57b775efSWhindmar Saksit CAvailableApplicationInfo::UninstallApplication(UninstallCommandFlags Flags)
383a9b1e059SJoachim Henze {
384a9b1e059SJoachim Henze ATLASSERT(FALSE && "Should not be called");
385a9b1e059SJoachim Henze return FALSE;
386a9b1e059SJoachim Henze }
387a9b1e059SJoachim Henze
CInstalledApplicationInfo(HKEY Key,const CStringW & KeyName,AppsCategories Category,UINT KeyInfo)388a9b1e059SJoachim Henze CInstalledApplicationInfo::CInstalledApplicationInfo(
389a9b1e059SJoachim Henze HKEY Key,
390a9b1e059SJoachim Henze const CStringW &KeyName,
391*57b775efSWhindmar Saksit AppsCategories Category, UINT KeyInfo)
392*57b775efSWhindmar Saksit : CAppInfo(KeyName, Category), m_hKey(Key), m_KeyInfo(KeyInfo)
393a9b1e059SJoachim Henze {
394a9b1e059SJoachim Henze if (GetApplicationRegString(L"DisplayName", szDisplayName))
395a9b1e059SJoachim Henze {
396a9b1e059SJoachim Henze GetApplicationRegString(L"DisplayIcon", szDisplayIcon);
397a9b1e059SJoachim Henze GetApplicationRegString(L"DisplayVersion", szDisplayVersion);
398a9b1e059SJoachim Henze GetApplicationRegString(L"Comments", szComments);
399a9b1e059SJoachim Henze }
400a9b1e059SJoachim Henze }
401a9b1e059SJoachim Henze
~CInstalledApplicationInfo()402a9b1e059SJoachim Henze CInstalledApplicationInfo::~CInstalledApplicationInfo()
403a9b1e059SJoachim Henze {
404a9b1e059SJoachim Henze }
405a9b1e059SJoachim Henze
406a9b1e059SJoachim Henze VOID
AddApplicationRegString(CAppRichEdit * RichEdit,UINT StringID,const CStringW & String,DWORD TextFlags)407a9b1e059SJoachim Henze CInstalledApplicationInfo::AddApplicationRegString(
408a9b1e059SJoachim Henze CAppRichEdit *RichEdit,
409a9b1e059SJoachim Henze UINT StringID,
410a9b1e059SJoachim Henze const CStringW &String,
411a9b1e059SJoachim Henze DWORD TextFlags)
412a9b1e059SJoachim Henze {
413a9b1e059SJoachim Henze CStringW Tmp;
414a9b1e059SJoachim Henze if (GetApplicationRegString(String, Tmp))
415a9b1e059SJoachim Henze {
416a9b1e059SJoachim Henze RichEdit->InsertTextWithString(StringID, Tmp, TextFlags);
417a9b1e059SJoachim Henze }
418a9b1e059SJoachim Henze }
419a9b1e059SJoachim Henze
420a9b1e059SJoachim Henze VOID
ShowAppInfo(CAppRichEdit * RichEdit)421a9b1e059SJoachim Henze CInstalledApplicationInfo::ShowAppInfo(CAppRichEdit *RichEdit)
422a9b1e059SJoachim Henze {
423a9b1e059SJoachim Henze RichEdit->SetText(szDisplayName, CFE_BOLD);
424a9b1e059SJoachim Henze RichEdit->InsertText(L"\n", 0);
425a9b1e059SJoachim Henze
426a9b1e059SJoachim Henze RichEdit->InsertTextWithString(IDS_INFO_VERSION, szDisplayVersion, 0);
427a9b1e059SJoachim Henze AddApplicationRegString(RichEdit, IDS_INFO_PUBLISHER, L"Publisher", 0);
428a9b1e059SJoachim Henze AddApplicationRegString(RichEdit, IDS_INFO_REGOWNER, L"RegOwner", 0);
429a9b1e059SJoachim Henze AddApplicationRegString(RichEdit, IDS_INFO_PRODUCTID, L"ProductID", 0);
430a9b1e059SJoachim Henze AddApplicationRegString(RichEdit, IDS_INFO_HELPLINK, L"HelpLink", CFM_LINK);
431a9b1e059SJoachim Henze AddApplicationRegString(RichEdit, IDS_INFO_HELPPHONE, L"HelpTelephone", 0);
432a9b1e059SJoachim Henze AddApplicationRegString(RichEdit, IDS_INFO_README, L"Readme", 0);
433a9b1e059SJoachim Henze AddApplicationRegString(RichEdit, IDS_INFO_CONTACT, L"Contact", 0);
434a9b1e059SJoachim Henze AddApplicationRegString(RichEdit, IDS_INFO_UPDATEINFO, L"URLUpdateInfo", CFM_LINK);
435a9b1e059SJoachim Henze AddApplicationRegString(RichEdit, IDS_INFO_INFOABOUT, L"URLInfoAbout", CFM_LINK);
436a9b1e059SJoachim Henze RichEdit->InsertTextWithString(IDS_INFO_COMMENTS, szComments, 0);
437a9b1e059SJoachim Henze
438a9b1e059SJoachim Henze if (m_szInstallDate.IsEmpty())
439a9b1e059SJoachim Henze {
440a9b1e059SJoachim Henze RetrieveInstallDate();
441a9b1e059SJoachim Henze }
442a9b1e059SJoachim Henze
443a9b1e059SJoachim Henze RichEdit->InsertTextWithString(IDS_INFO_INSTALLDATE, m_szInstallDate, 0);
444a9b1e059SJoachim Henze AddApplicationRegString(RichEdit, IDS_INFO_INSTLOCATION, L"InstallLocation", 0);
445a9b1e059SJoachim Henze AddApplicationRegString(RichEdit, IDS_INFO_INSTALLSRC, L"InstallSource", 0);
446a9b1e059SJoachim Henze
447a9b1e059SJoachim Henze if (m_szUninstallString.IsEmpty())
448a9b1e059SJoachim Henze {
449a9b1e059SJoachim Henze RetrieveUninstallStrings();
450a9b1e059SJoachim Henze }
451a9b1e059SJoachim Henze
452a9b1e059SJoachim Henze RichEdit->InsertTextWithString(IDS_INFO_UNINSTALLSTR, m_szUninstallString, 0);
453a9b1e059SJoachim Henze RichEdit->InsertTextWithString(IDS_INFO_MODIFYPATH, m_szModifyString, 0);
454a9b1e059SJoachim Henze }
455a9b1e059SJoachim Henze
456a9b1e059SJoachim Henze VOID
RetrieveInstallDate()457a9b1e059SJoachim Henze CInstalledApplicationInfo::RetrieveInstallDate()
458a9b1e059SJoachim Henze {
459a9b1e059SJoachim Henze DWORD dwInstallTimeStamp;
460a9b1e059SJoachim Henze SYSTEMTIME InstallLocalTime;
461a9b1e059SJoachim Henze if (GetApplicationRegString(L"InstallDate", m_szInstallDate))
462a9b1e059SJoachim Henze {
463a9b1e059SJoachim Henze ZeroMemory(&InstallLocalTime, sizeof(InstallLocalTime));
464a9b1e059SJoachim Henze // Check if we have 8 characters to parse the datetime.
465a9b1e059SJoachim Henze // Maybe other formats exist as well?
466a9b1e059SJoachim Henze m_szInstallDate = m_szInstallDate.Trim();
467a9b1e059SJoachim Henze if (m_szInstallDate.GetLength() == 8)
468a9b1e059SJoachim Henze {
469a9b1e059SJoachim Henze InstallLocalTime.wYear = wcstol(m_szInstallDate.Left(4).GetString(), NULL, 10);
470a9b1e059SJoachim Henze InstallLocalTime.wMonth = wcstol(m_szInstallDate.Mid(4, 2).GetString(), NULL, 10);
471a9b1e059SJoachim Henze InstallLocalTime.wDay = wcstol(m_szInstallDate.Mid(6, 2).GetString(), NULL, 10);
472a9b1e059SJoachim Henze }
473a9b1e059SJoachim Henze }
474a9b1e059SJoachim Henze // It might be a DWORD (Unix timestamp). try again.
475a9b1e059SJoachim Henze else if (GetApplicationRegDword(L"InstallDate", &dwInstallTimeStamp))
476a9b1e059SJoachim Henze {
477a9b1e059SJoachim Henze FILETIME InstallFileTime;
478a9b1e059SJoachim Henze SYSTEMTIME InstallSystemTime;
479a9b1e059SJoachim Henze
480a9b1e059SJoachim Henze UnixTimeToFileTime(dwInstallTimeStamp, &InstallFileTime);
481a9b1e059SJoachim Henze FileTimeToSystemTime(&InstallFileTime, &InstallSystemTime);
482a9b1e059SJoachim Henze
483a9b1e059SJoachim Henze // convert to localtime
484a9b1e059SJoachim Henze SystemTimeToTzSpecificLocalTime(NULL, &InstallSystemTime, &InstallLocalTime);
485a9b1e059SJoachim Henze }
486a9b1e059SJoachim Henze
487a9b1e059SJoachim Henze // convert to readable date string
488a9b1e059SJoachim Henze int cchTimeStrLen = GetDateFormatW(LOCALE_USER_DEFAULT, 0, &InstallLocalTime, NULL, 0, 0);
489a9b1e059SJoachim Henze
490a9b1e059SJoachim Henze GetDateFormatW(
491a9b1e059SJoachim Henze LOCALE_USER_DEFAULT, // use default locale for current user
492a9b1e059SJoachim Henze 0, &InstallLocalTime, NULL, m_szInstallDate.GetBuffer(cchTimeStrLen), cchTimeStrLen);
493a9b1e059SJoachim Henze m_szInstallDate.ReleaseBuffer();
494a9b1e059SJoachim Henze }
495a9b1e059SJoachim Henze
496a9b1e059SJoachim Henze VOID
RetrieveUninstallStrings()497a9b1e059SJoachim Henze CInstalledApplicationInfo::RetrieveUninstallStrings()
498a9b1e059SJoachim Henze {
499a9b1e059SJoachim Henze DWORD dwWindowsInstaller = 0;
500a9b1e059SJoachim Henze if (GetApplicationRegDword(L"WindowsInstaller", &dwWindowsInstaller) && dwWindowsInstaller)
501a9b1e059SJoachim Henze {
502a9b1e059SJoachim Henze // MSI has the same info in Uninstall / modify, so manually build it
503a9b1e059SJoachim Henze m_szUninstallString.Format(L"msiexec /x%s", szIdentifier.GetString());
504a9b1e059SJoachim Henze }
505a9b1e059SJoachim Henze else
506a9b1e059SJoachim Henze {
507a9b1e059SJoachim Henze GetApplicationRegString(L"UninstallString", m_szUninstallString);
508a9b1e059SJoachim Henze }
509a9b1e059SJoachim Henze DWORD dwNoModify = 0;
510a9b1e059SJoachim Henze if (!GetApplicationRegDword(L"NoModify", &dwNoModify))
511a9b1e059SJoachim Henze {
512a9b1e059SJoachim Henze CStringW Tmp;
513a9b1e059SJoachim Henze if (GetApplicationRegString(L"NoModify", Tmp))
514a9b1e059SJoachim Henze {
515a9b1e059SJoachim Henze dwNoModify = Tmp.GetLength() > 0 ? (Tmp[0] == '1') : 0;
516a9b1e059SJoachim Henze }
517a9b1e059SJoachim Henze else
518a9b1e059SJoachim Henze {
519a9b1e059SJoachim Henze dwNoModify = 0;
520a9b1e059SJoachim Henze }
521a9b1e059SJoachim Henze }
522a9b1e059SJoachim Henze if (!dwNoModify)
523a9b1e059SJoachim Henze {
524a9b1e059SJoachim Henze if (dwWindowsInstaller)
525a9b1e059SJoachim Henze {
526a9b1e059SJoachim Henze m_szModifyString.Format(L"msiexec /i%s", szIdentifier.GetString());
527a9b1e059SJoachim Henze }
528a9b1e059SJoachim Henze else
529a9b1e059SJoachim Henze {
530a9b1e059SJoachim Henze GetApplicationRegString(L"ModifyPath", m_szModifyString);
531a9b1e059SJoachim Henze }
532a9b1e059SJoachim Henze }
533a9b1e059SJoachim Henze }
534a9b1e059SJoachim Henze
535a9b1e059SJoachim Henze BOOL
Valid() const536a9b1e059SJoachim Henze CInstalledApplicationInfo::Valid() const
537a9b1e059SJoachim Henze {
538a9b1e059SJoachim Henze return !szDisplayName.IsEmpty();
539a9b1e059SJoachim Henze }
540a9b1e059SJoachim Henze
541a9b1e059SJoachim Henze BOOL
CanModify()542a9b1e059SJoachim Henze CInstalledApplicationInfo::CanModify()
543a9b1e059SJoachim Henze {
544a9b1e059SJoachim Henze if (m_szUninstallString.IsEmpty())
545a9b1e059SJoachim Henze {
546a9b1e059SJoachim Henze RetrieveUninstallStrings();
547a9b1e059SJoachim Henze }
548a9b1e059SJoachim Henze
549a9b1e059SJoachim Henze return !m_szModifyString.IsEmpty();
550a9b1e059SJoachim Henze }
551a9b1e059SJoachim Henze
552a9b1e059SJoachim Henze BOOL
RetrieveIcon(CStringW & Path) const553a9b1e059SJoachim Henze CInstalledApplicationInfo::RetrieveIcon(CStringW &Path) const
554a9b1e059SJoachim Henze {
555a9b1e059SJoachim Henze Path = szDisplayIcon;
556a9b1e059SJoachim Henze return !Path.IsEmpty();
557a9b1e059SJoachim Henze }
558a9b1e059SJoachim Henze
559a9b1e059SJoachim Henze BOOL
RetrieveScreenshot(CStringW &)560a9b1e059SJoachim Henze CInstalledApplicationInfo::RetrieveScreenshot(CStringW & /*Path*/)
561a9b1e059SJoachim Henze {
562a9b1e059SJoachim Henze return FALSE;
563a9b1e059SJoachim Henze }
564a9b1e059SJoachim Henze
565a9b1e059SJoachim Henze VOID
GetDownloadInfo(CStringW & Url,CStringW & Sha1,ULONG & SizeInBytes) const566a9b1e059SJoachim Henze CInstalledApplicationInfo::GetDownloadInfo(CStringW &Url, CStringW &Sha1, ULONG &SizeInBytes) const
567a9b1e059SJoachim Henze {
568a9b1e059SJoachim Henze ATLASSERT(FALSE && "Should not be called");
569a9b1e059SJoachim Henze }
570a9b1e059SJoachim Henze
571a9b1e059SJoachim Henze VOID
GetDisplayInfo(CStringW & License,CStringW & Size,CStringW & UrlSite,CStringW & UrlDownload)572a9b1e059SJoachim Henze CInstalledApplicationInfo::GetDisplayInfo(CStringW &License, CStringW &Size, CStringW &UrlSite, CStringW &UrlDownload)
573a9b1e059SJoachim Henze {
574a9b1e059SJoachim Henze ATLASSERT(FALSE && "Should not be called");
575a9b1e059SJoachim Henze }
576a9b1e059SJoachim Henze
577*57b775efSWhindmar Saksit InstallerType
GetInstallerType() const578*57b775efSWhindmar Saksit CInstalledApplicationInfo::GetInstallerType() const
579a9b1e059SJoachim Henze {
580*57b775efSWhindmar Saksit CRegKey reg;
581*57b775efSWhindmar Saksit if (reg.Open(m_hKey, GENERATE_ARPSUBKEY, KEY_READ) == ERROR_SUCCESS)
582*57b775efSWhindmar Saksit {
583*57b775efSWhindmar Saksit return INSTALLER_GENERATE;
584*57b775efSWhindmar Saksit }
585*57b775efSWhindmar Saksit return INSTALLER_UNKNOWN;
586*57b775efSWhindmar Saksit }
587*57b775efSWhindmar Saksit
588*57b775efSWhindmar Saksit BOOL
UninstallApplication(UninstallCommandFlags Flags)589*57b775efSWhindmar Saksit CInstalledApplicationInfo::UninstallApplication(UninstallCommandFlags Flags)
590*57b775efSWhindmar Saksit {
591*57b775efSWhindmar Saksit if (GetInstallerType() == INSTALLER_GENERATE)
592*57b775efSWhindmar Saksit {
593*57b775efSWhindmar Saksit return UninstallGenerated(*this, Flags);
594*57b775efSWhindmar Saksit }
595*57b775efSWhindmar Saksit
596*57b775efSWhindmar Saksit BOOL bModify = Flags & UCF_MODIFY;
597a9b1e059SJoachim Henze if (m_szUninstallString.IsEmpty())
598a9b1e059SJoachim Henze {
599a9b1e059SJoachim Henze RetrieveUninstallStrings();
600a9b1e059SJoachim Henze }
601a9b1e059SJoachim Henze
602*57b775efSWhindmar Saksit CStringW cmd = bModify ? m_szModifyString : m_szUninstallString;
603*57b775efSWhindmar Saksit if ((Flags & (UCF_MODIFY | UCF_SILENT)) == UCF_SILENT)
604*57b775efSWhindmar Saksit {
605*57b775efSWhindmar Saksit DWORD msi = 0;
606*57b775efSWhindmar Saksit msi = GetApplicationRegDword(L"WindowsInstaller", &msi) && msi;
607*57b775efSWhindmar Saksit if (msi)
608*57b775efSWhindmar Saksit {
609*57b775efSWhindmar Saksit cmd += L" /qn";
610*57b775efSWhindmar Saksit }
611*57b775efSWhindmar Saksit else
612*57b775efSWhindmar Saksit {
613*57b775efSWhindmar Saksit CStringW silentcmd;
614*57b775efSWhindmar Saksit if (GetApplicationRegString(L"QuietUninstallString", silentcmd) && !silentcmd.IsEmpty())
615*57b775efSWhindmar Saksit {
616*57b775efSWhindmar Saksit cmd = silentcmd;
617*57b775efSWhindmar Saksit }
618*57b775efSWhindmar Saksit }
619*57b775efSWhindmar Saksit }
620*57b775efSWhindmar Saksit
621*57b775efSWhindmar Saksit BOOL bSuccess = StartProcess(cmd, TRUE);
622a9b1e059SJoachim Henze
623a9b1e059SJoachim Henze if (bSuccess && !bModify)
624a9b1e059SJoachim Henze WriteLogMessage(EVENTLOG_SUCCESS, MSG_SUCCESS_REMOVE, szDisplayName);
625a9b1e059SJoachim Henze
626a9b1e059SJoachim Henze return bSuccess;
627a9b1e059SJoachim Henze }
628a9b1e059SJoachim Henze
629a9b1e059SJoachim Henze BOOL
GetApplicationRegString(LPCWSTR lpKeyName,CStringW & String)630a9b1e059SJoachim Henze CInstalledApplicationInfo::GetApplicationRegString(LPCWSTR lpKeyName, CStringW &String)
631a9b1e059SJoachim Henze {
632a9b1e059SJoachim Henze ULONG nChars = 0;
633a9b1e059SJoachim Henze // Get the size
634a9b1e059SJoachim Henze if (m_hKey.QueryStringValue(lpKeyName, NULL, &nChars) != ERROR_SUCCESS)
635a9b1e059SJoachim Henze {
636a9b1e059SJoachim Henze String.Empty();
637a9b1e059SJoachim Henze return FALSE;
638a9b1e059SJoachim Henze }
639a9b1e059SJoachim Henze
640a9b1e059SJoachim Henze LPWSTR Buffer = String.GetBuffer(nChars);
641a9b1e059SJoachim Henze LONG lResult = m_hKey.QueryStringValue(lpKeyName, Buffer, &nChars);
642a9b1e059SJoachim Henze if (nChars > 0 && Buffer[nChars - 1] == UNICODE_NULL)
643a9b1e059SJoachim Henze nChars--;
644a9b1e059SJoachim Henze String.ReleaseBuffer(nChars);
645a9b1e059SJoachim Henze
646a9b1e059SJoachim Henze if (lResult != ERROR_SUCCESS)
647a9b1e059SJoachim Henze {
648a9b1e059SJoachim Henze String.Empty();
649a9b1e059SJoachim Henze return FALSE;
650a9b1e059SJoachim Henze }
651a9b1e059SJoachim Henze
652a9b1e059SJoachim Henze if (String.Find('%') >= 0)
653a9b1e059SJoachim Henze {
654a9b1e059SJoachim Henze CStringW Tmp;
655a9b1e059SJoachim Henze DWORD dwLen = ExpandEnvironmentStringsW(String, NULL, 0);
656a9b1e059SJoachim Henze if (dwLen > 0)
657a9b1e059SJoachim Henze {
658a9b1e059SJoachim Henze BOOL bSuccess = ExpandEnvironmentStringsW(String, Tmp.GetBuffer(dwLen), dwLen) == dwLen;
659a9b1e059SJoachim Henze Tmp.ReleaseBuffer(dwLen - 1);
660a9b1e059SJoachim Henze if (bSuccess)
661a9b1e059SJoachim Henze {
662a9b1e059SJoachim Henze String = Tmp;
663a9b1e059SJoachim Henze }
664a9b1e059SJoachim Henze else
665a9b1e059SJoachim Henze {
666a9b1e059SJoachim Henze String.Empty();
667a9b1e059SJoachim Henze return FALSE;
668a9b1e059SJoachim Henze }
669a9b1e059SJoachim Henze }
670a9b1e059SJoachim Henze }
671a9b1e059SJoachim Henze
672a9b1e059SJoachim Henze return TRUE;
673a9b1e059SJoachim Henze }
674a9b1e059SJoachim Henze
675a9b1e059SJoachim Henze BOOL
GetApplicationRegDword(LPCWSTR lpKeyName,DWORD * lpValue)676a9b1e059SJoachim Henze CInstalledApplicationInfo::GetApplicationRegDword(LPCWSTR lpKeyName, DWORD *lpValue)
677a9b1e059SJoachim Henze {
678a9b1e059SJoachim Henze DWORD dwSize = sizeof(DWORD), dwType;
679a9b1e059SJoachim Henze if (RegQueryValueExW(m_hKey, lpKeyName, NULL, &dwType, (LPBYTE)lpValue, &dwSize) != ERROR_SUCCESS ||
680a9b1e059SJoachim Henze dwType != REG_DWORD)
681a9b1e059SJoachim Henze {
682a9b1e059SJoachim Henze return FALSE;
683a9b1e059SJoachim Henze }
684a9b1e059SJoachim Henze
685a9b1e059SJoachim Henze return TRUE;
686a9b1e059SJoachim Henze }
687