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)
12 #define ADD_TEXT(a, b, c, d) \
15 LoadStringW(hInst, a, szText, _countof(szText)); \
16 InsertRichEditText(szText, c); \
17 InsertRichEditText(b, d); \
20 #define GET_STRING1(a, b) \
21 if (!ParserGetString(a, b, _countof(b), FindFileData.cFileName)) \
24 #define GET_STRING2(a, b) \
25 if (!ParserGetString(a, b, _countof(b), FindFileData.cFileName)) \
28 LIST_ENTRY CachedEntriesHead
= { &CachedEntriesHead
, &CachedEntriesHead
};
29 PLIST_ENTRY pCachedEntry
= &CachedEntriesHead
;
32 ShowAvailableAppInfo(INT Index
)
34 PAPPLICATION_INFO Info
= (PAPPLICATION_INFO
) ListViewGetlParam(Index
);
35 WCHAR szText
[MAX_STR_LEN
];
37 if (!Info
) return FALSE
;
39 NewRichEditText(Info
->szName
, CFE_BOLD
);
41 InsertRichEditText(L
"\n", 0);
43 ADD_TEXT(IDS_AINFO_VERSION
, Info
->szVersion
, CFE_BOLD
, 0);
44 ADD_TEXT(IDS_AINFO_LICENSE
, Info
->szLicense
, CFE_BOLD
, 0);
45 ADD_TEXT(IDS_AINFO_SIZE
, Info
->szSize
, CFE_BOLD
, 0);
46 ADD_TEXT(IDS_AINFO_URLSITE
, Info
->szUrlSite
, CFE_BOLD
, CFE_LINK
);
47 ADD_TEXT(IDS_AINFO_DESCRIPTION
, Info
->szDesc
, CFE_BOLD
, 0);
48 ADD_TEXT(IDS_AINFO_URLDOWNLOAD
, Info
->szUrlDownload
, CFE_BOLD
, CFE_LINK
);
54 DeleteCurrentAppsDB(VOID
)
56 HANDLE hFind
= INVALID_HANDLE_VALUE
;
57 WIN32_FIND_DATAW FindFileData
;
58 WCHAR szCabPath
[MAX_PATH
];
59 WCHAR szSearchPath
[MAX_PATH
];
60 WCHAR szPath
[MAX_PATH
];
61 WCHAR szTmp
[MAX_PATH
];
65 if (!GetStorageDirectory(szPath
, _countof(szPath
)))
68 hr
= StringCbPrintfW(szCabPath
, sizeof(szCabPath
),
74 result
= result
&& DeleteFileW(szCabPath
);
76 hr
= StringCbCatW(szPath
, sizeof(szPath
), L
"\\rapps\\");
81 hr
= StringCbPrintfW(szSearchPath
, sizeof(szSearchPath
),
87 hFind
= FindFirstFileW(szSearchPath
, &FindFileData
);
89 if (hFind
== INVALID_HANDLE_VALUE
)
94 hr
= StringCbPrintfW(szTmp
, sizeof(szTmp
),
96 szPath
, FindFileData
.cFileName
);
99 result
= result
&& DeleteFileW(szTmp
);
101 } while (FindNextFileW(hFind
, &FindFileData
) != 0);
112 WCHAR szPath
[MAX_PATH
];
113 WCHAR szAppsPath
[MAX_PATH
];
114 WCHAR szCabPath
[MAX_PATH
];
116 if (!DeleteCurrentAppsDB())
119 DownloadApplicationsDB(APPLICATION_DATABASE_URL
);
121 if (!GetStorageDirectory(szPath
, _countof(szPath
)))
124 if (FAILED(StringCbPrintfW(szCabPath
, sizeof(szCabPath
),
131 if (FAILED(StringCbPrintfW(szAppsPath
, sizeof(szAppsPath
),
138 ExtractFilesFromCab(szCabPath
, szAppsPath
);
145 EnumAvailableApplications(INT EnumType
, AVAILENUMPROC lpEnumProc
)
147 HANDLE hFind
= INVALID_HANDLE_VALUE
;
148 WIN32_FIND_DATAW FindFileData
;
149 WCHAR szPath
[MAX_PATH
];
150 WCHAR szAppsPath
[MAX_PATH
];
151 WCHAR szCabPath
[MAX_PATH
];
152 PAPPLICATION_INFO Info
;
155 if (!GetStorageDirectory(szPath
, _countof(szPath
)))
158 hr
= StringCbPrintfW(szCabPath
, sizeof(szCabPath
),
164 hr
= StringCbCatW(szPath
, sizeof(szPath
), L
"\\rapps\\");
169 hr
= StringCbCopyW(szAppsPath
, sizeof(szAppsPath
), szPath
);
174 if (!CreateDirectory(szPath
, NULL
) &&
175 GetLastError() != ERROR_ALREADY_EXISTS
)
180 hr
= StringCbCatW(szPath
, sizeof(szPath
), L
"*.txt");
185 hFind
= FindFirstFileW(szPath
, &FindFileData
);
187 if (hFind
== INVALID_HANDLE_VALUE
)
189 if (GetFileAttributesW(szCabPath
) == INVALID_FILE_ATTRIBUTES
)
190 DownloadApplicationsDB(APPLICATION_DATABASE_URL
);
192 ExtractFilesFromCab(szCabPath
, szAppsPath
);
193 hFind
= FindFirstFileW(szPath
, &FindFileData
);
195 if (hFind
== INVALID_HANDLE_VALUE
)
201 /* loop for all the cached entries */
202 for (pCachedEntry
= CachedEntriesHead
.Flink
; pCachedEntry
!= &CachedEntriesHead
; pCachedEntry
= pCachedEntry
->Flink
)
204 Info
= CONTAINING_RECORD(pCachedEntry
, APPLICATION_INFO
, List
);
206 /* do we already have this entry in cache? */
207 if(_wcsicmp(FindFileData
.cFileName
, Info
->cFileName
) == 0)
209 /* is it current enough, or the file has been modified since our last time here? */
210 if (CompareFileTime(&FindFileData
.ftLastWriteTime
, &Info
->ftCacheStamp
) == 1)
212 /* recreate our cache, this is the slow path */
213 RemoveEntryList(&Info
->List
);
214 HeapFree(GetProcessHeap(), 0, Info
);
218 /* speedy path, compare directly, we already have the data */
226 /* create a new entry */
227 Info
= (PAPPLICATION_INFO
)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(APPLICATION_INFO
));
232 Info
->Category
= ParserGetInt(L
"Category", FindFileData
.cFileName
);
234 /* copy the cache-related fields for the next time */
235 RtlCopyMemory(&Info
->cFileName
, &FindFileData
.cFileName
, MAX_PATH
);
236 RtlCopyMemory(&Info
->ftCacheStamp
, &FindFileData
.ftLastWriteTime
, sizeof(FILETIME
));
238 /* add our cached entry to the cached list */
239 InsertTailList(&CachedEntriesHead
, &Info
->List
);
243 if (Info
->Category
== FALSE
)
246 if (EnumType
!= Info
->Category
&& EnumType
!= ENUM_ALL_AVAILABLE
)
249 /* if our cache hit was only partial, we need to parse
250 and lazily fill the rest of fields only when needed */
252 if (Info
->szUrlDownload
[0] == 0)
254 GET_STRING1(L
"Name", Info
->szName
);
255 GET_STRING1(L
"URLDownload", Info
->szUrlDownload
);
257 GET_STRING2(L
"RegName", Info
->szRegName
);
258 GET_STRING2(L
"Version", Info
->szVersion
);
259 GET_STRING2(L
"License", Info
->szLicense
);
260 GET_STRING2(L
"Description", Info
->szDesc
);
261 GET_STRING2(L
"Size", Info
->szSize
);
262 GET_STRING2(L
"URLSite", Info
->szUrlSite
);
263 GET_STRING2(L
"CDPath", Info
->szCDPath
);
264 GET_STRING2(L
"SHA1", Info
->szSHA1
);
267 if (!lpEnumProc(Info
))
270 } while (FindNextFileW(hFind
, &FindFileData
) != 0);
277 VOID
FreeCachedAvailableEntries(VOID
)
279 PAPPLICATION_INFO Info
;
281 /* loop and deallocate all the cached app infos in the list */
282 for (pCachedEntry
= CachedEntriesHead
.Flink
; pCachedEntry
!= &CachedEntriesHead
;)
284 Info
= CONTAINING_RECORD(pCachedEntry
, APPLICATION_INFO
, List
);
286 /* grab a reference to the next linked entry before getting rid of the current one */
287 pCachedEntry
= pCachedEntry
->Flink
;
289 /* flush them down the toilet :D */
290 RemoveEntryList(&Info
->List
);
291 HeapFree(GetProcessHeap(), 0, Info
);