#include "main.h" #include "./ml_imageloader.h" #include "api__gen_ml.h" #include "./ml_ipc_0313.h" #include #include #include #include #include static const GUID pngGUID = { 0x5e04fb28, 0x53f5, 0x4032, { 0xbd, 0x29, 0x3, 0x2b, 0x87, 0xec, 0x37, 0x25 } }; #ifndef LOAD_LIBRARY_AS_IMAGE_RESOURCE #define LOAD_LIBRARY_AS_IMAGE_RESOURCE 0x000000020 #endif //LOAD_LIBRARY_AS_IMAGE_RESOURCE static svc_imageLoader *wasabiPNGLoader = NULL; static api_memmgr *wasabiMemMgr = NULL; static BOOL InitializePNGService(void) { waServiceFactory *sf; if (!wasabiMemMgr) { sf = WASABI_API_SVC->service_getServiceByGuid(memMgrApiServiceGuid); if (sf) wasabiMemMgr = reinterpret_cast(sf->getInterface()); } if (wasabiMemMgr && !wasabiPNGLoader) { sf = WASABI_API_SVC->service_getServiceByGuid(pngGUID); if (sf) wasabiPNGLoader = reinterpret_cast(sf->getInterface()); } return (wasabiMemMgr && wasabiPNGLoader); } static HBITMAP LoadImage_LoadPngData(void *pngData, UINT pngSize, BOOL fPremultiply) { INT cx, cy; HBITMAP bitmap; if (NULL == wasabiPNGLoader) { if (FALSE == InitializePNGService() || NULL == wasabiPNGLoader) { return NULL; } } pngData = (FALSE != fPremultiply) ? wasabiPNGLoader->loadImage(pngData, pngSize, &cx, &cy) : wasabiPNGLoader->loadImageData(pngData, pngSize, &cx, &cy); if (NULL != pngData) { BITMAPINFOHEADER header; void *pixelData; ZeroMemory(&header, sizeof(BITMAPINFOHEADER)); header.biSize = sizeof(BITMAPINFOHEADER); header.biBitCount = 32; header.biPlanes = 1; header.biWidth = cx; header.biHeight = -cy; bitmap = CreateDIBSection(NULL, (LPBITMAPINFO)&header, DIB_RGB_COLORS, &pixelData, NULL, 0); if (NULL != bitmap) CopyMemory(pixelData, pngData, cx * cy * sizeof(DWORD)); wasabiMemMgr->sysFree(pngData); } else bitmap = NULL; return bitmap; } static HBITMAP LoadImage_PngResource(HINSTANCE hInstance, HINSTANCE langModule, LPCWSTR pszName, LPCWSTR pszType, BOOL fPremultiply) { HRSRC res; res = (NULL != langModule) ? FindResourceW(langModule, pszName, pszType) : NULL; if (NULL == res) { res = FindResourceW(hInstance, pszName, pszType); } else { hInstance = langModule; } if (NULL == res) return NULL; HANDLE handle = LoadResource(hInstance, res); if (NULL == handle) return NULL; UINT pngSize = SizeofResource(hInstance, res); if (0 == pngSize) return NULL; void *pngData = LockResource(handle); if (NULL == pngData) return NULL; return LoadImage_LoadPngData(pngData, pngSize, fPremultiply); } static HBITMAP LoadImage_BmpResource(HINSTANCE hInstace, HINSTANCE langModule, LPCWSTR pszName, LPCWSTR pszType, BOOL fPremultiply) { UINT flags = LR_DEFAULTCOLOR | LR_CREATEDIBSECTION; if (NULL != langModule) { HBITMAP bitmap; bitmap = (HBITMAP)LoadImageW(langModule, pszName, IMAGE_BITMAP, 0, 0, flags); if (NULL != bitmap) return bitmap; } return (HBITMAP)LoadImageW(hInstace, pszName, IMAGE_BITMAP, 0, 0, flags); } static BOOL LoadImage_IsValidGuidChar(wchar_t c) { if ((c >= L'0' && c <= L'9') || (c >= L'A' && c <= L'F') || (c >= L'a' && c <= L'f') || (L'-' == c)) { return TRUE; } return FALSE; } static HRESULT LoadImage_CrackResProtocol(LPCWSTR pszAddress, LPCWSTR pszDefaultType, HINSTANCE *module, HINSTANCE *langModule, LPCWSTR *name, wchar_t **type) { if (NULL == module) return E_POINTER; if (NULL == pszAddress || L'\0' == *pszAddress) return E_INVALIDARG; INT cchAddress = lstrlenW(pszAddress); const WCHAR szPrefix[] = L"res://"; INT cchPrefix = ARRAYSIZE(szPrefix) - 1; if (cchAddress <= cchPrefix || CSTR_EQUAL != CompareStringW(CSTR_INVARIANT, NORM_IGNORECASE, pszAddress, cchPrefix, szPrefix, cchPrefix)) { return S_FALSE; } pszAddress += cchPrefix; cchAddress -= cchPrefix; LPCWSTR resType = NULL; LPCWSTR resName = NULL; LPCWSTR p = pszAddress + cchAddress; while (p != pszAddress && L'/' != *p) p--; if (p != pszAddress && p < (pszAddress + cchAddress)) { resName = p + 1; p--; } if (NULL == resName || L'\0' == *resName) return E_FAIL; WCHAR szFile[MAX_PATH + 128] = {0}; if (FAILED(StringCchCopyNW(szFile, ARRAYSIZE(szFile), pszAddress, (resName - pszAddress - 1)))) return E_OUTOFMEMORY; while (p != pszAddress && L'/' != *p) p--; if (p != pszAddress && p < resName) { resType = p + 1; if (L'\0' == *resType) { resType = NULL; } else { size_t pos = (resType - pszAddress); szFile[pos - 1] = L'\0'; resType = &szFile[pos]; } } HINSTANCE hModule = LoadLibraryExW(szFile, NULL, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE); if (NULL == hModule && NULL != resType) { DWORD errorCode = GetLastError(); if (ERROR_FILE_NOT_FOUND == errorCode) { *((LPWSTR)(resType - 1)) = L'/'; resType = NULL; hModule = LoadLibraryExW(szFile, NULL, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE); } } if (NULL == hModule) return E_FAIL; if (NULL != type) { if (NULL == resType) resType = pszDefaultType; if (FALSE == IS_INTRESOURCE(resType)) { if (L'#' == *resType) { INT typeId; if (FALSE != StrToIntExW(resType + 1, STIF_DEFAULT, &typeId)) resType = MAKEINTRESOURCEW(typeId); else resType = NULL; } else { int length = lstrlenW(resType); wchar_t *str = (wchar_t*)malloc((length + 1) * sizeof(wchar_t)); if (NULL != str) CopyMemory(str, resType, sizeof(wchar_t) * (length + 1)); resType = str; } } *type = (wchar_t*)resType; } if (NULL != langModule) { *langModule = NULL; if (NULL != WASABI_API_LNG && FALSE == SENDWAIPC(plugin.hwndParent, IPC_GETLANGUAGEPACKINSTANCE, 1)) { wchar_t buffer[64], *lang_str; GUID lang_id; if (0 != LoadStringW(hModule, LANG_DLL_GUID_STRING_ID, buffer, ARRAYSIZE(buffer))) { lang_str = buffer; while(FALSE == LoadImage_IsValidGuidChar(*lang_str)) { if (L'0' == *lang_str) break; lang_str++; } int len = lstrlenW(lang_str); if (len > 0) { wchar_t *cursor = lang_str + (len - 1); while(FALSE == LoadImage_IsValidGuidChar(*cursor)) { if (lang_str == cursor) break; cursor--; } *(cursor+1) = L'\0'; } if (RPC_S_OK == UuidFromStringW((RPC_WSTR)lang_str, &lang_id)) { *langModule = WASABI_API_LNG->FindDllHandleByGUID(lang_id); if (*langModule == hModule) *langModule = NULL; } } } } *module = hModule; if (NULL != name) *name = resName; return S_OK; } static HBITMAP LoadImage_CrackHBitmapProtocol(const wchar_t *address) { INT addressLen, prefixLen; const WCHAR prefix[] = L"hbitmap://"; LONGLONG value; if (NULL == address || L'\0' == *address) return NULL; addressLen = lstrlenW(address); prefixLen = ARRAYSIZE(prefix) - 1; if (addressLen <= prefixLen || CSTR_EQUAL != CompareStringW(CSTR_INVARIANT, NORM_IGNORECASE, address, prefixLen, prefix, prefixLen)) { return NULL; } address += prefixLen; while(L'\0' != *address && L' ' == *address) address++; if (FALSE == StrToInt64ExW(address, STIF_SUPPORT_HEX, &value)) return NULL; return (HBITMAP)value; } static HBITMAP LoadImage_ResProtocol(LPCWSTR pszAddress, LPCWSTR pszDefaultType, BOOL fPremultiply, BOOL ignoreLocalized) { HRESULT hr; HINSTANCE hModule, langModule; LPCWSTR resName; wchar_t *resType; HBITMAP bitmap; BOOL loaded = FALSE; hr = LoadImage_CrackResProtocol(pszAddress, pszDefaultType, &hModule, (FALSE == ignoreLocalized) ? &langModule : NULL, &resName, &resType); if (FAILED(hr) || S_FALSE == hr) return NULL; if (FALSE != ignoreLocalized) langModule = NULL; if (NULL != resType) { if (IS_INTRESOURCE(resType)) { switch((INT)(INT_PTR)resType) { case (INT)(INT_PTR)RT_BITMAP: bitmap = LoadImage_BmpResource(hModule, langModule, resName, resType, fPremultiply); loaded = TRUE; break; } } } if (FALSE == loaded) { bitmap = LoadImage_PngResource(hModule, langModule, resName, resType, fPremultiply); } if (NULL != langModule) { // do not call FreeLibrary for langModule (it was never loaded) // FreeLibrary(langModule); } FreeLibrary(hModule); if (FALSE == IS_INTRESOURCE(resType)) free(resType); return bitmap; } static HBITMAP LoadImage_PngFile(LPCWSTR pszPath, BOOL fPremultiply, BOOL ignoreLocalized) { HANDLE hFile = CreateFileW(pszPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (INVALID_HANDLE_VALUE == hFile) return NULL; HBITMAP bitmap = NULL; UINT pngSize = GetFileSize(hFile, NULL); if (INVALID_FILE_SIZE != pngSize) { void *pngData = malloc(pngSize); if (NULL != pngData) { DWORD readed = 0; if (0 != ReadFile(hFile, pngData, pngSize, &readed, NULL) || pngSize != readed) { bitmap = LoadImage_LoadPngData(pngData, pngSize, fPremultiply); } free(pngData); } } CloseHandle(hFile); return bitmap; } static HBITMAP LoadImage_Png(const MLIMAGESOURCE_I *pImgSource) { HBITMAP bitmap; const wchar_t *path; BOOL premultiply, ignoreLocalized; path = pImgSource->lpszName; premultiply = (0 != (ISF_PREMULTIPLY_I & pImgSource->flags)); ignoreLocalized = (0 != (ISF_NOLOCALIZED_LOAD_I & pImgSource->flags)); if (FALSE == IS_INTRESOURCE(path)) { bitmap = LoadImage_CrackHBitmapProtocol(path); if (NULL != bitmap) { bitmap = (HBITMAP)CopyImage(bitmap,IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); return bitmap; } bitmap = LoadImage_ResProtocol(path, (LPCWSTR)RT_RCDATA, premultiply, ignoreLocalized); if (NULL != bitmap) return bitmap; if (0 != (ISF_LOADFROMFILE_I & pImgSource->flags)) return LoadImage_PngFile(path, premultiply, ignoreLocalized); } bitmap = LoadImage_PngResource(pImgSource->hInst, NULL, path, (LPCWSTR)RT_RCDATA, premultiply); if (NULL != bitmap) return bitmap; bitmap = LoadImage_PngResource(pImgSource->hInst, NULL, path, (LPCWSTR)L"PNG", premultiply); return bitmap; } static HBITMAP LoadImage_Bmp(const MLIMAGESOURCE_I *pImgSource) { HBITMAP bitmap; const wchar_t *path; BOOL premultiply, ignoreLocalized; path = pImgSource->lpszName; premultiply = (0 != (ISF_PREMULTIPLY_I & pImgSource->flags)); ignoreLocalized = (0 != (ISF_NOLOCALIZED_LOAD_I & pImgSource->flags)); if (FALSE == IS_INTRESOURCE(path)) { bitmap = LoadImage_CrackHBitmapProtocol(path); if (NULL != bitmap) { bitmap = (HBITMAP)CopyImage(bitmap,IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); return bitmap; } bitmap = LoadImage_ResProtocol(path, (LPCWSTR)RT_BITMAP, premultiply, ignoreLocalized); if (NULL != bitmap) return bitmap; } UINT flags = LR_DEFAULTCOLOR | LR_CREATEDIBSECTION; if (0 != (ISF_LOADFROMFILE_I & pImgSource->flags)) flags |= LR_LOADFROMFILE; bitmap = (HBITMAP)LoadImageW(pImgSource->hInst, path, IMAGE_BITMAP, 0, 0, flags); return bitmap; } static HBITMAP LoadImage_HIMAGELIST(const MLIMAGESOURCE_I *pImgSource) { // IMAGEINFO ii; // if (!pImgSource) return NULL; // return (ImageList_GetImageInfo((HIMAGELIST)pImgSource->hInst, (INT)(INT_PTR)pImgSource->lpszName, &ii)) ? ii.hbmImage : NULL; return NULL; // not supported; } static HBITMAP DuplicateStretchedDib(HBITMAP hbmpSrc, INT xSrc, INT ySrc, INT cxSrc, INT cySrc, INT cxDst, INT cyDst, INT bppDst, INT bppSrc, BOOL fStretch) { HDC hdcSrc, hdcDst; HBITMAP hbmpDst; LPVOID dib; BITMAPINFOHEADER bi; hdcSrc = CreateCompatibleDC(0); if (!hdcSrc) return NULL; hdcDst = CreateCompatibleDC(0); if (!hdcDst) { DeleteDC(hdcSrc); return NULL; } ZeroMemory(&bi, sizeof(BITMAPINFOHEADER)); bi.biSize = sizeof (BITMAPINFOHEADER); bi.biWidth = cxDst; bi.biHeight = -ABS(cyDst); bi.biPlanes = 1; bi.biBitCount = bppDst; hbmpDst = CreateDIBSection(hdcDst, (BITMAPINFO *)&bi, DIB_RGB_COLORS, &dib, NULL, NULL); if (hbmpDst) { HGDIOBJ hgdiDst = SelectObject(hdcDst, hbmpDst); HGDIOBJ hgdiSrc = SelectObject(hdcSrc, hbmpSrc); if (fStretch && (cxDst != cxSrc || cyDst != cySrc)) { if (32 == bppDst || 32 == bppSrc) { BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; GdiAlphaBlend(hdcDst, 0, 0, cxDst, cyDst, hdcSrc, xSrc, ySrc, cxSrc, cySrc, bf); } else { INT stretchModeOld = SetStretchBltMode(hdcDst, HALFTONE); StretchBlt(hdcDst, 0, 0, cxDst, ABS(cyDst), hdcSrc, xSrc, ySrc, cxSrc, cySrc, SRCCOPY); SetStretchBltMode(hdcDst, stretchModeOld); } } else BitBlt(hdcDst, 0, 0, cxDst, ABS(cyDst), hdcSrc, xSrc, ySrc, SRCCOPY); SelectObject(hdcSrc, hgdiSrc); SelectObject(hdcDst, hgdiDst); } DeleteDC(hdcSrc); DeleteDC(hdcDst); return hbmpDst; } HBITMAP MLImageLoaderI_LoadDib(const MLIMAGESOURCE_I *pImgSource) { HBITMAP hbmp; if (NULL == pImgSource) return NULL; switch(pImgSource->type) { case SRC_TYPE_BMP_I: hbmp = LoadImage_Bmp(pImgSource); break; case SRC_TYPE_PNG_I: hbmp = LoadImage_Png(pImgSource); break; case SRC_TYPE_HBITMAP_I: hbmp = (HBITMAP)CopyImage((HANDLE)pImgSource->lpszName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); break; case SRC_TYPE_HIMAGELIST_I: hbmp = LoadImage_HIMAGELIST(pImgSource); break; default: hbmp = NULL; break; } if (NULL != hbmp) // { // get bitmap info BITMAP bm; if (sizeof(bm) == GetObjectW(hbmp, sizeof(bm), &bm)) { if (((ISF_USE_OFFSET_I & pImgSource->flags) && (pImgSource->xSrc || pImgSource->ySrc)) || ((ISF_USE_SIZE_I & pImgSource->flags) && (pImgSource->cxSrc != bm.bmWidth || pImgSource->cySrc != bm.bmHeight)) || ((ISF_FORCE_SIZE_I & pImgSource->flags) && (pImgSource->cxDst != bm.bmWidth || pImgSource->cyDst != bm.bmHeight)) || ((ISF_FORCE_BPP_I & pImgSource->flags) && (pImgSource->bpp != bm.bmBitsPixel))) { HBITMAP hOldBmp; hOldBmp = hbmp; hbmp = DuplicateStretchedDib( hbmp, (ISF_USE_OFFSET_I & pImgSource->flags) ? pImgSource->xSrc : 0, (ISF_USE_OFFSET_I & pImgSource->flags) ? pImgSource->ySrc : 0, (ISF_USE_SIZE_I & pImgSource->flags) ? pImgSource->cxSrc : bm.bmWidth, (ISF_USE_SIZE_I & pImgSource->flags) ? pImgSource->cySrc : bm.bmHeight, (ISF_FORCE_SIZE_I & pImgSource->flags) ? pImgSource->cxDst: bm.bmWidth, (ISF_FORCE_SIZE_I & pImgSource->flags) ? pImgSource->cyDst: bm.bmHeight, (ISF_FORCE_BPP_I & pImgSource->flags) ? pImgSource->bpp : bm.bmBitsPixel, bm.bmBitsPixel, (ISF_SCALE_I & pImgSource->flags)); DeleteObject(hOldBmp); } } else { DeleteObject(hbmp); hbmp = NULL; } } return hbmp; } BOOL MLImageLoaderI_CopyData(MLIMAGESOURCE_I *pisDst, const MLIMAGESOURCE_I *pisSrc) { if (!pisDst || !pisSrc) return FALSE; CopyMemory(pisDst, pisSrc, sizeof(MLIMAGESOURCE_I)); if (SRC_TYPE_HBITMAP_I != pisSrc->type && SRC_TYPE_HIMAGELIST_I != pisSrc->type && pisSrc->lpszName && !IS_INTRESOURCE(pisSrc->lpszName)) pisDst->lpszName = _wcsdup(pisSrc->lpszName); return TRUE; } BOOL MLImageLoaderI_FreeData(MLIMAGESOURCE_I *pis) { if (!pis) return FALSE; if (SRC_TYPE_HBITMAP_I != pis->type && SRC_TYPE_HIMAGELIST_I != pis->type && pis->lpszName && !IS_INTRESOURCE(pis->lpszName)) free((LPWSTR)pis->lpszName); return TRUE; } BOOL MLImageLoaderI_CheckExist(const MLIMAGESOURCE_I *pis) { const wchar_t *resType; if (NULL == pis) return FALSE; switch(pis->type) { case SRC_TYPE_HBITMAP_I: return (NULL != pis->lpszName); case SRC_TYPE_HIMAGELIST_I: return FALSE; case SRC_TYPE_PNG_I: resType = (LPCWSTR)RT_RCDATA; break; case SRC_TYPE_BMP_I: resType = (LPCWSTR)RT_BITMAP; break; default: resType = NULL; break; } if (FALSE == IS_INTRESOURCE(pis->lpszName)) { BOOL result; HINSTANCE module, langModule; LPCWSTR name; wchar_t *type; HRESULT hr; if (NULL != LoadImage_CrackHBitmapProtocol(pis->lpszName)) return TRUE; result = FALSE; langModule = NULL; hr = LoadImage_CrackResProtocol(pis->lpszName, resType, &module, (0 == (ISF_NOLOCALIZED_LOAD_I & pis->flags)) ? &langModule : NULL, &name, &type); if (0 != (ISF_NOLOCALIZED_LOAD_I & pis->flags)) langModule = NULL; if (S_OK == hr) { if (NULL != langModule) { result = (NULL != FindResourceW(langModule, name, type)); // do not call FreeLibrary for langModule (it was never loaded) //FreeLibrary(langModule); } if (FALSE == result) result = (NULL != FindResourceW(module, name, type)); FreeLibrary(module); if (FALSE == IS_INTRESOURCE(type)) free(type); return result; } if (0 != (ISF_LOADFROMFILE_I & pis->flags)) { HANDLE hFile = CreateFileW(pis->lpszName, GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (INVALID_HANDLE_VALUE != hFile) { switch(pis->type) { case SRC_TYPE_PNG_I: if (NULL != wasabiPNGLoader || InitializePNGService()) { BYTE data[8] = {0}; // png signature len DWORD dataRead = 0; if(ReadFile(hFile, data, sizeof(data), &dataRead, NULL) && 0 != dataRead) result = wasabiPNGLoader->testData(data, dataRead); } break; default: result = TRUE; break; } CloseHandle(hFile); } return result; } } return (NULL != resType && NULL != FindResourceW(pis->hInst, pis->lpszName, resType)); }