2 * PROJECT: ReactOS Applications Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/applications/rapps/available.cpp
5 * PURPOSE: Functions for working with available applications
6 * PROGRAMMERS: Dmitry Chapyshev (dmitry@reactos.org)
7 * Ismael Ferreras Morezuelas (swyterzone+ros@gmail.com)
8 * Alexander Shaposhnikov (chaez.san@gmail.com)
13 ATL::CAtlList
<PAPPLICATION_INFO
> InfoList
;
16 InsertTextAfterLoaded_RichEdit(UINT uStringID
, const ATL::CStringW
& szText
, DWORD StringFlags
, DWORD TextFlags
)
18 ATL::CStringW szLoadedText
;
19 if (!szText
.IsEmpty() && szLoadedText
.LoadStringW(hInst
, uStringID
))
21 InsertRichEditText(szLoadedText
, StringFlags
);
22 InsertRichEditText(szText
, TextFlags
);
27 InsertLoadedTextNewl_RichEdit(UINT uStringID
, DWORD StringFlags
)
29 ATL::CStringW szLoadedText
;
30 if (szLoadedText
.LoadStringW(hInst
, uStringID
))
32 InsertRichEditText(L
"\n", 0);
33 InsertRichEditText(szLoadedText
, StringFlags
);
34 InsertRichEditText(L
"\n", 0);
39 GetString(LPCWSTR lpKeyName
, ATL::CStringW
& ReturnedString
, const ATL::CStringW
& cFileName
)
41 if (!ParserGetString(lpKeyName
, cFileName
, ReturnedString
))
43 ReturnedString
.Empty();
49 //Check both registry keys in 64bit system
50 //TODO: check system type beforehand to avoid double checks?
52 GetInstalledVersionEx(PAPPLICATION_INFO Info
, ATL::CStringW
* szVersion
, REGSAM key
)
54 return (!Info
->szRegName
.IsEmpty()
55 && (GetInstalledVersion_WowUser(szVersion
, Info
->szRegName
, TRUE
, key
)
56 || GetInstalledVersion_WowUser(szVersion
, Info
->szRegName
, FALSE
, key
)))
57 || (!Info
->szName
.IsEmpty()
58 && (GetInstalledVersion_WowUser(szVersion
, Info
->szName
, TRUE
, key
)
59 || GetInstalledVersion_WowUser(szVersion
, Info
->szName
, FALSE
, key
)));
63 GetInstalledVersion(PAPPLICATION_INFO Info
, ATL::CStringW
* szVersion
)
65 return GetInstalledVersionEx(Info
, szVersion
, KEY_WOW64_32KEY
)
66 || GetInstalledVersionEx(Info
, szVersion
, KEY_WOW64_64KEY
);
70 IsAppInstalled(PAPPLICATION_INFO Info
)
72 return GetInstalledVersion(Info
, NULL
);
75 ATL::CSimpleArray
<ATL::CStringW
>
76 ParserGetAppLanguages(const ATL::CStringW
& szFileName
)
78 const WCHAR cDelimiter
= L
'|';
79 ATL::CStringW szBuffer
;
81 if (!ParserGetString(L
"Languages", szFileName
, szBuffer
))
82 return CSimpleArray
<ATL::CStringW
>();
84 ATL::CStringW szLocale
;
85 ATL::CSimpleArray
<ATL::CStringW
> arrLocalesResult
;
86 for (INT i
= 0; szBuffer
[i
] != UNICODE_NULL
; ++i
)
88 if (szBuffer
[i
] != cDelimiter
)
90 szLocale
+= szBuffer
[i
];
92 arrLocalesResult
.Add(szLocale
);
96 // For the text after delimiter
97 if (!szLocale
.IsEmpty())
99 arrLocalesResult
.Add(szLocale
);
101 return arrLocalesResult
;
105 HasNativeLanguage(PAPPLICATION_INFO Info
)
111 //TODO: make the actual check
115 HasEnglishLanguage(PAPPLICATION_INFO Info
)
121 //TODO: make the actual check
126 ParserGetLicenseType(const ATL::CStringW
& szFileName
)
128 INT IntBuffer
= ParserGetInt(L
"LicenseType", szFileName
);
129 if (IntBuffer
< 0 || IntBuffer
> LICENSE_TYPE::Max
)
131 return LICENSE_TYPE::None
;
133 return (LICENSE_TYPE
) IntBuffer
;
136 LIST_ENTRY CachedEntriesHead
= {&CachedEntriesHead
, &CachedEntriesHead
};
137 PLIST_ENTRY pCachedEntry
= &CachedEntriesHead
;
140 InsertVersionInfo_RichEdit(PAPPLICATION_INFO Info
)
142 ATL::CStringW szVersion
;
143 BOOL bIsInstalled
= IsAppInstalled(Info
),
144 bHasVersion
= GetInstalledVersion(Info
, &szVersion
);
150 if (Info
->szVersion
.Compare(szVersion
) > 0)
151 InsertLoadedTextNewl_RichEdit(IDS_STATUS_UPDATE_AVAILABLE
, CFE_ITALIC
);
153 InsertLoadedTextNewl_RichEdit(IDS_STATUS_INSTALLED
, CFE_ITALIC
);
155 InsertTextAfterLoaded_RichEdit(IDS_AINFO_VERSION
, szVersion
, CFE_BOLD
, 0);
159 InsertLoadedTextNewl_RichEdit(IDS_STATUS_INSTALLED
, CFE_ITALIC
);
164 InsertLoadedTextNewl_RichEdit(IDS_STATUS_NOTINSTALLED
, CFE_ITALIC
);
167 InsertTextAfterLoaded_RichEdit(IDS_AINFO_AVAILABLEVERSION
, Info
->szVersion
, CFE_BOLD
, 0);
171 InsertLicenseInfo_RichEdit(PAPPLICATION_INFO Info
)
173 ATL::CStringW szLicense
;
174 switch (Info
->LicenseType
)
176 case LICENSE_TYPE::OpenSource
:
177 szLicense
.LoadStringW(hInst
, IDS_LICENSE_OPENSOURCE
);
179 case LICENSE_TYPE::Freeware
:
180 szLicense
.LoadStringW(hInst
, IDS_LICENSE_FREEWARE
);
182 case LICENSE_TYPE::Trial
:
183 szLicense
.LoadStringW(hInst
, IDS_LICENSE_TRIAL
);
189 if (szLicense
.IsEmpty())
191 InsertTextAfterLoaded_RichEdit(IDS_AINFO_LICENSE
, Info
->szLicense
, CFE_BOLD
, 0);
195 szLicense
.Format(L
"(%ls)", Info
->szLicense
);
196 InsertTextAfterLoaded_RichEdit(IDS_AINFO_LICENSE
, szLicense
, CFE_BOLD
, 0);
202 InsertLanguageInfo_RichEdit(PAPPLICATION_INFO Info
)
204 const INT nTranslations
= Info
->Languages
.GetSize();
205 ATL::CStringW szLangInfo
;
206 ATL::CStringW szLoadedTextAvailability
;
207 ATL::CStringW szLoadedAInfoText
;
208 szLoadedAInfoText
.LoadStringW(IDS_AINFO_LANGUAGES
);
210 if(HasNativeLanguage(Info
))
212 szLoadedTextAvailability
.LoadStringW(IDS_LANGUAGE_AVAILABLE_TRANSLATION
);
214 else if (HasEnglishLanguage(Info
))
216 szLoadedTextAvailability
.LoadStringW(IDS_LANGUAGE_ENGLISH_TRANSLATION
);
220 szLoadedTextAvailability
.LoadStringW(IDS_LANGUAGE_NO_TRANSLATION
);
223 if (nTranslations
> 1)
225 szLangInfo
.Format(L
" (+%d more)", nTranslations
- 1);
228 InsertRichEditText(szLoadedAInfoText
, CFE_BOLD
);
229 InsertRichEditText(szLoadedTextAvailability
, NULL
);
230 InsertRichEditText(szLangInfo
, CFE_ITALIC
);
234 ShowAvailableAppInfo(INT Index
)
236 PAPPLICATION_INFO Info
= (PAPPLICATION_INFO
) ListViewGetlParam(Index
);
237 if (!Info
) return FALSE
;
239 NewRichEditText(Info
->szName
, CFE_BOLD
);
240 InsertVersionInfo_RichEdit(Info
);
241 InsertLicenseInfo_RichEdit(Info
);
242 InsertLanguageInfo_RichEdit(Info
);
244 InsertTextAfterLoaded_RichEdit(IDS_AINFO_SIZE
, Info
->szSize
, CFE_BOLD
, 0);
245 InsertTextAfterLoaded_RichEdit(IDS_AINFO_URLSITE
, Info
->szUrlSite
, CFE_BOLD
, CFE_LINK
);
246 InsertTextAfterLoaded_RichEdit(IDS_AINFO_DESCRIPTION
, Info
->szDesc
, CFE_BOLD
, 0);
247 InsertTextAfterLoaded_RichEdit(IDS_AINFO_URLDOWNLOAD
, Info
->szUrlDownload
, CFE_BOLD
, CFE_LINK
);
253 DeleteCurrentAppsDB(VOID
)
255 HANDLE hFind
= INVALID_HANDLE_VALUE
;
256 WIN32_FIND_DATAW FindFileData
;
257 ATL::CStringW szCabPath
;
258 ATL::CStringW szSearchPath
;
259 ATL::CStringW szPath
;
262 if (!GetStorageDirectory(szPath
))
265 szCabPath
= szPath
+ L
"\\rappmgr.cab";
266 result
= result
&& DeleteFileW(szCabPath
.GetString());
268 szPath
+= L
"\\rapps\\";
269 szSearchPath
= szPath
+ L
"*.txt";
271 hFind
= FindFirstFileW(szSearchPath
.GetString(), &FindFileData
);
273 if (hFind
== INVALID_HANDLE_VALUE
)
279 szTmp
= szPath
+ FindFileData
.cFileName
;
280 result
= result
&& DeleteFileW(szTmp
.GetString());
281 } while (FindNextFileW(hFind
, &FindFileData
) != 0);
291 ATL::CStringW szPath
;
292 ATL::CStringW szAppsPath
;
293 ATL::CStringW szCabPath
;
295 if (!DeleteCurrentAppsDB())
298 DownloadApplicationsDB(APPLICATION_DATABASE_URL
);
300 if (!GetStorageDirectory(szPath
))
303 szCabPath
= szPath
+ L
"\\rappmgr.cab";
304 szAppsPath
= szPath
+ L
"\\rapps\\";
306 if (!ExtractFilesFromCab(szCabPath
, szAppsPath
))
316 EnumAvailableApplications(INT EnumType
, AVAILENUMPROC lpEnumProc
)
318 HANDLE hFind
= INVALID_HANDLE_VALUE
;
319 WIN32_FIND_DATAW FindFileData
;
320 ATL::CStringW szPath
;
321 ATL::CStringW szAppsPath
;
322 ATL::CStringW szCabPath
;
323 PAPPLICATION_INFO Info
;
325 if (!GetStorageDirectory(szPath
))
328 szCabPath
= szPath
+ L
"\\rappmgr.cab";
329 szPath
+= L
"\\rapps\\";
332 if (!CreateDirectoryW(szPath
.GetString(), NULL
) &&
333 GetLastError() != ERROR_ALREADY_EXISTS
)
339 hFind
= FindFirstFileW(szPath
.GetString(), &FindFileData
);
341 if (hFind
== INVALID_HANDLE_VALUE
)
343 if (GetFileAttributesW(szCabPath
) == INVALID_FILE_ATTRIBUTES
)
344 DownloadApplicationsDB(APPLICATION_DATABASE_URL
);
346 ExtractFilesFromCab(szCabPath
, szAppsPath
);
347 hFind
= FindFirstFileW(szPath
, &FindFileData
);
349 if (hFind
== INVALID_HANDLE_VALUE
)
355 /* loop for all the cached entries */
356 POSITION CurrentListPosition
= InfoList
.GetHeadPosition();
358 while (CurrentListPosition
!= NULL
)
360 POSITION LastListPosition
= CurrentListPosition
;
361 Info
= InfoList
.GetNext(CurrentListPosition
);
363 /* do we already have this entry in cache? */
364 if (!Info
->cFileName
.Compare(FindFileData
.cFileName
))
366 /* is it current enough, or the file has been modified since our last time here? */
367 if (CompareFileTime(&FindFileData
.ftLastWriteTime
, &Info
->ftCacheStamp
) == 1)
369 /* recreate our cache, this is the slow path */
370 InfoList
.RemoveAt(LastListPosition
);
376 /* speedy path, compare directly, we already have the data */
382 /* create a new entry */
383 Info
= new APPLICATION_INFO();
388 Info
->Category
= ParserGetInt(L
"Category", FindFileData
.cFileName
);
389 Info
->LicenseType
= ParserGetLicenseType(FindFileData
.cFileName
);
390 Info
->Languages
= ParserGetAppLanguages(FindFileData
.cFileName
);
392 /* copy the cache-related fields for the next time */
393 Info
->cFileName
= FindFileData
.cFileName
;
394 RtlCopyMemory(&Info
->ftCacheStamp
, &FindFileData
.ftLastWriteTime
, sizeof(FILETIME
));
396 /* add our cached entry to the cached list */
397 InfoList
.AddTail(Info
);
400 if (Info
->Category
== FALSE
)
403 if (EnumType
!= Info
->Category
&& EnumType
!= ENUM_ALL_AVAILABLE
)
406 /* if our cache hit was only partial, we need to parse
407 and lazily fill the rest of fields only when needed */
409 if (Info
->szUrlDownload
.IsEmpty())
411 if (!GetString(L
"Name", Info
->szName
, FindFileData
.cFileName
)
412 || !GetString(L
"URLDownload", Info
->szUrlDownload
, FindFileData
.cFileName
))
417 GetString(L
"RegName", Info
->szRegName
, FindFileData
.cFileName
);
418 GetString(L
"Version", Info
->szVersion
, FindFileData
.cFileName
);
419 GetString(L
"License", Info
->szLicense
, FindFileData
.cFileName
);
420 GetString(L
"Description", Info
->szDesc
, FindFileData
.cFileName
);
421 GetString(L
"Size", Info
->szSize
, FindFileData
.cFileName
);
422 GetString(L
"URLSite", Info
->szUrlSite
, FindFileData
.cFileName
);
423 GetString(L
"CDPath", Info
->szCDPath
, FindFileData
.cFileName
);
424 GetString(L
"Language", Info
->szRegName
, FindFileData
.cFileName
);
425 GetString(L
"SHA1", Info
->szSHA1
, FindFileData
.cFileName
);
428 if (!lpEnumProc(Info
))
431 } while (FindNextFileW(hFind
, &FindFileData
) != 0);
438 VOID
FreeCachedAvailableEntries(VOID
)
440 PAPPLICATION_INFO Info
;
441 POSITION InfoListPosition
= InfoList
.GetHeadPosition();
443 /* loop and deallocate all the cached app infos in the list */
444 while (InfoListPosition
)
446 Info
= InfoList
.GetAt(InfoListPosition
);
447 InfoList
.RemoveHead();
448 InfoListPosition
= InfoList
.GetHeadPosition();