windows-nt/Source/XPSP1/NT/shell/themes/preview/preview.cpp
2020-09-26 16:20:57 +08:00

472 lines
13 KiB
C++

//----------------------------------------------------------------------------
// Preview.cpp - image preview app for theme authoring
//----------------------------------------------------------------------------
#include "stdafx.h"
#include "resource.h"
#include "shlwapip.h"
#include "themeldr.h"
//----------------------------------------------------------------------------
#define MAX_LOADSTRING 100
//----------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HRESULT InitDib(HINSTANCE hInstance, LPCWSTR pszFileName);
void SetBackground(HWND hWnd, HINSTANCE hinst, int id, int iMenuId);
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
void OnFileOpen(HINSTANCE hInst, HWND hWnd);
void SetZoom(HWND hWnd, HINSTANCE hInstance, int iZoomPercent, int iMenuId);
//----------------------------------------------------------------------------
HINSTANCE hInst;
HBITMAP hCenterDIB = NULL;
HBITMAP hbrBackground = NULL;
int iDibWidth;
int iDibHeight;
int iCurrentBgMenu = 0;
int iCurrentZoomMenu = 0;
int iZoomFactor = 100;
BOOL fAlpha;
//----------------------------------------------------------------------------
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR lpCmdLine, int nCmdShow)
{
MSG msg;
HACCEL hAccelTable;
TCHAR szWindowClass[MAX_LOADSTRING];
TCHAR szTitle[MAX_LOADSTRING];
//---- initialize globals from themeldr.lib ----
ThemeLibStartUp(FALSE);
//---- Initialize global strings ----
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_PREVIEW, szWindowClass, MAX_LOADSTRING);
//---- register window class ----
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_PREVIEW);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = NULL;
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_PREVIEW);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
RegisterClassEx(&wcex);
if (*lpCmdLine)
InitDib(hInstance, lpCmdLine);
//---- create the main window ----
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
return 1;
SetBackground(hWnd, hInstance, IDB_PINKGRAY, ID_BACKGROUND_GRAYPINK);
SetZoom(hWnd, hInstance, 100, ID_ZOOM_100);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_PREVIEW);
//---- initialize us as a drag target ----
DragAcceptFiles(hWnd, TRUE);
//---- main message loop ----
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
//----------------------------------------------------------------------------
void SetBackground(HWND hWnd, HINSTANCE hInstance, int id, int iMenuId)
{
if (hbrBackground)
DeleteObject(hbrBackground);
hbrBackground = LoadBitmap(hInstance, MAKEINTRESOURCE(id));
InvalidateRect(hWnd, NULL, TRUE);
//---- update menu items ----
HMENU hMenu = GetMenu(hWnd);
hMenu = GetSubMenu(hMenu, 1);
if (iCurrentBgMenu)
CheckMenuItem(hMenu, iCurrentBgMenu, MF_BYCOMMAND | MF_UNCHECKED);
CheckMenuItem(hMenu, iMenuId, MF_BYCOMMAND | MF_CHECKED);
iCurrentBgMenu = iMenuId;
}
//----------------------------------------------------------------------------
HRESULT InitDib(HINSTANCE hInstance, LPCWSTR pszFileName)
{
if (hCenterDIB)
{
DeleteObject(hCenterDIB);
hCenterDIB = NULL;
}
int iRetVal = 0;
fAlpha = FALSE;
WCHAR *pszOutputName = L"$temp$.bmp";
HRESULT hr = S_OK;
HDC hdc = NULL;
DWORD *pBits = NULL;
//---- ensure file exists ----
if (! FileExists(pszFileName))
{
hr = MakeError32(STG_E_FILENOTFOUND);
goto exit;
}
//---- convert file, if needed ----
WCHAR szDrive[_MAX_DRIVE], szDir[_MAX_DIR], szBaseName[_MAX_FNAME], szExt[_MAX_EXT];
_wsplitpath(pszFileName, szDrive, szDir, szBaseName, szExt);
if (lstrcmpi(szExt, L".bmp") != 0) // not a .bmp file
{
//---- protect ourselves from crashes ----
try
{
hr = SHConvertGraphicsFile(pszFileName, pszOutputName, SHCGF_REPLACEFILE);
}
catch (...)
{
hr = MakeError32(E_FAIL);
}
if ((SUCCEEDED(hr)) && (! FileExists(pszOutputName)))
hr = MakeError32(E_FAIL);
if (FAILED(hr))
goto exit;
pszFileName = pszOutputName;
}
//---- load the specified center bitmap as a DIB ----
hCenterDIB = (HBITMAP) LoadImage(hInstance, pszFileName, IMAGE_BITMAP,
0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE);
if (! hCenterDIB)
{
hr = MakeErrorLast();
goto exit;
}
BITMAP bminfo;
GetObject(hCenterDIB, sizeof(bminfo), &bminfo);
iDibWidth = bminfo.bmWidth;
iDibHeight = bminfo.bmHeight;
if (bminfo.bmBitsPixel < 32)
iRetVal = 1;
else
{
pBits = new DWORD[(iDibWidth+20)*iDibHeight];
if (! pBits)
{
hr = MakeError32(E_OUTOFMEMORY);
goto exit;
}
BITMAPINFOHEADER BitMapHdr = {sizeof(BITMAPINFOHEADER), iDibWidth, iDibHeight, 1, 32, BI_RGB};
hdc = GetWindowDC(NULL);
if (! hdc)
{
hr = MakeErrorLast();
goto exit;
}
iRetVal = GetDIBits(hdc, hCenterDIB, 0, iDibHeight, pBits, (BITMAPINFO *)&BitMapHdr, DIB_RGB_COLORS);
if (! iRetVal)
{
hr = MakeErrorLast();
goto exit;
}
DWORD *pdw = pBits;
//---- pre-multiply bits - required by AlphaBlend() API ----
for (int r=0; r < iDibHeight; r++)
{
for (int c=0; c < iDibWidth; c++)
{
COLORREF cr = *pdw;
int iAlpha = ALPHACHANNEL(cr);
if (iAlpha)
{
int iRed = (RED(cr)*iAlpha)/255;
int iGreen = (GREEN(cr)*iAlpha)/255;
int iBlue = (BLUE(cr)*iAlpha)/255;
*pdw++ = (RGB(iRed, iGreen, iBlue) | (iAlpha << 24));
fAlpha = TRUE;
}
else
*pdw++ = 0;
}
}
if (fAlpha)
{
iRetVal = SetDIBits(NULL, hCenterDIB, 0, iDibHeight, pBits, (BITMAPINFO *)&BitMapHdr, DIB_RGB_COLORS);
if (! iRetVal)
{
hr = MakeErrorLast();
goto exit;
}
}
else
MessageBox(NULL, L"Alpha Channel of bitmap is all zero's", L"Warning", MB_OK);
}
exit:
if (hdc)
ReleaseDC(NULL, hdc);
if (pBits)
delete [] pBits;
if (FAILED(hr))
MessageBox(NULL, L"Error loading bitmap", L"Error", MB_OK);
return hr;
}
//----------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_DROPFILES:
{
HDROP hDrop = (HDROP)wParam;
WCHAR szFileName[_MAX_PATH+1];
int iGot = DragQueryFile(hDrop, 0, szFileName, ARRAYSIZE(szFileName));
DragFinish(hDrop);
if (iGot) // got a valid filename
{
HRESULT hr = InitDib(hInst, szFileName);
if (SUCCEEDED(hr))
InvalidateRect(hWnd, NULL, TRUE);
}
}
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case ID_FILE_OPEN:
OnFileOpen(hInst, hWnd);
break;
case IDM_ABOUT:
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
case ID_BACKGROUND_GRAYPINK:
SetBackground(hWnd, hInst, IDB_PINKGRAY, wmId);
break;
case ID_BACKGROUND_BLUEGRAY:
SetBackground(hWnd, hInst, IDB_BLUEGRAY, wmId);
break;
case ID_BACKGROUND_WHITE:
SetBackground(hWnd, hInst, IDB_WHITE, wmId);
break;
case ID_BACKGROUND_GRAY:
SetBackground(hWnd, hInst, IDB_GRAY, wmId);
break;
case ID_ZOOM_50:
SetZoom(hWnd, hInst, 50, wmId);
break;
case ID_ZOOM_100:
SetZoom(hWnd, hInst, 100, wmId);
break;
case ID_ZOOM_200:
SetZoom(hWnd, hInst, 200, wmId);
break;
case ID_ZOOM_400:
SetZoom(hWnd, hInst, 400, wmId);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_ERASEBKGND:
HBRUSH hbr;
hbr = CreatePatternBrush(hbrBackground);
hdc = (HDC)wParam;
if ((hbr) && (hdc))
{
RECT rect;
GetClientRect(hWnd, &rect);
FillRect(hdc, &rect, hbr);
DeleteObject(hbr);
}
return 1;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
XFORM xForm;
xForm.eM11 = (FLOAT)(iZoomFactor/100.);
xForm.eM12 = (FLOAT) 0.0;
xForm.eM21 = (FLOAT) 0.0;
xForm.eM22 = (FLOAT)(iZoomFactor/100.);
xForm.eDx = (FLOAT) 0.0;
xForm.eDy = (FLOAT) 0.0;
SetGraphicsMode(hdc, GM_ADVANCED);
SetWorldTransform(hdc, &xForm);
//---- get scaled rect ----
RECT rc;
GetClientRect(hWnd, &rc);
rc.right = (rc.right*100)/iZoomFactor;
rc.bottom = (rc.bottom*100)/iZoomFactor;
//---- paint the center bitmap ----
HDC dc2;
dc2 = CreateCompatibleDC(hdc);
if ((dc2) && (hCenterDIB))
{
HBITMAP hOldBitmap2;
hOldBitmap2 = (HBITMAP) SelectObject(dc2, hCenterDIB);
int x = ((rc.right - rc.left) - iDibWidth)/2;
int y = ((rc.bottom - rc.top) - iDibHeight)/2;
BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
if (fAlpha)
{
AlphaBlend(hdc, x, y, iDibWidth, iDibHeight,
dc2, 0, 0, iDibWidth, iDibHeight, bf);
}
else
{
BitBlt(hdc, x, y, iDibWidth, iDibHeight,
dc2, 0, 0, SRCCOPY);
}
SelectObject(dc2, hOldBitmap2);
DeleteDC(dc2);
}
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
//----------------------------------------------------------------------------
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
break;
}
return FALSE;
}
//----------------------------------------------------------------------------
void OnFileOpen(HINSTANCE hInst, HWND hWnd)
{
const WCHAR *filter =
L"Bitmap Files (*.bmp)\0*.bmp\0"
L"PNG Files (*.png)\0*.png\0"
L"All Files (*.*)\0*.*\0\0";
OPENFILENAME ofn = {sizeof(ofn)};
WCHAR szFile[_MAX_PATH+1] = {0};
//---- init ofn ----
ofn.hwndOwner = hWnd;
ofn.hInstance = hInst;
ofn.lpstrFile = szFile;
ofn.nMaxFile = ARRAYSIZE(szFile);
ofn.lpstrFilter = filter;
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = L"Select an Image File to preview";
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
// Display the Open dialog box.
if (GetOpenFileName(&ofn))
{
HRESULT hr = InitDib(hInst, szFile);
if (SUCCEEDED(hr))
InvalidateRect(hWnd, NULL, TRUE);
}
}
//----------------------------------------------------------------------------
void SetZoom(HWND hWnd, HINSTANCE hInstance, int iZoomPercent, int iMenuId)
{
iZoomFactor = iZoomPercent;
InvalidateRect(hWnd, NULL, TRUE);
//---- update menu items ----
HMENU hMenu = GetMenu(hWnd);
hMenu = GetSubMenu(hMenu, 2);
if (iCurrentZoomMenu)
CheckMenuItem(hMenu, iCurrentZoomMenu, MF_BYCOMMAND | MF_UNCHECKED);
CheckMenuItem(hMenu, iMenuId, MF_BYCOMMAND | MF_CHECKED);
iCurrentZoomMenu = iMenuId;
}
//----------------------------------------------------------------------------