//---------------------------------------------------------------------------- // 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; } //----------------------------------------------------------------------------