mirror of
https://github.com/reactos/reactos.git
synced 2025-02-22 16:36:33 +00:00
[RAPPS] snapshot url support (#2925)
* [RAPPS] add snapshot url support * [RAPPS] fix snapshot prev window won't update if size not changed * [RAPPS] fix crash after cancel download * [RAPPS] show broken-img if failed to create file / make network request * [RAPPS] create a snapshots folder if it does not exist * [RAPPS] add a helper function to perform callback * [RAPPS] check bIsCancelled when handling ERROR_INVALID_HANDLE * [RAPPS] remove W suffix for AsyncInetDownload * [RAPPS] add assert for unknown event * [RAPPS] Improve AsyncInetDownload error handling * [RAPPS] move DisplayFailed to private, fix crash when cancelling * [RAPPS] check for ERROR_INTERNET_OPERATION_CANCELLED * [RAPPS] improve error logging * [RAPPS] remove \r in error logging * [RAPPS] rewrite AsyncInet
This commit is contained in:
parent
fbf119fde1
commit
e506581454
6 changed files with 735 additions and 40 deletions
|
@ -7,6 +7,7 @@ include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/cryptlib)
|
||||||
include_directories(include)
|
include_directories(include)
|
||||||
|
|
||||||
list(APPEND SOURCE
|
list(APPEND SOURCE
|
||||||
|
asyncinet.cpp
|
||||||
available.cpp
|
available.cpp
|
||||||
cabinet.cpp
|
cabinet.cpp
|
||||||
gui.cpp
|
gui.cpp
|
||||||
|
@ -18,6 +19,7 @@ list(APPEND SOURCE
|
||||||
winmain.cpp
|
winmain.cpp
|
||||||
unattended.cpp
|
unattended.cpp
|
||||||
include/rapps.h
|
include/rapps.h
|
||||||
|
include/asyncinet.h
|
||||||
include/available.h
|
include/available.h
|
||||||
include/dialogs.h
|
include/dialogs.h
|
||||||
include/installed.h
|
include/installed.h
|
||||||
|
|
453
base/applications/rapps/asyncinet.cpp
Normal file
453
base/applications/rapps/asyncinet.cpp
Normal file
|
@ -0,0 +1,453 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Applications Manager
|
||||||
|
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||||
|
* PURPOSE: Async Internet operation using WinINet
|
||||||
|
* COPYRIGHT: Copyright 2020 He Yang (1160386205@qq.com)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "rapps.h"
|
||||||
|
#include <wininet.h>
|
||||||
|
#include <atlbase.h>
|
||||||
|
#include "asyncinet.h"
|
||||||
|
|
||||||
|
|
||||||
|
BOOL AsyncInetIsCanceled(pASYNCINET AsyncInet);
|
||||||
|
BOOL AsyncInetAcquire(pASYNCINET AsyncInet);
|
||||||
|
VOID AsyncInetRelease(pASYNCINET AsyncInet);
|
||||||
|
int AsyncInetPerformCallback(pASYNCINET AsyncInet,
|
||||||
|
ASYNC_EVENT Event,
|
||||||
|
WPARAM wParam,
|
||||||
|
LPARAM lParam
|
||||||
|
);
|
||||||
|
VOID CALLBACK AsyncInetStatusCallback(
|
||||||
|
HINTERNET hInternet,
|
||||||
|
DWORD_PTR dwContext,
|
||||||
|
DWORD dwInternetStatus,
|
||||||
|
LPVOID lpvStatusInformation,
|
||||||
|
DWORD dwStatusInformationLength
|
||||||
|
);
|
||||||
|
VOID AsyncInetReadFileLoop(pASYNCINET AsyncInet);
|
||||||
|
BOOL AsyncInetCleanUp(pASYNCINET AsyncInet);
|
||||||
|
VOID AsyncInetFree(pASYNCINET AsyncInet);
|
||||||
|
|
||||||
|
pASYNCINET AsyncInetDownload(LPCWSTR lpszAgent,
|
||||||
|
DWORD dwAccessType,
|
||||||
|
LPCWSTR lpszProxy,
|
||||||
|
LPCWSTR lpszProxyBypass,
|
||||||
|
LPCWSTR lpszUrl,
|
||||||
|
BOOL bAllowCache,
|
||||||
|
ASYNCINET_CALLBACK Callback,
|
||||||
|
VOID* Extension
|
||||||
|
) // allocate memory for AsyncInet and start a download task
|
||||||
|
{
|
||||||
|
pASYNCINET AsyncInet = NULL;
|
||||||
|
BOOL bSuccess = FALSE;
|
||||||
|
DWORD InetOpenUrlFlag = 0;
|
||||||
|
INTERNET_STATUS_CALLBACK OldCallbackFunc;
|
||||||
|
|
||||||
|
AsyncInet = (pASYNCINET)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ASYNCINET));
|
||||||
|
if (!AsyncInet)
|
||||||
|
{
|
||||||
|
OutputDebugStringA("At File: " __FILE__ " HeapAlloc returned 0\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncInet->bCancelled = FALSE;
|
||||||
|
|
||||||
|
AsyncInet->hInternet = NULL;
|
||||||
|
AsyncInet->hInetFile = NULL;
|
||||||
|
|
||||||
|
AsyncInet->Callback = Callback;
|
||||||
|
AsyncInet->Extension = Extension;
|
||||||
|
|
||||||
|
AsyncInet->hEventHandleCreated = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||||
|
|
||||||
|
InitializeCriticalSection(&(AsyncInet->CriticalSection));
|
||||||
|
AsyncInet->ReferenceCnt = 1; // 1 for callee itself
|
||||||
|
AsyncInet->hEventHandleClose = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||||
|
|
||||||
|
if (AsyncInet->hEventHandleCreated && AsyncInet->hEventHandleClose)
|
||||||
|
{
|
||||||
|
AsyncInet->hInternet = InternetOpenW(lpszAgent, dwAccessType, lpszProxy, lpszProxyBypass, INTERNET_FLAG_ASYNC);
|
||||||
|
|
||||||
|
if (AsyncInet->hInternet)
|
||||||
|
{
|
||||||
|
OldCallbackFunc = InternetSetStatusCallbackW(AsyncInet->hInternet, AsyncInetStatusCallback);
|
||||||
|
if (OldCallbackFunc != INTERNET_INVALID_STATUS_CALLBACK)
|
||||||
|
{
|
||||||
|
InetOpenUrlFlag |= INTERNET_FLAG_PASSIVE | INTERNET_FLAG_RESYNCHRONIZE;
|
||||||
|
if (!bAllowCache)
|
||||||
|
{
|
||||||
|
InetOpenUrlFlag |= INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_RELOAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncInet->hInetFile = InternetOpenUrlW(AsyncInet->hInternet, lpszUrl, 0, 0, InetOpenUrlFlag, (DWORD_PTR)AsyncInet);
|
||||||
|
|
||||||
|
if (AsyncInet->hInetFile)
|
||||||
|
{
|
||||||
|
// operate complete synchronously
|
||||||
|
bSuccess = TRUE;
|
||||||
|
AsyncInetReadFileLoop(AsyncInet);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (GetLastError() == ERROR_IO_PENDING)
|
||||||
|
{
|
||||||
|
// everything fine. waiting for handle created
|
||||||
|
switch (WaitForSingleObject(AsyncInet->hEventHandleCreated, INFINITE))
|
||||||
|
{
|
||||||
|
case WAIT_OBJECT_0:
|
||||||
|
if (AsyncInet->hInetFile)
|
||||||
|
{
|
||||||
|
bSuccess = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bSuccess)
|
||||||
|
{
|
||||||
|
AsyncInetFree(AsyncInet);
|
||||||
|
AsyncInet = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AsyncInet)
|
||||||
|
{
|
||||||
|
// add reference count for caller.
|
||||||
|
// the caller is responsible for call AsyncInetRelease when no longer using it.
|
||||||
|
AsyncInetAcquire(AsyncInet);
|
||||||
|
}
|
||||||
|
return AsyncInet;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL AsyncInetCancel(pASYNCINET AsyncInet) // mark as cancelled (this will send a cancel notificaion at last) and do graceful cleanup.
|
||||||
|
{
|
||||||
|
if (AsyncInet)
|
||||||
|
{
|
||||||
|
HINTERNET hInetFile;
|
||||||
|
EnterCriticalSection(&(AsyncInet->CriticalSection));
|
||||||
|
AsyncInet->bCancelled = TRUE;
|
||||||
|
hInetFile = AsyncInet->hInetFile;
|
||||||
|
AsyncInet->hInetFile = NULL;
|
||||||
|
LeaveCriticalSection(&(AsyncInet->CriticalSection));
|
||||||
|
|
||||||
|
if (hInetFile)
|
||||||
|
{
|
||||||
|
InternetCloseHandle(hInetFile);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL AsyncInetIsCanceled(pASYNCINET AsyncInet) // if returned TRUE, no operation should be exectued further
|
||||||
|
{
|
||||||
|
if (AsyncInet)
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&(AsyncInet->CriticalSection));
|
||||||
|
if (AsyncInet->bCancelled)
|
||||||
|
{
|
||||||
|
LeaveCriticalSection(&(AsyncInet->CriticalSection));
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
LeaveCriticalSection(&(AsyncInet->CriticalSection));
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL AsyncInetAcquire(pASYNCINET AsyncInet) // try to increase refcnt by 1. if returned FALSE, AsyncInet should not be used anymore
|
||||||
|
{
|
||||||
|
BOOL bResult = FALSE;
|
||||||
|
if (AsyncInet)
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&(AsyncInet->CriticalSection));
|
||||||
|
ATLASSERT(AsyncInet->ReferenceCnt > 0);
|
||||||
|
if (!AsyncInetIsCanceled(AsyncInet))
|
||||||
|
{
|
||||||
|
AsyncInet->ReferenceCnt++;
|
||||||
|
bResult = TRUE;
|
||||||
|
}
|
||||||
|
// otherwise (AsyncInet->bCleanUp == TRUE)
|
||||||
|
// AsyncInetAcquire will return FALSE.
|
||||||
|
// In this case, any thread should no longer use this AsyncInet
|
||||||
|
|
||||||
|
LeaveCriticalSection(&(AsyncInet->CriticalSection));
|
||||||
|
}
|
||||||
|
|
||||||
|
return bResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID AsyncInetRelease(pASYNCINET AsyncInet) // try to decrease refcnt by 1
|
||||||
|
{
|
||||||
|
BOOL bCleanUp = FALSE;
|
||||||
|
if (AsyncInet)
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&(AsyncInet->CriticalSection));
|
||||||
|
|
||||||
|
ATLASSERT(AsyncInet->ReferenceCnt);
|
||||||
|
AsyncInet->ReferenceCnt--;
|
||||||
|
if (AsyncInet->ReferenceCnt == 0)
|
||||||
|
{
|
||||||
|
bCleanUp = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
LeaveCriticalSection(&(AsyncInet->CriticalSection));
|
||||||
|
|
||||||
|
if (bCleanUp)
|
||||||
|
{
|
||||||
|
AsyncInetCleanUp(AsyncInet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int AsyncInetPerformCallback(pASYNCINET AsyncInet,
|
||||||
|
ASYNC_EVENT Event,
|
||||||
|
WPARAM wParam,
|
||||||
|
LPARAM lParam
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (AsyncInet && AsyncInet->Callback)
|
||||||
|
{
|
||||||
|
return AsyncInet->Callback(AsyncInet, Event, wParam, lParam, AsyncInet->Extension);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID CALLBACK AsyncInetStatusCallback(
|
||||||
|
HINTERNET hInternet,
|
||||||
|
DWORD_PTR dwContext,
|
||||||
|
DWORD dwInternetStatus,
|
||||||
|
LPVOID lpvStatusInformation,
|
||||||
|
DWORD dwStatusInformationLength
|
||||||
|
)
|
||||||
|
{
|
||||||
|
pASYNCINET AsyncInet = (pASYNCINET)dwContext;
|
||||||
|
switch (dwInternetStatus)
|
||||||
|
{
|
||||||
|
case INTERNET_STATUS_HANDLE_CREATED:
|
||||||
|
{
|
||||||
|
// retrieve handle created by InternetOpenUrlW
|
||||||
|
AsyncInet->hInetFile = *((LPHINTERNET)lpvStatusInformation);
|
||||||
|
SetEvent(AsyncInet->hEventHandleCreated);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case INTERNET_STATUS_HANDLE_CLOSING:
|
||||||
|
{
|
||||||
|
if (AsyncInetIsCanceled(AsyncInet))
|
||||||
|
{
|
||||||
|
AsyncInetPerformCallback(AsyncInet, ASYNCINET_CANCELLED, 0, 0);
|
||||||
|
}
|
||||||
|
SetEvent(AsyncInet->hEventHandleClose);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case INTERNET_STATUS_REQUEST_COMPLETE:
|
||||||
|
{
|
||||||
|
INTERNET_ASYNC_RESULT* AsyncResult = (INTERNET_ASYNC_RESULT*)lpvStatusInformation;
|
||||||
|
|
||||||
|
if (!AsyncInet->hInetFile)
|
||||||
|
{
|
||||||
|
if (!AsyncInetIsCanceled(AsyncInet))
|
||||||
|
{
|
||||||
|
// some error occurs during InternetOpenUrl
|
||||||
|
// and INTERNET_STATUS_HANDLE_CREATED is skipped
|
||||||
|
SetEvent(AsyncInet->hEventHandleCreated);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (AsyncResult->dwError)
|
||||||
|
{
|
||||||
|
case ERROR_SUCCESS:
|
||||||
|
{
|
||||||
|
// there are two possibilities:
|
||||||
|
// 1: InternetOpenUrlW (async mode) complete. (this should be only for the first time)
|
||||||
|
// 2: InternetReadFile (async mode) complete.
|
||||||
|
// so I use bIsOpenUrlComplete field in ASYNCINET to indicate this.
|
||||||
|
|
||||||
|
if (!(AsyncInet->bIsOpenUrlComplete)) // InternetOpenUrlW completed
|
||||||
|
{
|
||||||
|
AsyncInet->bIsOpenUrlComplete = TRUE;
|
||||||
|
}
|
||||||
|
else // asynchronous InternetReadFile complete
|
||||||
|
{
|
||||||
|
AsyncInetPerformCallback(AsyncInet, ASYNCINET_DATA, (WPARAM)(AsyncInet->ReadBuffer), (LPARAM)(AsyncInet->BytesRead));
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncInetReadFileLoop(AsyncInet);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ERROR_INVALID_HANDLE:
|
||||||
|
case ERROR_INTERNET_OPERATION_CANCELLED:
|
||||||
|
case ERROR_CANCELLED:
|
||||||
|
if (AsyncInetIsCanceled(AsyncInet))
|
||||||
|
{
|
||||||
|
AsyncInetRelease(AsyncInet);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fall down
|
||||||
|
default:
|
||||||
|
// something went wrong
|
||||||
|
if (AsyncInetIsCanceled(AsyncInet))
|
||||||
|
{
|
||||||
|
// sending both ASYNCINET_ERROR and ASYNCINET_CANCELLED may lead to unpredictable behavior
|
||||||
|
// TODO: log the error
|
||||||
|
AsyncInetRelease(AsyncInet);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AsyncInetPerformCallback(AsyncInet, ASYNCINET_ERROR, 0, (LPARAM)(AsyncResult->dwError));
|
||||||
|
AsyncInetRelease(AsyncInet);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID AsyncInetReadFileLoop(pASYNCINET AsyncInet)
|
||||||
|
{
|
||||||
|
if ((!AsyncInet) || (!AsyncInet->hInetFile))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (AsyncInetIsCanceled(AsyncInet))
|
||||||
|
{
|
||||||
|
// abort now.
|
||||||
|
AsyncInetRelease(AsyncInet);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL bRet = InternetReadFile(AsyncInet->hInetFile,
|
||||||
|
AsyncInet->ReadBuffer,
|
||||||
|
_countof(AsyncInet->ReadBuffer),
|
||||||
|
&(AsyncInet->BytesRead));
|
||||||
|
|
||||||
|
if (bRet)
|
||||||
|
{
|
||||||
|
if (AsyncInet->BytesRead == 0)
|
||||||
|
{
|
||||||
|
// everything read. now complete.
|
||||||
|
AsyncInetPerformCallback(AsyncInet, ASYNCINET_COMPLETE, 0, 0);
|
||||||
|
AsyncInetRelease(AsyncInet);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// read completed immediately.
|
||||||
|
AsyncInetPerformCallback(AsyncInet, ASYNCINET_DATA, (WPARAM)(AsyncInet->ReadBuffer), (LPARAM)(AsyncInet->BytesRead));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DWORD dwError;
|
||||||
|
if ((dwError = GetLastError()) == ERROR_IO_PENDING)
|
||||||
|
{
|
||||||
|
// performing asynchronous IO, everything OK.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (dwError == ERROR_INVALID_HANDLE ||
|
||||||
|
dwError == ERROR_INTERNET_OPERATION_CANCELLED ||
|
||||||
|
dwError == ERROR_CANCELLED)
|
||||||
|
{
|
||||||
|
if (AsyncInetIsCanceled(AsyncInet))
|
||||||
|
{
|
||||||
|
// not an error. just normally cancelling
|
||||||
|
AsyncInetRelease(AsyncInet);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!AsyncInetIsCanceled(AsyncInet)) // can not send both ASYNCINET_ERROR and ASYNCINET_CANCELLED
|
||||||
|
{
|
||||||
|
AsyncInetPerformCallback(AsyncInet, ASYNCINET_ERROR, 0, dwError);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: log the error
|
||||||
|
}
|
||||||
|
AsyncInetRelease(AsyncInet);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL AsyncInetCleanUp(pASYNCINET AsyncInet) // close all handle and clean up
|
||||||
|
{
|
||||||
|
if (AsyncInet)
|
||||||
|
{
|
||||||
|
ATLASSERT(AsyncInet->ReferenceCnt == 0);
|
||||||
|
// close the handle, waiting for all pending request cancelled.
|
||||||
|
|
||||||
|
if (AsyncInet->bCancelled) // already closed
|
||||||
|
{
|
||||||
|
AsyncInet->hInetFile = NULL;
|
||||||
|
}
|
||||||
|
else if (AsyncInet->hInetFile)
|
||||||
|
{
|
||||||
|
InternetCloseHandle(AsyncInet->hInetFile);
|
||||||
|
AsyncInet->hInetFile = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// only cleanup when handle closed notification received
|
||||||
|
switch (WaitForSingleObject(AsyncInet->hEventHandleClose, INFINITE))
|
||||||
|
{
|
||||||
|
case WAIT_OBJECT_0:
|
||||||
|
{
|
||||||
|
AsyncInetFree(AsyncInet); // now safe to free the structure
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
ATLASSERT(FALSE);
|
||||||
|
AsyncInetFree(AsyncInet);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID AsyncInetFree(pASYNCINET AsyncInet) // close all handles, free the memory occupied by AsyncInet
|
||||||
|
{
|
||||||
|
if (AsyncInet)
|
||||||
|
{
|
||||||
|
DeleteCriticalSection(&(AsyncInet->CriticalSection));
|
||||||
|
|
||||||
|
if (AsyncInet->hEventHandleCreated)
|
||||||
|
{
|
||||||
|
CloseHandle(AsyncInet->hEventHandleCreated);
|
||||||
|
AsyncInet->hEventHandleCreated = NULL;
|
||||||
|
}
|
||||||
|
if (AsyncInet->hEventHandleClose)
|
||||||
|
{
|
||||||
|
CloseHandle(AsyncInet->hEventHandleClose);
|
||||||
|
AsyncInet->hEventHandleClose = NULL;
|
||||||
|
}
|
||||||
|
if (AsyncInet->hInternet)
|
||||||
|
{
|
||||||
|
InternetCloseHandle(AsyncInet->hInternet);
|
||||||
|
AsyncInet->hInternet = NULL;
|
||||||
|
}
|
||||||
|
if (AsyncInet->hInetFile)
|
||||||
|
{
|
||||||
|
InternetCloseHandle(AsyncInet->hInetFile);
|
||||||
|
AsyncInet->hInetFile = NULL;
|
||||||
|
}
|
||||||
|
HeapFree(GetProcessHeap(), 0, AsyncInet);
|
||||||
|
}
|
||||||
|
}
|
|
@ -59,22 +59,28 @@ VOID CAvailableApplicationInfo::RetrieveGeneralInfo(AvailableStrings& AvlbString
|
||||||
{
|
{
|
||||||
WCHAR SnapshotField[sizeof("Snapshot") + 4];
|
WCHAR SnapshotField[sizeof("Snapshot") + 4];
|
||||||
wsprintfW(SnapshotField, L"Snapshot%d", i + 1);
|
wsprintfW(SnapshotField, L"Snapshot%d", i + 1);
|
||||||
ATL::CStringW SnapshotFileName;
|
ATL::CStringW SnapshotLocation;
|
||||||
if (!GetString(SnapshotField, SnapshotFileName))
|
if (!GetString(SnapshotField, SnapshotLocation))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add URL Support
|
|
||||||
|
|
||||||
// TODO: Does the filename contain anything stuff like "\\" ".." ":" "<" ">" ?
|
if (PathIsURLW(SnapshotLocation.GetString()))
|
||||||
// these stuff may lead to security issues
|
{
|
||||||
|
m_szSnapshotLocation.Add(SnapshotLocation);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: Does the filename contain anything stuff like "\\" ".." ":" "<" ">" ?
|
||||||
|
// these stuff may lead to security issues
|
||||||
|
|
||||||
ATL::CStringW SnapshotName = AvlbStrings.szAppsPath;
|
ATL::CStringW SnapshotName = AvlbStrings.szAppsPath;
|
||||||
PathAppendW(SnapshotName.GetBuffer(MAX_PATH), L"snapshots");
|
PathAppendW(SnapshotName.GetBuffer(MAX_PATH), L"snapshots");
|
||||||
PathAppendW(SnapshotName.GetBuffer(), SnapshotFileName.GetString());
|
PathAppendW(SnapshotName.GetBuffer(), SnapshotLocation.GetString());
|
||||||
SnapshotName.ReleaseBuffer();
|
SnapshotName.ReleaseBuffer();
|
||||||
m_szSnapshotFilename.Add(SnapshotName);
|
m_szSnapshotLocation.Add(SnapshotName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RetrieveSize();
|
RetrieveSize();
|
||||||
|
@ -232,11 +238,11 @@ BOOL CAvailableApplicationInfo::HasUpdate() const
|
||||||
|
|
||||||
BOOL CAvailableApplicationInfo::RetrieveSnapshot(UINT Index,ATL::CStringW& SnapshotFileName) const
|
BOOL CAvailableApplicationInfo::RetrieveSnapshot(UINT Index,ATL::CStringW& SnapshotFileName) const
|
||||||
{
|
{
|
||||||
if (Index >= (UINT)m_szSnapshotFilename.GetSize())
|
if (Index >= (UINT)m_szSnapshotLocation.GetSize())
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
SnapshotFileName = m_szSnapshotFilename[Index];
|
SnapshotFileName = m_szSnapshotLocation[Index];
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "rapps.h"
|
#include "rapps.h"
|
||||||
#include "rosui.h"
|
#include "rosui.h"
|
||||||
#include "crichedit.h"
|
#include "crichedit.h"
|
||||||
|
#include "asyncinet.h"
|
||||||
|
|
||||||
#include <shlobj_undoc.h>
|
#include <shlobj_undoc.h>
|
||||||
#include <shlguid_undoc.h>
|
#include <shlguid_undoc.h>
|
||||||
|
@ -43,11 +44,16 @@ using namespace Gdiplus;
|
||||||
// minimum width of richedit
|
// minimum width of richedit
|
||||||
#define RICHEDIT_MIN_WIDTH 160
|
#define RICHEDIT_MIN_WIDTH 160
|
||||||
|
|
||||||
|
|
||||||
|
// user-defined window message
|
||||||
|
#define WM_RAPPS_DOWNLOAD_COMPLETE (WM_USER + 1) // notify download complete. wParam is error code, and lParam is a pointer to SnapshotDownloadParam
|
||||||
|
#define WM_RAPPS_RESIZE_CHILDREN (WM_USER + 2) // ask parent window to resize children.
|
||||||
|
|
||||||
enum SNPSHT_STATUS
|
enum SNPSHT_STATUS
|
||||||
{
|
{
|
||||||
SNPSHTPREV_EMPTY, // show nothing
|
SNPSHTPREV_EMPTY, // show nothing
|
||||||
SNPSHTPREV_LOADING, // image is loading (most likely downloading)
|
SNPSHTPREV_LOADING, // image is loading (most likely downloading)
|
||||||
SNPSHTPREV_FILE, // display image from a file
|
SNPSHTPREV_IMAGE, // display image from a file
|
||||||
SNPSHTPREV_FAILED // image can not be shown (download failure or wrong image)
|
SNPSHTPREV_FAILED // image can not be shown (download failure or wrong image)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -59,6 +65,14 @@ enum SNPSHT_STATUS
|
||||||
|
|
||||||
#define PI 3.1415927
|
#define PI 3.1415927
|
||||||
|
|
||||||
|
typedef struct __SnapshotDownloadParam
|
||||||
|
{
|
||||||
|
LONGLONG ID;
|
||||||
|
HANDLE hFile;
|
||||||
|
HWND hwndNotify;
|
||||||
|
ATL::CStringW DownloadFileName;
|
||||||
|
} SnapshotDownloadParam;
|
||||||
|
|
||||||
INT GetSystemColorDepth()
|
INT GetSystemColorDepth()
|
||||||
{
|
{
|
||||||
DEVMODEW pDevMode;
|
DEVMODEW pDevMode;
|
||||||
|
@ -290,6 +304,40 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int SnapshotDownloadCallback(
|
||||||
|
pASYNCINET AsyncInet,
|
||||||
|
ASYNC_EVENT Event,
|
||||||
|
WPARAM wParam,
|
||||||
|
LPARAM lParam,
|
||||||
|
VOID* Extension
|
||||||
|
)
|
||||||
|
{
|
||||||
|
SnapshotDownloadParam* DownloadParam = (SnapshotDownloadParam*)Extension;
|
||||||
|
switch (Event)
|
||||||
|
{
|
||||||
|
case ASYNCINET_DATA:
|
||||||
|
DWORD BytesWritten;
|
||||||
|
WriteFile(DownloadParam->hFile, (LPCVOID)wParam, (DWORD)lParam, &BytesWritten, NULL);
|
||||||
|
break;
|
||||||
|
case ASYNCINET_COMPLETE:
|
||||||
|
CloseHandle(DownloadParam->hFile);
|
||||||
|
SendMessage(DownloadParam->hwndNotify, WM_RAPPS_DOWNLOAD_COMPLETE, (WPARAM)ERROR_SUCCESS, (LPARAM)DownloadParam);
|
||||||
|
break;
|
||||||
|
case ASYNCINET_CANCELLED:
|
||||||
|
CloseHandle(DownloadParam->hFile);
|
||||||
|
SendMessage(DownloadParam->hwndNotify, WM_RAPPS_DOWNLOAD_COMPLETE, (WPARAM)ERROR_CANCELLED, (LPARAM)DownloadParam);
|
||||||
|
break;
|
||||||
|
case ASYNCINET_ERROR:
|
||||||
|
CloseHandle(DownloadParam->hFile);
|
||||||
|
SendMessage(DownloadParam->hwndNotify, WM_RAPPS_DOWNLOAD_COMPLETE, wParam, (LPARAM)DownloadParam);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ATLASSERT(FALSE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
class CAppSnapshotPreview :
|
class CAppSnapshotPreview :
|
||||||
public CWindowImpl<CAppSnapshotPreview>
|
public CWindowImpl<CAppSnapshotPreview>
|
||||||
{
|
{
|
||||||
|
@ -301,6 +349,9 @@ private:
|
||||||
BOOL bLoadingTimerOn = FALSE;
|
BOOL bLoadingTimerOn = FALSE;
|
||||||
int LoadingAnimationFrame = 0;
|
int LoadingAnimationFrame = 0;
|
||||||
int BrokenImgSize = BROKENIMG_ICON_SIZE;
|
int BrokenImgSize = BROKENIMG_ICON_SIZE;
|
||||||
|
pASYNCINET AsyncInet = NULL;
|
||||||
|
LONGLONG ContentID = 0; // used to determine whether image has been switched when download complete. Increase by 1 each time the content of this window changed
|
||||||
|
ATL::CStringW TempImagePath; // currently displayed temp file
|
||||||
|
|
||||||
BOOL ProcessWindowMessage(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT& theResult, DWORD dwMapId)
|
BOOL ProcessWindowMessage(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT& theResult, DWORD dwMapId)
|
||||||
{
|
{
|
||||||
|
@ -324,6 +375,42 @@ private:
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case WM_RAPPS_DOWNLOAD_COMPLETE:
|
||||||
|
{
|
||||||
|
SnapshotDownloadParam* DownloadParam = (SnapshotDownloadParam*)lParam;
|
||||||
|
AsyncInetRelease(AsyncInet);
|
||||||
|
AsyncInet = NULL;
|
||||||
|
switch (wParam)
|
||||||
|
{
|
||||||
|
case ERROR_SUCCESS:
|
||||||
|
if (ContentID == DownloadParam->ID)
|
||||||
|
{
|
||||||
|
DisplayFile(DownloadParam->DownloadFileName);
|
||||||
|
// send a message to trigger resizing
|
||||||
|
::SendMessageW(::GetParent(m_hWnd), WM_RAPPS_RESIZE_CHILDREN, 0, 0);
|
||||||
|
InvalidateRect(0, 0);
|
||||||
|
TempImagePath = DownloadParam->DownloadFileName; // record tmp file path in order to delete it when cleanup
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// the picture downloaded is already outdated. delete it.
|
||||||
|
DeleteFileW(DownloadParam->DownloadFileName);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ERROR_CANCELLED:
|
||||||
|
DeleteFileW(DownloadParam->DownloadFileName);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DisplayFailed();
|
||||||
|
// send a message to trigger resizing
|
||||||
|
::SendMessageW(::GetParent(m_hWnd), WM_RAPPS_RESIZE_CHILDREN, 0, 0);
|
||||||
|
InvalidateRect(0, 0);
|
||||||
|
DeleteFileW(DownloadParam->DownloadFileName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
delete DownloadParam;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case WM_PAINT:
|
case WM_PAINT:
|
||||||
{
|
{
|
||||||
PAINTSTRUCT ps;
|
PAINTSTRUCT ps;
|
||||||
|
@ -388,6 +475,38 @@ private:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VOID DisplayLoading()
|
||||||
|
{
|
||||||
|
SetStatus(SNPSHTPREV_LOADING);
|
||||||
|
if (bLoadingTimerOn)
|
||||||
|
{
|
||||||
|
KillTimer(TIMER_LOADING_ANIMATION);
|
||||||
|
}
|
||||||
|
LoadingAnimationFrame = 0;
|
||||||
|
bLoadingTimerOn = TRUE;
|
||||||
|
SetTimer(TIMER_LOADING_ANIMATION, 1000 / LOADING_ANIMATION_FPS, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID DisplayFailed()
|
||||||
|
{
|
||||||
|
InterlockedIncrement64(&ContentID);
|
||||||
|
SetStatus(SNPSHTPREV_FAILED);
|
||||||
|
PreviousDisplayCleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL DisplayFile(LPCWSTR lpszFileName)
|
||||||
|
{
|
||||||
|
PreviousDisplayCleanup();
|
||||||
|
SetStatus(SNPSHTPREV_IMAGE);
|
||||||
|
pImage = Bitmap::FromFile(lpszFileName, 0);
|
||||||
|
if (pImage->GetLastStatus() != Ok)
|
||||||
|
{
|
||||||
|
DisplayFailed();
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
VOID SetStatus(SNPSHT_STATUS Status)
|
VOID SetStatus(SNPSHT_STATUS Status)
|
||||||
{
|
{
|
||||||
SnpshtPrevStauts = Status;
|
SnpshtPrevStauts = Status;
|
||||||
|
@ -445,7 +564,7 @@ private:
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SNPSHTPREV_FILE:
|
case SNPSHTPREV_IMAGE:
|
||||||
{
|
{
|
||||||
if (pImage)
|
if (pImage)
|
||||||
{
|
{
|
||||||
|
@ -541,39 +660,82 @@ public:
|
||||||
delete pImage;
|
delete pImage;
|
||||||
pImage = NULL;
|
pImage = NULL;
|
||||||
}
|
}
|
||||||
|
if (AsyncInet)
|
||||||
|
{
|
||||||
|
AsyncInetCancel(AsyncInet);
|
||||||
|
}
|
||||||
|
if (!TempImagePath.IsEmpty())
|
||||||
|
{
|
||||||
|
DeleteFileW(TempImagePath.GetString());
|
||||||
|
TempImagePath.Empty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID DisplayEmpty()
|
VOID DisplayEmpty()
|
||||||
{
|
{
|
||||||
|
InterlockedIncrement64(&ContentID);
|
||||||
SetStatus(SNPSHTPREV_EMPTY);
|
SetStatus(SNPSHTPREV_EMPTY);
|
||||||
PreviousDisplayCleanup();
|
PreviousDisplayCleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID DisplayLoading()
|
BOOL DisplayImage(LPCWSTR lpszLocation)
|
||||||
{
|
{
|
||||||
SetStatus(SNPSHTPREV_LOADING);
|
LONGLONG ID = InterlockedIncrement64(&ContentID);
|
||||||
PreviousDisplayCleanup();
|
PreviousDisplayCleanup();
|
||||||
bLoadingTimerOn = TRUE;
|
|
||||||
SetTimer(TIMER_LOADING_ANIMATION, 1000 / LOADING_ANIMATION_FPS, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL DisplayFile(LPCWSTR lpszFileName)
|
if (PathIsURLW(lpszLocation))
|
||||||
{
|
|
||||||
SetStatus(SNPSHTPREV_FILE);
|
|
||||||
PreviousDisplayCleanup();
|
|
||||||
pImage = Bitmap::FromFile(lpszFileName, 0);
|
|
||||||
if (pImage->GetLastStatus() != Ok)
|
|
||||||
{
|
{
|
||||||
DisplayFailed();
|
DisplayLoading();
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID DisplayFailed()
|
SnapshotDownloadParam* DownloadParam = new SnapshotDownloadParam;
|
||||||
{
|
if (!DownloadParam) return FALSE;
|
||||||
SetStatus(SNPSHTPREV_FAILED);
|
|
||||||
PreviousDisplayCleanup();
|
DownloadParam->hwndNotify = m_hWnd;
|
||||||
|
DownloadParam->ID = ID;
|
||||||
|
// generate a filename
|
||||||
|
ATL::CStringW SnapshotFolder = CAvailableApps::m_Strings.szAppsPath;
|
||||||
|
PathAppendW(SnapshotFolder.GetBuffer(MAX_PATH), L"snapshots");
|
||||||
|
SnapshotFolder.ReleaseBuffer();
|
||||||
|
|
||||||
|
if (!PathIsDirectoryW(SnapshotFolder.GetString()))
|
||||||
|
{
|
||||||
|
CreateDirectoryW(SnapshotFolder.GetString(), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GetTempFileNameW(SnapshotFolder.GetString(), L"img",
|
||||||
|
0, DownloadParam->DownloadFileName.GetBuffer(MAX_PATH)))
|
||||||
|
{
|
||||||
|
DownloadParam->DownloadFileName.ReleaseBuffer();
|
||||||
|
delete DownloadParam;
|
||||||
|
DisplayFailed();
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
DownloadParam->DownloadFileName.ReleaseBuffer();
|
||||||
|
|
||||||
|
DownloadParam->hFile = CreateFileW(DownloadParam->DownloadFileName.GetString(),
|
||||||
|
GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
if (DownloadParam->hFile == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
delete DownloadParam;
|
||||||
|
DisplayFailed();
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncInet = AsyncInetDownload(0, INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, lpszLocation, TRUE, SnapshotDownloadCallback, DownloadParam);
|
||||||
|
if (!AsyncInet)
|
||||||
|
{
|
||||||
|
CloseHandle(DownloadParam->hFile);
|
||||||
|
DeleteFileW(DownloadParam->DownloadFileName.GetBuffer());
|
||||||
|
delete DownloadParam;
|
||||||
|
DisplayFailed();
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return DisplayFile(lpszLocation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetRequestedWidth(int Height) // calculate requested window width by given height
|
int GetRequestedWidth(int Height) // calculate requested window width by given height
|
||||||
|
@ -584,7 +746,7 @@ public:
|
||||||
return 0;
|
return 0;
|
||||||
case SNPSHTPREV_LOADING:
|
case SNPSHTPREV_LOADING:
|
||||||
return 200;
|
return 200;
|
||||||
case SNPSHTPREV_FILE:
|
case SNPSHTPREV_IMAGE:
|
||||||
if (pImage)
|
if (pImage)
|
||||||
{
|
{
|
||||||
// return the width needed to display image inside the window.
|
// return the width needed to display image inside the window.
|
||||||
|
@ -631,6 +793,11 @@ private:
|
||||||
ResizeChildren(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
|
ResizeChildren(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case WM_RAPPS_RESIZE_CHILDREN:
|
||||||
|
{
|
||||||
|
ResizeChildren();
|
||||||
|
break;
|
||||||
|
}
|
||||||
case WM_COMMAND:
|
case WM_COMMAND:
|
||||||
{
|
{
|
||||||
OnCommand(wParam, lParam);
|
OnCommand(wParam, lParam);
|
||||||
|
@ -777,10 +944,10 @@ public:
|
||||||
|
|
||||||
BOOL ShowAvailableAppInfo(CAvailableApplicationInfo* Info)
|
BOOL ShowAvailableAppInfo(CAvailableApplicationInfo* Info)
|
||||||
{
|
{
|
||||||
ATL::CStringW SnapshotFilename;
|
ATL::CStringW SnapshotLocation;
|
||||||
if (Info->RetrieveSnapshot(0, SnapshotFilename))
|
if (Info->RetrieveSnapshot(0, SnapshotLocation))
|
||||||
{
|
{
|
||||||
SnpshtPrev->DisplayFile(SnapshotFilename);
|
SnpshtPrev->DisplayImage(SnapshotLocation);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
66
base/applications/rapps/include/asyncinet.h
Normal file
66
base/applications/rapps/include/asyncinet.h
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
#ifndef ASYNC_INET
|
||||||
|
#define ASYNC_INET
|
||||||
|
|
||||||
|
|
||||||
|
enum ASYNC_EVENT
|
||||||
|
{
|
||||||
|
ASYNCINET_DATA, // wParam is the Data retrieved from the internet, lParam is the length of Data
|
||||||
|
|
||||||
|
ASYNCINET_COMPLETE, // wParam and lParam are not used.
|
||||||
|
// when receiving this, AsyncInet will be free soon and should not used anymore
|
||||||
|
|
||||||
|
ASYNCINET_CANCELLED, // wParam and lParam are not used.
|
||||||
|
// when receiving this, AsyncInet will be free soon and should not used anymore
|
||||||
|
|
||||||
|
ASYNCINET_ERROR // wParam is not used. lParam specify the error code (if there is one).
|
||||||
|
// when receiving this, AsyncInet will be free soon and should not used anymore
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct __AsyncInet ASYNCINET, * pASYNCINET;
|
||||||
|
|
||||||
|
typedef int
|
||||||
|
(*ASYNCINET_CALLBACK)(
|
||||||
|
pASYNCINET AsyncInet,
|
||||||
|
ASYNC_EVENT Event,
|
||||||
|
WPARAM wParam,
|
||||||
|
LPARAM lParam,
|
||||||
|
VOID* Extension
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef struct __AsyncInet
|
||||||
|
{
|
||||||
|
HINTERNET hInternet;
|
||||||
|
HINTERNET hInetFile;
|
||||||
|
|
||||||
|
HANDLE hEventHandleCreated;
|
||||||
|
|
||||||
|
UINT ReferenceCnt;
|
||||||
|
CRITICAL_SECTION CriticalSection;
|
||||||
|
HANDLE hEventHandleClose;
|
||||||
|
|
||||||
|
BOOL bIsOpenUrlComplete;
|
||||||
|
|
||||||
|
BOOL bCancelled;
|
||||||
|
|
||||||
|
BYTE ReadBuffer[4096];
|
||||||
|
DWORD BytesRead;
|
||||||
|
|
||||||
|
ASYNCINET_CALLBACK Callback;
|
||||||
|
VOID* Extension;
|
||||||
|
} ASYNCINET, * pASYNCINET;
|
||||||
|
|
||||||
|
pASYNCINET AsyncInetDownload(LPCWSTR lpszAgent,
|
||||||
|
DWORD dwAccessType,
|
||||||
|
LPCWSTR lpszProxy,
|
||||||
|
LPCWSTR lpszProxyBypass,
|
||||||
|
LPCWSTR lpszUrl,
|
||||||
|
BOOL bAllowCache,
|
||||||
|
ASYNCINET_CALLBACK Callback,
|
||||||
|
VOID* Extension
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL AsyncInetCancel(pASYNCINET AsyncInet);
|
||||||
|
|
||||||
|
VOID AsyncInetRelease(pASYNCINET AsyncInet);
|
||||||
|
|
||||||
|
#endif
|
|
@ -51,7 +51,7 @@ struct CAvailableApplicationInfo
|
||||||
ATL::CStringW m_szUrlSite;
|
ATL::CStringW m_szUrlSite;
|
||||||
ATL::CStringW m_szUrlDownload;
|
ATL::CStringW m_szUrlDownload;
|
||||||
ATL::CSimpleArray<LCID> m_LanguageLCIDs;
|
ATL::CSimpleArray<LCID> m_LanguageLCIDs;
|
||||||
ATL::CSimpleArray<ATL::CStringW> m_szSnapshotFilename;
|
ATL::CSimpleArray<ATL::CStringW> m_szSnapshotLocation;
|
||||||
|
|
||||||
ULONG m_SizeBytes;
|
ULONG m_SizeBytes;
|
||||||
|
|
||||||
|
@ -100,10 +100,11 @@ typedef BOOL(CALLBACK *AVAILENUMPROC)(CAvailableApplicationInfo *Info, LPCWSTR s
|
||||||
|
|
||||||
class CAvailableApps
|
class CAvailableApps
|
||||||
{
|
{
|
||||||
static AvailableStrings m_Strings;
|
|
||||||
ATL::CAtlList<CAvailableApplicationInfo*> m_InfoList;
|
ATL::CAtlList<CAvailableApplicationInfo*> m_InfoList;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
static AvailableStrings m_Strings;
|
||||||
|
|
||||||
CAvailableApps();
|
CAvailableApps();
|
||||||
|
|
||||||
static BOOL UpdateAppsDB();
|
static BOOL UpdateAppsDB();
|
||||||
|
|
Loading…
Reference in a new issue