/* Splash Screen Plugin for Miranda-IM (www.miranda-im.org) (c) 2004-2007 nullbie, (c) 2005-2007 Thief 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 File name : $URL: http://svn.miranda.im/mainrepo/splashscreen/trunk/src/main.cpp $ Revision : $Rev: 1586 $ Last change on : $Date: 2010-04-09 12:34:01 +0300 (Пт, 09 апр 2010) $ Last change by : $Author: Thief $ */ #include "headers.h" HINSTANCE hInst = 0; PLUGINLINK *pluginLink; static HMODULE hUserDll = NULL; static HMODULE hAdvaimg = NULL; pfnConvertPng2dib png2dibConvertor = NULL; bool bstartup = true; // startup? bool bserviceinvoked = false; bool bmodulesloaded = false; // modules are loaded bool png2dibavail = true; // can we use png2dib service? char *mirandaVerString; char szPrefix[128]; PVOID pVerInfo; // path to miranda's dir, config file path, splash path, sound path char szMirDir[MAX_PATH], szIniFile[MAX_PATH], szDllName[MAX_PATH], szSplashFile[MAX_PATH], szSoundFile [MAX_PATH], szhAdvaimgPath [MAX_PATH]; #ifdef _DEBUG char szLogFile[MAX_PATH]; #endif static char inBuf[80]; SPLASHOPTS options; // Options handle. Declarated in options.cpp extern BOOL CALLBACK DlgProcOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); extern int OptInit(WPARAM wParam, LPARAM lParam); extern bool ShowSplash(bool bpreview); extern void ReadIniConfig(); HANDLE hShowSplashService, hTestService; // Service functions declarated in service.cpp extern int ShowSplashService(WPARAM wparam,LPARAM lparam); #ifdef _DEBUG extern int TestService(WPARAM wParam,LPARAM lParam); #endif extern BOOL (WINAPI *MyUpdateLayeredWindow) (HWND hwnd, HDC hdcDST, POINT *pptDst, SIZE *psize, HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend, DWORD dwFlags); extern HWND hwndSplash; PLUGININFOEX pluginInfo={ sizeof(PLUGININFOEX), #ifndef _DEBUG "Splash Screen", #else "Splash Screen (Debug)", #endif __VERSION_DWORD, "Shows a splash at Miranda startup", "nullbie, Thief", "thief@miranda.im", "2004-2007 Victor Pavlychko, 2005-2010 Alexander Turyak ["BuildDate"]", "http://addons.miranda-im.org/details.php?id=2624", 0, //not transient 0, //doesn't replace anything built-in {0xc64cc8e0, 0xcf03, 0x474a, {0x8b, 0x11, 0x8b, 0xd4, 0x56, 0x5c, 0xcf, 0x04}} /* C64CC8E0-CF03-474A-8B11-8BD4565CC */ }; PLUGININFO oldpluginInfo={ sizeof(PLUGININFO), pluginInfo.shortName, pluginInfo.version, pluginInfo.description, pluginInfo.author, pluginInfo.authorEmail, pluginInfo.copyright, pluginInfo.homepage, pluginInfo.flags, pluginInfo.replacesDefaultModule }; /* 91CB1E8D-C33C-43C0-BDD8-6725B070B3E0 */ #define MIID_SPLASHSCREEN {0x91cb1e8d, 0xc33c, 0x43c0, {0xbd, 0xd8, 0x67, 0x25, 0xb0, 0x70, 0xb3, 0xe0}} extern "C" __declspec(dllexport) const MUUID* MirandaPluginInterfaces(void) { static const MUUID interfaces[] = {MIID_SPLASHSCREEN, MIID_LAST}; return interfaces; } HANDLE hSplashThread, hModulesLoaded, hPlugDisableHook, hOptInit, hSystemOKToExit; LRESULT CALLBACK SplashWindowProc(HWND, UINT, WPARAM, LPARAM); int ModulesLoaded(WPARAM wParam,LPARAM lParam); int PlugDisableHook(WPARAM wParam,LPARAM lParam); int onSystemOKToExit(WPARAM wParam,LPARAM lParam); extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { hInst = hinstDLL; return TRUE; } void SplashMain() { if (bstartup) { DWORD unused; DWORD verInfoSize; UINT blockSize; // Retrive path to exe of current running Miranda is located GetModuleFileName(GetModuleHandle(NULL), szMirDir, sizeof(szMirDir)); verInfoSize = GetFileVersionInfoSizeA(szMirDir,&unused); pVerInfo = /*mir_*/malloc(verInfoSize); GetFileVersionInfoA(szMirDir,0,verInfoSize,pVerInfo); VerQueryValueA(pVerInfo,"\\StringFileInfo\\000004b0\\ProductVersion",(PVOID*)&mirandaVerString,&blockSize); // Remove 'miranda32.exe' from string char *pos; pos = strrchr(szMirDir, '\\'); if(pos != NULL) *pos = 0; lstrcat(szMirDir,"\\"); // Get the name string of plugin's dll name whatever it named static char* sztmpstr; GetModuleFileName(hInst, szDllName, sizeof(szDllName)); sztmpstr = _strrev(szDllName); pos = strchr(sztmpstr, '\\'); if(pos != NULL) *pos = 0; strcpy(szDllName, _strrev(sztmpstr)); static char szPath[MAX_PATH]; lstrcat(szPath,szMirDir); lstrcat(szPath,"plugins\\splash.ini"); lstrcat(szhAdvaimgPath,szMirDir); lstrcat(szhAdvaimgPath,"plugins\\advaimg.dll"); #ifdef _DEBUG lstrcat(szLogFile,szMirDir); lstrcat(szLogFile,PlugName); lstrcat(szLogFile,".log"); #endif #ifdef _DEBUG initLog(); logTimeStamp(); #endif #ifdef _DEBUG logMessage("Miranda version", mirandaVerString); #endif static char szMirandaBootIni[MAX_PATH]; lstrcat(szMirandaBootIni,szMirDir); lstrcat(szMirandaBootIni,"mirandaboot.ini"); GetPrivateProfileString("Splash","Ini","",inBuf,sizeof(inBuf),szMirandaBootIni); if (strlen(inBuf)) { char szExpandedIniPath[MAX_PATH]; ExpandEnvironmentStringsA(inBuf, szExpandedIniPath,sizeof(szExpandedIniPath)); lstrcat(szIniFile,szExpandedIniPath); } else { FILE *fp; fp = fopen(szPath, "r"); if (!fp) { #ifdef _DEBUG logMessage("error! couldn't open", szPath); #endif lstrcat(szIniFile,szMirDir); lstrcat(szIniFile,"mirandaboot.ini"); } else { lstrcat(szIniFile,szPath); fclose(fp); } } ReadIniConfig(); #ifdef _DEBUG logMessage("Dll Name", szDllName); logMessage("Ini path",szIniFile); logMessage("Advaimg path", szhAdvaimgPath); #endif } if (bstartup & (options.active == 1)) { if (options.runonce) { WritePrivateProfileString("Splash","Active","0",szIniFile); WritePrivateProfileString("Splash","DisableAfterStartup","0",szIniFile); } if (hUserDll == NULL) { hUserDll = LoadLibrary("user32.dll"); if (hUserDll) { MyUpdateLayeredWindow = (BOOL (WINAPI *)(HWND, HDC, POINT *, SIZE *, HDC, POINT *, COLORREF, BLENDFUNCTION *, DWORD))GetProcAddress(hUserDll, "UpdateLayeredWindow"); } } if (hAdvaimg == NULL) { hAdvaimg = LoadLibrary(szhAdvaimgPath); if (hAdvaimg == NULL) { png2dibavail = false; bstartup = false; } if (hAdvaimg) { png2dibConvertor = (pfnConvertPng2dib) GetProcAddress(hAdvaimg, "mempng2dib"); if (png2dibConvertor == NULL) { FreeLibrary(hAdvaimg); hAdvaimg = NULL; MessageBoxA(NULL, "Your advaimg.dll is either obsolete or damaged. Get latest from Miranda alpha builds.", "Error", MB_OK | MB_ICONSTOP); } #ifdef _DEBUG if (png2dibConvertor) logMessage("Loading advaimg","done"); #endif } } //for 9x "alfa" testing //MyUpdateLayeredWindow = 0; GetPrivateProfileString("Splash","VersionPrefix","",inBuf,sizeof(inBuf),szIniFile); strcpy(szPrefix,inBuf); GetPrivateProfileString("Splash","Path","splash\\splash.png",inBuf,sizeof(inBuf),szIniFile); char szExpandedSplashFile[MAX_PATH]; ExpandEnvironmentStringsA(inBuf, szExpandedSplashFile,sizeof(szExpandedSplashFile)); lstrcpy(inBuf, szExpandedSplashFile); char *pos3 = 0; pos3 = strrchr(inBuf, ':'); if (pos3 == NULL) { lstrcpy(szSplashFile, szMirDir); } lstrcat(szSplashFile, inBuf); GetPrivateProfileString("Splash","Sound","sounds\\startup.wav",inBuf,sizeof(inBuf),szIniFile); char szExpandedSoundFile[MAX_PATH]; ExpandEnvironmentStringsA(inBuf, szExpandedSoundFile,sizeof(szExpandedSoundFile)); lstrcpy(inBuf, szExpandedSoundFile); char *pos2; pos2 = strchr(inBuf, ':'); if (pos2 == NULL) { lstrcat(szSoundFile, szMirDir); } lstrcat(szSoundFile, inBuf); #ifdef _DEBUG logMessage("SoundFilePath",szSoundFile); #endif char szOldPath[MAX_PATH] = {0}; if(options.random) // randomly select a splash file { int filescount = 0; char szSplashDir[MAX_PATH] = {0}, szSearch[MAX_PATH] = {0}; char* p = 0; char files [255][50]; //TODO: make memory allocation dynamic lstrcpy(szSplashDir, szSplashFile); lstrcpy(szOldPath, szSplashFile); // find the last \ and null it out, this leaves no trailing slash p = strrchr(szSplashDir, '\\'); if (p) *p = 0; // create the search filter mir_snprintf(szSearch,sizeof(szSearch),"%s\\*.*", szSplashDir); // FFFN will return filenames HANDLE hFind = INVALID_HANDLE_VALUE; WIN32_FIND_DATAA ffd; hFind = FindFirstFileA(szSearch, &ffd); if ( hFind != INVALID_HANDLE_VALUE ) { do { if (!(ffd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)) { #ifdef _DEBUG logMessage("Found file",ffd.cFileName); #endif //files = new char[strlen(ffd.cFileName)]; //files[filescount] = new char[strlen(ffd.cFileName)]; char ext[5]; memcpy(ext,ffd.cFileName+(strlen(ffd.cFileName)-4),5); #ifdef _DEBUG logMessage("Extention",ext); #endif if (lstrcmpi(ext,".png") & lstrcmpi(ext,".bmp")) continue; #ifdef _DEBUG logMessage("File has valid ext",ext); #endif strcpy(files[filescount++],ffd.cFileName); } //if } while (FindNextFileA(hFind, &ffd)); srand((unsigned) time(NULL)); int r = 0; if (filescount) r = (rand() % filescount) + 1; ZeroMemory(&szSplashFile,sizeof(szSplashFile)); lstrcpy(szSplashFile, szSplashDir); lstrcat(szSplashFile,"\\"); lstrcat(szSplashFile,files[r-1]); #ifdef _DEBUG logMessage("final file",szSplashFile); #endif FindClose(hFind); } //if } // Call splash display routine ShowSplash(false); if (options.random) { ZeroMemory(&szSplashFile,sizeof(szSplashFile)); lstrcpy(szSplashFile, szOldPath); } } bstartup = false; } extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) { SplashMain(); return &pluginInfo; } extern "C" __declspec(dllexport) PLUGININFO* MirandaPluginInfo(DWORD mirandaVersion) { SplashMain(); return &oldpluginInfo; } extern "C" int __declspec(dllexport) Load(PLUGINLINK *link) { pluginLink = link; hModulesLoaded = HookEvent(ME_SYSTEM_MODULESLOADED, ModulesLoaded); hSystemOKToExit = HookEvent(ME_SYSTEM_OKTOEXIT,onSystemOKToExit); return 0; } extern "C" int __declspec(dllexport) Unload(void) { free(pVerInfo); if (hSplashThread) CloseHandle(hSplashThread); UnregisterClass(SPLASH_CLASS, hInst); // Freeing loaded libraries if (hUserDll) FreeLibrary(hUserDll); if (hAdvaimg) FreeLibrary(hAdvaimg); #ifdef _DEBUG logMessage("Unload","Job done"); #endif return 0; } int onSystemOKToExit(WPARAM wParam,LPARAM lParam) { // Hooked events need to be unhooked UnhookEvent(hModulesLoaded); UnhookEvent(hSystemOKToExit); UnhookEvent(hPlugDisableHook); UnhookEvent(hOptInit); DestroyServiceFunction(hShowSplashService); #ifdef _DEBUG DestroyServiceFunction(hTestService); #endif return 0; } int ModulesLoaded(WPARAM wParam, LPARAM lParam) { bmodulesloaded = true; // all modules are loaded now, let other parts know about this fact if (hwndSplash) { if (PostMessage(hwndSplash, WM_LOADED, 0, 0)) { #ifdef _DEBUG logMessage("Posted WM_LOADED message","done"); #endif } } // Options initialize hook hOptInit = HookEvent(ME_OPT_INITIALISE, OptInit); hPlugDisableHook = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, PlugDisableHook); // Service to call splash hShowSplashService = CreateServiceFunction(MS_SHOWSPLASH, ShowSplashService); #ifdef _DEBUG hTestService = CreateServiceFunction("Splash/Test",TestService); CLISTMENUITEM mi; ZeroMemory(&mi,sizeof(mi)); mi.cbSize = sizeof(mi); mi.flags = 0; mi.hIcon = LoadSkinnedIcon(SKINICON_OTHER_MIRANDA); mi.hotKey = 0; mi.position = -0x7FFFFFFF; mi.pszName = "Call Splash Service"; mi.pszService = "Splash/Test"; CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi); #endif if (ServiceExists(MS_UPDATE_REGISTER)) { // register with updater Update update = {0}; char szVersion[16]; update.cbSize = sizeof(Update); update.szComponentName = pluginInfo.shortName; update.pbVersion = (BYTE *)CreateVersionString(pluginInfo.version, szVersion); update.cpbVersion = strlen((char *)update.pbVersion); update.szUpdateURL = UPDATER_AUTOREGISTER; // these are the three lines that matter - the archive, the page containing the version string, and the text (or data) // before the version that we use to locate it on the page // (note that if the update URL and the version URL point to standard file listing entries, the backend xml // data will be used to check for updates rather than the actual web page - this is not true for beta urls) update.szBetaUpdateURL = "http://thief.miranda.im/advsplashscreen.zip"; update.szBetaVersionURL = "http://thief.miranda.im/updater/splash_version.txt"; update.szBetaChangelogURL = "http://thief.miranda.im"; update.pbBetaVersionPrefix = (BYTE *)"Splash Screen "; update.cpbBetaVersionPrefix = strlen((char *)update.pbBetaVersionPrefix); CallService(MS_UPDATE_REGISTER, 0, (WPARAM)&update); } #ifdef _DEBUG logMessage("Loading modules","done"); #endif return 0; } int PlugDisableHook(WPARAM wParam, LPARAM lParam) { char buf [128]; DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING*)lParam; if(options.inheritGS) if (!lstrcmp(cws->szModule,"Skin") & !lstrcmp(cws->szSetting,"UseSound")) { sprintf(buf,"%d",cws->value.bVal); WritePrivateProfileString("Splash","PlaySound",buf,szIniFile); #ifdef _DEBUG cws->value.bVal ? _DebugPopup(NULL, "Sounds enabled.", "") : _DebugPopup(NULL, "Sounds disabled.", ""); logMessage("Module",cws->szModule); logMessage("Setting",cws->szSetting); logMessage("Value",buf); #endif } if (!lstrcmp(cws->szModule,"PluginDisable") & (!lstrcmp(cws->szSetting,szDllName))) { sprintf(buf,"%d",!cws->value.bVal); WritePrivateProfileString("Splash","Active",buf,szIniFile); #ifdef _DEBUG cws->value.bVal ? _DebugPopup(NULL, "Disabled.", "") : _DebugPopup(NULL, "Enabled.", ""); logMessage("PlugDisableHook","Triggered"); logMessage("Module",cws->szModule); logMessage("Setting",cws->szSetting); logMessage("Value",buf); #endif } return 0; }