https://git.reactos.org/?p=reactos.git;a=commitdiff;h=fbf119fde1fe00f0e5920…
commit fbf119fde1fe00f0e5920070d37b73983c7cfb5a
Author: He Yang <1160386205(a)qq.com>
AuthorDate: Sun Jun 14 21:22:58 2020 +0800
Commit: Mark Jansen <mark.jansen(a)reactos.org>
CommitDate: Sun Sep 6 17:09:19 2020 +0200
[RAPPS] Screenshot preview and other trivial fixes (#2894)
* add one more layer of window
* using Path* API to operate path
* always use rappmgr.cab as file name when downloading db. ignore the URL
* add snapshot preview window
* show a broken-image icon when failed to load image
* add a padding between image and content, and make sure always some space is reserved
for richedit
* hide the padding if snapshot window does not have a width
* some work to avoid blinking when window resizing
* add WM_PRINTCLIENT handling
---
base/applications/rapps/CMakeLists.txt | 2 +-
base/applications/rapps/available.cpp | 67 +++-
base/applications/rapps/gui.cpp | 491 ++++++++++++++++++++++++++--
base/applications/rapps/include/available.h | 38 ++-
base/applications/rapps/include/misc.h | 1 -
base/applications/rapps/include/resource.h | 1 +
base/applications/rapps/loaddlg.cpp | 15 +-
base/applications/rapps/misc.cpp | 5 +-
base/applications/rapps/rapps.rc | 3 +-
base/applications/rapps/res/brokenimg.ico | Bin 0 -> 152126 bytes
base/applications/rapps/winmain.cpp | 20 ++
11 files changed, 574 insertions(+), 69 deletions(-)
diff --git a/base/applications/rapps/CMakeLists.txt
b/base/applications/rapps/CMakeLists.txt
index 33225ae5c04..226a8badcbd 100644
--- a/base/applications/rapps/CMakeLists.txt
+++ b/base/applications/rapps/CMakeLists.txt
@@ -39,7 +39,7 @@ add_rc_deps(rapps.rc ${rapps_rc_deps})
add_executable(rapps ${SOURCE} rapps.rc)
set_module_type(rapps win32gui UNICODE)
target_link_libraries(rapps uuid wine)
-add_importlibs(rapps advapi32 comctl32 gdi32 wininet user32 shell32 shlwapi ole32
setupapi msvcrt kernel32 ntdll)
+add_importlibs(rapps advapi32 comctl32 gdi32 wininet user32 shell32 shlwapi ole32
setupapi gdiplus msvcrt kernel32 ntdll)
add_pch(rapps include/rapps.h SOURCE)
add_dependencies(rapps rappsmsg)
add_message_headers(ANSI rappsmsg.mc)
diff --git a/base/applications/rapps/available.cpp
b/base/applications/rapps/available.cpp
index c7c78e180a9..be376c1c05b 100644
--- a/base/applications/rapps/available.cpp
+++ b/base/applications/rapps/available.cpp
@@ -18,23 +18,23 @@
#include <atlstr.h>
// CAvailableApplicationInfo
-CAvailableApplicationInfo::CAvailableApplicationInfo(const ATL::CStringW&
sFileNameParam)
+CAvailableApplicationInfo::CAvailableApplicationInfo(const ATL::CStringW&
sFileNameParam, AvailableStrings& AvlbStrings)
: m_IsSelected(FALSE), m_LicenseType(LICENSE_NONE), m_SizeBytes(0),
m_sFileName(sFileNameParam),
m_IsInstalled(FALSE), m_HasLanguageInfo(FALSE), m_HasInstalledVersion(FALSE)
{
- RetrieveGeneralInfo();
+ RetrieveGeneralInfo(AvlbStrings);
}
-VOID CAvailableApplicationInfo::RefreshAppInfo()
+VOID CAvailableApplicationInfo::RefreshAppInfo(AvailableStrings& AvlbStrings)
{
if (m_szUrlDownload.IsEmpty())
{
- RetrieveGeneralInfo();
+ RetrieveGeneralInfo(AvlbStrings);
}
}
// Lazily load general info from the file
-VOID CAvailableApplicationInfo::RetrieveGeneralInfo()
+VOID CAvailableApplicationInfo::RetrieveGeneralInfo(AvailableStrings& AvlbStrings)
{
m_Parser = new CConfigParser(m_sFileName);
@@ -52,10 +52,31 @@ VOID CAvailableApplicationInfo::RetrieveGeneralInfo()
GetString(L"License", m_szLicense);
GetString(L"Description", m_szDesc);
GetString(L"URLSite", m_szUrlSite);
- GetString(L"CDPath", m_szCDPath);
- GetString(L"Language", m_szRegName);
GetString(L"SHA1", m_szSHA1);
+ static_assert(MAX_SNAPSHOT_NUM < 10000, "MAX_SNAPSHOT_NUM is too big");
+ for (int i = 0; i < MAX_SNAPSHOT_NUM; i++)
+ {
+ WCHAR SnapshotField[sizeof("Snapshot") + 4];
+ wsprintfW(SnapshotField, L"Snapshot%d", i + 1);
+ ATL::CStringW SnapshotFileName;
+ if (!GetString(SnapshotField, SnapshotFileName))
+ {
+ 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);
+ }
+
RetrieveSize();
RetrieveLicenseType();
RetrieveLanguages();
@@ -209,6 +230,16 @@ BOOL CAvailableApplicationInfo::HasUpdate() const
return (m_szInstalledVersion.Compare(m_szVersion) < 0) ? TRUE : FALSE;
}
+BOOL CAvailableApplicationInfo::RetrieveSnapshot(UINT Index,ATL::CStringW&
SnapshotFileName) const
+{
+ if (Index >= (UINT)m_szSnapshotFilename.GetSize())
+ {
+ return FALSE;
+ }
+ SnapshotFileName = m_szSnapshotFilename[Index];
+ return TRUE;
+}
+
VOID CAvailableApplicationInfo::SetLastWriteTime(FILETIME* ftTime)
{
RtlCopyMemory(&m_ftCacheStamp, ftTime, sizeof(FILETIME));
@@ -231,11 +262,19 @@ AvailableStrings::AvailableStrings()
//FIXME: maybe provide a fallback?
if (GetStorageDirectory(szPath))
{
- szAppsPath = szPath + L"\\rapps\\";
+ szAppsPath = szPath;
+ PathAppendW(szAppsPath.GetBuffer(MAX_PATH), L"rapps");
+ szAppsPath.ReleaseBuffer();
+
szCabName = L"rappmgr.cab";
szCabDir = szPath;
- szCabPath = (szCabDir + L"\\") + szCabName;
- szSearchPath = szAppsPath + L"*.txt";
+ szCabPath = szCabDir;
+ PathAppendW(szCabPath.GetBuffer(MAX_PATH), szCabName);
+ szCabPath.ReleaseBuffer();
+
+ szSearchPath = szAppsPath;
+ PathAppendW(szSearchPath.GetBuffer(MAX_PATH), L"*.txt");
+ szSearchPath.ReleaseBuffer();
}
}
// AvailableStrings
@@ -273,7 +312,9 @@ VOID CAvailableApps::DeleteCurrentAppsDB()
ATL::CStringW szTmp;
do
{
- szTmp = m_Strings.szAppsPath + FindFileData.cFileName;
+ szTmp = m_Strings.szAppsPath;
+ PathAppendW(szTmp.GetBuffer(MAX_PATH), FindFileData.cFileName);
+ szTmp.ReleaseBuffer();
DeleteFileW(szTmp.GetString());
} while (FindNextFileW(hFind, &FindFileData) != 0);
FindClose(hFind);
@@ -369,7 +410,7 @@ BOOL CAvailableApps::Enum(INT EnumType, AVAILENUMPROC lpEnumProc,
PVOID param)
}
// create a new entry
- Info = new CAvailableApplicationInfo(FindFileData.cFileName);
+ Info = new CAvailableApplicationInfo(FindFileData.cFileName, m_Strings);
// set a timestamp for the next time
Info->SetLastWriteTime(&FindFileData.ftLastWriteTime);
@@ -380,7 +421,7 @@ skip_if_cached:
|| EnumType == ENUM_ALL_AVAILABLE
|| (EnumType == ENUM_CAT_SELECTED && Info->m_IsSelected))
{
- Info->RefreshAppInfo();
+ Info->RefreshAppInfo(m_Strings);
if (lpEnumProc)
lpEnumProc(Info, m_Strings.szAppsPath.GetString(), param);
diff --git a/base/applications/rapps/gui.cpp b/base/applications/rapps/gui.cpp
index a1d1e0075c8..e8d2e4057de 100644
--- a/base/applications/rapps/gui.cpp
+++ b/base/applications/rapps/gui.cpp
@@ -17,15 +17,48 @@
#include <atlbase.h>
#include <atlcom.h>
+#include <atltypes.h>
#include <atlwin.h>
#include <wininet.h>
#include <shellutils.h>
#include <rosctrls.h>
+#include <gdiplus.h>
+#include <math.h>
+
+using namespace Gdiplus;
#define SEARCH_TIMER_ID 'SR'
#define LISTVIEW_ICON_SIZE 24
#define TREEVIEW_ICON_SIZE 24
+// default broken-image icon size
+#define BROKENIMG_ICON_SIZE 96
+
+// the boundary of w/h ratio of snapshot preview window
+#define SNPSHT_MAX_ASPECT_RAT 2.5
+
+// padding between snapshot preview and richedit (in pixel)
+#define INFO_DISPLAY_PADDING 10
+
+// minimum width of richedit
+#define RICHEDIT_MIN_WIDTH 160
+
+enum SNPSHT_STATUS
+{
+ SNPSHTPREV_EMPTY, // show nothing
+ SNPSHTPREV_LOADING, // image is loading (most likely downloading)
+ SNPSHTPREV_FILE, // display image from a file
+ SNPSHTPREV_FAILED // image can not be shown (download failure or wrong image)
+};
+
+#define TIMER_LOADING_ANIMATION 1 // Timer ID
+
+#define LOADING_ANIMATION_PERIOD 3 // Animation cycling period (in seconds)
+#define LOADING_ANIMATION_FPS 18 // Animation Frame Per Second
+
+
+#define PI 3.1415927
+
INT GetSystemColorDepth()
{
DEVMODEW pDevMode;
@@ -257,6 +290,322 @@ public:
}
};
+class CAppSnapshotPreview :
+ public CWindowImpl<CAppSnapshotPreview>
+{
+private:
+
+ SNPSHT_STATUS SnpshtPrevStauts = SNPSHTPREV_EMPTY;
+ Image* pImage = NULL;
+ HICON hBrokenImgIcon = NULL;
+ BOOL bLoadingTimerOn = FALSE;
+ int LoadingAnimationFrame = 0;
+ int BrokenImgSize = BROKENIMG_ICON_SIZE;
+
+ BOOL ProcessWindowMessage(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam,
LRESULT& theResult, DWORD dwMapId)
+ {
+ theResult = 0;
+ switch (Msg)
+ {
+ case WM_CREATE:
+ hBrokenImgIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_BROKEN_IMAGE),
IMAGE_ICON, BrokenImgSize, BrokenImgSize, 0);
+ break;
+ case WM_SIZE:
+ {
+ if (BrokenImgSize != min(min(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)),
BROKENIMG_ICON_SIZE))
+ {
+ BrokenImgSize = min(min(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)),
BROKENIMG_ICON_SIZE);
+
+ if (hBrokenImgIcon)
+ {
+ DeleteObject(hBrokenImgIcon);
+ hBrokenImgIcon = (HICON)LoadImage(hInst,
MAKEINTRESOURCE(IDI_BROKEN_IMAGE), IMAGE_ICON, BrokenImgSize, BrokenImgSize, 0);
+ }
+ }
+ break;
+ }
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(&ps);
+ CRect rect;
+ GetClientRect(&rect);
+
+ PaintOnDC(hdc,
+ rect.Width(),
+ rect.Height(),
+ ps.fErase);
+
+ EndPaint(&ps);
+ break;
+ }
+ case WM_PRINTCLIENT:
+ {
+ if (lParam & PRF_CHECKVISIBLE)
+ {
+ if (!IsWindowVisible()) break;
+ }
+ CRect rect;
+ GetClientRect(&rect);
+
+ PaintOnDC((HDC)wParam,
+ rect.Width(),
+ rect.Height(),
+ lParam & PRF_ERASEBKGND);
+ break;
+ }
+ case WM_ERASEBKGND:
+ {
+ return TRUE; // do not erase to avoid blinking
+ }
+ case WM_TIMER:
+ {
+ switch (wParam)
+ {
+ case TIMER_LOADING_ANIMATION:
+ LoadingAnimationFrame++;
+ LoadingAnimationFrame %= (LOADING_ANIMATION_PERIOD *
LOADING_ANIMATION_FPS);
+ HDC hdc = GetDC();
+ CRect rect;
+ GetClientRect(&rect);
+
+ PaintOnDC(hdc,
+ rect.Width(),
+ rect.Height(),
+ TRUE);
+ ReleaseDC(hdc);
+ }
+ break;
+ }
+ case WM_DESTROY:
+ {
+ PreviousDisplayCleanup();
+ DeleteObject(hBrokenImgIcon);
+ hBrokenImgIcon = NULL;
+ break;
+ }
+ }
+ return FALSE;
+ }
+
+ VOID SetStatus(SNPSHT_STATUS Status)
+ {
+ SnpshtPrevStauts = Status;
+ }
+
+ VOID PaintOnDC(HDC hdc, int width, int height, BOOL bDrawBkgnd)
+ {
+ // use an off screen dc to avoid blinking
+ HDC hdcMem = CreateCompatibleDC(hdc);
+ HBITMAP hBitmap = CreateCompatibleBitmap(hdc, width, height);
+ SelectObject(hdcMem, hBitmap);
+
+ if (bDrawBkgnd)
+ {
+ HBRUSH hOldBrush = (HBRUSH)SelectObject(hdcMem,
(HGDIOBJ)GetSysColorBrush(COLOR_BTNFACE));
+ PatBlt(hdcMem, 0, 0, width, height, PATCOPY);
+ SelectObject(hdcMem, hOldBrush);
+ }
+
+ switch (SnpshtPrevStauts)
+ {
+ case SNPSHTPREV_EMPTY:
+ {
+
+ }
+ break;
+
+ case SNPSHTPREV_LOADING:
+ {
+ Graphics graphics(hdcMem);
+ Color color(255, 0, 0);
+ SolidBrush dotBrush(Color(255, 100, 100, 100));
+
+ graphics.SetSmoothingMode(SmoothingMode::SmoothingModeAntiAlias);
+
+ // Paint three dot
+ float DotWidth = GetLoadingDotWidth(width, height);
+ graphics.FillEllipse((Brush*)(&dotBrush),
+ (REAL)width / 2.0 - min(width, height) * 2.0 / 16.0 - DotWidth / 2.0,
+ (REAL)height / 2.0 - GetFrameDotShift(LoadingAnimationFrame +
LOADING_ANIMATION_FPS / 4, width, height) - DotWidth / 2.0,
+ DotWidth,
+ DotWidth);
+
+ graphics.FillEllipse((Brush*)(&dotBrush),
+ (REAL)width / 2.0 - DotWidth / 2.0,
+ (REAL)height / 2.0 - GetFrameDotShift(LoadingAnimationFrame, width,
height) - DotWidth / 2.0,
+ DotWidth,
+ DotWidth);
+
+ graphics.FillEllipse((Brush*)(&dotBrush),
+ (REAL)width / 2.0 + min(width, height) * 2.0 / 16.0 - DotWidth / 2.0,
+ (REAL)height / 2.0 - GetFrameDotShift(LoadingAnimationFrame -
LOADING_ANIMATION_FPS / 4, width, height) - DotWidth / 2.0,
+ DotWidth,
+ DotWidth);
+ }
+ break;
+
+ case SNPSHTPREV_FILE:
+ {
+ if (pImage)
+ {
+ // always draw entire image inside the window.
+ Graphics graphics(hdcMem);
+ float ZoomRatio = min(((float)width / (float)pImage->GetWidth()),
((float)height / (float)pImage->GetHeight()));
+ float ZoomedImgWidth = ZoomRatio * (float)pImage->GetWidth();
+ float ZoomedImgHeight = ZoomRatio * (float)pImage->GetHeight();
+
+ graphics.DrawImage(pImage,
+ ((float)width - ZoomedImgWidth) / 2.0, ((float)height -
ZoomedImgHeight) / 2.0,
+ ZoomedImgWidth, ZoomedImgHeight);
+ }
+ }
+ break;
+
+ case SNPSHTPREV_FAILED:
+ {
+ DrawIconEx(hdcMem,
+ (width - BrokenImgSize) / 2,
+ (height - BrokenImgSize) / 2,
+ hBrokenImgIcon,
+ BrokenImgSize,
+ BrokenImgSize,
+ NULL,
+ NULL,
+ DI_NORMAL | DI_COMPAT);
+ }
+ break;
+ }
+
+ // copy the content form off-screen dc to hdc
+ BitBlt(hdc, 0, 0, width, height, hdcMem, 0, 0, SRCCOPY);
+ DeleteDC(hdcMem);
+ DeleteObject(hBitmap);
+ }
+
+ float GetLoadingDotWidth(int width, int height)
+ {
+ return min(width, height) / 20.0;
+ }
+
+ float GetFrameDotShift(int Frame, int width, int height)
+ {
+ return min(width, height) *
+ (1.0 / 16.0) *
+ (2.0 / (2.0 - sqrt(3.0))) *
+ (max(sin((float)Frame * 2 * PI / (LOADING_ANIMATION_PERIOD *
LOADING_ANIMATION_FPS)), sqrt(3.0) / 2.0) - sqrt(3.0) / 2.0);
+ }
+
+public:
+ static ATL::CWndClassInfo& GetWndClassInfo()
+ {
+ DWORD csStyle = CS_VREDRAW | CS_HREDRAW;
+ static ATL::CWndClassInfo wc =
+ {
+ {
+ sizeof(WNDCLASSEX),
+ csStyle,
+ StartWindowProc,
+ 0,
+ 0,
+ NULL,
+ 0,
+ LoadCursorW(NULL, IDC_ARROW),
+ (HBRUSH)(COLOR_BTNFACE + 1),
+ 0,
+ L"RAppsSnapshotPreview",
+ NULL
+ },
+ NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
+ };
+ return wc;
+ }
+
+ HWND Create(HWND hParent)
+ {
+ RECT r = { 0,0,0,0 };
+
+ return CWindowImpl::Create(hParent, r, L"", WS_CHILD | WS_VISIBLE);
+ }
+
+ VOID PreviousDisplayCleanup()
+ {
+ if (bLoadingTimerOn)
+ {
+ KillTimer(TIMER_LOADING_ANIMATION);
+ bLoadingTimerOn = FALSE;
+ }
+ LoadingAnimationFrame = 0;
+ if (pImage)
+ {
+ delete pImage;
+ pImage = NULL;
+ }
+ }
+
+ VOID DisplayEmpty()
+ {
+ SetStatus(SNPSHTPREV_EMPTY);
+ PreviousDisplayCleanup();
+ }
+
+ VOID DisplayLoading()
+ {
+ SetStatus(SNPSHTPREV_LOADING);
+ 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)
+ {
+ DisplayFailed();
+ return FALSE;
+ }
+ return TRUE;
+ }
+
+ VOID DisplayFailed()
+ {
+ SetStatus(SNPSHTPREV_FAILED);
+ PreviousDisplayCleanup();
+ }
+
+ int GetRequestedWidth(int Height) // calculate requested window width by given
height
+ {
+ switch (SnpshtPrevStauts)
+ {
+ case SNPSHTPREV_EMPTY:
+ return 0;
+ case SNPSHTPREV_LOADING:
+ return 200;
+ case SNPSHTPREV_FILE:
+ if (pImage)
+ {
+ // return the width needed to display image inside the window.
+ // and always keep window w/h ratio inside [ 1/SNPSHT_MAX_ASPECT_RAT,
SNPSHT_MAX_ASPECT_RAT ]
+ return (int)floor((float)Height *
+ max(min((float)pImage->GetWidth() / (float)pImage->GetHeight(),
(float)SNPSHT_MAX_ASPECT_RAT), 1.0/ (float)SNPSHT_MAX_ASPECT_RAT));
+ }
+ return 0;
+ case SNPSHTPREV_FAILED:
+ return 200;
+ default:
+ return 0;
+ }
+ }
+
+ ~CAppSnapshotPreview()
+ {
+ PreviousDisplayCleanup();
+ }
+};
+
class CAppInfoDisplay :
public CUiWindow<CWindowImpl<CAppInfoDisplay>>
{
@@ -272,16 +621,18 @@ private:
{
RichEdit = new CAppRichEdit();
RichEdit->Create(hwnd);
+
+ SnpshtPrev = new CAppSnapshotPreview();
+ SnpshtPrev->Create(hwnd);
break;
}
case WM_SIZE:
{
- ::MoveWindow(RichEdit->m_hWnd, 0, 0, GET_X_LPARAM(lParam),
GET_Y_LPARAM(lParam), TRUE);
+ ResizeChildren(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
break;
}
case WM_COMMAND:
{
-
OnCommand(wParam, lParam);
break;
}
@@ -304,9 +655,94 @@ private:
return FALSE;
}
+ VOID ResizeChildren()
+ {
+ CRect rect;
+ GetWindowRect(&rect);
+ ResizeChildren(rect.Width(), rect.Height());
+ }
+
+ VOID ResizeChildren(int Width, int Height)
+ {
+ int SnpshtWidth = SnpshtPrev->GetRequestedWidth(Height);
+
+ // make sure richedit always have room to display
+ SnpshtWidth = min(SnpshtWidth, Width - INFO_DISPLAY_PADDING -
RICHEDIT_MIN_WIDTH);
+
+ DWORD dwError = ERROR_SUCCESS;
+ HDWP hDwp = BeginDeferWindowPos(2);
+
+ if (hDwp)
+ {
+ hDwp = ::DeferWindowPos(hDwp, SnpshtPrev->m_hWnd, NULL,
+ 0, 0, SnpshtWidth, Height, 0);
+
+ if (hDwp)
+ {
+ // hide the padding if snapshot window width == 0
+ int RicheditPosX = SnpshtWidth ? (SnpshtWidth + INFO_DISPLAY_PADDING) :
0;
+
+ hDwp = ::DeferWindowPos(hDwp, RichEdit->m_hWnd, NULL,
+ RicheditPosX, 0, Width - RicheditPosX, Height, 0);
+
+ if (hDwp)
+ {
+ EndDeferWindowPos(hDwp);
+ }
+ else
+ {
+ dwError = GetLastError();
+ }
+ }
+ else
+ {
+ dwError = GetLastError();
+ }
+ }
+ else
+ {
+ dwError = GetLastError();
+ }
+
+
+#if DBG
+ ATLASSERT(dwError == ERROR_SUCCESS);
+#endif
+
+ UpdateWindow();
+ }
+
+ VOID OnLink(ENLINK* Link)
+ {
+ switch (Link->msg)
+ {
+ case WM_LBUTTONUP:
+ case WM_RBUTTONUP:
+ {
+ if (pLink) HeapFree(GetProcessHeap(), 0, pLink);
+
+ pLink = (LPWSTR)HeapAlloc(GetProcessHeap(), 0,
+ (max(Link->chrg.cpMin, Link->chrg.cpMax) -
+ min(Link->chrg.cpMin, Link->chrg.cpMax) + 1) * sizeof(WCHAR));
+ if (!pLink)
+ {
+ /* TODO: Error message */
+ return;
+ }
+
+ RichEdit->SendMessageW(EM_SETSEL, Link->chrg.cpMin,
Link->chrg.cpMax);
+ RichEdit->SendMessageW(EM_GETSELTEXT, 0, (LPARAM)pLink);
+
+ ShowPopupMenuEx(m_hWnd, m_hWnd, IDR_LINKMENU, -1);
+ }
+ break;
+ }
+ }
+
public:
CAppRichEdit * RichEdit;
+ CAppSnapshotPreview * SnpshtPrev;
static ATL::CWndClassInfo& GetWndClassInfo()
{
@@ -336,51 +772,38 @@ public:
{
RECT r = { 0,0,0,0 };
- return CWindowImpl::Create(hwndParent, r, L"", WS_CHILD | WS_VISIBLE);
+ return CWindowImpl::Create(hwndParent, r, L"", WS_CHILD | WS_VISIBLE |
WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
}
BOOL ShowAvailableAppInfo(CAvailableApplicationInfo* Info)
{
+ ATL::CStringW SnapshotFilename;
+ if (Info->RetrieveSnapshot(0, SnapshotFilename))
+ {
+ SnpshtPrev->DisplayFile(SnapshotFilename);
+ }
+ else
+ {
+ SnpshtPrev->DisplayEmpty();
+ }
+ ResizeChildren();
return RichEdit->ShowAvailableAppInfo(Info);
}
BOOL ShowInstalledAppInfo(PINSTALLED_INFO Info)
{
+ SnpshtPrev->DisplayEmpty();
+ ResizeChildren();
return RichEdit->ShowInstalledAppInfo(Info);
}
VOID SetWelcomeText()
{
+ SnpshtPrev->DisplayEmpty();
+ ResizeChildren();
RichEdit->SetWelcomeText();
}
- VOID OnLink(ENLINK* Link)
- {
- switch (Link->msg)
- {
- case WM_LBUTTONUP:
- case WM_RBUTTONUP:
- {
- if (pLink) HeapFree(GetProcessHeap(), 0, pLink);
-
- pLink = (LPWSTR)HeapAlloc(GetProcessHeap(), 0,
- (max(Link->chrg.cpMin, Link->chrg.cpMax) -
- min(Link->chrg.cpMin, Link->chrg.cpMax) + 1) * sizeof(WCHAR));
- if (!pLink)
- {
- /* TODO: Error message */
- return;
- }
-
- RichEdit->SendMessageW(EM_SETSEL, Link->chrg.cpMin,
Link->chrg.cpMax);
- RichEdit->SendMessageW(EM_GETSELTEXT, 0, (LPARAM)pLink);
-
- ShowPopupMenuEx(m_hWnd, m_hWnd, IDR_LINKMENU, -1);
- }
- break;
- }
- }
-
VOID OnCommand(WPARAM wParam, LPARAM lParam)
{
WORD wCommand = LOWORD(wParam);
@@ -1804,8 +2227,12 @@ private:
}
/* Load icon from file */
- ATL::CStringW szIconPath;
- szIconPath.Format(L"%lsicons\\%ls.ico", szFolderPath,
Info->m_szName.GetString());
+ ATL::CStringW szIconPath = szFolderPath;
+ PathAppendW(szIconPath.GetBuffer(MAX_PATH), L"icons");
+ PathAppendW(szIconPath.GetBuffer(), Info->m_szName.GetString());
+ PathAddExtensionW(szIconPath.GetBuffer(), L".ico");
+ szIconPath.ReleaseBuffer();
+
hIcon = (HICON) LoadImageW(NULL,
szIconPath.GetString(),
IMAGE_ICON,
diff --git a/base/applications/rapps/include/available.h
b/base/applications/rapps/include/available.h
index 5e3a464fc03..e52c1970a30 100644
--- a/base/applications/rapps/include/available.h
+++ b/base/applications/rapps/include/available.h
@@ -7,6 +7,9 @@
#include "misc.h"
+
+#define MAX_SNAPSHOT_NUM 16
+
enum LicenseType
{
LICENSE_NONE,
@@ -22,6 +25,18 @@ inline BOOL IsLicenseType(INT x)
return (x >= LICENSE_MIN && x <= LICENSE_MAX);
}
+struct AvailableStrings
+{
+ ATL::CStringW szPath;
+ ATL::CStringW szCabPath;
+ ATL::CStringW szAppsPath;
+ ATL::CStringW szSearchPath;
+ ATL::CStringW szCabName;
+ ATL::CStringW szCabDir;
+
+ AvailableStrings();
+};
+
struct CAvailableApplicationInfo
{
INT m_Category;
@@ -35,8 +50,9 @@ struct CAvailableApplicationInfo
ATL::CStringW m_szSize;
ATL::CStringW m_szUrlSite;
ATL::CStringW m_szUrlDownload;
- ATL::CStringW m_szCDPath;
ATL::CSimpleArray<LCID> m_LanguageLCIDs;
+ ATL::CSimpleArray<ATL::CStringW> m_szSnapshotFilename;
+
ULONG m_SizeBytes;
// Caching mechanism related entries
@@ -48,17 +64,17 @@ struct CAvailableApplicationInfo
ATL::CStringW m_szInstalledVersion;
// Create an object from file
- CAvailableApplicationInfo(const ATL::CStringW& sFileNameParam);
+ CAvailableApplicationInfo(const ATL::CStringW& sFileNameParam,
AvailableStrings& m_Strings);
// Load all info from the file
- VOID RefreshAppInfo();
+ VOID RefreshAppInfo(AvailableStrings& m_Strings);
BOOL HasLanguageInfo() const;
BOOL HasNativeLanguage() const;
BOOL HasEnglishLanguage() const;
BOOL IsInstalled() const;
BOOL HasInstalledVersion() const;
BOOL HasUpdate() const;
-
+ BOOL RetrieveSnapshot(UINT Index, ATL::CStringW& SnapshotFileName) const;
// Set a timestamp
VOID SetLastWriteTime(FILETIME* ftTime);
@@ -71,7 +87,7 @@ private:
inline BOOL GetString(LPCWSTR lpKeyName, ATL::CStringW& ReturnedString);
// Lazily load general info from the file
- VOID RetrieveGeneralInfo();
+ VOID RetrieveGeneralInfo(AvailableStrings& m_Strings);
VOID RetrieveInstalledStatus();
VOID RetrieveInstalledVersion();
VOID RetrieveLanguages();
@@ -82,18 +98,6 @@ private:
typedef BOOL(CALLBACK *AVAILENUMPROC)(CAvailableApplicationInfo *Info, LPCWSTR
szFolderPath, PVOID param);
-struct AvailableStrings
-{
- ATL::CStringW szPath;
- ATL::CStringW szCabPath;
- ATL::CStringW szAppsPath;
- ATL::CStringW szSearchPath;
- ATL::CStringW szCabName;
- ATL::CStringW szCabDir;
-
- AvailableStrings();
-};
-
class CAvailableApps
{
static AvailableStrings m_Strings;
diff --git a/base/applications/rapps/include/misc.h
b/base/applications/rapps/include/misc.h
index fd914c4c468..50354c0f7ff 100644
--- a/base/applications/rapps/include/misc.h
+++ b/base/applications/rapps/include/misc.h
@@ -9,7 +9,6 @@ INT GetClientWindowWidth(HWND hwnd);
INT GetClientWindowHeight(HWND hwnd);
VOID CopyTextToClipboard(LPCWSTR lpszText);
-VOID SetWelcomeText();
VOID ShowPopupMenuEx(HWND hwnd, HWND hwndOwner, UINT MenuID, UINT DefaultItem);
VOID ShowPopupMenu(HWND hwnd, UINT MenuID, UINT DefaultItem);
BOOL StartProcess(ATL::CStringW &Path, BOOL Wait);
diff --git a/base/applications/rapps/include/resource.h
b/base/applications/rapps/include/resource.h
index 49dc2105b4f..26b6cf706db 100644
--- a/base/applications/rapps/include/resource.h
+++ b/base/applications/rapps/include/resource.h
@@ -14,6 +14,7 @@
#define IDI_UPDATE_DB 20
#define IDI_CHECK_ALL 21
#define IDI_SELECTEDFORINST 22
+#define IDI_BROKEN_IMAGE 23
/* Icons for categories */
#define IDI_CAT_AUDIO 50
diff --git a/base/applications/rapps/loaddlg.cpp b/base/applications/rapps/loaddlg.cpp
index cc88af6cc16..60f999967cb 100644
--- a/base/applications/rapps/loaddlg.cpp
+++ b/base/applications/rapps/loaddlg.cpp
@@ -650,8 +650,19 @@ unsigned int WINAPI CDownloadManager::ThreadFunc(LPVOID param)
}
// append a \ to the provided file system path, and the filename portion from the
URL after that
- Path += L"\\";
- Path += (LPWSTR) (p + 1);
+
+ PathAddBackslashW(Path.GetBuffer(MAX_PATH));
+ switch (InfoArray[iAppId].DLType)
+ {
+ case DLTYPE_DBUPDATE:
+ case DLTYPE_DBUPDATE_UNOFFICIAL:
+ PathAppendW(Path.GetBuffer(), L"rappmgr.cab"); // whatever the URL
is, use the file name L"rappmgr.cab"
+ break;
+ case DLTYPE_APPLICATION:
+ PathAppendW(Path.GetBuffer(), (LPWSTR)(p + 1)); // use the filename retrieved
from URL
+ break;
+ }
+ Path.ReleaseBuffer();
if ((InfoArray[iAppId].DLType == DLTYPE_APPLICATION) &&
InfoArray[iAppId].szSHA1[0] && GetFileAttributesW(Path.GetString()) !=
INVALID_FILE_ATTRIBUTES)
{
diff --git a/base/applications/rapps/misc.cpp b/base/applications/rapps/misc.cpp
index d0f13cac232..9ee6a391f63 100644
--- a/base/applications/rapps/misc.cpp
+++ b/base/applications/rapps/misc.cpp
@@ -177,14 +177,15 @@ BOOL StartProcess(LPWSTR lpPath, BOOL Wait)
BOOL GetStorageDirectory(ATL::CStringW& Directory)
{
- if (!SHGetSpecialFolderPathW(NULL, Directory.GetBuffer(MAX_PATH),
CSIDL_LOCAL_APPDATA, TRUE))
+ LPWSTR DirectoryStr = Directory.GetBuffer(MAX_PATH);
+ if (!SHGetSpecialFolderPathW(NULL, DirectoryStr, CSIDL_LOCAL_APPDATA, TRUE))
{
Directory.ReleaseBuffer();
return FALSE;
}
+ PathAppendW(DirectoryStr, L"rapps");
Directory.ReleaseBuffer();
- Directory += L"\\rapps";
return (CreateDirectoryW(Directory.GetString(), NULL) || GetLastError() ==
ERROR_ALREADY_EXISTS);
}
diff --git a/base/applications/rapps/rapps.rc b/base/applications/rapps/rapps.rc
index c67e1de5442..5debb642bdd 100644
--- a/base/applications/rapps/rapps.rc
+++ b/base/applications/rapps/rapps.rc
@@ -23,6 +23,8 @@ IDI_APPUPD ICON "res/appupd.ico"
IDI_CATEGORY ICON "res/cat.ico"
IDI_UPDATE_DB ICON "res/updatedb.ico"
IDI_CHECK_ALL ICON "res/select.ico"
+IDI_SELECTEDFORINST ICON "res/select.ico"
+IDI_BROKEN_IMAGE ICON "res/brokenimg.ico"
/* Categories */
IDI_CAT_AUDIO ICON "res/cats/audio.ico"
@@ -41,7 +43,6 @@ IDI_CAT_SCIENCE ICON "res/cats/science.ico"
IDI_CAT_TOOLS ICON "res/cats/tools.ico"
IDI_CAT_VIDEO ICON "res/cats/video.ico"
IDI_CAT_THEMES ICON "res/cats/themes.ico"
-IDI_SELECTEDFORINST ICON "res/select.ico"
/* Accelerators -- key bindings */
HOTKEYS ACCELERATORS
diff --git a/base/applications/rapps/res/brokenimg.ico
b/base/applications/rapps/res/brokenimg.ico
new file mode 100644
index 00000000000..58454f74041
Binary files /dev/null and b/base/applications/rapps/res/brokenimg.ico differ
diff --git a/base/applications/rapps/winmain.cpp b/base/applications/rapps/winmain.cpp
index d55edca46fa..ad14c9fd80b 100644
--- a/base/applications/rapps/winmain.cpp
+++ b/base/applications/rapps/winmain.cpp
@@ -13,6 +13,8 @@
#include <atlcom.h>
+#include <gdiplus.h>
+
HWND hMainWnd;
HINSTANCE hInst;
SETTINGS_INFO SettingsInfo;
@@ -28,6 +30,10 @@ END_OBJECT_MAP()
CRAppsModule gModule;
CAtlWinModule gWinModule;
+Gdiplus::GdiplusStartupInput gdiplusStartupInput;
+ULONG_PTR gdiplusToken;
+
+
static VOID InitializeAtlModule(HINSTANCE hInstance, BOOL bInitialize)
{
if (bInitialize)
@@ -40,6 +46,18 @@ static VOID InitializeAtlModule(HINSTANCE hInstance, BOOL bInitialize)
}
}
+VOID InitializeGDIPlus(BOOL bInitialize)
+{
+ if (bInitialize)
+ {
+ Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
+ }
+ else
+ {
+ Gdiplus::GdiplusShutdown(gdiplusToken);
+ }
+}
+
VOID FillDefaultSettings(PSETTINGS_INFO pSettingsInfo)
{
ATL::CStringW szDownloadDir;
@@ -129,6 +147,7 @@ INT WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPWSTR lpCmdLi
BOOL bIsFirstLaunch;
InitializeAtlModule(hInstance, TRUE);
+ InitializeGDIPlus(TRUE);
if (GetUserDefaultUILanguage() == MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT))
{
@@ -169,6 +188,7 @@ INT WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPWSTR lpCmdLi
if (hMutex)
CloseHandle(hMutex);
+ InitializeGDIPlus(FALSE);
InitializeAtlModule(hInstance, FALSE);
return 0;