/* DBACKP.CPP ** ** Copyright (C) Microsoft, 1997, All Rights Reserved. ** ** window class to display a preview of the screen background, ** complete with rudimentary palette handling and stretching ** of bitmaps to fit the preview screen. ** ** this can be replaced with a static bitmap control only ** if palettes can also be handled by the control. ** */ #include "stdafx.h" #pragma hdrstop #define GWW_INFO 0 #define CXYDESKPATTERN 8 BOOL g_bInfoSet = FALSE; HBITMAP g_hbmPreview = NULL; // the bitmap used for previewing HBITMAP g_hbmDefault = NULL; // default bitmap HBITMAP g_hbmWall = NULL; // bitmap image of wallpaper HDC g_hdcWall = NULL; // memory DC with g_hbmWall selected HDC g_hdcMemory = NULL; // memory DC HPALETTE g_hpalWall = NULL; // palette that goes with hbmWall bitmap HBRUSH g_hbrBack = NULL; // brush for the desktop background IThumbnail *g_pthumb = NULL; // Html to Bitmap converter DWORD g_dwWallpaperID = 0; // ID to identify which bitmap we received #define WM_HTML_BITMAP (WM_USER + 100) #define WM_ASYNC_BITMAP (WM_HTML_BITMAP + 1) HPALETTE PaletteFromDS(HDC hdc) { DWORD adw[257]; int i,n; n = GetDIBColorTable(hdc, 0, 256, (LPRGBQUAD)&adw[1]); adw[0] = MAKELONG(0x300, n); for (i=1; i<=n; i++) adw[i] = RGB(GetBValue(adw[i]),GetGValue(adw[i]),GetRValue(adw[i])); if (n == 0) return NULL; else return CreatePalette((LPLOGPALETTE)&adw[0]); } typedef struct{ HWND hwnd; HBITMAP hbmp; DWORD id; WPARAM flags; TCHAR szFile[MAX_PATH]; } ASYNCWALLPARAM, * PASYNCWALLPARAM; DWORD CALLBACK UpdateWallProc(LPVOID pv) { ASSERT(pv); PASYNCWALLPARAM pawp = (PASYNCWALLPARAM) pv; pawp->hbmp = (HBITMAP)LoadImage(NULL, pawp->szFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION); if (pawp->hbmp) { // if all is good, then the window will handle cleaning up if (IsWindow(pawp->hwnd) && PostMessage(pawp->hwnd, WM_ASYNC_BITMAP, 0, (LPARAM)pawp)) return TRUE; DeleteObject(pawp->hbmp); } LocalFree(pawp); return TRUE; } const GUID CLSID_HtmlThumbnailExtractor = {0xeab841a0, 0x9550, 0x11cf, 0x8c, 0x16, 0x0, 0x80, 0x5f, 0x14, 0x8, 0xf3}; DWORD CALLBACK UpdateWallProcHTML(LPVOID pv) { if (SUCCEEDED(CoInitialize(NULL))) { ASSERT(pv); if (pv) { PASYNCWALLPARAM pawp = (PASYNCWALLPARAM) pv; IPersistFile *ppf; HRESULT hr = CoCreateInstance(CLSID_HtmlThumbnailExtractor, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IPersistFile, &ppf)); if (SUCCEEDED(hr)) { hr = ppf->Load(pawp->szFile, STGM_READ); if (SUCCEEDED(hr)) { IExtractImage *pei= NULL; hr = ppf->QueryInterface(IID_PPV_ARG(IExtractImage, &pei)); if (SUCCEEDED(hr)) { DWORD dwPriority = 0; DWORD dwFlags = IEIFLAG_SCREEN | IEIFLAG_OFFLINE; WCHAR szLocation[MAX_PATH]; SIZEL rgSize = {MON_DX, MON_DY}; hr = pei->GetLocation(szLocation, ARRAYSIZE(szLocation), &dwPriority, &rgSize, SHGetCurColorRes(), &dwFlags); if (SUCCEEDED(hr)) { HBITMAP hbm; hr = pei->Extract(&hbm); if (SUCCEEDED(hr)) { if (!SendMessage(pawp->hwnd, WM_HTML_BITMAP, pawp->id, (LPARAM)hbm)) { DeleteObject(hbm); } } } pei->Release(); } } ppf->Release(); } LocalFree(pawp); } CoUninitialize(); } return TRUE; } void LoadWallpaperAsync(LPCTSTR pszFile, HWND hwnd, DWORD dwID, WPARAM flags, BOOL bHTML) { PASYNCWALLPARAM pawp = (PASYNCWALLPARAM) LocalAlloc(LPTR, SIZEOF(ASYNCWALLPARAM)); if (pawp) { pawp->hwnd = hwnd; pawp->flags = flags; pawp->id = dwID; StrCpyN(pawp->szFile, pszFile, SIZECHARS(pawp->szFile)); if (!bHTML) { if (!SHQueueUserWorkItem(UpdateWallProc, pawp, 0, (DWORD_PTR)0, (DWORD_PTR *)NULL, NULL, 0)) LocalFree(pawp); } else { if (!SHQueueUserWorkItem(UpdateWallProcHTML, pawp, 0, (DWORD_PTR)0, (DWORD_PTR *)NULL, NULL, 0)) LocalFree(pawp); } } } void _InitPreview(void) { if( g_hbmPreview ) DeleteObject( g_hbmPreview ); g_hbmPreview = LoadMonitorBitmap(); } void _BuildPattern(void) { WCHAR wszBuf[MAX_PATH]; HBITMAP hbmTemp; COLORREF clrOldBk, clrOldText; HBRUSH hbr = NULL; WORD patbits[CXYDESKPATTERN] = {0, 0, 0, 0, 0, 0, 0, 0}; // get rid of old brush if there was one if (g_hbrBack) DeleteObject(g_hbrBack); g_pActiveDesk->GetPattern(wszBuf, ARRAYSIZE(wszBuf), 0); if (wszBuf[0] != 0L) { LPTSTR pszPatternBuf; #ifndef UNICODE CHAR szTemp[MAX_PATH]; SHUnicodeToAnsi(wszBuf, szTemp, ARRAYSIZE(szTemp)); pszPatternBuf = szTemp; #else pszPatternBuf = wszBuf; #endif PatternToWords(pszPatternBuf, patbits); hbmTemp = CreateBitmap(8, 8, 1, 1, patbits); if (hbmTemp) { g_hbrBack = CreatePatternBrush(hbmTemp); DeleteObject(hbmTemp); } } else { g_hbrBack = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND)); } if (!g_hbrBack) { g_hbrBack = (HBRUSH)GetStockObject(BLACK_BRUSH); } clrOldText = SetTextColor(g_hdcMemory, GetSysColor(COLOR_BACKGROUND)); clrOldBk = SetBkColor(g_hdcMemory, GetSysColor(COLOR_WINDOWTEXT)); hbr = (HBRUSH)SelectObject(g_hdcMemory, g_hbrBack); PatBlt(g_hdcMemory, MON_X, MON_Y, MON_DX, MON_DY, PATCOPY); SelectObject(g_hdcMemory, hbr); SetTextColor(g_hdcMemory, clrOldText); SetBkColor(g_hdcMemory, clrOldBk); } void _InitWall(void) { if (g_hbmWall) { SelectObject(g_hdcWall, g_hbmDefault); DeleteObject(g_hbmWall); g_hbmWall = NULL; if (g_hpalWall) { DeleteObject(g_hpalWall); g_hpalWall = NULL; } } } void _GetWallpaperAsync(HWND hwnd, WPARAM flags) { WCHAR wszWallpaper[INTERNET_MAX_URL_LENGTH]; LPTSTR pszWallpaper; g_pActiveDesk->GetWallpaper(wszWallpaper, ARRAYSIZE(wszWallpaper), 0); #ifndef UNICODE CHAR szWallpaper[ARRAYSIZE(wszWallpaper)]; SHUnicodeToAnsi(wszWallpaper, szWallpaper, ARRAYSIZE(szWallpaper)); pszWallpaper = szWallpaper; #else pszWallpaper = wszWallpaper; #endif g_dwWallpaperID++; if (!*pszWallpaper || !lstrcmpi(pszWallpaper, g_szNone)) return; { if (IsNormalWallpaper(pszWallpaper)) { LoadWallpaperAsync(pszWallpaper, hwnd, g_dwWallpaperID, flags, FALSE); } else { if(IsWallpaperPicture(pszWallpaper)) { // This is a picture (GIF, JPG etc.,) // We need to generate a small HTML file that has this picture // as the background image. // // Compute the filename for the Temporary HTML file. // GetTempPath(ARRAYSIZE(wszWallpaper), pszWallpaper); lstrcat(pszWallpaper, PREVIEW_PICTURE_FILENAME); #ifndef UNICODE SHAnsiToUnicode(szWallpaper, wszWallpaper, ARRAYSIZE(wszWallpaper)); #endif // // Generate the preview picture html file. // g_pActiveDesk->GenerateDesktopItemHtml(wszWallpaper, NULL, 0); } // // Will cause a WM_HTML_BITMAP to get sent to us. // LoadWallpaperAsync(pszWallpaper, hwnd, g_dwWallpaperID, flags, TRUE); } } } void _DrawWall(HBITMAP hbm, WPARAM flags) { int dxWall; // size of wallpaper int dyWall; BITMAP bm; // init the global g_hbmWall = hbm; SelectObject(g_hdcWall, g_hbmWall); // bitmap stays in this DC GetObject(g_hbmWall, sizeof(bm), &bm); TraceMsg(TF_ALWAYS, "for bitmap %08X we have bpp=%d and planes=%d", g_hbmWall, bm.bmBitsPixel, bm.bmPlanes); if (GetDeviceCaps(g_hdcMemory, RASTERCAPS) & RC_PALETTE) { if (bm.bmBitsPixel * bm.bmPlanes > 8) g_hpalWall = CreateHalftonePalette(g_hdcMemory); else if (bm.bmBitsPixel * bm.bmPlanes == 8) g_hpalWall = PaletteFromDS(g_hdcWall); else g_hpalWall = NULL; //!!! assume 1 or 4bpp images dont have palettes } GetObject(g_hbmWall, sizeof(bm), &bm); if(flags & BP_EXTERNALWALL) { //For external wallpapers, we ask the image extractor to generate // bitmaps the size that we want to show (NOT the screen size). dxWall = MON_DX; dyWall = MON_DY; } else { dxWall = MulDiv(bm.bmWidth, MON_DX, GetDeviceCaps(g_hdcMemory, HORZRES)); dyWall = MulDiv(bm.bmHeight, MON_DY, GetDeviceCaps(g_hdcMemory, VERTRES)); } if (dxWall < 1) dxWall = 1; if (dyWall < 1) dyWall = 1; if (g_hpalWall) { SelectPalette(g_hdcMemory, g_hpalWall, TRUE); RealizePalette(g_hdcMemory); } IntersectClipRect(g_hdcMemory, MON_X, MON_Y, MON_X + MON_DX, MON_Y + MON_DY); SetStretchBltMode(g_hdcMemory, COLORONCOLOR); if (flags & BP_TILE) { int i; StretchBlt(g_hdcMemory, MON_X, MON_Y, dxWall, dyWall, g_hdcWall, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY); for (i = MON_X+dxWall; i < (MON_X + MON_DX); i+= dxWall) BitBlt(g_hdcMemory, i, MON_Y, dxWall, dyWall, g_hdcMemory, MON_X, MON_Y, SRCCOPY); for (i = MON_Y; i < (MON_Y + MON_DY); i += dyWall) BitBlt(g_hdcMemory, MON_X, i, MON_DX, dyWall, g_hdcMemory, MON_X, MON_Y, SRCCOPY); } else { //We want to stretch the Bitmap to the preview monitor size ONLY for new platforms. if (flags & BP_STRETCH) { //Stretch the bitmap to the whole preview monitor. dxWall = MON_DX; dyWall = MON_DY; } //Center the bitmap in the preview monitor StretchBlt(g_hdcMemory, MON_X + (MON_DX - dxWall)/2, MON_Y + (MON_DY - dyWall)/2, dxWall, dyWall, g_hdcWall, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY); } // restore dc SelectPalette(g_hdcMemory, (HPALETTE)GetStockObject(DEFAULT_PALETTE), TRUE); SelectClipRgn(g_hdcMemory, NULL); } /*-------------------------------------------------------------------- ** Build the preview bitmap. ** ** both the pattern and the bitmap are drawn each time, but ** if the flags dictate the need, new pattern and bitmap ** globals are built as needed. **--------------------------------------------------------------------*/ void NEAR PASCAL BuildPreviewBitmap(HWND hwnd, HBITMAP hbmp, WPARAM flags) { _InitPreview(); HBITMAP hbmOld = (HBITMAP)SelectObject(g_hdcMemory, g_hbmPreview); _BuildPattern(); _InitWall(); /* ** now, position the wallpaper appropriately */ if (hbmp) { // use the one that was passed in _DrawWall(hbmp, flags); } else { // this means that we need to set up the stuff // to get the bmp ASYNC _GetWallpaperAsync(hwnd, flags); } SelectObject(g_hdcMemory, hbmOld); } BOOL NEAR PASCAL BP_CreateGlobals(HWND hwnd) { HDC hdc; hdc = GetDC(NULL); g_hdcWall = CreateCompatibleDC(hdc); g_hdcMemory = CreateCompatibleDC(hdc); ReleaseDC(NULL, hdc); g_hbmPreview = LoadMonitorBitmap(); HBITMAP hbm; hbm = CreateBitmap(1, 1, 1, 1, NULL); g_hbmDefault = (HBITMAP)SelectObject(g_hdcMemory, hbm); SelectObject(g_hdcMemory, g_hbmDefault); DeleteObject(hbm); HRESULT hr = E_FAIL; hr = CoCreateInstance(CLSID_Thumbnail, NULL, CLSCTX_INPROC_SERVER, IID_IThumbnail, (void **)&g_pthumb); if(SUCCEEDED(hr)) { g_pthumb->Init(hwnd, WM_HTML_BITMAP); } if (!g_hdcWall || !g_hbmPreview || !SUCCEEDED(hr)) return FALSE; else return TRUE; } void NEAR PASCAL BP_DestroyGlobals(void) { if (g_hbmPreview) { DeleteObject(g_hbmPreview); g_hbmPreview = NULL; } if (g_hbmWall) { SelectObject(g_hdcWall, g_hbmDefault); DeleteObject(g_hbmWall); g_hbmWall = NULL; } if (g_hpalWall) { SelectPalette(g_hdcWall, (HPALETTE)GetStockObject(DEFAULT_PALETTE), TRUE); DeleteObject(g_hpalWall); g_hpalWall = NULL; } if (g_hdcWall) { DeleteDC(g_hdcWall); g_hdcWall = NULL; } if (g_hbrBack) { DeleteObject(g_hbrBack); g_hbrBack = NULL; } if (g_hdcMemory) { DeleteDC(g_hdcMemory); g_hdcMemory = NULL; } if (g_hbmDefault) { DeleteObject(g_hbmDefault); g_hbmDefault = NULL; } if (g_pthumb) { g_pthumb->Release(); g_pthumb = NULL; } } void InvalidateBackPrevContents(HWND hwnd) { BITMAP bm; RECT rc; // // Only invalidate the "screen" part of the monitor bitmap. // GetObject(g_hbmPreview, SIZEOF(bm), &bm); GetClientRect(hwnd, &rc); rc.left = ( rc.right - bm.bmWidth ) / 2 + MON_X; rc.top = ( rc.bottom - bm.bmHeight ) / 2 + MON_Y; rc.right = rc.left + MON_DX; rc.bottom = rc.top + MON_DY; InvalidateRect(hwnd, &rc, FALSE); } LRESULT BackPreviewWndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; BITMAP bm; RECT rc; HBITMAP hbmOld; HPALETTE hpalOld; switch(message) { case WM_CREATE: if (!BP_CreateGlobals(hWnd)) return -1L; break; case WM_DESTROY: MSG msg; BP_DestroyGlobals(); while (PeekMessage(&msg, hWnd, WM_HTML_BITMAP, WM_ASYNC_BITMAP, PM_REMOVE)) { if ( msg.lParam ) { if (msg.message == WM_ASYNC_BITMAP) { // clean up this useless crap DeleteObject(((PASYNCWALLPARAM)(msg.lParam))->hbmp); LocalFree((PASYNCWALLPARAM)(msg.lParam)); } else // WM_HTML_BITMAP DeleteObject((HBITMAP)msg.lParam); } } break; case WM_SETBACKINFO: if (g_hbmPreview) { BuildPreviewBitmap(hWnd, NULL, wParam); g_bInfoSet = TRUE; InvalidateBackPrevContents(hWnd); } break; case WM_ASYNC_BITMAP: if (lParam) { PASYNCWALLPARAM pawp = (PASYNCWALLPARAM) lParam; ASSERT(pawp->hbmp); if (pawp->id == g_dwWallpaperID) { BuildPreviewBitmap(hWnd, pawp->hbmp, pawp->flags); InvalidateBackPrevContents(hWnd); } else { // clean up this useless crap DeleteObject(pawp->hbmp); LocalFree(pawp); } } break; case WM_HTML_BITMAP: { // may come through with NULL if the image extraction failed.... if (wParam == g_dwWallpaperID && lParam) { BuildPreviewBitmap(hWnd, (HBITMAP)lParam, BP_EXTERNALWALL); InvalidateBackPrevContents(hWnd); // Take ownership of bitmap return 1; } // Bitmap for something no longer selected return 0; } case WM_PALETTECHANGED: if ((HWND)wParam == hWnd) break; //fallthru case WM_QUERYNEWPALETTE: if (g_hpalWall) InvalidateRect(hWnd, NULL, FALSE); break; case WM_PAINT: BeginPaint(hWnd,&ps); if (g_hbmPreview && g_bInfoSet) { hbmOld = (HBITMAP)SelectObject(g_hdcMemory, g_hbmPreview); if (g_hpalWall) { hpalOld = SelectPalette(ps.hdc, g_hpalWall, FALSE); RealizePalette(ps.hdc); } GetObject(g_hbmPreview, sizeof(bm), &bm); GetClientRect(hWnd, &rc); rc.left = ( rc.right - bm.bmWidth ) / 2; rc.top = ( rc.bottom - bm.bmHeight ) / 2; BitBlt(ps.hdc, rc.left, rc.top, bm.bmWidth, bm.bmHeight, g_hdcMemory, 0, 0, SRCCOPY); if (g_hpalWall) { SelectPalette(ps.hdc, hpalOld, TRUE); RealizePalette(ps.hdc); } SelectObject(g_hdcMemory, hbmOld); } EndPaint(hWnd,&ps); return 0; } return DefWindowProc(hWnd,message,wParam,lParam); } BOOL RegisterBackPreviewClass() { WNDCLASS wc; if (!GetClassInfo(HINST_THISDLL, c_szBackgroundPreview2, &wc)) { wc.style = 0; wc.lpfnWndProc = BackPreviewWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = HINST_THISDLL; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_3DFACE+1); wc.lpszMenuName = NULL; wc.lpszClassName = c_szBackgroundPreview2; if (!RegisterClass(&wc)) return FALSE; } return TRUE; }