include_directories(include)
list(APPEND SOURCE
+ asyncinet.cpp
available.cpp
cabinet.cpp
gui.cpp
winmain.cpp
unattended.cpp
include/rapps.h
+ include/asyncinet.h
include/available.h
include/dialogs.h
include/installed.h
--- /dev/null
+/*
+ * 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);
+ }
+}
{
WCHAR SnapshotField[sizeof("Snapshot") + 4];
wsprintfW(SnapshotField, L"Snapshot%d", i + 1);
- ATL::CStringW SnapshotFileName;
- if (!GetString(SnapshotField, SnapshotFileName))
+ ATL::CStringW SnapshotLocation;
+ if (!GetString(SnapshotField, SnapshotLocation))
{
continue;
}
- // TODO: Add URL Support
- // TODO: Does the filename contain anything stuff like "\\" ".." ":" "<" ">" ?
- // these stuff may lead to security issues
-
- ATL::CStringW SnapshotName = AvlbStrings.szAppsPath;
- PathAppendW(SnapshotName.GetBuffer(MAX_PATH), L"snapshots");
- PathAppendW(SnapshotName.GetBuffer(), SnapshotFileName.GetString());
- SnapshotName.ReleaseBuffer();
- m_szSnapshotFilename.Add(SnapshotName);
+ if (PathIsURLW(SnapshotLocation.GetString()))
+ {
+ 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;
+ PathAppendW(SnapshotName.GetBuffer(MAX_PATH), L"snapshots");
+ PathAppendW(SnapshotName.GetBuffer(), SnapshotLocation.GetString());
+ SnapshotName.ReleaseBuffer();
+ m_szSnapshotLocation.Add(SnapshotName);
+ }
}
RetrieveSize();
BOOL CAvailableApplicationInfo::RetrieveSnapshot(UINT Index,ATL::CStringW& SnapshotFileName) const
{
- if (Index >= (UINT)m_szSnapshotFilename.GetSize())
+ if (Index >= (UINT)m_szSnapshotLocation.GetSize())
{
return FALSE;
}
- SnapshotFileName = m_szSnapshotFilename[Index];
+ SnapshotFileName = m_szSnapshotLocation[Index];
return TRUE;
}
#include "rapps.h"
#include "rosui.h"
#include "crichedit.h"
+#include "asyncinet.h"
#include <shlobj_undoc.h>
#include <shlguid_undoc.h>
// minimum width of richedit
#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
{
SNPSHTPREV_EMPTY, // show nothing
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)
};
#define PI 3.1415927
+typedef struct __SnapshotDownloadParam
+{
+ LONGLONG ID;
+ HANDLE hFile;
+ HWND hwndNotify;
+ ATL::CStringW DownloadFileName;
+} SnapshotDownloadParam;
+
INT GetSystemColorDepth()
{
DEVMODEW pDevMode;
}
};
+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 :
public CWindowImpl<CAppSnapshotPreview>
{
BOOL bLoadingTimerOn = FALSE;
int LoadingAnimationFrame = 0;
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)
{
}
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:
{
PAINTSTRUCT ps;
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)
{
SnpshtPrevStauts = Status;
}
break;
- case SNPSHTPREV_FILE:
+ case SNPSHTPREV_IMAGE:
{
if (pImage)
{
delete pImage;
pImage = NULL;
}
+ if (AsyncInet)
+ {
+ AsyncInetCancel(AsyncInet);
+ }
+ if (!TempImagePath.IsEmpty())
+ {
+ DeleteFileW(TempImagePath.GetString());
+ TempImagePath.Empty();
+ }
}
VOID DisplayEmpty()
{
+ InterlockedIncrement64(&ContentID);
SetStatus(SNPSHTPREV_EMPTY);
PreviousDisplayCleanup();
}
- VOID DisplayLoading()
+ BOOL DisplayImage(LPCWSTR lpszLocation)
{
- SetStatus(SNPSHTPREV_LOADING);
+ LONGLONG ID = InterlockedIncrement64(&ContentID);
PreviousDisplayCleanup();
- bLoadingTimerOn = TRUE;
- SetTimer(TIMER_LOADING_ANIMATION, 1000 / LOADING_ANIMATION_FPS, 0);
- }
- BOOL DisplayFile(LPCWSTR lpszFileName)
- {
- SetStatus(SNPSHTPREV_FILE);
- PreviousDisplayCleanup();
- pImage = Bitmap::FromFile(lpszFileName, 0);
- if (pImage->GetLastStatus() != Ok)
+ if (PathIsURLW(lpszLocation))
{
- DisplayFailed();
- return FALSE;
- }
- return TRUE;
- }
+ DisplayLoading();
- VOID DisplayFailed()
- {
- SetStatus(SNPSHTPREV_FAILED);
- PreviousDisplayCleanup();
+ SnapshotDownloadParam* DownloadParam = new SnapshotDownloadParam;
+ if (!DownloadParam) return FALSE;
+
+ 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
return 0;
case SNPSHTPREV_LOADING:
return 200;
- case SNPSHTPREV_FILE:
+ case SNPSHTPREV_IMAGE:
if (pImage)
{
// return the width needed to display image inside the window.
ResizeChildren(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
break;
}
+ case WM_RAPPS_RESIZE_CHILDREN:
+ {
+ ResizeChildren();
+ break;
+ }
case WM_COMMAND:
{
OnCommand(wParam, lParam);
BOOL ShowAvailableAppInfo(CAvailableApplicationInfo* Info)
{
- ATL::CStringW SnapshotFilename;
- if (Info->RetrieveSnapshot(0, SnapshotFilename))
+ ATL::CStringW SnapshotLocation;
+ if (Info->RetrieveSnapshot(0, SnapshotLocation))
{
- SnpshtPrev->DisplayFile(SnapshotFilename);
+ SnpshtPrev->DisplayImage(SnapshotLocation);
}
else
{
--- /dev/null
+#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
ATL::CStringW m_szUrlSite;
ATL::CStringW m_szUrlDownload;
ATL::CSimpleArray<LCID> m_LanguageLCIDs;
- ATL::CSimpleArray<ATL::CStringW> m_szSnapshotFilename;
+ ATL::CSimpleArray<ATL::CStringW> m_szSnapshotLocation;
ULONG m_SizeBytes;
class CAvailableApps
{
- static AvailableStrings m_Strings;
ATL::CAtlList<CAvailableApplicationInfo*> m_InfoList;
public:
+ static AvailableStrings m_Strings;
+
CAvailableApps();
static BOOL UpdateAppsDB();