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
;
15 inline void InsertTextAfterLoaded_RichEdit(UINT uStringID
, const ATL::CStringW
& szText
, DWORD StringFlags
, DWORD TextFlags
)
17 ATL::CStringW szLoadedText
;
18 if (!szText
.IsEmpty() && szLoadedText
.LoadStringW(hInst
, uStringID
))
20 InsertRichEditText(szLoadedText
, StringFlags
);
21 InsertRichEditText(szText
, TextFlags
);
25 inline void InsertLoadedTextNewl_RichEdit(UINT uStringID
, DWORD StringFlags
)
27 ATL::CStringW szLoadedText
;
28 if (szLoadedText
.LoadStringW(hInst
, uStringID
))
30 InsertRichEditText(L
"\n", 0);
31 InsertRichEditText(szLoadedText
, StringFlags
);
32 InsertRichEditText(L
"\n", 0);
36 inline BOOL
GetString(LPCWSTR lpKeyName
, ATL::CStringW
& ReturnedString
, const ATL::CStringW
& cFileName
)
38 if (!ParserGetString(lpKeyName
, cFileName
, ReturnedString
))
40 ReturnedString
.Empty();
46 //App is "installed" if the RegName or Name is in the registry
47 inline BOOL
IsAppInstalledKey(PAPPLICATION_INFO Info
, REGSAM key
)
49 return (!Info
->szRegName
.IsEmpty()
50 && (IsInstalledApplication(Info
->szRegName
, TRUE
, key
)
51 || IsInstalledApplication(Info
->szRegName
, FALSE
, key
)))
52 || (!Info
->szName
.IsEmpty()
53 && (IsInstalledApplication(Info
->szName
, TRUE
, key
)
54 || IsInstalledApplication(Info
->szName
, FALSE
, key
)));
58 //Check both registry keys in 64bit system
59 //TODO: check system type beforehand to avoid double checks?
60 inline BOOL
IsAppInstalled(PAPPLICATION_INFO Info
)
62 return IsAppInstalledKey(Info
, KEY_WOW64_32KEY
)
63 || IsAppInstalledKey(Info
, KEY_WOW64_64KEY
);
66 //App is "installed" if the RegName or Name is in the registry
67 inline BOOL
GetInstalledVersionWithKey(PAPPLICATION_INFO Info
, ATL::CStringW
& szVersion
, REGSAM key
)
69 return (!Info
->szRegName
.IsEmpty()
70 && (InstalledVersion(szVersion
, Info
->szRegName
, TRUE
, key
)
71 || InstalledVersion(szVersion
, Info
->szRegName
, FALSE
, key
)))
72 || (!Info
->szName
.IsEmpty()
73 && (InstalledVersion(szVersion
, Info
->szName
, TRUE
, key
)
74 || InstalledVersion(szVersion
, Info
->szName
, FALSE
, key
)));
77 inline BOOL
GetInstalledVersion(PAPPLICATION_INFO Info
, ATL::CStringW
& szVersion
)
79 return GetInstalledVersionWithKey(Info
, szVersion
, KEY_WOW64_32KEY
)
80 || GetInstalledVersionWithKey(Info
, szVersion
, KEY_WOW64_64KEY
);
83 LIST_ENTRY CachedEntriesHead
= {&CachedEntriesHead
, &CachedEntriesHead
};
84 PLIST_ENTRY pCachedEntry
= &CachedEntriesHead
;
87 ShowAvailableAppInfo(INT Index
)
89 PAPPLICATION_INFO Info
= (PAPPLICATION_INFO
) ListViewGetlParam(Index
);
90 ATL::CStringW szVersion
;
91 ATL::CStringW szLicense
;
92 BOOL bIsInstalled
= IsAppInstalled(Info
),
93 bHasVersion
= GetInstalledVersion(Info
, szVersion
);
95 if (!Info
) return FALSE
;
97 NewRichEditText(Info
->szName
, CFE_BOLD
);
103 if (Info
->szVersion
.Compare(szVersion
) > 0)
104 InsertLoadedTextNewl_RichEdit(IDS_STATUS_UPDATE_AVAILABLE
, CFE_ITALIC
);
106 InsertLoadedTextNewl_RichEdit(IDS_STATUS_INSTALLED
, CFE_ITALIC
);
108 InsertTextAfterLoaded_RichEdit(IDS_AINFO_VERSION
, szVersion
, CFE_BOLD
, 0);
111 InsertLoadedTextNewl_RichEdit(IDS_STATUS_INSTALLED
, CFE_ITALIC
);
115 InsertLoadedTextNewl_RichEdit(IDS_STATUS_NOTINSTALLED
, CFE_ITALIC
);
117 InsertTextAfterLoaded_RichEdit(IDS_AINFO_AVAILABLEVERSION
, Info
->szVersion
, CFE_BOLD
, 0);
119 switch (Info
->LicenseType
)
121 case LICENSE_TYPE::OpenSource
:
122 szLicense
.LoadStringW(hInst
, IDS_LICENSE_OPENSOURCE
);
124 case LICENSE_TYPE::Freeware
:
125 szLicense
.LoadStringW(hInst
, IDS_LICENSE_FREEWARE
);
127 case LICENSE_TYPE::Trial
:
128 szLicense
.LoadStringW(hInst
, IDS_LICENSE_TRIAL
);
134 if (szLicense
.IsEmpty())
136 InsertTextAfterLoaded_RichEdit(IDS_AINFO_LICENSE
, Info
->szLicense
, CFE_BOLD
, 0);
140 szLicense
.Format(L
"(%ls)", Info
->szLicense
);
141 InsertTextAfterLoaded_RichEdit(IDS_AINFO_LICENSE
, szLicense
, CFE_BOLD
, 0);
144 InsertTextAfterLoaded_RichEdit(IDS_AINFO_SIZE
, Info
->szSize
, CFE_BOLD
, 0);
145 InsertTextAfterLoaded_RichEdit(IDS_AINFO_URLSITE
, Info
->szUrlSite
, CFE_BOLD
, CFE_LINK
);
146 InsertTextAfterLoaded_RichEdit(IDS_AINFO_DESCRIPTION
, Info
->szDesc
, CFE_BOLD
, 0);
147 InsertTextAfterLoaded_RichEdit(IDS_AINFO_URLDOWNLOAD
, Info
->szUrlDownload
, CFE_BOLD
, CFE_LINK
);
153 DeleteCurrentAppsDB(VOID
)
155 HANDLE hFind
= INVALID_HANDLE_VALUE
;
156 WIN32_FIND_DATAW FindFileData
;
157 ATL::CStringW szCabPath
;
158 ATL::CStringW szSearchPath
;
159 ATL::CStringW szPath
;
162 if (!GetStorageDirectory(szPath
))
165 szCabPath
= szPath
+ L
"\\rappmgr.cab";
166 result
= result
&& DeleteFileW(szCabPath
.GetString());
168 szPath
+= L
"\\rapps\\";
169 szSearchPath
= szPath
+ L
"*.txt";
171 hFind
= FindFirstFileW(szSearchPath
.GetString(), &FindFileData
);
173 if (hFind
== INVALID_HANDLE_VALUE
)
179 szTmp
= szPath
+ FindFileData
.cFileName
;
180 result
= result
&& DeleteFileW(szTmp
.GetString());
181 } while (FindNextFileW(hFind
, &FindFileData
) != 0);
191 ATL::CStringW szPath
;
192 ATL::CStringW szAppsPath
;
193 ATL::CStringW szCabPath
;
195 if (!DeleteCurrentAppsDB())
198 DownloadApplicationsDB(APPLICATION_DATABASE_URL
);
200 if (!GetStorageDirectory(szPath
))
203 szCabPath
= szPath
+ L
"\\rappmgr.cab";
204 szAppsPath
= szPath
+ L
"\\rapps\\";
206 if (!ExtractFilesFromCab(szCabPath
, szAppsPath
))
216 EnumAvailableApplications(INT EnumType
, AVAILENUMPROC lpEnumProc
)
218 HANDLE hFind
= INVALID_HANDLE_VALUE
;
219 WIN32_FIND_DATAW FindFileData
;
220 ATL::CStringW szPath
;
221 ATL::CStringW szAppsPath
;
222 ATL::CStringW szCabPath
;
223 PAPPLICATION_INFO Info
;
226 if (!GetStorageDirectory(szPath
))
229 szCabPath
= szPath
+ L
"\\rappmgr.cab";
230 szPath
+= L
"\\rapps\\";
233 if (!CreateDirectoryW(szPath
.GetString(), NULL
) &&
234 GetLastError() != ERROR_ALREADY_EXISTS
)
240 hFind
= FindFirstFileW(szPath
.GetString(), &FindFileData
);
242 if (hFind
== INVALID_HANDLE_VALUE
)
244 if (GetFileAttributesW(szCabPath
) == INVALID_FILE_ATTRIBUTES
)
245 DownloadApplicationsDB(APPLICATION_DATABASE_URL
);
247 ExtractFilesFromCab(szCabPath
, szAppsPath
);
248 hFind
= FindFirstFileW(szPath
, &FindFileData
);
250 if (hFind
== INVALID_HANDLE_VALUE
)
256 /* loop for all the cached entries */
257 POSITION CurrentListPosition
= InfoList
.GetHeadPosition();
259 while (CurrentListPosition
!= NULL
)
261 POSITION LastListPosition
= CurrentListPosition
;
262 Info
= InfoList
.GetNext(CurrentListPosition
);
264 /* do we already have this entry in cache? */
265 if (!Info
->cFileName
.Compare(FindFileData
.cFileName
))
267 /* is it current enough, or the file has been modified since our last time here? */
268 if (CompareFileTime(&FindFileData
.ftLastWriteTime
, &Info
->ftCacheStamp
) == 1)
270 /* recreate our cache, this is the slow path */
271 InfoList
.RemoveAt(LastListPosition
);
277 /* speedy path, compare directly, we already have the data */
283 /* create a new entry */
284 Info
= new APPLICATION_INFO();
289 Info
->Category
= ParserGetInt(L
"Category", FindFileData
.cFileName
);
290 INT IntBuffer
= ParserGetInt(L
"LicenseType", FindFileData
.cFileName
);
291 if (IntBuffer
< LICENSE_TYPE::Max
)
293 Info
->LicenseType
= (LICENSE_TYPE
) IntBuffer
;
296 /* copy the cache-related fields for the next time */
297 Info
->cFileName
= FindFileData
.cFileName
;
298 RtlCopyMemory(&Info
->ftCacheStamp
, &FindFileData
.ftLastWriteTime
, sizeof(FILETIME
));
300 /* add our cached entry to the cached list */
301 InfoList
.AddTail(Info
);
305 if (Info
->Category
== FALSE
)
308 if (EnumType
!= Info
->Category
&& EnumType
!= ENUM_ALL_AVAILABLE
)
311 /* if our cache hit was only partial, we need to parse
312 and lazily fill the rest of fields only when needed */
314 if (Info
->szUrlDownload
.IsEmpty())
316 if (!GetString(L
"Name", Info
->szName
, FindFileData
.cFileName
)
317 || !GetString(L
"URLDownload", Info
->szUrlDownload
, FindFileData
.cFileName
))
322 GetString(L
"RegName", Info
->szRegName
, FindFileData
.cFileName
);
323 GetString(L
"Version", Info
->szVersion
, FindFileData
.cFileName
);
324 GetString(L
"License", Info
->szLicense
, FindFileData
.cFileName
);
325 GetString(L
"Description", Info
->szDesc
, FindFileData
.cFileName
);
326 GetString(L
"Size", Info
->szSize
, FindFileData
.cFileName
);
327 GetString(L
"URLSite", Info
->szUrlSite
, FindFileData
.cFileName
);
328 GetString(L
"CDPath", Info
->szCDPath
, FindFileData
.cFileName
);
329 GetString(L
"Language", Info
->szRegName
, FindFileData
.cFileName
);
330 GetString(L
"SHA1", Info
->szSHA1
, FindFileData
.cFileName
);
333 if (!lpEnumProc(Info
))
336 } while (FindNextFileW(hFind
, &FindFileData
) != 0);
343 VOID
FreeCachedAvailableEntries(VOID
)
345 PAPPLICATION_INFO Info
;
346 POSITION InfoListPosition
= InfoList
.GetHeadPosition();
347 /* loop and deallocate all the cached app infos in the list */
348 while (InfoListPosition
)
350 Info
= InfoList
.GetAt(InfoListPosition
);
351 InfoList
.RemoveHead();
353 /* flush them down the toilet :D */
356 InfoListPosition
= InfoList
.GetHeadPosition();