/* Miranda IM: the free IM client for Microsoft* Windows* Copyright 2000-12 Miranda IM, 2012-13 Miranda NG project, all portions of this codebase are copyrighted to the people listed in contributors.txt. 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. */ #include "commonheaders.h" #define MMI_SIZE_V1 (4*sizeof(void*)) #define MMI_SIZE_V2 (7*sizeof(void*)) int LoadDefaultModules(void); void UnloadNewPluginsModule(void); void UnloadDefaultModules(void); pfnDrawThemeTextEx drawThemeTextEx; pfnSetWindowThemeAttribute setWindowThemeAttribute; pfnBufferedPaintInit bufferedPaintInit; pfnBufferedPaintUninit bufferedPaintUninit; pfnBeginBufferedPaint beginBufferedPaint; pfnEndBufferedPaint endBufferedPaint; pfnGetBufferedPaintBits getBufferedPaintBits; pfnDwmExtendFrameIntoClientArea dwmExtendFrameIntoClientArea; pfnDwmIsCompositionEnabled dwmIsCompositionEnabled; ITaskbarList3 * pTaskbarInterface; HANDLE hOkToExitEvent, hModulesLoadedEvent; HANDLE hShutdownEvent, hPreShutdownEvent; static HANDLE hWaitObjects[MAXIMUM_WAIT_OBJECTS-1]; static char *pszWaitServices[MAXIMUM_WAIT_OBJECTS-1]; static int waitObjectCount = 0; HANDLE hMirandaShutdown; HINSTANCE hInst; DWORD hMainThreadId; int hLangpack = 0; bool bModulesLoadedFired = false; ///////////////////////////////////////////////////////////////////////////////////////// // exception handling static INT_PTR srvGetExceptionFilter(WPARAM, LPARAM) { return (INT_PTR)GetExceptionFilter(); } static INT_PTR srvSetExceptionFilter(WPARAM, LPARAM lParam) { return (INT_PTR)SetExceptionFilter((pfnExceptionFilter)lParam); } ///////////////////////////////////////////////////////////////////////////////////////// typedef LONG (WINAPI *pNtQIT)(HANDLE, LONG, PVOID, ULONG, PULONG); #define ThreadQuerySetWin32StartAddress 9 INT_PTR MirandaIsTerminated(WPARAM, LPARAM) { return WaitForSingleObject(hMirandaShutdown, 0) == WAIT_OBJECT_0; } static void __cdecl compactHeapsThread(void*) { Thread_SetName("compactHeapsThread"); while ( !Miranda_Terminated()) { HANDLE hHeaps[256]; DWORD hc; SleepEx((1000*60)*5, TRUE); // every 5 minutes hc = GetProcessHeaps(255, (PHANDLE)&hHeaps); if (hc != 0 && hc < 256) { DWORD j; for (j = 0; j < hc; j++) HeapCompact(hHeaps[j], 0); } } //while } void (*SetIdleCallback) (void) = NULL; static INT_PTR SystemSetIdleCallback(WPARAM, LPARAM lParam) { if (lParam && SetIdleCallback == NULL) { SetIdleCallback = (void (*)(void))lParam; return 1; } return 0; } static DWORD dwEventTime = 0; void checkIdle(MSG * msg) { switch(msg->message) { case WM_MOUSEACTIVATE: case WM_MOUSEMOVE: case WM_CHAR: dwEventTime = GetTickCount(); } } static INT_PTR SystemGetIdle(WPARAM, LPARAM lParam) { if (lParam) *(DWORD*)lParam = dwEventTime; return 0; } static int SystemShutdownProc(WPARAM, LPARAM) { UnloadDefaultModules(); return 0; } #define MIRANDA_PROCESS_WAIT_TIMEOUT 60000 #define MIRANDA_PROCESS_WAIT_RESOLUTION 1000 #define MIRANDA_PROCESS_WAIT_STEPS (MIRANDA_PROCESS_WAIT_TIMEOUT/MIRANDA_PROCESS_WAIT_RESOLUTION) static INT_PTR CALLBACK WaitForProcessDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_INITDIALOG: TranslateDialogDefault(hwnd); SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam); SendDlgItemMessage(hwnd, IDC_PROGRESSBAR, PBM_SETRANGE, 0, MAKELPARAM(0, MIRANDA_PROCESS_WAIT_STEPS)); SendDlgItemMessage(hwnd, IDC_PROGRESSBAR, PBM_SETSTEP, 1, 0); SetTimer(hwnd, 1, MIRANDA_PROCESS_WAIT_RESOLUTION, NULL); break; case WM_TIMER: if ( SendDlgItemMessage(hwnd, IDC_PROGRESSBAR, PBM_STEPIT, 0, 0) == MIRANDA_PROCESS_WAIT_STEPS) EndDialog(hwnd, 0); if ( WaitForSingleObject((HANDLE)GetWindowLongPtr(hwnd, GWLP_USERDATA), 1) != WAIT_TIMEOUT) { SendDlgItemMessage(hwnd, IDC_PROGRESSBAR, PBM_SETPOS, MIRANDA_PROCESS_WAIT_STEPS, 0); EndDialog(hwnd, 0); } break; case WM_COMMAND: if ( LOWORD(wParam) == IDCANCEL) { SendDlgItemMessage(hwnd, IDC_PROGRESSBAR, PBM_SETPOS, MIRANDA_PROCESS_WAIT_STEPS, 0); EndDialog(hwnd, 1); } break; } return FALSE; } int CheckRestart() { int result = 0; LPCTSTR tszPID = CmdLine_GetOption( _T("restart")); if (tszPID) { HANDLE hProcess = OpenProcess(SYNCHRONIZE, FALSE, _ttol(tszPID)); if (hProcess) { result = DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_WAITRESTART), NULL, WaitForProcessDlgProc, (LPARAM)hProcess); CloseHandle(hProcess); } } return result; } static void crtErrorHandler(const wchar_t*, const wchar_t*, const wchar_t*, unsigned, uintptr_t) { } int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE, LPTSTR cmdLine, int) { hInst = hInstance; hMainThreadId = GetCurrentThreadId(); _set_invalid_parameter_handler(&crtErrorHandler); #ifdef _DEBUG _CrtSetReportMode(_CRT_ASSERT, 0); #endif CmdLine_Parse(cmdLine); setlocale(LC_ALL, ""); #ifdef _DEBUG if ( CmdLine_GetOption( _T("memdebug"))) _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); #endif if ( IsWinVerVistaPlus()) { HINSTANCE hDwmApi = LoadLibraryA("dwmapi.dll"); if (hDwmApi) { dwmExtendFrameIntoClientArea = (pfnDwmExtendFrameIntoClientArea)GetProcAddress(hDwmApi, "DwmExtendFrameIntoClientArea"); dwmIsCompositionEnabled = (pfnDwmIsCompositionEnabled)GetProcAddress(hDwmApi, "DwmIsCompositionEnabled"); } HINSTANCE hThemeAPI = LoadLibraryA("uxtheme.dll"); if (hThemeAPI) { drawThemeTextEx = (pfnDrawThemeTextEx)GetProcAddress(hThemeAPI, "DrawThemeTextEx"); setWindowThemeAttribute = (pfnSetWindowThemeAttribute)GetProcAddress(hThemeAPI, "SetWindowThemeAttribute"); bufferedPaintInit = (pfnBufferedPaintInit)GetProcAddress(hThemeAPI, "BufferedPaintInit"); bufferedPaintUninit = (pfnBufferedPaintUninit)GetProcAddress(hThemeAPI, "BufferedPaintUninit"); beginBufferedPaint = (pfnBeginBufferedPaint)GetProcAddress(hThemeAPI, "BeginBufferedPaint"); endBufferedPaint = (pfnEndBufferedPaint)GetProcAddress(hThemeAPI, "EndBufferedPaint"); getBufferedPaintBits = (pfnGetBufferedPaintBits)GetProcAddress(hThemeAPI, "GetBufferedPaintBits"); } } if (bufferedPaintInit) bufferedPaintInit(); OleInitialize(NULL); if ( IsWinVer7Plus()) CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_ALL, IID_ITaskbarList3, (void**)&pTaskbarInterface); int result = 0; if ( LoadDefaultModules()) { SetEvent(hMirandaShutdown); NotifyEventHooks(hPreShutdownEvent, 0, 0); NotifyEventHooks(hShutdownEvent, 0, 0); UnloadDefaultModules(); result = 1; goto exit; } NotifyEventHooks(hModulesLoadedEvent, 0, 0); bModulesLoadedFired = true; // ensure that the kernel hooks the SystemShutdownProc() after all plugins HookEvent(ME_SYSTEM_SHUTDOWN, SystemShutdownProc); forkthread(compactHeapsThread, 0, NULL); CreateServiceFunction(MS_SYSTEM_SETIDLECALLBACK, SystemSetIdleCallback); CreateServiceFunction(MS_SYSTEM_GETIDLE, SystemGetIdle); dwEventTime = GetTickCount(); DWORD myPid = GetCurrentProcessId(); bool messageloop = true; while (messageloop) { MSG msg; DWORD rc; BOOL dying = FALSE; rc = MsgWaitForMultipleObjectsEx(waitObjectCount, hWaitObjects, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE); if (rc >= WAIT_OBJECT_0 && rc < WAIT_OBJECT_0 + waitObjectCount) { rc -= WAIT_OBJECT_0; CallService(pszWaitServices[rc], (WPARAM) hWaitObjects[rc], 0); } // while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message != WM_QUIT) { HWND h = GetForegroundWindow(); DWORD pid = 0; checkIdle(&msg); if (h != NULL && GetWindowThreadProcessId(h, &pid) && pid == myPid && GetClassLongPtr(h, GCW_ATOM) == 32770) if (IsDialogMessage(h, &msg)) continue; TranslateMessage(&msg); DispatchMessage(&msg); if (SetIdleCallback != NULL) SetIdleCallback(); } else if ( !dying) { dying++; SetEvent(hMirandaShutdown); NotifyEventHooks(hPreShutdownEvent, 0, 0); // this spins and processes the msg loop, objects and APC. Thread_Wait(); NotifyEventHooks(hShutdownEvent, 0, 0); // if the hooks generated any messages, it'll get processed before the second WM_QUIT PostQuitMessage(0); } else if (dying) messageloop = false; } } exit: UnloadNewPluginsModule(); UnloadCoreModule(); CloseHandle(hMirandaShutdown); if (pTaskbarInterface) pTaskbarInterface->Release(); OleUninitialize(); if (bufferedPaintUninit) bufferedPaintUninit(); return result; } static INT_PTR OkToExit(WPARAM, LPARAM) { return NotifyEventHooks(hOkToExitEvent, 0, 0) == 0; } static INT_PTR GetMirandaVersion(WPARAM, LPARAM) { TCHAR filename[MAX_PATH]; GetModuleFileName(NULL, filename, SIZEOF(filename)); DWORD unused, verInfoSize = GetFileVersionInfoSize(filename, &unused); PVOID pVerInfo = _alloca(verInfoSize); GetFileVersionInfo(filename, 0, verInfoSize, pVerInfo); UINT blockSize; VS_FIXEDFILEINFO *vsffi; VerQueryValue(pVerInfo, _T("\\"), (PVOID*)&vsffi, &blockSize); DWORD ver = (((vsffi->dwProductVersionMS>>16)&0xFF)<<24)| ((vsffi->dwProductVersionMS&0xFF)<<16)| (((vsffi->dwProductVersionLS>>16)&0xFF)<<8)| (vsffi->dwProductVersionLS&0xFF); return (INT_PTR)ver; } static INT_PTR GetMirandaFileVersion(WPARAM, LPARAM lParam) { TCHAR filename[MAX_PATH]; GetModuleFileName(NULL, filename, SIZEOF(filename)); DWORD unused, verInfoSize = GetFileVersionInfoSize(filename, &unused); PVOID pVerInfo = _alloca(verInfoSize); GetFileVersionInfo(filename, 0, verInfoSize, pVerInfo); UINT blockSize; VS_FIXEDFILEINFO *vsffi; VerQueryValue(pVerInfo, _T("\\"), (PVOID*)&vsffi, &blockSize); WORD* p = (WORD*)lParam; p[0] = HIWORD(vsffi->dwProductVersionMS); p[1] = LOWORD(vsffi->dwProductVersionMS); p[2] = HIWORD(vsffi->dwProductVersionLS); p[3] = LOWORD(vsffi->dwProductVersionLS); return 0; } static INT_PTR GetMirandaVersionText(WPARAM wParam, LPARAM lParam) { TCHAR filename[MAX_PATH], *productVersion; GetModuleFileName(NULL, filename, SIZEOF(filename)); DWORD unused, verInfoSize = GetFileVersionInfoSize(filename, &unused); PVOID pVerInfo = _alloca(verInfoSize); GetFileVersionInfo(filename, 0, verInfoSize, pVerInfo); UINT blockSize; VerQueryValue(pVerInfo, _T("\\StringFileInfo\\000004b0\\ProductVersion"), (LPVOID*)&productVersion, &blockSize); strncpy((char*)lParam, _T2A(productVersion), wParam); #if defined(_WIN64) strcat_s((char*)lParam, wParam, " x64"); #endif return 0; } INT_PTR WaitOnHandle(WPARAM wParam, LPARAM lParam) { if (waitObjectCount >= MAXIMUM_WAIT_OBJECTS-1) return 1; hWaitObjects[waitObjectCount] = (HANDLE)wParam; pszWaitServices[waitObjectCount] = (char*)lParam; waitObjectCount++; return 0; } static INT_PTR RemoveWait(WPARAM wParam, LPARAM) { int i; for (i=0;i