/* Fingerprint Mod+ (client version) icons module for Miranda IM Copyright © 2006-2007 Artem Shpynov aka FYR, Bio, Faith Healer. 2009-2010 HierOS 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; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ //Start of header #include "global.h" #include "fingerprints.h" //Including of fingerprint masks #define LIB_REG 2 #define LIB_USE 3 //#define USE_MY_SERVER #define REGISTER_BETA //#define REGISTER_AUTO //#define mir_strncpy(a, b, c) { strncpy(a, b, c)[c - 1] = 0; } //#define mir_tcsncpy_s(a, b, c, d) { _tcsncpy_s(a, b, c, d); c[d - 1] = 0; } //#define _qtoupper(_c) (((_c) >= 'a' && (_c) <= 'z') ? ((_c) - 'a' + 'A') : (_c)) //#define _qtoupper(_c) (((_c) >= 'a' && (_c) <= 'z') ? ((_c) & 0x5F) : (_c)) void InitFingerEvents(); void UninitFingerEvents(); void FASTCALL ClearFI(); int OnIconsChanged(WPARAM wParam, LPARAM lParam); int OnExtraIconClick(WPARAM wParam, LPARAM lParam); int OnExtraIconListRebuild(WPARAM wParam, LPARAM lParam); int OnExtraImageApply(WPARAM wParam, LPARAM lParam); int OnContactSettingChanged(WPARAM wParam, LPARAM lParam); int OnOptInitialise(WPARAM wParam, LPARAM lParam); int OnModulesLoaded(WPARAM wParam, LPARAM lParam); int OnPreShutdown(WPARAM wParam, LPARAM lParam); INT_PTR ServiceSameClientsA(WPARAM wParam, LPARAM lParam); INT_PTR ServiceGetClientIconA(WPARAM wParam, LPARAM lParam); INT_PTR ServiceSameClientsW(WPARAM wParam, LPARAM lParam); INT_PTR ServiceGetClientIconW(WPARAM wParam, LPARAM lParam); HICON FASTCALL CreateJoinedIcon(HICON hBottom, HICON hTop); HBITMAP __inline CreateBitmap32(int cx, int cy); HBITMAP FASTCALL CreateBitmap32Point(int cx, int cy, LPVOID* bits); HANDLE FASTCALL GetIconIndexFromFI(LPTSTR szMirVer); HICON FASTCALL LoadIconFromExternalFile(LPTSTR filename, int nLibrary, LPSTR IconName, int flag, LPTSTR Description, int internalidx, LPBOOL NeedFree); BOOL FASTCALL WildCompareA(LPSTR name, LPSTR mask); BOOL FASTCALL WildCompareW(LPWSTR name, LPWSTR mask); BOOL __inline WildCompareProcA(LPSTR name, LPSTR mask); BOOL __inline WildCompareProcW(LPWSTR name, LPWSTR mask); #define WildCompare WildCompareW #define GetIconsIndexes GetIconsIndexesW HINSTANCE g_hInst; PLUGINLINK* pluginLink; MM_INTERFACE mmi; // miranda memory interface int hLangpack; BOOL g_bExtraIcon_Register_ServiceExist = FALSE; BOOL g_bCList_Extra_Set_Icon_ServiceExist = FALSE; HANDLE hHeap = NULL; HANDLE hExtraImageListRebuild = NULL; // hook event handle for ME_CLIST_EXTRA_LIST_REBUILD HANDLE hExtraImageApply = NULL; // hook event handle for ME_CLIST_EXTRA_IMAGE_APPLY HANDLE hContactSettingChanged = NULL; // hook event handle for ME_DB_CONTACT_SETTINGCHANGED HANDLE hOptInitialise = NULL; // hook event handle for ME_OPT_INITIALISE HANDLE hIconsChanged = NULL; // hook event handle for ME_SKIN2_ICONSCHANGED HANDLE hPreShutdown = NULL; // hook event handle for ME_SYSTEM_PRESHUTDOWN HANDLE hExtraIconClick = NULL; // hook event handle for ME_CLIST_EXTRA_CLICK HANDLE compClientServA = NULL; HANDLE getClientIconA = NULL; HANDLE compClientServW = NULL; HANDLE getClientIconW = NULL; LPSTR g_szClientDescription = NULL; HANDLE hStaticHooks[1] = { NULL }; HANDLE hExtraIcon = NULL; HANDLE hFolderChanged = NULL, hIconFolder = NULL; TCHAR g_szSkinLib[MAX_PATH]; BYTE bColumn = EXTRA_ICON_CLIENT; FOUNDINFO* fiList = NULL; int nFICount = 0; BYTE gbUnicodeAPI; UINT g_LPCodePage; //End of header // PluginInfo & PluginInfoEx PLUGININFOEX pluginInfoEx = { sizeof(PLUGININFOEX), __INTERNAL_NAME_STRING, __VERSION_DWORD, "Fingerprint Mod+ (client version) icons module set extra icon of your buddies according to their client version.", "Artem Shpynov aka FYR, Bio, Faith Healer, HierOS", "crazy.hieros@gmail.com", __LEGAL_COPYRIGHT_STRING, "http://code.google.com/p/fingerprintmod/", UNICODE_AWARE, 0, MIID_THIS_PLUGIN }; static void LoadDBCheckState(HWND hwndDlg, int idCtrl, LPCSTR szSetting, BYTE bDef) { CheckDlgButton(hwndDlg, idCtrl, DBGetContactSettingByte(NULL, "Finger", szSetting, bDef)); } static void StoreDBCheckState(HWND hwndDlg, int idCtrl, LPCSTR szSetting) { DBWriteContactSettingByte(NULL, "Finger", szSetting, (BYTE)IsDlgButtonChecked(hwndDlg, idCtrl)); } static void OptDlgChanged(HWND hwndDlg, BOOL show) { if (show) ShowWindow(GetDlgItem(hwndDlg, IDC_OPTCHANGENOTE), SW_SHOW); SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); } BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { g_hInst = hinstDLL; return TRUE; } extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) { return &pluginInfoEx; } extern "C" __declspec(dllexport) const MUUID* MirandaPluginInterfaces() { static const MUUID interfaces[] = {MIID_THIS_PLUGIN, MIID_FINGERPRINT, MIID_LAST }; return interfaces; } extern "C" int __declspec(dllexport) Load(PLUGINLINK* link) { pluginLink = link; mir_getMMI(&mmi); mir_getLP(&pluginInfoEx); hStaticHooks[0] = HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded); hPreShutdown = HookEvent(ME_SYSTEM_PRESHUTDOWN, OnPreShutdown); compClientServA = CreateServiceFunction(MS_FP_SAMECLIENTS, ServiceSameClientsA); getClientIconA = CreateServiceFunction(MS_FP_GETCLIENTICON, ServiceGetClientIconA); compClientServW = CreateServiceFunction(MS_FP_SAMECLIENTSW, ServiceSameClientsW); getClientIconW = CreateServiceFunction(MS_FP_GETCLIENTICONW, ServiceGetClientIconW); hHeap = HeapCreate(HEAP_NO_SERIALIZE, 0, 0); gbUnicodeAPI = IsWinVerNT(); return 0; } extern "C" int __declspec(dllexport) Unload() { size_t i; if(g_szClientDescription != NULL) mir_free(g_szClientDescription); HeapDestroy(hHeap); ClearFI(); for(i = 0; i < SIZEOF(hStaticHooks); i++) { UnhookEvent(hStaticHooks[i]); hStaticHooks[i] = NULL; } return 0; } /* * FreeIcon * for mode > 0 it releases icon from iconlib * for mode < 0 it destroys icon */ void FASTCALL FreeIcon(HICON hIcon, BOOL mode) { if (!mode) return; if(mode > 0) CallService(MS_SKIN2_RELEASEICON, (WPARAM)hIcon, (WPARAM)0); else DestroyIcon(hIcon); } /* * Prepare * prepares upperstring masks and registers them in IcoLib */ void FASTCALL Prepare(KN_FP_MASK* mask) { if (!mask->szMask) return; size_t iMaskLen; LPTSTR pszNewMask; LPTSTR pszTranslatedMask; if(mask == &def_kn_fp_mask[UNKNOWN_MASK_NUMBER]) pszTranslatedMask = TranslateTS(mask->szMask); else pszTranslatedMask = mask->szMask; iMaskLen = _tcslen(pszTranslatedMask) + 1; pszNewMask = (LPTSTR)HeapAlloc(hHeap, HEAP_NO_SERIALIZE, iMaskLen * sizeof(TCHAR)); _tcscpy_s(pszNewMask, iMaskLen, pszTranslatedMask); _tcsupr_s(pszNewMask, iMaskLen); mask->szMask = pszNewMask; LoadIconFromExternalFile(mask->szIconFileName, LIB_REG, mask->szIconName, mask->iSectionFlag, mask->szClientDescription, mask->iIconIndex, NULL); } /* * OnModulesLoaded * Hook necessary events here */ int OnModulesLoaded(WPARAM wParam, LPARAM lParam) { int i; Update update = { 0 }; char szVersion[16]; g_LPCodePage = CallService(MS_LANGPACK_GETCODEPAGE, 0, 0); g_bExtraIcon_Register_ServiceExist = ServiceExists(MS_EXTRAICON_REGISTER); g_bCList_Extra_Set_Icon_ServiceExist = ServiceExists(MS_CLIST_EXTRA_SET_ICON); //Hook necessary events hIconsChanged = HookEvent(ME_SKIN2_ICONSCHANGED, OnIconsChanged); hContactSettingChanged = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, OnContactSettingChanged); hOptInitialise = HookEvent(ME_OPT_INITIALISE, OnOptInitialise); if(g_bExtraIcon_Register_ServiceExist) { EXTRAICON_INFO ico = { 0 }; ico.cbSize = sizeof(ico); ico.type = EXTRAICON_TYPE_CALLBACK; ico.RebuildIcons = OnExtraIconListRebuild; ico.ApplyIcon = OnExtraImageApply; ico.OnClick = (MIRANDAHOOKPARAM)OnExtraIconClick; ico.name = "Client"; ico.description= "Fingerprint"; ico.descIcon = "client_Miranda_Unknown"; hExtraIcon = (HANDLE)CallService(MS_EXTRAICON_REGISTER, (WPARAM)&ico, 0); } else { InitFingerEvents(); } if (ServiceExists(MS_FOLDERS_REGISTER_PATH)) { hIconFolder = FoldersRegisterCustomPathT("Fingerprint", "Icons", _T(MIRANDA_PATH) _T("\\") DEFAULT_SKIN_FOLDER); FoldersGetCustomPathT(hIconFolder, g_szSkinLib, SIZEOF(g_szSkinLib), _T("")); } else CallService(MS_UTILS_PATHTOABSOLUTET, (WPARAM)DEFAULT_SKIN_FOLDER, (LPARAM)g_szSkinLib); #ifdef USE_MY_SERVER update.cbSize = sizeof(Update); update.szComponentName = pluginInfoEx.shortName; update.pbVersion = (LPBYTE)CreateVersionString(__VERSION_DWORD, szVersion); update.cpbVersion = (int)strlen((LPSTR)update.pbVersion); update.szUpdateURL = "http://fingerprintmod.googlecode.com/svn/branches/updater/" __BETA_FILE_TITLE ".zip"; update.szVersionURL = "http://fingerprintmod.googlecode.com/svn/branches/updater/" __BETA_FILE_TITLE ".txt"; update.pbVersionPrefix = (LPBYTE)__INTERNAL_NAME_STRING " version "; update.cpbVersionPrefix = (int)strlen((LPSTR)update.pbVersionPrefix); CallService(MS_UPDATE_REGISTER, 0, (WPARAM)&update); #else //!USE_MY_SERVER #ifdef REGISTER_BETA update.cbSize = sizeof(Update); update.szComponentName = pluginInfoEx.shortName; update.pbVersion = (LPBYTE)CreateVersionString(__VERSION_DWORD, szVersion); update.cpbVersion = (int)strlen((LPSTR)update.pbVersion); update.szBetaChangelogURL = "http://code.google.com/p/fingerprintmod/source/list"; #ifdef REGISTER_AUTO update.szUpdateURL = UPDATER_AUTOREGISTER; #else //!REGISTER_AUTO update.szUpdateURL = "http://addons.miranda-im.org/download.php?dlfile=" __PLUGIN_ID_STR; update.szVersionURL = "http://addons.miranda-im.org/details.php?action=viewfile&id=" __PLUGIN_ID_STR; update.pbVersionPrefix = (LPBYTE)"" __INTERNAL_NAME_STRING " "; update.cpbVersionPrefix = (int)strlen((LPSTR)update.pbVersionPrefix); #endif //REGISTER_AUTO update.szBetaUpdateURL = "http://fingerprintmod.googlecode.com/svn/branches/updater/" __BETA_FILE_TITLE ".zip"; update.szBetaVersionURL = "http://fingerprintmod.googlecode.com/svn/branches/updater/" __BETA_FILE_TITLE ".txt"; update.pbBetaVersionPrefix = (LPBYTE)__INTERNAL_NAME_STRING " version "; update.cpbBetaVersionPrefix = (int)strlen((LPSTR)update.pbBetaVersionPrefix); CallService(MS_UPDATE_REGISTER, 0, (WPARAM)&update); #else // !REGISTER_BETA CallService(MS_UPDATE_REGISTERFL, (WPARAM)__PLUGIN_ID, (LPARAM)&pluginInfoEx); #endif // REGISTER_BETA #endif // USE_MY_SERVER // prepare masks KN_FP_MASK* mask; for(i = 0; i < DEFAULT_KN_FP_MASK_COUNT; i++) { mask = &def_kn_fp_mask[i]; if(mask) Prepare(mask); } if(DBGetContactSettingByte(NULL, "Finger", "Overlay1", 1)) { for(i = 0; i < DEFAULT_KN_FP_OVERLAYS_COUNT; i++) { mask = &def_kn_fp_overlays_mask[i]; if(mask) Prepare(mask); } } if(DBGetContactSettingByte(NULL, "Finger", "Overlay2", 1)) { if (DBGetContactSettingByte(NULL, "Finger", "ShowVersion", 0)) { for(i = 0; i < DEFAULT_KN_FP_OVERLAYS2_COUNT; i++) { mask = &def_kn_fp_overlays2_mask[i]; if(mask) Prepare(mask); } } else { for(i = 0; i < DEFAULT_KN_FP_OVERLAYS2_NO_VER_COUNT; i++) { mask = &def_kn_fp_overlays2_mask[i]; if(mask) Prepare(mask); } } } if(DBGetContactSettingByte(NULL, "Finger", "Overlay3", 1)) { for(i = 0; i < DEFAULT_KN_FP_OVERLAYS3_COUNT; i++) { mask = &def_kn_fp_overlays3_mask[i]; if(mask) Prepare(mask); } } return 0; } int OnExtraIconClicked(WPARAM wParam, LPARAM lParam) { if(lParam == bColumn) CallService(MS_USERINFO_SHOWDIALOG, wParam, NULL); return 0; } /* * OnPreShutdown * Unhook events here (this is valid place to unhook all events to prevent crash on exiting) */ int OnPreShutdown(WPARAM wParam, LPARAM lParam) { //Unhook events UnhookEvent(hContactSettingChanged); UnhookEvent(hPreShutdown); UnhookEvent(hIconsChanged); UnhookEvent(hOptInitialise); if (!g_bExtraIcon_Register_ServiceExist) UninitFingerEvents(); UnhookEvent(hFolderChanged); DestroyServiceFunction(compClientServA); DestroyServiceFunction(getClientIconA); DestroyServiceFunction(compClientServW); DestroyServiceFunction(getClientIconW); return 0; } /* ApplyFingerprintImage * 1)Try to find appropriate mask * 2)Register icon in extraimage list if not yet registered (0xFF) * 3)Set ExtraImage for contact */ int FASTCALL ApplyFingerprintImage(HANDLE hContact, LPTSTR szMirVer) { HANDLE hImage = INVALID_HANDLE_VALUE; if(szMirVer) hImage = GetIconIndexFromFI(szMirVer); if(hContact == NULL) return 0; if(g_bCList_Extra_Set_Icon_ServiceExist && !g_bExtraIcon_Register_ServiceExist) { IconExtraColumn iec; WORD bColumn = DBGetContactSettingWord(NULL, "Finger", "Column", EXTRA_ICON_CLIENT); if(bColumn <= 0 || bColumn > EXTRA_ICON_COUNT) { bColumn = EXTRA_ICON_CLIENT; } iec.cbSize = sizeof(IconExtraColumn); iec.hImage = hImage; iec.ColumnType = bColumn; CallService(MS_CLIST_EXTRA_SET_ICON, (WPARAM)hContact, (LPARAM)&iec); } else if(g_bExtraIcon_Register_ServiceExist && hExtraIcon != INVALID_HANDLE_VALUE && hExtraIcon != NULL) { EXTRAICON ei = { 0 }; ei.cbSize = sizeof(ei); ei.hExtraIcon = hExtraIcon; ei.hContact = hContact; ei.hImage = hImage; CallService(MS_EXTRAICON_SET_ICON, (WPARAM)&ei, 0); } return 0; } void InitFingerEvents() { hExtraIconClick = HookEvent(ME_CLIST_EXTRA_CLICK, OnExtraIconClicked); hExtraImageListRebuild = HookEvent(ME_CLIST_EXTRA_LIST_REBUILD, OnExtraIconListRebuild); hExtraImageApply = HookEvent(ME_CLIST_EXTRA_IMAGE_APPLY, OnExtraImageApply); } void UninitFingerEvents() { UnhookEvent(hExtraImageListRebuild); UnhookEvent(hExtraImageApply); UnhookEvent(hExtraIconClick); } int OnExtraIconClick(WPARAM wParam, LPARAM lParam) { CallService(MS_USERINFO_SHOWDIALOG, wParam, NULL); return 0; } /* * OnExtraIconListRebuild * Set all registered indexes in array to 0xFF (unregistered icon) */ int OnExtraIconListRebuild(WPARAM wParam, LPARAM lParam) { ClearFI(); return 0; } /* * OnIconsChanged */ int OnIconsChanged(WPARAM wParam, LPARAM lParam) { ClearFI(); return 0; } /* * OnExtraImageApply * Try to get MirVer value from db for contact and if success calls ApplyFingerprintImage */ int OnExtraImageApply(WPARAM wParam, LPARAM lParam) { HANDLE hContact = (HANDLE)wParam; if(hContact == NULL) return 0; char *szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,wParam,0); if(szProto!=NULL) { DBVARIANT dbvMirVer = { 0 }; if (!DBGetContactSettingTString(hContact, szProto, "MirVer", &dbvMirVer)) { ApplyFingerprintImage(hContact, dbvMirVer.ptszVal); DBFreeVariant(&dbvMirVer); } else ApplyFingerprintImage(hContact, NULL); } else ApplyFingerprintImage(hContact, NULL); return 0; } /* * OnContactSettingChanged * if contact settings changed apply new image or remove it */ int OnContactSettingChanged(WPARAM wParam, LPARAM lParam) { if ((HANDLE)wParam == NULL) return 0; { DBCONTACTWRITESETTING* cws = (DBCONTACTWRITESETTING*)lParam; if(cws && cws->szSetting && !strcmp(cws->szSetting, "MirVer")) { if(cws->value.type == DBVT_UTF8) { LPWSTR wszVal = NULL; int iValLen; iValLen = MultiByteToWideChar(CP_UTF8, 0, cws->value.pszVal, -1, NULL, 0); if(iValLen > 0) { wszVal = (LPWSTR)mir_alloc(iValLen * sizeof(WCHAR)); MultiByteToWideChar(CP_UTF8, 0, cws->value.pszVal, -1, wszVal, iValLen); } ApplyFingerprintImage((HANDLE)wParam, wszVal); mir_free(wszVal); } else if(cws->value.type == DBVT_ASCIIZ) { LPWSTR wszVal = NULL; int iValLen; iValLen = MultiByteToWideChar(g_LPCodePage, 0, cws->value.pszVal, -1, NULL, 0); if(iValLen > 0) { wszVal = (LPWSTR)mir_alloc(iValLen * sizeof(WCHAR)); MultiByteToWideChar(g_LPCodePage, 0, cws->value.pszVal, -1, wszVal, iValLen); } ApplyFingerprintImage((HANDLE)wParam, wszVal); mir_free(wszVal); } else if(cws->value.type == DBVT_WCHAR) { ApplyFingerprintImage((HANDLE)wParam, cws->value.pwszVal); } else ApplyFingerprintImage((HANDLE)wParam, NULL); } } return 0; } /* * LoadIconFromExternalFile * If iconlib module presents register icon there * Register and return icon within iconlib * or from resourse */ // TO DO: Extracting icons from clienticons.dll or other external files require futher // destroying of icon... need to add field to list, modify it and remove icon on unload // Otherwise it will cause gdi resources leaking. // So nowtime it is commented out HICON FASTCALL LoadIconFromExternalFile(LPTSTR filename, int nLibrary, LPSTR IconName, int flag, LPTSTR Description, int internalidx, LPBOOL NeedFree) { HICON hIcon = NULL; TCHAR destfile[MAX_PATH]; if(IconName == NULL) return NULL; if (filename == _T("")) GetModuleFileName(g_hInst,destfile,MAX_PATH); else { mir_sntprintf(destfile, SIZEOF(destfile), _T("%s\\%s.dll"), g_szSkinLib, filename); struct _stat64i32 stFileInfo; if (_tstat(destfile, &stFileInfo) == -1) return hIcon; } if(nLibrary == LIB_USE) { hIcon = ((HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)IconName)); if (!hIcon) { ExtractIconEx(destfile, -internalidx, NULL, &hIcon, 1); return hIcon; } } else { SKINICONDESC sid; LPTSTR SectName = NULL; switch(flag) { #include "finger_groups.h" } if(SectName == NULL) return hIcon; ZeroMemory(&sid, sizeof(sid)); sid.cbSize = sizeof(sid); sid.flags = SIDF_ALL_TCHAR; sid.ptszSection = SectName; sid.pszName = IconName; sid.ptszDescription = Description; sid.ptszDefaultFile = destfile; sid.iDefaultIndex = -internalidx; sid.cx = sid.cy = 16; CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid); hIcon = ((HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)IconName)); } if(NeedFree) *NeedFree = (BOOL)hIcon; return hIcon; } /* * WildCompareA * Compare 'name' string with 'mask' strings. * Masks can contain '*' or '?' wild symbols * Asterics '*' symbol covers 'empty' symbol too e.g WildCompare("Tst","T*st*"), returns TRUE * In order to handle situation 'at least one any sybol' use "?*" combination: * e.g WildCompare("Tst","T?*st*"), returns FALSE, but both WildCompare("Test","T?*st*") and * WildCompare("Teeest","T?*st*") return TRUE. * * Function is case sensitive! so convert input or modify func to use _qtoupper() * * Mask can contain several submasks. In this case each submask (including first) * should start from '|' e.g: "|first*submask|second*mask". * * Dec 25, 2006 by FYR: * Added Exception to masks: the mask "|^mask3|mask2|mask1" means: * if NOT according to mask 3 AND (mask1 OR mask2) * EXCEPTION should be BEFORE main mask: * IF Exception match - the comparing stops as FALSE * IF Exception does not match - comparing continue * IF Mask match - comparing stops as TRUE * IF Mask does not not match comparing continue */ BOOL FASTCALL WildCompareA(LPSTR szName, LPSTR szMask) { if (*szMask != '|') return WildCompareProcA(szName, szMask); { size_t s = 1, e = 1; // static char temp[100]; //lets made temp static local var - should be faster than dynamic LPSTR szTemp = (LPSTR)_alloca(strlen(szMask) * sizeof(CHAR) + sizeof(CHAR)); BOOL bExcept; while(szMask[e] != '\0') { s = e; while(szMask[e] != '\0' && szMask[e] != '|') e++; // exception mask bExcept = (*(szMask + s) == '^'); if(bExcept) s++; memcpy(szTemp, szMask + s, (e - s) * sizeof(CHAR)); szTemp[e - s] = '\0'; if(WildCompareProcA(szName, szTemp)) return !bExcept; if(szMask[e] != '\0') e++; else return FALSE; } return FALSE; } } /* * WildCompareW * Compare 'name' string with 'mask' strings. * Masks can contain '*' or '?' wild symbols * Asterics '*' symbol covers 'empty' symbol too e.g WildCompare("Tst","T*st*"), returns TRUE * In order to handle situation 'at least one any sybol' use "?*" combination: * e.g WildCompare("Tst","T?*st*"), returns FALSE, but both WildCompare("Test","T?*st*") and * WildCompare("Teeest","T?*st*") return TRUE. * * Function is case sensitive! so convert input or modify func to use _qtoupper() * * Mask can contain several submasks. In this case each submask (including first) * should start from '|' e.g: "|first*submask|second*mask". * * Dec 25, 2006 by FYR: * Added Exception to masks: the mask "|^mask3|mask2|mask1" means: * if NOT according to mask 3 AND (mask1 OR mask2) * EXCEPTION should be BEFORE main mask: * IF Exception match - the comparing stops as FALSE * IF Exception does not match - comparing continue * IF Mask match - comparing stops as TRUE * IF Mask does not not match comparing continue */ BOOL FASTCALL WildCompareW(LPWSTR wszName, LPWSTR wszMask) { if (*wszMask != L'|') return WildCompareProcW(wszName, wszMask); { size_t s = 1, e = 1; // static char temp[100]; //lets made temp static local var - should be faster than dynamic LPWSTR wszTemp = (LPWSTR)_alloca(wcslen(wszMask) * sizeof(WCHAR) + sizeof(WCHAR)); BOOL bExcept; while(wszMask[e] != L'\0') { s = e; while(wszMask[e] != L'\0' && wszMask[e] != L'|') e++; // exception mask bExcept = (*(wszMask + s) == L'^'); if(bExcept) s++; memcpy(wszTemp, wszMask + s, (e - s) * sizeof(WCHAR)); wszTemp[e - s] = L'\0'; if(WildCompareProcW(wszName, wszTemp)) return !bExcept; if(wszMask[e] != L'\0') e++; else return FALSE; } return FALSE; } } INT_PTR CALLBACK DlgProcOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_INITDIALOG: { TranslateDialogDefault(hwndDlg); for (int i = 0; i < DEFAULT_SETTINGS_COUNT; i++) { if (lstrcmpA(settings[i].szSetName, "ShowVersion") == 0) LoadDBCheckState(hwndDlg, settings[i].idCtrl, settings[i].szSetName, 0); else LoadDBCheckState(hwndDlg, settings[i].idCtrl, settings[i].szSetName, 1); } LPTSTR CIdComboBox[] = { _T("Email"), _T("Protocol"), _T("SMS"), _T("Advanced 1"), _T("Advanced 2"), _T("Web"), _T("Client (default)"), _T("VisMode"), _T("Advanced 3"), _T("Advanced 4") }; for(int i = 0; i < SIZEOF(CIdComboBox); i++) ComboBoxAddString(GetDlgItem(hwndDlg, IDC_ADVICON), CIdComboBox[i], i); SendDlgItemMessage(hwndDlg, IDC_ADVICON, CB_SETCURSEL, (DBGetContactSettingWord(NULL, "Finger", "Column", EXTRA_ICON_CLIENT)) - 1, 0); if(g_bExtraIcon_Register_ServiceExist) EnableWindow(GetDlgItem(hwndDlg, IDC_ADVICON), FALSE); ShowWindow(GetDlgItem(hwndDlg, IDC_OPTCHANGENOTE), SW_HIDE); } break; case WM_COMMAND: switch(LOWORD(wParam)) { BOOL show; case IDC_ADVICON: if(HIWORD(wParam) == CBN_SELCHANGE) OptDlgChanged(hwndDlg, true); break; case IDC_OVERLAY1: case IDC_OVERLAY2: case IDC_OVERLAY3: case IDC_VERSION: show = true; OptDlgChanged(hwndDlg, show); break; case IDC_GROUPMIRANDA: case IDC_GROUPMULTI: case IDC_GROUPPACKS: case IDC_GROUPOTHERS: case IDC_GROUPAIM: case IDC_GROUPGADU: case IDC_GROUPICQ: case IDC_GROUPIRC: case IDC_GROUPJABBER: case IDC_GROUPMAIL: case IDC_GROUPMSN: case IDC_GROUPQQ: case IDC_GROUPRSS: case IDC_GROUPSKYPE: case IDC_GROUPTLEN: case IDC_GROUPVOIP: case IDC_GROUPWEATHER: case IDC_GROUPYAHOO: show = false; OptDlgChanged(hwndDlg, show); break; default: return 0; } break; case WM_NOTIFY: { NMHDR *hdr = (NMHDR *)lParam; if (hdr && hdr->code == PSN_APPLY) { int i = SendDlgItemMessage(hwndDlg, IDC_ADVICON, CB_GETCURSEL, 0, 0) + 1; DBWriteContactSettingWord(NULL, "Finger", "Column", (WORD)i); // prepare masks KN_FP_MASK* mask; for(i = 0; i < DEFAULT_KN_FP_MASK_COUNT; i++) { mask = &def_kn_fp_mask[i]; if(mask) CallService(MS_SKIN2_REMOVEICON, 0, (LPARAM)mask->szIconName); } if(DBGetContactSettingByte(NULL, "Finger", "Overlay1", 1)) { for(i = 0; i < DEFAULT_KN_FP_OVERLAYS_COUNT; i++) { mask = &def_kn_fp_overlays_mask[i]; if(mask) CallService(MS_SKIN2_REMOVEICON, 0, (LPARAM)mask->szIconName); } } if(DBGetContactSettingByte(NULL, "Finger", "Overlay2", 1)) { if (DBGetContactSettingByte(NULL, "Finger", "ShowVersion", 0)) { for(i = 0; i < DEFAULT_KN_FP_OVERLAYS2_COUNT; i++) { mask = &def_kn_fp_overlays2_mask[i]; if(mask) CallService(MS_SKIN2_REMOVEICON, 0, (LPARAM)mask->szIconName); } } else { for(i = 0; i < DEFAULT_KN_FP_OVERLAYS2_NO_VER_COUNT; i++) { mask = &def_kn_fp_overlays2_mask[i]; if(mask) CallService(MS_SKIN2_REMOVEICON, 0, (LPARAM)mask->szIconName); } } } if(DBGetContactSettingByte(NULL, "Finger", "Overlay3", 1)) { for(i = 0; i < DEFAULT_KN_FP_OVERLAYS3_COUNT; i++) { mask = &def_kn_fp_overlays3_mask[i]; if(mask) CallService(MS_SKIN2_REMOVEICON, 0, (LPARAM)mask->szIconName); } } for (int i = 0; i < DEFAULT_SETTINGS_COUNT; i++) StoreDBCheckState(hwndDlg, settings[i].idCtrl, settings[i].szSetName); for(i = 0; i < DEFAULT_KN_FP_MASK_COUNT; i++) { mask = &def_kn_fp_mask[i]; if(mask) Prepare(mask); } if(DBGetContactSettingByte(NULL, "Finger", "Overlay1", 1)) { for(i = 0; i < DEFAULT_KN_FP_OVERLAYS_COUNT; i++) { mask = &def_kn_fp_overlays_mask[i]; if(mask) Prepare(mask); } } if(DBGetContactSettingByte(NULL, "Finger", "Overlay2", 1)) { if (DBGetContactSettingByte(NULL, "Finger", "ShowVersion", 0)) { for(i = 0; i < DEFAULT_KN_FP_OVERLAYS2_COUNT; i++) { mask = &def_kn_fp_overlays2_mask[i]; if(mask) Prepare(mask); } } else { for(i = 0; i < DEFAULT_KN_FP_OVERLAYS2_NO_VER_COUNT; i++) { mask = &def_kn_fp_overlays2_mask[i]; if(mask) Prepare(mask); } } } if(DBGetContactSettingByte(NULL, "Finger", "Overlay3", 1)) { for(i = 0; i < DEFAULT_KN_FP_OVERLAYS3_COUNT; i++) { mask = &def_kn_fp_overlays3_mask[i]; if(mask) Prepare(mask); } } } break; } case WM_DESTROY: break; } return FALSE; } int OnOptInitialise(WPARAM wParam, LPARAM lParam) { OPTIONSDIALOGPAGE odp; ZeroMemory(&odp, sizeof(odp)); odp.cbSize = sizeof(odp); odp.position = 0; odp.hInstance = g_hInst; odp.ptszGroup = LPGENT("Customize"); odp.pszTemplate = MAKEINTRESOURCEA(IDD_DIALOG); odp.ptszTitle = LPGENT("Fingerprint"); odp.pfnDlgProc = DlgProcOptions; odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR; Options_AddPage(wParam, &odp); return 0; } BOOL __inline WildCompareProcA(LPSTR szName, LPSTR szMask) { LPSTR szLast = NULL; for (;; szMask++, szName++) { if (*szMask != '?' && *szMask != *szName) break; if (*szName == '\0') return ((BOOL)!*szMask); } if (*szMask != '*') return FALSE; for (;; szMask++, szName++) { while(*szMask == '*') { szLast = szMask++; if (*szMask == '\0') return ((BOOL)!*szMask); /* true */ } if (*szName == '\0') return ((BOOL)!*szMask); /* *mask == EOS */ if (*szMask != '?' && *szMask != *szName && szLast != NULL) { szName -= (size_t)(szMask - szLast) - 1; szMask = szLast; } } } BOOL __inline WildCompareProcW(LPWSTR wszName, LPWSTR wszMask) { LPWSTR wszLast = NULL; for (;; wszMask++, wszName++) { if (*wszMask != L'?' && *wszMask != *wszName) break; if (*wszName == L'\0') return ((BOOL)!*wszMask); } if (*wszMask != L'*') return FALSE; for (;; wszMask++, wszName++) { while(*wszMask == L'*') { wszLast = wszMask++; if (*wszMask == L'\0') return ((BOOL)!*wszMask); /* true */ } if (*wszName == L'\0') return ((BOOL)!*wszMask); /* *mask == EOS */ if (*wszMask != L'?' && *wszMask != *wszName && wszLast != NULL) { wszName -= (size_t)(wszMask - wszLast) - 1; wszMask = wszLast; } } } /* GetIconsIndexesA * Retrieves Icons indexes by Mirver */ void FASTCALL GetIconsIndexesA(LPSTR szMirVer, short *base, short *overlay,short *overlay2,short *overlay3) { LPTSTR tszMirVerUp; int iMirVerUpLen; short i = 0, j = -1, k = -1, n = -1; if(strcmp(szMirVer, "?") == 0) { *base = UNKNOWN_MASK_NUMBER; *overlay = -1; *overlay2 = -1; *overlay3 = -1; return; } iMirVerUpLen = MultiByteToWideChar(g_LPCodePage, 0, szMirVer, -1, NULL, 0); tszMirVerUp = (LPTSTR)mir_alloc(iMirVerUpLen * sizeof(TCHAR)); MultiByteToWideChar(g_LPCodePage, 0, szMirVer, -1, tszMirVerUp, iMirVerUpLen); _tcsupr_s(tszMirVerUp, iMirVerUpLen); while(i < DEFAULT_KN_FP_MASK_COUNT) { if(WildCompare(tszMirVerUp, def_kn_fp_mask[i].szMask)) { if (def_kn_fp_mask[i].szIconFileName != _T("")) { TCHAR destfile[MAX_PATH]; mir_sntprintf(destfile, SIZEOF(destfile), _T("%s\\%s.dll"), g_szSkinLib, def_kn_fp_mask[i].szIconFileName); struct _stat64i32 stFileInfo; if (_tstat(destfile, &stFileInfo) == -1) i = NOTFOUND_MASK_NUMBER; } break; } i++; } if (!def_kn_fp_mask[i].fNotUseOverlay && i < DEFAULT_KN_FP_MASK_COUNT) { j = 0; while(j < DEFAULT_KN_FP_OVERLAYS_COUNT) { if(WildCompare(tszMirVerUp, def_kn_fp_overlays_mask[j].szMask)) { if (def_kn_fp_overlays_mask[j].szIconFileName == _T("ClientIcons_Packs")) { TCHAR destfile[MAX_PATH]; mir_sntprintf(destfile, SIZEOF(destfile), _T("%s\\%s.dll"), g_szSkinLib, def_kn_fp_overlays_mask[i].szIconFileName); struct _stat64i32 stFileInfo; if (_tstat(destfile, &stFileInfo) == -1) j++; else break; } else break; } j++; } k = 0; while(k < DEFAULT_KN_FP_OVERLAYS2_COUNT) { if(WildCompare(tszMirVerUp, def_kn_fp_overlays2_mask[k].szMask)) break; k++; } n = 0; while(n < DEFAULT_KN_FP_OVERLAYS3_COUNT) { if(WildCompare(tszMirVerUp, def_kn_fp_overlays3_mask[n].szMask)) break; n++; } } *base = (i < DEFAULT_KN_FP_MASK_COUNT) ? i : -1; *overlay = (j < DEFAULT_KN_FP_OVERLAYS_COUNT) ? j : -1; *overlay2 = (k < DEFAULT_KN_FP_OVERLAYS2_COUNT) ? k : -1; *overlay3 = (n < DEFAULT_KN_FP_OVERLAYS3_COUNT) ? n : -1; mir_free(tszMirVerUp); } /* GetIconsIndexesW * Retrieves Icons indexes by Mirver */ void FASTCALL GetIconsIndexesW(LPWSTR wszMirVer, short *base, short *overlay,short *overlay2,short *overlay3) { LPWSTR wszMirVerUp; size_t iMirVerUpLen; short i = 0, j = -1, k = -1, n = -1; if(wcscmp(wszMirVer, L"?") == 0) { *base = UNKNOWN_MASK_NUMBER; *overlay = -1; *overlay2 = -1; *overlay3 = -1; return; } iMirVerUpLen = wcslen(wszMirVer) + 1; wszMirVerUp = (LPWSTR)mir_alloc(iMirVerUpLen * sizeof(WCHAR)); wcscpy_s(wszMirVerUp, iMirVerUpLen, wszMirVer); _wcsupr_s(wszMirVerUp, iMirVerUpLen); while(i < DEFAULT_KN_FP_MASK_COUNT) { if(WildCompareW(wszMirVerUp, def_kn_fp_mask[i].szMask)) { if (def_kn_fp_mask[i].szIconFileName != _T("")) { TCHAR destfile[MAX_PATH]; mir_sntprintf(destfile, SIZEOF(destfile), _T("%s\\%s.dll"), g_szSkinLib, def_kn_fp_mask[i].szIconFileName); struct _stat64i32 stFileInfo; if (_tstat(destfile, &stFileInfo) == -1) i = NOTFOUND_MASK_NUMBER; } break; } i++; } if (!def_kn_fp_mask[i].fNotUseOverlay && i < DEFAULT_KN_FP_MASK_COUNT) { j = 0; while(j < DEFAULT_KN_FP_OVERLAYS_COUNT) { if(WildCompare(wszMirVerUp, def_kn_fp_overlays_mask[j].szMask)) { if (def_kn_fp_overlays_mask[j].szIconFileName == _T("ClientIcons_Packs")) { TCHAR destfile[MAX_PATH]; mir_sntprintf(destfile, SIZEOF(destfile), _T("%s\\%s.dll"), g_szSkinLib, def_kn_fp_overlays_mask[j].szIconFileName); struct _stat64i32 stFileInfo; if (_tstat(destfile, &stFileInfo) == -1) j++; else break; } else break; } j++; } k = 0; while(k < DEFAULT_KN_FP_OVERLAYS2_COUNT) { if(WildCompareW(wszMirVerUp, def_kn_fp_overlays2_mask[k].szMask)) break; k++; } n = 0; while(n < DEFAULT_KN_FP_OVERLAYS3_COUNT) { if(WildCompareW(wszMirVerUp, def_kn_fp_overlays3_mask[n].szMask)) break; n++; } } *base = (i < DEFAULT_KN_FP_MASK_COUNT) ? i : -1; *overlay = (j < DEFAULT_KN_FP_OVERLAYS_COUNT) ? j : -1; *overlay2 = (k < DEFAULT_KN_FP_OVERLAYS2_COUNT) ? k : -1; *overlay3 = (n < DEFAULT_KN_FP_OVERLAYS3_COUNT) ? n : -1; mir_free(wszMirVerUp); } /* * CreateIconFromIndexes * returns hIcon of joined icon by given indexes */ HICON FASTCALL CreateIconFromIndexes(short base, short overlay, short overlay2, short overlay3) { HICON hIcon = NULL; // returned HICON HICON hTmp = NULL; HICON icMain = NULL; HICON icOverlay = NULL; HICON icOverlay2 = NULL; HICON icOverlay3 = NULL; BOOL needFreeBase = FALSE; BOOL needFreeOverlay = FALSE; BOOL needFreeOverlay2 = FALSE; BOOL needFreeOverlay3 = FALSE; KN_FP_MASK* mainMask = &(def_kn_fp_mask[base]); icMain = LoadIconFromExternalFile(mainMask->szIconFileName, LIB_USE, mainMask->szIconName, mainMask->iSectionFlag, mainMask->szClientDescription, mainMask->iIconIndex, &needFreeBase); if(icMain) { KN_FP_MASK* overlayMask = (overlay != -1) ? &(def_kn_fp_overlays_mask[overlay]) : NULL; KN_FP_MASK* overlay2Mask = (overlay2 != -1) ? &(def_kn_fp_overlays2_mask[overlay2]) : NULL; KN_FP_MASK* overlay3Mask = (overlay3 != -1) ? &(def_kn_fp_overlays3_mask[overlay3]) : NULL; icOverlay = (overlayMask == NULL) ? NULL : LoadIconFromExternalFile(overlayMask->szIconFileName, LIB_USE, overlayMask->szIconName, overlayMask->iSectionFlag, overlayMask->szClientDescription, overlayMask->iIconIndex, &needFreeOverlay); icOverlay2 = (overlay2Mask == NULL) ? NULL : LoadIconFromExternalFile(overlay2Mask->szIconFileName, LIB_USE, overlay2Mask->szIconName, overlay2Mask->iSectionFlag, overlay2Mask->szClientDescription, overlay2Mask->iIconIndex, &needFreeOverlay2); icOverlay3 = (overlay3Mask == NULL) ? NULL : LoadIconFromExternalFile(overlay3Mask->szIconFileName, LIB_USE, overlay3Mask->szIconName, overlay3Mask->iSectionFlag, overlay3Mask->szClientDescription, overlay3Mask->iIconIndex, &needFreeOverlay3); hIcon = icMain; if(overlayMask) { hIcon = CreateJoinedIcon(hIcon, icOverlay); hTmp = hIcon; } if(overlay2Mask) { hIcon = CreateJoinedIcon(hIcon, icOverlay2); if(hTmp) DestroyIcon(hTmp); hTmp = hIcon; } if(overlay3Mask) { hIcon = CreateJoinedIcon(hIcon, icOverlay3); if(hTmp) DestroyIcon(hTmp); } } if(hIcon == icMain) hIcon = CopyIcon(icMain); FreeIcon(icMain, needFreeBase); FreeIcon(icOverlay, needFreeOverlay); FreeIcon(icOverlay2, needFreeOverlay2); FreeIcon(icOverlay3, needFreeOverlay3); return hIcon; } /* * ServiceGetClientIconA * MS_FP_GETCLIENTICON service implementation. * wParam - char * MirVer value to get client for. * lParam - int noCopy - if wParam is equal to "1" will return icon handler without copiing icon. * ICON IS ALWAYS COPIED!!! */ INT_PTR ServiceGetClientIconA(WPARAM wParam, LPARAM lParam) { LPSTR szMirVer = (LPSTR)wParam; // MirVer value to get client for. /* static HICON hIcon = NULL; // returned HICON if(hIcon) { DestroyIcon(hIcon); hIcon = NULL; } */ if(szMirVer == NULL) return 0; { HICON hIcon = NULL; // returned HICON int NoCopy = (int)lParam; // noCopy short base, overlay, overlay2, overlay3; GetIconsIndexesA(szMirVer, &base, &overlay, &overlay2, &overlay3); if(base != -1) { hIcon = CreateIconFromIndexes(base, overlay, overlay2, overlay3); } /* if(hIcon && !NoCopy) return (INT_PTR)CopyIcon(hIcon); */ return (INT_PTR)hIcon; } } /* * ServiceSameClientA * MS_FP_SAMECLIENTS service implementation. * wParam - char * first MirVer value * lParam - char * second MirVer value * return pointer to char string - client desription (do not destroy) if clients are same */ INT_PTR ServiceSameClientsA(WPARAM wParam, LPARAM lParam) { LPSTR szMirVerFirst = (LPSTR)wParam; // MirVer value to get client for. LPSTR szMirVerSecond = (LPSTR)lParam; // MirVer value to get client for. int firstIndex, secondIndex; BOOL Result = FALSE; firstIndex = secondIndex = 0; if (!szMirVerFirst || !szMirVerSecond) return (INT_PTR)NULL; //one of its is not null { LPTSTR tszMirVerFirstUp, tszMirVerSecondUp; int iMirVerFirstUpLen, iMirVerSecondUpLen; iMirVerFirstUpLen = MultiByteToWideChar(g_LPCodePage, 0, szMirVerFirst, -1, NULL, 0); iMirVerSecondUpLen = MultiByteToWideChar(g_LPCodePage, 0, szMirVerSecond, -1, NULL, 0); tszMirVerFirstUp = (LPTSTR)mir_alloc(iMirVerFirstUpLen * sizeof(TCHAR)); tszMirVerSecondUp = (LPTSTR)mir_alloc(iMirVerSecondUpLen * sizeof(TCHAR)); MultiByteToWideChar(g_LPCodePage, 0, szMirVerFirst, -1, tszMirVerFirstUp, iMirVerFirstUpLen); MultiByteToWideChar(g_LPCodePage, 0, szMirVerSecond, -1, tszMirVerSecondUp, iMirVerSecondUpLen); _tcsupr_s(tszMirVerFirstUp, iMirVerFirstUpLen); _tcsupr_s(tszMirVerSecondUp, iMirVerSecondUpLen); if(_tcscmp(tszMirVerFirstUp, _T("?")) == 0) firstIndex = UNKNOWN_MASK_NUMBER; else while(firstIndex < DEFAULT_KN_FP_MASK_COUNT) { if(WildCompare(tszMirVerFirstUp, def_kn_fp_mask[firstIndex].szMask)) break; firstIndex++; } if(_tcscmp(tszMirVerSecondUp, _T("?")) == 0) secondIndex = UNKNOWN_MASK_NUMBER; else while(secondIndex < DEFAULT_KN_FP_MASK_COUNT) { if(WildCompare(tszMirVerSecondUp, def_kn_fp_mask[secondIndex].szMask)) break; secondIndex++; } mir_free(tszMirVerFirstUp); mir_free(tszMirVerSecondUp); if(firstIndex == secondIndex && firstIndex < DEFAULT_KN_FP_MASK_COUNT) { int iClientDescriptionLen = WideCharToMultiByte(g_LPCodePage, 0, def_kn_fp_mask[firstIndex].szClientDescription, -1, NULL, 0, NULL, NULL); if(iClientDescriptionLen > 0) g_szClientDescription = (LPSTR)mir_realloc(g_szClientDescription, iClientDescriptionLen * sizeof(CHAR)); else return (INT_PTR)NULL; WideCharToMultiByte(g_LPCodePage, 0, def_kn_fp_mask[firstIndex].szClientDescription, -1, g_szClientDescription, iClientDescriptionLen, NULL, NULL); return (INT_PTR)g_szClientDescription; } } return (INT_PTR)NULL; } /* * ServiceGetClientIconW * MS_FP_GETCLIENTICONW service implementation. * wParam - LPWSTR MirVer value to get client for. * lParam - int noCopy - if wParam is equal to "1" will return icon handler without copiing icon. * ICON IS ALWAYS COPIED!!! */ INT_PTR ServiceGetClientIconW(WPARAM wParam, LPARAM lParam) { LPWSTR wszMirVer = (LPWSTR)wParam; // MirVer value to get client for. /* static HICON hIcon = NULL; // returned HICON if(hIcon) { DestroyIcon(hIcon); hIcon = NULL; } */ if(wszMirVer == NULL) return 0; { HICON hIcon = NULL; // returned HICON int NoCopy = (int)lParam; // noCopy short base, overlay, overlay2, overlay3; GetIconsIndexesW(wszMirVer, &base, &overlay, &overlay2, &overlay3); if(base != -1) { hIcon = CreateIconFromIndexes(base, overlay, overlay2, overlay3); } /* if(hIcon && !NoCopy) return (INT_PTR)CopyIcon(hIcon); */ return (INT_PTR)hIcon; } } /* * ServiceSameClientW * MS_FP_SAMECLIENTSW service implementation. * wParam - LPWSTR first MirVer value * lParam - LPWSTR second MirVer value * return pointer to char string - client desription (do not destroy) if clients are same */ INT_PTR ServiceSameClientsW(WPARAM wParam, LPARAM lParam) { LPWSTR wszMirVerFirst = (LPWSTR)wParam; // MirVer value to get client for. LPWSTR wszMirVerSecond = (LPWSTR)lParam; // MirVer value to get client for. int firstIndex, secondIndex; BOOL Result = FALSE; firstIndex = secondIndex = 0; if (!wszMirVerFirst || !wszMirVerSecond) return (INT_PTR)NULL; //one of its is not null { LPWSTR wszMirVerFirstUp, wszMirVerSecondUp; size_t iMirVerFirstUpLen, iMirVerSecondUpLen; iMirVerFirstUpLen = wcslen(wszMirVerFirst) + 1; iMirVerSecondUpLen = wcslen(wszMirVerSecond) + 1; wszMirVerFirstUp = (LPWSTR)mir_alloc(iMirVerFirstUpLen * sizeof(WCHAR)); wszMirVerSecondUp = (LPWSTR)mir_alloc(iMirVerSecondUpLen * sizeof(WCHAR)); wcscpy_s(wszMirVerFirstUp, iMirVerFirstUpLen, wszMirVerFirst); wcscpy_s(wszMirVerSecondUp, iMirVerSecondUpLen, wszMirVerSecond); _wcsupr_s(wszMirVerFirstUp, iMirVerFirstUpLen); _wcsupr_s(wszMirVerSecondUp, iMirVerSecondUpLen); if(wcscmp(wszMirVerFirstUp, L"?") == 0) firstIndex = UNKNOWN_MASK_NUMBER; else while(firstIndex < DEFAULT_KN_FP_MASK_COUNT) { if(WildCompareW(wszMirVerFirstUp, def_kn_fp_mask[firstIndex].szMask)) break; firstIndex++; } if(wcscmp(wszMirVerSecondUp, L"?") == 0) secondIndex = UNKNOWN_MASK_NUMBER; else while(secondIndex < DEFAULT_KN_FP_MASK_COUNT) { if(WildCompareW(wszMirVerSecondUp, def_kn_fp_mask[secondIndex].szMask)) break; secondIndex++; } mir_free(wszMirVerFirstUp); mir_free(wszMirVerSecondUp); if(firstIndex == secondIndex && firstIndex < DEFAULT_KN_FP_MASK_COUNT) { return (INT_PTR)def_kn_fp_mask[firstIndex].szClientDescription; } } return (INT_PTR)NULL; } /****************************************************************************** * Futher routines is for creating joined 'overlay' icons. ******************************************************************************/ /* * CreateBitmap32 - Create DIB 32 bitmap with sizes cx*cy */ HBITMAP __inline CreateBitmap32(int cx, int cy) { return CreateBitmap32Point(cx, cy, NULL); } /* * CreateBitmap32 - Create DIB 32 bitmap with sizes cx*cy and put reference * to new bitmap pixel image memory area to void ** bits */ HBITMAP FASTCALL CreateBitmap32Point(int cx, int cy, LPVOID* bits) { BITMAPINFO bmpi = { 0 }; LPVOID ptPixels = NULL; HBITMAP DirectBitmap; if(cx < 0 || cy < 0) return NULL; bmpi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmpi.bmiHeader.biWidth = cx; bmpi.bmiHeader.biHeight = cy; bmpi.bmiHeader.biPlanes = 1; // bmpi.bmiHeader.biCompression = BI_RGB; bmpi.bmiHeader.biBitCount = 32; DirectBitmap = CreateDIBSection(NULL, &bmpi, DIB_RGB_COLORS, &ptPixels, NULL, 0); GdiFlush(); if(ptPixels) memset(ptPixels, 0, cx * cy * 4); if(bits != NULL) *bits = ptPixels; return DirectBitmap; } /* * checkHasAlfa - checks if image has at least one BYTE in alpha channel * that is not a 0. (is image real 32 bit or just 24 bit) */ BOOL FASTCALL checkHasAlfa(LPBYTE from, int width, int height) { LPDWORD pt = (LPDWORD)from; LPDWORD lim = pt + width * height; while(pt < lim) { if (*pt & 0xFF000000) return TRUE; pt++; } return FALSE; } /* * checkMaskUsed - checks if mask image has at least one that is not a 0. * Not sure is it required or not */ BOOL FASTCALL checkMaskUsed(LPBYTE from) { int i; for(i = 0; i < 16 * 16 / 8; i++) { if(from[i] != 0) return TRUE; } return FALSE; } /* * GetMaskBit - return value of apropriate mask bit in line at x position */ BOOL __inline GetMaskBit(LPBYTE line, int x) { return ((*(line + (x >> 3))) & (0x01 << (7 - (x & 0x07)))) != 0; } /* * blend - alpha blend ARGB values of 2 pixels. X1 - underlaying, * X2 - overlaying points. */ DWORD FASTCALL blend(DWORD X1,DWORD X2) { RGBA* q1 = (RGBA*)&X1; RGBA* q2 = (RGBA*)&X2; BYTE a_1 = ~q1->a; BYTE a_2 = ~q2->a; WORD am = q1->a * a_2; WORD ar = q1->a + ((a_1 * q2->a) / 255); // if a2 more than 0 than result should be more // or equal (if a1==0) to a2, else in combination // with mask we can get here black points ar = (q2->a > ar) ? q2->a : ar; if(ar == 0) return 0; { WORD arm = ar * 255; WORD rr = ((q1->r * am + q2->r * q2->a * 255)) / arm; WORD gr = ((q1->g * am + q2->g * q2->a * 255)) / arm; WORD br = ((q1->b * am + q2->b * q2->a * 255)) / arm; return (ar << 24) | (rr << 16) | (gr << 8) | br; } } /* * CreateJoinedIcon - creates new icon by drawing hTop over hBottom. */ HICON FASTCALL CreateJoinedIcon(HICON hBottom, HICON hTop) { BOOL drawn = FALSE; HDC tempDC, tempDC2, tempDC3; HICON res = NULL; HBITMAP oImage,nImage; HBITMAP nMask, hbm, obmp, obmp2; LPBYTE ptPixels = NULL; ICONINFO iNew = { 0 }; BYTE p[32] = { 0 }; tempDC = CreateCompatibleDC(NULL); nImage = CreateBitmap32Point(16, 16, (LPVOID*)&ptPixels); oImage = (HBITMAP)SelectObject(tempDC, nImage); // if(ptPixels) memset(ptPixels, 0, 16 * 16 * 4); if(IsWinVerXPPlus()) { ICONINFO iciBottom = { 0 }; ICONINFO iciTop = { 0 }; BITMAP bmp_top = { 0 }; BITMAP bmp_top_mask = { 0 }; BITMAP bmp_bottom = { 0 }; BITMAP bmp_bottom_mask = { 0 }; GetIconInfo(hBottom, &iciBottom); GetObject(iciBottom.hbmColor, sizeof(BITMAP), &bmp_bottom); GetObject(iciBottom.hbmMask, sizeof(BITMAP), &bmp_bottom_mask); GetIconInfo(hTop, &iciTop); GetObject(iciTop.hbmColor, sizeof(BITMAP), &bmp_top); GetObject(iciTop.hbmMask, sizeof(BITMAP), &bmp_top_mask); if(bmp_bottom.bmBitsPixel == 32 && bmp_top.bmBitsPixel == 32) { LPBYTE BottomBuffer, TopBuffer, BottomMaskBuffer, TopMaskBuffer; LPBYTE bb, tb, bmb, tmb; LPBYTE db = ptPixels; int vstep_d = 16 * 4; int vstep_b = bmp_bottom.bmWidthBytes; int vstep_t = bmp_top.bmWidthBytes; int vstep_bm = bmp_bottom_mask.bmWidthBytes; int vstep_tm = bmp_top_mask.bmWidthBytes; if(bmp_bottom.bmBits) bb = BottomBuffer = (LPBYTE)bmp_bottom.bmBits; else { BottomBuffer = (LPBYTE)_alloca(bmp_bottom.bmHeight * bmp_bottom.bmWidthBytes); GetBitmapBits(iciBottom.hbmColor, bmp_bottom.bmHeight * bmp_bottom.bmWidthBytes, BottomBuffer); bb = BottomBuffer + vstep_b * (bmp_bottom.bmHeight - 1); vstep_b = -vstep_b; } if(bmp_top.bmBits) tb = TopBuffer = (LPBYTE)bmp_top.bmBits; else { TopBuffer = (LPBYTE)_alloca(bmp_top.bmHeight * bmp_top.bmWidthBytes); GetBitmapBits(iciTop.hbmColor, bmp_top.bmHeight * bmp_top.bmWidthBytes, TopBuffer); tb = TopBuffer + vstep_t * (bmp_top.bmHeight - 1); vstep_t = -vstep_t; } if(bmp_bottom_mask.bmBits) bmb = BottomMaskBuffer = (LPBYTE)bmp_bottom_mask.bmBits; else { BottomMaskBuffer = (LPBYTE)_alloca(bmp_bottom_mask.bmHeight * bmp_bottom_mask.bmWidthBytes); GetBitmapBits(iciBottom.hbmMask, bmp_bottom_mask.bmHeight * bmp_bottom_mask.bmWidthBytes, BottomMaskBuffer); bmb = BottomMaskBuffer + vstep_bm * (bmp_bottom_mask.bmHeight - 1); vstep_bm = -vstep_bm; } if(bmp_top_mask.bmBits) tmb = TopMaskBuffer = (LPBYTE)bmp_top_mask.bmBits; else { TopMaskBuffer = (LPBYTE)_alloca(bmp_top_mask.bmHeight * bmp_top_mask.bmWidthBytes); GetBitmapBits(iciTop.hbmMask, bmp_top_mask.bmHeight * bmp_top_mask.bmWidthBytes, TopMaskBuffer); tmb = TopMaskBuffer + vstep_tm * (bmp_top_mask.bmHeight - 1); vstep_tm = -vstep_tm; } { int x; int y; BOOL topHasAlpha = checkHasAlfa(TopBuffer, bmp_top.bmWidth, bmp_top.bmHeight); BOOL bottomHasAlpha = checkHasAlfa(BottomBuffer, bmp_bottom.bmWidth, bmp_bottom.bmHeight); BOOL topMaskUsed = !topHasAlpha && checkMaskUsed(TopMaskBuffer); BOOL bottomMaskUsed = !bottomHasAlpha && checkMaskUsed(BottomMaskBuffer); for(y = 0; y < 16; y++) { for(x = 0; x < 16; x++) { DWORD bottom_d = ((LPDWORD)bb)[x]; DWORD top_d = ((LPDWORD)tb)[x]; if(topMaskUsed) { if(GetMaskBit(tmb, x)) top_d &= 0x00FFFFFF; else top_d |= 0xFF000000; } else if (!topHasAlpha) top_d |= 0xFF000000; if(bottomMaskUsed) { if(GetMaskBit(bmb, x)) bottom_d &= 0x00FFFFFF; else bottom_d |= 0xFF000000; } else if (!bottomHasAlpha) bottom_d |= 0xFF000000; ((LPDWORD)db)[x] = blend(bottom_d, top_d); } bb += vstep_b; tb += vstep_t; bmb += vstep_bm; tmb += vstep_tm; db += vstep_d; } } drawn = TRUE; } DeleteObject(iciBottom.hbmColor); DeleteObject(iciTop.hbmColor); DeleteObject(iciBottom.hbmMask); DeleteObject(iciTop.hbmMask); } if (!drawn) { DrawIconEx(tempDC, 0, 0, hBottom, 16, 16, 0, NULL, DI_NORMAL); DrawIconEx(tempDC, 0, 0, hTop, 16, 16, 0, NULL, DI_NORMAL); } nMask = CreateBitmap(16, 16, 1, 1, p); tempDC2 = CreateCompatibleDC(NULL); tempDC3 = CreateCompatibleDC(NULL); hbm = CreateCompatibleBitmap(tempDC3, 16, 16); obmp = (HBITMAP)SelectObject(tempDC2, nMask); obmp2 = (HBITMAP)SelectObject(tempDC3, hbm); DrawIconEx(tempDC2, 0, 0, hBottom, 16, 16, 0, NULL, DI_MASK); DrawIconEx(tempDC3, 0, 0, hTop, 16, 16, 0, NULL, DI_MASK); BitBlt(tempDC2, 0, 0, 16, 16, tempDC3, 0, 0, SRCAND); GdiFlush(); SelectObject(tempDC2, obmp); DeleteDC(tempDC2); SelectObject(tempDC3, obmp2); DeleteDC(tempDC3); SelectObject(tempDC, oImage); DeleteDC(tempDC); DeleteObject(hbm); iNew.fIcon = TRUE; iNew.hbmColor = nImage; iNew.hbmMask = nMask; res = CreateIconIndirect(&iNew); DeleteObject(nImage); DeleteObject(nMask); return res; } HANDLE FASTCALL GetIconIndexFromFI(LPTSTR szMirVer) { int i; DWORD val; HANDLE hFoundImage = INVALID_HANDLE_VALUE; short base, overlay, overlay2, overlay3; GetIconsIndexes(szMirVer, &base, &overlay, &overlay2, &overlay3); if(base == -1 || nFICount == 0xFF) return hFoundImage; // MAX: 1024 + 256 + 128 + 128 val = (base << 22) | ((overlay & 0xFF) << 14) | ((overlay2 & 0x7F) << 7) | (overlay3 & 0x7F); for(i = 0; i < nFICount; i++) { if(fiList[i].dwArray == val) { hFoundImage = fiList[i].hRegisteredImage; break; } } if(hFoundImage == INVALID_HANDLE_VALUE && i == nFICount) //not found - then add { HICON hIcon = CreateIconFromIndexes(base, overlay, overlay2, overlay3); fiList = (FOUNDINFO*)mir_realloc(fiList, sizeof(FOUNDINFO) * (nFICount + 1)); fiList[nFICount].dwArray = val; if(hIcon != NULL) { fiList[nFICount].hRegisteredImage = (hIcon) ? (HANDLE)CallService(MS_CLIST_EXTRA_ADD_ICON, (WPARAM)hIcon, 0) : INVALID_HANDLE_VALUE; hFoundImage = fiList[nFICount].hRegisteredImage; DestroyIcon(hIcon); } else { fiList[nFICount].hRegisteredImage = INVALID_HANDLE_VALUE; } nFICount++; } return hFoundImage; } VOID FASTCALL ClearFI() { if(fiList != NULL) mir_free(fiList); fiList = NULL; nFICount = 0; return; }