[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:
He Yang 2020-06-21 18:26:41 +08:00 committed by Mark Jansen
parent fbf119fde1
commit e506581454
No known key found for this signature in database
GPG key ID: B39240EE84BEAE8B
6 changed files with 735 additions and 40 deletions

View file

@ -11,6 +11,7 @@
#include "rapps.h"
#include "rosui.h"
#include "crichedit.h"
#include "asyncinet.h"
#include <shlobj_undoc.h>
#include <shlguid_undoc.h>
@ -43,11 +44,16 @@ using namespace Gdiplus;
// 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)
};
@ -59,6 +65,14 @@ enum SNPSHT_STATUS
#define PI 3.1415927
typedef struct __SnapshotDownloadParam
{
LONGLONG ID;
HANDLE hFile;
HWND hwndNotify;
ATL::CStringW DownloadFileName;
} SnapshotDownloadParam;
INT GetSystemColorDepth()
{
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 :
public CWindowImpl<CAppSnapshotPreview>
{
@ -301,6 +349,9 @@ private:
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)
{
@ -324,6 +375,42 @@ private:
}
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;
@ -388,6 +475,38 @@ private:
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;
@ -445,7 +564,7 @@ private:
}
break;
case SNPSHTPREV_FILE:
case SNPSHTPREV_IMAGE:
{
if (pImage)
{
@ -541,39 +660,82 @@ public:
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
@ -584,7 +746,7 @@ public:
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.
@ -631,6 +793,11 @@ private:
ResizeChildren(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
break;
}
case WM_RAPPS_RESIZE_CHILDREN:
{
ResizeChildren();
break;
}
case WM_COMMAND:
{
OnCommand(wParam, lParam);
@ -777,10 +944,10 @@ public:
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
{