/* "Spam Filter"-Plugin for Miranda IM Copyright 2003-2006 Heiko Herkenrath This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program ("SpamFilter-License.txt"); if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // -- Includes #include "common.h" // ----------------------------------------- // -- Error Output -- static void ThreadMessageBox(void* arg) { MSGBOXPARAMS* pmbp = (MSGBOXPARAMS*)arg; MessageBoxIndirect(pmbp); mir_free((WCHAR*)pmbp->lpszCaption); mir_free((WCHAR*)pmbp->lpszText); mir_free(pmbp); } void ShowInfoMessage(UINT uIconID, const WCHAR* pszCaption, const WCHAR* pszTextFmt, size_t cchExtraSize, ...) { // Params: // uIconID - NIIF_INFO, NIIF_WARNING or NIIF_ERROR // pszCaption - Only 64chars of it will be used. // pszTextFmt - Only 256chars of it will be used. va_list va; WCHAR* pszText; BOOL bErrorShown = FALSE; if (!pszCaption || !pszTextFmt || Miranda_Terminated()) return; pszText = mir_alloc((lstrlen(pszTextFmt)+((cchExtraSize>0)?cchExtraSize:0)+1)*sizeof(WCHAR)); if (!pszText) return; if (cchExtraSize <= 0) { mir_sntprintf(pszText, lstrlen(pszTextFmt)+1, _T("%s"), pszTextFmt); } else { va_start(va, cchExtraSize); mir_vsntprintf(pszText, lstrlen(pszTextFmt)+((cchExtraSize>0)?cchExtraSize:0)+1, pszTextFmt, va); va_end(va); } if (ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) { // Output balloon tip if supported MIRANDASYSTRAYNOTIFY msn; ZeroMemory(&msn, sizeof(msn)); // forward compatibility msn.cbSize = sizeof(msn); #if defined(UNICODE) // SystrayNotify does not support Unicode // We need to convert Unicode->Ansi mir_utf8decode(msn.szInfoTitle,&pszCaption); mir_utf8decode(msn.szInfo,&pszText); #else msn.szInfoTitle = (char*)pszCaption; msn.szInfo = (char*)pszText; #endif //msn.szProto = NULL; msn.uTimeout = 20000; // 30 sec is current max timeout that is possible if (uIconID == NIIF_ERROR) msn.dwInfoFlags = NIIF_ERROR; else if (uIconID == NIIF_WARNING) msn.dwInfoFlags = NIIF_WARNING; else msn.dwInfoFlags = NIIF_INFO; // I don't know if service is thread safe therefor using sync bErrorShown = (CallServiceSync(MS_CLIST_SYSTRAY_NOTIFY, 0, (LPARAM)&msn) == 0); #if defined(UNICODE) if (msn.szInfoTitle) mir_free(msn.szInfoTitle); if (msn.szInfo) mir_free(msn.szInfo); #endif #if defined(UNICODE) } else if (ServiceExists(MS_POPUP_ADDPOPUPW)) { // Output a popup message as alternative POPUPDATAW ppd; ZeroMemory(&ppd, sizeof(ppd)); mir_sntprintf(ppd.lpwzContactName, ARRAYSIZE(ppd.lpwzContactName), _T("%s"), pszCaption); mir_sntprintf(ppd.lpwzText, ARRAYSIZE(ppd.lpwzText), _T("%s"), pszText); //ppd.iSeconds = 0; //ppd.lchContact = NULL; //ppd.colorText = GetSysColor(COLOR_INFOTEXT); // or GetSysColor(COLOR_WINDOWTEXT) //ppd.colorBack = GetSysColor(COLOR_INFOBK); // or GetSysColor(COLOR_3DFACE) if (uIconID == NIIF_WARNING) ppd.lchIcon = (HICON)LoadImage(NULL, MAKEINTRESOURCE(IDI_WARNING), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED); else if (uIconID == NIIF_ERROR) ppd.lchIcon = (HICON)LoadImage(NULL, MAKEINTRESOURCE(IDI_ERROR), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED); else ppd.lchIcon = (HICON)LoadImage(NULL, MAKEINTRESOURCE(IDI_INFORMATION), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED); // I don't know if popup module author made it thread safe... bErrorShown = (CallServiceSync(MS_POPUP_ADDPOPUPW, (WPARAM)&ppd, 0) >= 0); } #else } else if (ServiceExists(MS_POPUP_ADDPOPUPEX)) { // Output a popup message as alternative POPUPDATAEX ppd; ZeroMemory(&ppd, sizeof(ppd)); mir_snprintf(ppd.lpzContactName, ARRAYSIZE(ppd.lpzContactName), "%s", pszCaption); mir_snprintf(ppd.lpzText, ARRAYSIZE(ppd.lpzText), "%s", pszText); //ppd.iSeconds = 0; //ppd.lchContact = NULL; //ppd.colorText = GetSysColor(COLOR_INFOTEXT); // or GetSysColor(COLOR_WINDOWTEXT) //ppd.colorBack = GetSysColor(COLOR_INFOBK); // or GetSysColor(COLOR_3DFACE) if (ServiceExists(MS_POPUP_ADDCLASS)) { //ppd.skinBack = ppd.colorBack; ppd.colorBack = POPUP_USE_SKINNED_BG; } if (uIconID == NIIF_WARNING) { ppd.lchIcon = (HICON)LoadImage(NULL, MAKEINTRESOURCE(IDI_WARNING), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED); if (ppd.colorBack == POPUP_USE_SKINNED_BG) ppd.lpzClass = (LPCTSTR)POPUP_CLASS_NOTIFY; // type "LPCTSTR" of lpzClass is wrong! } else if (uIconID == NIIF_ERROR) { ppd.lchIcon = (HICON)LoadImage(NULL, MAKEINTRESOURCE(IDI_ERROR), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED); if (ppd.colorBack == POPUP_USE_SKINNED_BG) ppd.lpzClass = (LPCTSTR)POPUP_CLASS_WARNING; // type "LPCTSTR" of lpzClass is wrong! } else { ppd.lchIcon = (HICON)LoadImage(NULL, MAKEINTRESOURCE(IDI_INFORMATION), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED); if (ppd.colorBack == POPUP_USE_SKINNED_BG) ppd.lpzClass = (LPCTSTR)POPUP_CLASS_DEFAULT; // type "LPCTSTR" of lpzClass is wrong! } bErrorShown = (CallServiceSync(MS_POPUP_ADDPOPUPEX, (WPARAM)&ppd, 0) >= 0); // I don't know if popup module author made it thread safe... } #endif if (!bErrorShown) { // Output normal message dialog when popup plugin is not installed // or when Windows doesn't support balloon tips // or if an popup error occured MSGBOXPARAMS* pmbp = (MSGBOXPARAMS*)mir_alloc(sizeof(MSGBOXPARAMS)); if (pmbp) { ZeroMemory(pmbp, sizeof(MSGBOXPARAMS)); pmbp->cbSize = sizeof(MSGBOXPARAMS); pmbp->lpszCaption = mir_wstrdup(pszCaption); // will be freed by thread pmbp->lpszText = pszText; // will be freed by thread pszText = NULL; pmbp->hwndOwner = NULL; pmbp->dwStyle = MB_OK|MB_SETFOREGROUND|MB_TASKMODAL; pmbp->dwLanguageId = LANGIDFROMLCID(GetThreadLocale()); if (uIconID == NIIF_WARNING) pmbp->dwStyle |= MB_ICONWARNING; else if (uIconID == NIIF_ERROR) pmbp->dwStyle |= MB_ICONERROR; else pmbp->dwStyle |= MB_ICONINFORMATION; forkthread(ThreadMessageBox, 0, pmbp); } } if (pszText) mir_free(pszText); } WCHAR* GetLastErrorDescription(DWORD dwLastError) { WCHAR* pszReturn; #if defined(UNICODE) #if defined(MICROSOFT_LAYER_FOR_UNICODE) char* pszLastError = NULL; // FormatMessageW does not work with UnicoWS layer on Win9x/ME if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwLastError, 0, (LPSTR)&pszLastError, 0, NULL) != 0) { pszReturn = mir_utf8encodeW(pszLastError); LocalFree(pszLastError); } else { pszReturn = NULL; } #else WCHAR* pwszLastError; if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwLastError, 0, (LPWSTR)&pwszLastError, 0, NULL) != 0) { pszReturn = mir_wstrdup(pwszLastError); LocalFree(pwszLastError); } else { pszReturn = NULL; } #endif #else WCHAR* pszLastError; if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwLastError, 0, (LPTSTR)&pszLastError, 0, NULL) != 0) { pszReturn = mir_strdup(pszLastError); LocalFree(pszLastError); } else { pszReturn = NULL; } #endif return pszReturn; } // -- Sounds -- void SkinAddNewSoundBundled(const char* pszName, const char* pszSection, const char* pszDescription, const WCHAR* pszDefaultFile) { SKINSOUNDDESCEX ssd; WCHAR szFileName[MAX_PATH]; char szFileNameFin[MAX_PATH]; ZeroMemory(&ssd, sizeof(ssd)); ssd.cbSize = sizeof(ssd); ssd.pszSection = (char*)pszSection; ssd.pszName = (char*)pszName; ssd.pszDescription = (char*)pszDescription; PConstructLocalPath(szFileName, CSIDL_EXT_EXECUTABLE, SOUNDS_SUBDIRECTORY, (WCHAR*)pszDefaultFile, NULL); if (PathFileExists(szFileName)) { #if defined(UNICODE) WCHAR* pszBuf; mir_utf8decode((char*)szFileName,&pszBuf); if (pszBuf) { if (CallService(MS_UTILS_PATHTORELATIVE, (WPARAM)pszBuf, (LPARAM)szFileNameFin) <= 0) mir_snprintf(szFileNameFin, ARRAYSIZE(szFileNameFin), "%s", pszBuf); ssd.pszDefaultFile = szFileNameFin; mir_free(pszBuf); } #else if (CallService(MS_UTILS_PATHTORELATIVE, (WPARAM)szFileName, (LPARAM)szFileNameFin) <= 0) ssd.pszDefaultFile = szFileName; else ssd.pszDefaultFile = szFileNameFin; #endif } CallService(MS_SKIN_ADDNEWSOUND, 0, (LPARAM)&ssd); } // -- Icons -- void SkinAddNewIcon(const char* pszName, const WCHAR* pszSection, const WCHAR* pszDescription, int iDefResID, BOOL bLarge) { // Support for IcoLib if (ServiceExists(MS_SKIN2_ADDICON) && ServiceExists(MS_SKIN2_GETICON)) { SKINICONDESC sid; ZeroMemory(&sid, sizeof(sid)); sid.cbSize = sizeof(sid); sid.ptszSection = (WCHAR*)pszSection; sid.ptszDescription = (WCHAR*)pszDescription; sid.pszName = (char*)pszName; sid.hDefaultIcon = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(iDefResID), IMAGE_ICON, bLarge?0:GetSystemMetrics(SM_CXSMICON), bLarge?0:GetSystemMetrics(SM_CYSMICON), (bLarge?LR_DEFAULTSIZE:0)|LR_SHARED); sid.cx = GetSystemMetrics(bLarge?SM_CXICON:SM_CXSMICON); sid.cy = GetSystemMetrics(bLarge?SM_CYICON:SM_CYSMICON); sid.flags = SIDF_UNICODE; CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid); } } HICON SkinGetIcon(const char* pszName, int iDefResID, BOOL bLarge) { // Support for IcoLib if (ServiceExists(MS_SKIN2_GETICON) && ServiceExists(MS_SKIN2_ADDICON)) { HICON hIcon = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)pszName); if (hIcon) return hIcon; } if (iDefResID <= 0) return NULL; return (HICON)LoadImage(hInstance, MAKEINTRESOURCE(iDefResID), IMAGE_ICON, bLarge?0:GetSystemMetrics(SM_CXSMICON), bLarge?0:GetSystemMetrics(SM_CYSMICON), (bLarge?LR_DEFAULTSIZE:0)|LR_SHARED); } // -- Hotkeys -- /* void SkinAddNewHotkey(const char* pszName, const char* pszSection, const char* pszDescription, const int iDefHotkey, const char* pszServiceName) { // Support for CList_MW if (ServiceExists(MS_SKIN_ADDHOTKEY)) { SKINHOTKEYDESCEX shd; ZeroMemory(&shd, sizeof(shd)); shd.cbSize = sizeof(shd); shd.pszName = (char*)pszName; shd.pszDescription = (char*)pszDescription; shd.pszSection = (char*)pszSection; shd.pszService = (char*)pszServiceName; shd.DefHotKey = iDefHotkey; CallService(MS_SKIN_ADDHOTKEY, 0, (LPARAM)&shd); } } */ // -- Fonts -- /* void SkinAddNewFont(const char* pszName, const char* pszSection, const char* pszDescription, COLORREF clrColor, const char* pszFace, int iSize, DWORD dwStyleFlags) { if (pszName && ServiceExists(MS_FONT_REGISTER)) { FontID fid; ZeroMemory(&fid, sizeof(fid)); fid.cbSize = sizeof(fid); mir_snprintf(fid.name, ARRAYSIZE(fid.name), "%s", pszName); mir_snprintf(fid.group, ARRAYSIZE(fid.group), "%s", pszSection ? pszSection : Translate("Other")); mir_snprintf(fid.dbSettingsGroup, ARRAYSIZE(fid.dbSettingsGroup), "%s", DB_MODULE_NAME); mir_snprintf(fid.prefix, ARRAYSIZE(fid.prefix), "%s", "Font_"); //fid.order = 0; fid.flags = FIDF_DEFAULTVALID|FIDF_ALLOWEFFECTS; fid.deffontsettings.charset = DEFAULT_CHARSET; fid.deffontsettings.colour = clrColor; fid.deffontsettings.size = (iSize > 0)?iSize:12; fid.deffontsettings.style = dwStyleFlags; mir_snprintf(fid.deffontsettings.szFace, ARRAYSIZE(fid.deffontsettings.szFace), "%s", pszFace ? pszFace : "MS Sans Serif"); CallService(MS_FONT_REGISTER, (WPARAM)&fid, 0); } } BOOL SkinAddNewFontSameAs(const char* pszDescription, const char* pszSection, const char* pszSameAsDescription) { if (ServiceExists(MS_FONT_REGISTER)) { FontID fid; LOGFONT lf; ZeroMemory(&fid, sizeof(fid)); fid.cbSize = sizeof(fid); mir_snprintf(fid.name, ARRAYSIZE(fid.name), "%s", pszDescription); mir_snprintf(fid.group, ARRAYSIZE(fid.group), "%s", pszSection ? pszSection : Translate("Other")); mir_snprintf(fid.dbSettingsGroup, ARRAYSIZE(fid.dbSettingsGroup), "%s", DB_MODULE_NAME); mir_snprintf(fid.prefix, ARRAYSIZE(fid.name), "%s", "Font_"); //fid.order = 0; fid.flags = FIDF_ALLOWEFFECTS; if (pszSameAsDescription) { ZeroMemory(&lf, sizeof(lf)); // not good; SkinGetFont has no error indicating value (workaround) fid.deffontsettings.colour = SkinGetFont(pszSameAsDescription, &lf); fid.deffontsettings.charset = lf.lfCharSet; fid.deffontsettings.size = (char)lf.lfHeight; fid.deffontsettings.style = 0; mir_snprintf(fid.deffontsettings.szFace, ARRAYSIZE(fid.deffontsettings.szFace), "%s", lf.lfFaceName); if (lf.lfItalic) fid.deffontsettings.style = DBFONTF_ITALIC; if (lf.lfWeight) fid.deffontsettings.style = DBFONTF_BOLD; if (lf.lfUnderline) fid.deffontsettings.style = DBFONTF_UNDERLINE; if (lf.lfStrikeOut) fid.deffontsettings.style = DBFONTF_STRIKEOUT; fid.flags |= FIDF_DEFAULTVALID; CallService(MS_FONT_REGISTER, (WPARAM)&fid, 0); return TRUE; } else { CallService(MS_FONT_REGISTER, (WPARAM)&fid, 0); return FALSE; } } } BOOL SkinGetFont(const char* pszDescription, const char* pszSection, COLORREF* pclrColor, LOGFONT* plfFont) { if (pszName && pclrColor && plfFont && ServiceExists(MS_FONT_GET)) { FontID fid; mir_snprintf(fid.name, 64, "%s", pszDescription); mir_snprintf(fid.group, 64, "%s", pszSection ? pszSection : Translate("Other")); *pclrColor = (COLORREF)CallService(MS_FONT_GET, (WPARAM)&fid, (LPARAM)plfFont); return TRUE; } else { return FALSE; } } */ // -- Colors -- void SkinAddNewColor(const char* pszDbName, const char* pszSection, const char* pszDescription, COLORREF clrDefColor, BOOL bFontRelated) { if (!pszSection || (pszDbName && !pszDescription)) return; // Support for FontService if (bFontRelated && ServiceExists(MS_COLOUR_REGISTER) && ServiceExists(MS_COLOUR_GET)) { ColourID cid; ZeroMemory(&cid, sizeof(cid)); cid.cbSize = sizeof(cid); cid.defcolour = clrDefColor; mir_snprintf(cid.dbSettingsGroup, ARRAYSIZE(cid.dbSettingsGroup), "%s", DB_MODULE_NAME); mir_snprintf(cid.group, ARRAYSIZE(cid.group), "%s", pszSection); mir_snprintf(cid.setting, ARRAYSIZE(cid.setting), "%s", pszDbName?pszDbName:"BkgColour"); mir_snprintf(cid.name, ARRAYSIZE(cid.name), "%s", pszDbName?pszDescription:Translate("Background")); CallService(MS_COLOUR_REGISTER, (WPARAM)&cid, 0); return; } } COLORREF SkinGetColor(const char* pszDbName, const char* pszDescription, const char* pszSection, COLORREF clrDefColor, BOOL bFontRelated) { if (!pszSection || (pszDbName && !pszDescription)) return clrDefColor; // Support for FontService if (bFontRelated && ServiceExists(MS_COLOUR_REGISTER) && ServiceExists(MS_COLOUR_GET)) { ColourID cid; ZeroMemory(&cid, sizeof(cid)); cid.cbSize = sizeof(cid); mir_snprintf(cid.setting, ARRAYSIZE(cid.setting), "%s", pszDbName?pszDbName:"BkgColour"); mir_snprintf(cid.group, ARRAYSIZE(cid.group), "%s", pszSection); mir_snprintf(cid.name, ARRAYSIZE(cid.name), "%s", pszDescription?(char*)pszDescription:Translate("Background")); return (COLORREF)CallService(MS_COLOUR_GET, (WPARAM)&cid, 0); } return clrDefColor; } // -- System Icons -- HIMAGELIST LoadSystemCheckboxImageList(void) { HWND hwndTreeView; HIMAGELIST hImageList, hImgLstBuf; INITCOMMONCONTROLSEX icc; ZeroMemory(&icc, sizeof(icc)); icc.dwSize = sizeof(icc); icc.dwICC = ICC_TREEVIEW_CLASSES; InitCommonControlsEx(&icc); // Create hidden treeview hwndTreeView = CreateWindowEx(0, WC_TREEVIEW, NULL, 0, 0, 0, 0, 0, NULL, 0, hInstance, NULL); if (!hwndTreeView) return NULL; SetWindowLongPtr(hwndTreeView, GWL_STYLE, (LONG_PTR)TVS_CHECKBOXES); // Style needs to be set after creating // Get imagelist hImgLstBuf = TreeView_GetImageList(hwndTreeView, TVSIL_STATE); hImageList = ImageList_Duplicate(hImgLstBuf); // Destroy treeview TreeView_SetImageList(hwndTreeView, NULL, TVSIL_STATE); // Avoiding Access Violation in CommonControls DLL ImageList_Destroy(hImgLstBuf); DestroyWindow(hwndTreeView); return hImageList; } HICON LoadSystemIcon(int iListID, int iIconIndex) // Returned icon needs to be destroyed using DestroyIcon() { /* Index values for IDB_HIST_LARGE_COLOR and IDB_HIST_SMALL_COLOR: (Microsoft Windows Explorer bitmaps) HIST_ADDTOFAVORITES Add to favorites. HIST_BACK Move back. HIST_FAVORITES Open favorites folder. HIST_FORWARD Move forward. HIST_VIEWTREE View tree. Index values for IDB_STD_LARGE_COLOR and IDB_STD_SMALL_COLOR: (Standard bitmaps) STD_COPY Copy operation. STD_CUT Cut operation. STD_DELETE Delete operation. STD_FILENEW New file operation. STD_FILEOPEN Open file operation. STD_FILESAVE Save file operation. STD_FIND Find operation. STD_HELP Help operation. STD_PASTE Paste operation. STD_PRINT Print operation. STD_PRINTPRE Print preview operation. STD_PROPERTIES Properties operation. STD_REDOW Redo operation. STD_REPLACE Replace operation. STD_UNDO Undo operation. Index values for IDB_VIEW_LARGE_COLOR and IDB_VIEW_SMALL_COLOR: (View bitmaps) VIEW_DETAILS Details view. VIEW_LARGEICONS Large icons view. VIEW_LIST List view. VIEW_NETCONNECT Connect to network drive. VIEW_NETDISCONNECT Disconnect from network drive. VIEW_NEWFOLDER New folder. VIEW_PARENTFOLDER Go to parent folder. VIEW_SMALLICONS Small icon view. VIEW_SORTDATE Sort by date. VIEW_SORTNAME Sort by name. VIEW_SORTSIZE Sort by size. VIEW_SORTTYPE Sort by type. */ HWND hwndToolbar; HICON hIcon; INITCOMMONCONTROLSEX icc; ZeroMemory(&icc, sizeof(icc)); icc.dwSize = sizeof(icc); icc.dwICC = ICC_BAR_CLASSES; InitCommonControlsEx(&icc); // Create hidden toolbar hwndToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, _T(""), 0, 0, 0, 0, 0, NULL, 0, hInstance, NULL); if (!hwndToolbar) return NULL; SendMessage(hwndToolbar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0); // Get icon SendMessage(hwndToolbar, TB_LOADIMAGES, (WPARAM)iListID, (LPARAM)HINST_COMMCTRL); hIcon = ImageList_GetIcon((HIMAGELIST)SendMessage(hwndToolbar, TB_GETIMAGELIST, 0, 0), iIconIndex, ILD_TRANSPARENT); // Destroy toolbar DestroyWindow(hwndToolbar); return hIcon; } // -- Icon Overlay -- HICON OverlayIcon(HICON hMainIcon, HICON hOverlayIcon, int cxWidth, int cyHeight) { HICON hIconReturn; HIMAGELIST himlIconList, himlIconListBuf; // New image lists int iMainIcon, iOverlayIcon; if ((cxWidth < 0) || (cyHeight < 0) || !hMainIcon || !hOverlayIcon) return NULL; himlIconList = ImageList_Create((cxWidth==0)?GetSystemMetrics(SM_CXICON):cxWidth, (cyHeight==0)?GetSystemMetrics(SM_CYICON):cyHeight, (IsWinVerXPPlus()?ILC_COLOR32:ILC_COLOR16)|ILC_MASK,2, 0); iMainIcon = ImageList_AddIcon(himlIconList, hMainIcon); iOverlayIcon = ImageList_AddIcon(himlIconList, hOverlayIcon); himlIconListBuf = ImageList_Merge(himlIconList, iMainIcon, himlIconList, iOverlayIcon, 0, 0); ImageList_Destroy(himlIconList); hIconReturn = ImageList_GetIcon(himlIconListBuf, iMainIcon, ILD_TRANSPARENT); ImageList_Destroy(himlIconListBuf); return hIconReturn; // returned HICON needs to be destroyed (DestroyIcon()) }