summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/commonheaders.cpp2
-rw-r--r--src/core/commonheaders.h102
-rw-r--r--src/core/forkthread.h63
-rw-r--r--src/core/memory.cpp280
-rw-r--r--src/core/miranda.cpp941
-rw-r--r--src/core/miranda.h370
-rw-r--r--src/core/modules.cpp784
-rw-r--r--src/core/modules.h268
8 files changed, 2810 insertions, 0 deletions
diff --git a/src/core/commonheaders.cpp b/src/core/commonheaders.cpp
new file mode 100644
index 0000000000..95b2201163
--- /dev/null
+++ b/src/core/commonheaders.cpp
@@ -0,0 +1,2 @@
+#include "commonheaders.h"
+
diff --git a/src/core/commonheaders.h b/src/core/commonheaders.h
new file mode 100644
index 0000000000..8aec3a5dc5
--- /dev/null
+++ b/src/core/commonheaders.h
@@ -0,0 +1,102 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM 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.
+*/
+
+// to enable all 0.9.0 core functions
+#define MIRANDA_VER 0x1000
+
+#define _ALPHA_BASE_ 1 // defined for CVS builds
+#define _ALPHA_FUSE_ 1 // defined for fuse powered core
+
+#define WINVER 0x0700
+#define _WIN32_WINNT 0x0700
+#define _WIN32_IE 0x0601
+
+#include "m_stdhdr.h"
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <windows.h>
+#include <windowsx.h>
+#include <shlobj.h>
+#include <uxtheme.h>
+#include <commctrl.h>
+#include <vssym32.h>
+
+#include <stdio.h>
+#include <time.h>
+#include <stddef.h>
+#include <process.h>
+#include <io.h>
+#include <limits.h>
+#include <string.h>
+#include <locale.h>
+#include <direct.h>
+
+#include <win2k.h>
+
+#include "modules.h"
+
+#include <m_system.h>
+#include <m_system_cpp.h>
+#include <newpluginapi.h>
+#include <m_database.h>
+#include <m_clc.h>
+#include <m_clui.h>
+#include <m_crypto.h>
+#include <m_langpack.h>
+#include <m_clist.h>
+#include <m_clistint.h>
+#include <m_avatars.h>
+#include <m_button.h>
+#include <m_protosvc.h>
+#include <m_protomod.h>
+#include <m_protocols.h>
+#include <m_protoint.h>
+#include <m_plugins.h>
+#include <m_options.h>
+#include <m_skin.h>
+#include <m_contacts.h>
+#include <m_message.h>
+#include <m_userinfo.h>
+#include <m_history.h>
+#include <m_addcontact.h>
+#include <m_findadd.h>
+#include <m_file.h>
+#include <m_email.h>
+#include <m_awaymsg.h>
+#include <m_idle.h>
+#include <m_ignore.h>
+#include <m_icolib.h>
+#include <m_modernopt.h>
+#include <m_help.h>
+#include <m_timezones.h>
+
+#include "forkthread.h"
+#include "miranda.h"
+#include "../modules/database/dblists.h"
+
+#include <m_ssl.h>
+#include <m_netlib.h>
+#include <m_xml.h>
+
+#include "../resource.h" \ No newline at end of file
diff --git a/src/core/forkthread.h b/src/core/forkthread.h
new file mode 100644
index 0000000000..d920b7867e
--- /dev/null
+++ b/src/core/forkthread.h
@@ -0,0 +1,63 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM 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.
+*/
+
+/*
+
+Purpose:
+
+ A safe version of _beginthread()
+
+Description:
+
+ A new thread is created and the source thread is paused until
+ internal code to call MS_SYSTEM_THREAD_PUSH is made in the context
+ if the new thread.
+
+ The source thread is then released and then the user supplied
+ code is called, when that function returns -- MS_SYSTEM_THREAD_POP
+ is called and then the thread returns.
+
+ This insures that Miranda will not exit whilst new threads
+ are trying to be born; and the unwind wait stack will unsure
+ that Miranda will wait for all created threads to return as well.
+
+Cavets:
+
+ The function must be reimplemented across MT plugins, since thread
+ creation depends on CRT which can not be shared.
+
+*/
+UINT_PTR forkthread (
+ void (__cdecl *threadcode)(void*),
+ unsigned long stacksize,
+ void *arg
+);
+
+UINT_PTR forkthreadex(
+ void *sec,
+ unsigned stacksize,
+ unsigned (__stdcall *threadcode)(void*),
+ void *owner,
+ void *arg,
+ unsigned *thraddr
+);
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
new file mode 100644
index 0000000000..04252e1c34
--- /dev/null
+++ b/src/core/memory.cpp
@@ -0,0 +1,280 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM 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 BLOCK_ALLOCED 0xABBABABA
+#define BLOCK_FREED 0xDEADBEEF
+
+static int CheckBlock( void* blk )
+{
+ int result = FALSE;
+ char* p = ( char* )blk - sizeof(DWORD)*2;
+ DWORD size, *b, *e;
+
+ __try
+ {
+ size = *( DWORD* )p;
+ b = ( DWORD* )&p[ sizeof( DWORD ) ];
+ e = ( DWORD* )&p[ sizeof( DWORD )*2 + size ];
+
+ if ( *b != BLOCK_ALLOCED || *e != BLOCK_ALLOCED )
+ {
+ if ( *b == BLOCK_FREED && *e == BLOCK_FREED )
+ OutputDebugStringA( "memory block is already deleted\n" );
+ else
+ OutputDebugStringA( "memory block is corrupted\n" );
+ #if defined( _DEBUG )
+ DebugBreak();
+ #endif
+ }
+ else result = TRUE;
+ }
+ __except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ OutputDebugStringA( "access violation during checking memory block\n" );
+ #if defined( _DEBUG )
+ DebugBreak();
+ #endif
+ }
+
+ return result;
+}
+
+/******************************************************************************/
+
+void* mir_alloc( size_t size )
+{
+ if ( size == 0 )
+ return NULL;
+ {
+ char* p = (char*)malloc( size + sizeof(DWORD)*3 );
+ if ( p == NULL ) {
+ OutputDebugStringA( "memory overflow\n" );
+ #if defined( _DEBUG )
+ DebugBreak();
+ #endif
+ return NULL;
+ }
+
+ *( DWORD* )p = ( DWORD )size;
+ *( DWORD* )&p[ sizeof(DWORD) ] = BLOCK_ALLOCED;
+ *( DWORD* )&p[ size + sizeof(DWORD)*2 ] = BLOCK_ALLOCED;
+ return p + sizeof( DWORD )*2;
+} }
+
+/******************************************************************************/
+
+void* mir_calloc( size_t size )
+{
+ void* p = mir_alloc( size );
+ if ( p != NULL )
+ memset( p, 0, size );
+ return p;
+}
+
+/******************************************************************************/
+
+void* mir_realloc( void* ptr, size_t size )
+{
+ char* p;
+
+ if ( ptr != NULL ) {
+ if ( !CheckBlock( ptr ))
+ return NULL;
+ p = ( char* )ptr - sizeof(DWORD)*2;
+ }
+ else p = NULL;
+
+ p = ( char* )realloc( p, size + sizeof(DWORD)*3 );
+ if ( p == NULL ) {
+ OutputDebugStringA( "memory overflow\n" );
+ #if defined( _DEBUG )
+ DebugBreak();
+ #endif
+ return NULL;
+ }
+
+ *( DWORD* )p = ( DWORD )size;
+ *( DWORD* )&p[ sizeof(DWORD) ] = BLOCK_ALLOCED;
+ *( DWORD* )&p[ size + sizeof(DWORD)*2 ] = BLOCK_ALLOCED;
+ return p + sizeof( DWORD )*2;
+}
+
+/******************************************************************************/
+
+void mir_free( void* ptr )
+{
+ char* p;
+ DWORD size;
+
+ if ( ptr == NULL )
+ return;
+ if ( !CheckBlock( ptr ))
+ return;
+
+ p = ( char* )ptr - sizeof(DWORD)*2;
+ size = *( DWORD* )p;
+ *( DWORD* )&p[ sizeof(DWORD) ] = BLOCK_FREED;
+ *( DWORD* )&p[ size + sizeof(DWORD)*2 ] = BLOCK_FREED;
+ free( p );
+}
+
+/******************************************************************************/
+
+char* mir_strdup( const char* str )
+{
+ if ( str != NULL ) {
+ char* p = ( char* )mir_alloc( strlen( str )+1 );
+ if ( p )
+ strcpy( p, str );
+ return p;
+ }
+ return NULL;
+}
+
+/******************************************************************************/
+
+char* mir_strndup( const char* str, size_t len )
+{
+ if ( str != NULL && len != 0 ) {
+ char* p = ( char* )mir_alloc( len + 1 );
+ if ( !p ) {
+ memcpy( p, str, len );
+ p[ len ] = 0;
+ }
+ return p;
+ }
+ return NULL;
+}
+
+/******************************************************************************/
+
+WCHAR* mir_wstrdup( const WCHAR* str )
+{
+ if ( str != NULL ) {
+ WCHAR* p = ( WCHAR* )mir_alloc( sizeof( WCHAR )*( wcslen( str )+1 ));
+ if ( p )
+ wcscpy( p, str );
+ return p;
+ }
+ return NULL;
+}
+
+/******************************************************************************/
+
+int mir_snprintf(char *buffer, size_t count, const char* fmt, ...)
+{
+ va_list va;
+ int len;
+
+ va_start(va, fmt);
+ len = _vsnprintf(buffer, count-1, fmt, va);
+ va_end(va);
+ buffer[count-1] = 0;
+ return len;
+}
+
+/******************************************************************************/
+
+int mir_sntprintf(TCHAR *buffer, size_t count, const TCHAR* fmt, ...)
+{
+ va_list va;
+ int len;
+
+ va_start(va, fmt);
+ len = _vsntprintf(buffer, count-1, fmt, va);
+ va_end(va);
+ buffer[count-1] = 0;
+ return len;
+}
+
+/******************************************************************************/
+
+int mir_vsnprintf(char *buffer, size_t count, const char* fmt, va_list va)
+{
+ int len;
+
+ len = _vsnprintf(buffer, count-1, fmt, va);
+ buffer[count-1] = 0;
+ return len;
+}
+
+/******************************************************************************/
+
+int mir_vsntprintf(TCHAR *buffer, size_t count, const TCHAR* fmt, va_list va)
+{
+ int len;
+
+ len = _vsntprintf(buffer, count-1, fmt, va);
+ buffer[count-1] = 0;
+ return len;
+}
+
+/******************************************************************************/
+
+wchar_t* mir_a2u_cp( const char* src, int codepage )
+{
+ if ( src == NULL )
+ return NULL;
+
+ int cbLen = MultiByteToWideChar( codepage, 0, src, -1, NULL, 0 );
+ wchar_t* result = ( wchar_t* )mir_alloc( sizeof( wchar_t )*(cbLen+1));
+ if ( result == NULL )
+ return NULL;
+
+ MultiByteToWideChar( codepage, 0, src, -1, result, cbLen );
+ result[ cbLen ] = 0;
+ return result;
+}
+
+/******************************************************************************/
+
+wchar_t* mir_a2u( const char* src )
+{
+ return mir_a2u_cp( src, LangPackGetDefaultCodePage());
+}
+
+/******************************************************************************/
+
+char* mir_u2a_cp( const wchar_t* src, int codepage )
+{
+ if ( src == NULL )
+ return NULL;
+
+ int cbLen = WideCharToMultiByte( codepage, 0, src, -1, NULL, 0, NULL, NULL );
+ char* result = ( char* )mir_alloc( cbLen+1 );
+ if ( result == NULL )
+ return NULL;
+
+ WideCharToMultiByte( codepage, 0, src, -1, result, cbLen, NULL, NULL );
+ result[ cbLen ] = 0;
+ return result;
+}
+
+/******************************************************************************/
+
+char* mir_u2a( const wchar_t* src )
+{
+ return mir_u2a_cp( src, LangPackGetDefaultCodePage());
+}
diff --git a/src/core/miranda.cpp b/src/core/miranda.cpp
new file mode 100644
index 0000000000..fe38d096e1
--- /dev/null
+++ b/src/core/miranda.cpp
@@ -0,0 +1,941 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2012 Miranda ICQ/IM 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 InitPathUtils(void);
+int InitialiseModularEngine(void);
+int LoadDefaultModules(void);
+void DestroyModularEngine(void);
+void UnloadNewPluginsModule(void);
+void UnloadDefaultModules(void);
+void RecalculateTime(void);
+
+HINSTANCE GetInstByAddress( void* codePtr );
+
+pfnMyMonitorFromPoint MyMonitorFromPoint;
+pfnMyMonitorFromRect MyMonitorFromRect;
+pfnMyMonitorFromWindow MyMonitorFromWindow;
+pfnMyGetMonitorInfo MyGetMonitorInfo;
+
+typedef DWORD (WINAPI *pfnMsgWaitForMultipleObjectsEx)(DWORD,CONST HANDLE*,DWORD,DWORD,DWORD);
+pfnMsgWaitForMultipleObjectsEx msgWaitForMultipleObjectsEx;
+
+pfnSHAutoComplete shAutoComplete;
+pfnSHGetSpecialFolderPathA shGetSpecialFolderPathA;
+pfnSHGetSpecialFolderPathW shGetSpecialFolderPathW;
+
+pfnOpenInputDesktop openInputDesktop;
+pfnCloseDesktop closeDesktop;
+
+pfnAnimateWindow animateWindow;
+pfnSetLayeredWindowAttributes setLayeredWindowAttributes;
+
+pfnOpenThemeData openThemeData;
+pfnIsThemeBackgroundPartiallyTransparent isThemeBackgroundPartiallyTransparent;
+pfnDrawThemeParentBackground drawThemeParentBackground;
+pfnDrawThemeBackground drawThemeBackground;
+pfnDrawThemeText drawThemeText;
+pfnDrawThemeTextEx drawThemeTextEx;
+pfnGetThemeBackgroundContentRect getThemeBackgroundContentRect;
+pfnGetThemeFont getThemeFont;
+pfnCloseThemeData closeThemeData;
+pfnEnableThemeDialogTexture enableThemeDialogTexture;
+pfnSetWindowTheme setWindowTheme;
+pfnSetWindowThemeAttribute setWindowThemeAttribute;
+pfnIsThemeActive isThemeActive;
+pfnBufferedPaintInit bufferedPaintInit;
+pfnBufferedPaintUninit bufferedPaintUninit;
+pfnBeginBufferedPaint beginBufferedPaint;
+pfnEndBufferedPaint endBufferedPaint;
+pfnGetBufferedPaintBits getBufferedPaintBits;
+
+pfnDwmExtendFrameIntoClientArea dwmExtendFrameIntoClientArea;
+pfnDwmIsCompositionEnabled dwmIsCompositionEnabled;
+
+pfnGetaddrinfo MyGetaddrinfo;
+pfnFreeaddrinfo MyFreeaddrinfo;
+
+ITaskbarList3 * pTaskbarInterface;
+
+static DWORD MsgWaitForMultipleObjectsExWorkaround(DWORD nCount, const HANDLE *pHandles,
+ DWORD dwMsecs, DWORD dwWakeMask, DWORD dwFlags);
+
+static HANDLE hOkToExitEvent,hModulesLoadedEvent;
+static HANDLE hShutdownEvent,hPreShutdownEvent;
+static HANDLE hWaitObjects[MAXIMUM_WAIT_OBJECTS-1];
+static char *pszWaitServices[MAXIMUM_WAIT_OBJECTS-1];
+static int waitObjectCount=0;
+HANDLE hStackMutex,hMirandaShutdown,hThreadQueueEmpty;
+HINSTANCE hMirandaInst;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// exception handling
+
+static DWORD __cdecl sttDefaultFilter( DWORD, EXCEPTION_POINTERS* )
+{
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+
+pfnExceptionFilter pMirandaExceptFilter = sttDefaultFilter;
+
+static INT_PTR GetExceptionFilter( WPARAM, LPARAM )
+{
+ return ( INT_PTR )pMirandaExceptFilter;
+}
+
+static INT_PTR SetExceptionFilter( WPARAM, LPARAM lParam )
+{
+ pfnExceptionFilter oldOne = pMirandaExceptFilter;
+ if ( lParam != 0 )
+ pMirandaExceptFilter = ( pfnExceptionFilter )lParam;
+ return ( INT_PTR )oldOne;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// thread support functions
+
+typedef struct
+{
+ DWORD dwThreadId; // valid if hThread isn't signalled
+ HANDLE hThread;
+ HINSTANCE hOwner;
+ void* pObject;
+ PVOID addr;
+}
+THREAD_WAIT_ENTRY;
+
+static LIST<THREAD_WAIT_ENTRY> threads( 10, NumericKeySortT );
+
+struct FORK_ARG {
+ HANDLE hEvent;
+ pThreadFunc threadcode;
+ pThreadFuncEx threadcodeex;
+ void *arg, *owner;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// forkthread - starts a new thread
+
+void __cdecl forkthread_r(void * arg)
+{
+ struct FORK_ARG * fa = (struct FORK_ARG *) arg;
+ void (*callercode)(void*)=fa->threadcode;
+ void * cookie=fa->arg;
+ CallService(MS_SYSTEM_THREAD_PUSH,0,(LPARAM)callercode);
+ SetEvent(fa->hEvent);
+ __try
+ {
+ callercode(cookie);
+ }
+ __except( pMirandaExceptFilter( GetExceptionCode(), GetExceptionInformation()))
+ {
+ Netlib_Logf( NULL, "Unhandled exception in thread %x", GetCurrentThreadId());
+ }
+
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
+ CallService(MS_SYSTEM_THREAD_POP,0,0);
+ return;
+}
+
+UINT_PTR forkthread (
+ void (__cdecl *threadcode)(void*),
+ unsigned long stacksize,
+ void *arg
+ )
+{
+ UINT_PTR rc;
+ struct FORK_ARG fa;
+ fa.hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
+ fa.threadcode=threadcode;
+ fa.arg=arg;
+ rc=_beginthread(forkthread_r,stacksize,&fa);
+ if ((UINT_PTR)-1L != rc)
+ WaitForSingleObject(fa.hEvent,INFINITE);
+
+ CloseHandle(fa.hEvent);
+ return rc;
+}
+
+static INT_PTR ForkThreadService(WPARAM wParam, LPARAM lParam)
+{
+ return (INT_PTR)forkthread(( pThreadFunc )wParam, 0, ( void* )lParam );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// forkthreadex - starts a new thread with the extended info and returns the thread id
+
+unsigned __stdcall forkthreadex_r(void * arg)
+{
+ struct FORK_ARG *fa = (struct FORK_ARG *)arg;
+ pThreadFuncEx threadcode = fa->threadcodeex;
+ pThreadFuncOwner threadcodeex = ( pThreadFuncOwner )fa->threadcodeex;
+ void *cookie = fa->arg;
+ void *owner = fa->owner;
+ unsigned long rc = 0;
+
+ CallService(MS_SYSTEM_THREAD_PUSH, (WPARAM)fa->owner, (LPARAM)threadcode);
+ SetEvent(fa->hEvent);
+ __try
+ {
+ if ( owner )
+ rc = threadcodeex( owner, cookie );
+ else
+ rc = threadcode( cookie );
+ }
+ __except( pMirandaExceptFilter( GetExceptionCode(), GetExceptionInformation()))
+ {
+ Netlib_Logf( NULL, "Unhandled exception in thread %x", GetCurrentThreadId());
+ }
+
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
+ CallService(MS_SYSTEM_THREAD_POP,0,0);
+ return rc;
+}
+
+UINT_PTR forkthreadex(
+ void *sec,
+ unsigned stacksize,
+ unsigned (__stdcall *threadcode)(void*),
+ void* owner,
+ void *arg,
+ unsigned *thraddr )
+{
+ UINT_PTR rc;
+ struct FORK_ARG fa = { 0 };
+ fa.threadcodeex = threadcode;
+ fa.arg = arg;
+ fa.owner = owner;
+ fa.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
+ rc = _beginthreadex(sec,stacksize,forkthreadex_r,(void *)&fa,0,thraddr);
+ if (rc)
+ WaitForSingleObject(fa.hEvent,INFINITE);
+
+ CloseHandle(fa.hEvent);
+ return rc;
+}
+
+static INT_PTR ForkThreadServiceEx(WPARAM wParam, LPARAM lParam)
+{
+ FORK_THREADEX_PARAMS* params = (FORK_THREADEX_PARAMS*)lParam;
+ if ( params == NULL )
+ return 0;
+
+ UINT threadID;
+ return forkthreadex( NULL, params->iStackSize, params->pFunc, ( void* )wParam, params->arg, params->threadID ? params->threadID : &threadID );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// APC and mutex functions
+
+static void __stdcall DummyAPCFunc(ULONG_PTR)
+{
+ /* called in the context of thread that cleared it's APC queue */
+ return;
+}
+
+static int MirandaWaitForMutex(HANDLE hEvent)
+{
+ for (;;) {
+ // will get WAIT_IO_COMPLETE for QueueUserAPC() which isnt a result
+ DWORD rc = MsgWaitForMultipleObjectsExWorkaround(1, &hEvent, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE);
+ if ( rc == WAIT_OBJECT_0 + 1 ) {
+ MSG msg;
+ while ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) {
+ if ( IsDialogMessage(msg.hwnd, &msg) ) continue;
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ } else if ( rc==WAIT_OBJECT_0 ) {
+ // got object
+ return 1;
+ } else if ( rc==WAIT_ABANDONED_0 || rc == WAIT_FAILED ) return 0;
+ }
+}
+
+VOID CALLBACK KillAllThreads(HWND, UINT, UINT_PTR, DWORD)
+{
+ if ( MirandaWaitForMutex( hStackMutex )) {
+ for ( int j=0; j < threads.getCount(); j++ ) {
+ THREAD_WAIT_ENTRY* p = threads[j];
+ char szModuleName[ MAX_PATH ];
+ GetModuleFileNameA( p->hOwner, szModuleName, sizeof(szModuleName));
+ Netlib_Logf( NULL, "Thread %p was abnormally terminated because module '%s' didn't release it. Entry point: %p",
+ p->hThread, szModuleName, p->addr );
+ TerminateThread( p->hThread, 9999 );
+ CloseHandle(p->hThread);
+ mir_free( p );
+ }
+
+ threads.destroy();
+
+ ReleaseMutex( hStackMutex );
+ SetEvent( hThreadQueueEmpty );
+ }
+}
+
+void KillObjectThreads( void* owner )
+{
+ if ( owner == NULL )
+ return;
+
+ WaitForSingleObject( hStackMutex, INFINITE );
+
+ HANDLE* threadPool = ( HANDLE* )alloca( threads.getCount()*sizeof( HANDLE ));
+ int threadCount = 0;
+
+ for ( int j = threads.getCount(); j--; ) {
+ THREAD_WAIT_ENTRY* p = threads[j];
+ if ( p->pObject == owner )
+ threadPool[ threadCount++ ] = p->hThread;
+ }
+ ReleaseMutex(hStackMutex);
+
+ // is there anything to kill?
+ if ( threadCount > 0 ) {
+ if ( WaitForMultipleObjects( threadCount, threadPool, TRUE, 5000 ) == WAIT_TIMEOUT ) {
+ // forcibly kill all remaining threads after 5 secs
+ WaitForSingleObject( hStackMutex, INFINITE );
+ for ( int j = threads.getCount()-1; j >= 0; j-- ) {
+ THREAD_WAIT_ENTRY* p = threads[j];
+ if ( p->pObject == owner ) {
+ TerminateThread( p->hThread, 9999 );
+ CloseHandle( p->hThread );
+ threads.remove( j );
+ mir_free( p );
+ }
+ }
+ ReleaseMutex(hStackMutex);
+ }
+ }
+}
+
+static void UnwindThreadWait(void)
+{
+ // acquire the list and wake up any alertable threads
+ if ( MirandaWaitForMutex(hStackMutex) ) {
+ int j;
+ for ( j=0; j < threads.getCount(); j++ )
+ QueueUserAPC(DummyAPCFunc,threads[j]->hThread, 0);
+ ReleaseMutex(hStackMutex);
+ }
+
+ // give all unclosed threads 5 seconds to close
+ SetTimer( NULL, 0, 5000, KillAllThreads );
+
+ // wait til the thread list is empty
+ MirandaWaitForMutex(hThreadQueueEmpty);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+typedef LONG (WINAPI *pNtQIT)(HANDLE, LONG, PVOID, ULONG, PULONG);
+#define ThreadQuerySetWin32StartAddress 9
+
+void* GetCurrentThreadEntryPoint()
+{
+ LONG ntStatus;
+ HANDLE hDupHandle, hCurrentProcess;
+ DWORD_PTR dwStartAddress;
+
+ pNtQIT NtQueryInformationThread = (pNtQIT)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "NtQueryInformationThread" );
+ if(NtQueryInformationThread == NULL) return 0;
+
+ hCurrentProcess = GetCurrentProcess();
+ if(!DuplicateHandle(hCurrentProcess, GetCurrentThread(), hCurrentProcess, &hDupHandle, THREAD_QUERY_INFORMATION, FALSE, 0)){
+ SetLastError(ERROR_ACCESS_DENIED);
+ return NULL;
+ }
+ ntStatus = NtQueryInformationThread(hDupHandle, ThreadQuerySetWin32StartAddress, &dwStartAddress, sizeof(DWORD_PTR), NULL);
+ CloseHandle(hDupHandle);
+
+ if(ntStatus != ERROR_SUCCESS) return 0;
+ return ( void* )dwStartAddress;
+}
+
+INT_PTR UnwindThreadPush(WPARAM wParam,LPARAM lParam)
+{
+ ResetEvent(hThreadQueueEmpty); // thread list is not empty
+ if (WaitForSingleObject(hStackMutex, INFINITE) == WAIT_OBJECT_0)
+ {
+ THREAD_WAIT_ENTRY* p = (THREAD_WAIT_ENTRY*)mir_calloc(sizeof(THREAD_WAIT_ENTRY));
+
+ DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &p->hThread, 0, FALSE, DUPLICATE_SAME_ACCESS);
+ p->dwThreadId = GetCurrentThreadId();
+ p->pObject = (void*)wParam;
+ p->hOwner = GetInstByAddress((void*)lParam);
+ p->addr = (void*)lParam;
+ threads.insert(p);
+
+ //Netlib_Logf( NULL, "*** pushing thread %x[%x] (%d)", hThread, GetCurrentThreadId(), threads.count );
+ ReleaseMutex(hStackMutex);
+ } //if
+ return 0;
+}
+
+INT_PTR UnwindThreadPop(WPARAM,LPARAM)
+{
+ if (WaitForSingleObject(hStackMutex,INFINITE)==WAIT_OBJECT_0)
+ {
+ DWORD dwThreadId=GetCurrentThreadId();
+ int j;
+ //Netlib_Logf( NULL, "*** popping thread %x, %d threads left", dwThreadId, threads.count);
+ for ( j=0; j < threads.getCount(); j++ ) {
+ THREAD_WAIT_ENTRY* p = threads[j];
+ if ( p->dwThreadId == dwThreadId ) {
+ SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL );
+ CloseHandle( p->hThread );
+ threads.remove( j );
+ mir_free( p );
+
+ if ( !threads.getCount()) {
+ threads.destroy();
+ ReleaseMutex( hStackMutex );
+ SetEvent(hThreadQueueEmpty); // thread list is empty now
+ return 0;
+ }
+
+ ReleaseMutex(hStackMutex);
+ return 0;
+ } //if
+ } //for
+ ReleaseMutex(hStackMutex);
+ } //if
+ return 1;
+}
+
+INT_PTR MirandaIsTerminated(WPARAM, LPARAM)
+{
+ return WaitForSingleObject(hMirandaShutdown,0)==WAIT_OBJECT_0;
+}
+
+static void __cdecl compactHeapsThread(void*)
+{
+ 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
+}
+
+LRESULT CALLBACK APCWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if (msg==WM_NULL) SleepEx(0,TRUE);
+ if (msg == WM_TIMECHANGE) RecalculateTime();
+ return DefWindowProc(hwnd,msg,wParam,lParam);
+}
+
+HWND hAPCWindow=NULL;
+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 DWORD MsgWaitForMultipleObjectsExWorkaround(DWORD nCount, const HANDLE *pHandles,
+ DWORD dwMsecs, DWORD dwWakeMask, DWORD dwFlags)
+{
+ DWORD rc;
+ if ( msgWaitForMultipleObjectsEx != NULL )
+ return msgWaitForMultipleObjectsEx(nCount, pHandles, dwMsecs, dwWakeMask, dwFlags);
+ rc=MsgWaitForMultipleObjects(nCount, pHandles, FALSE, 50, QS_ALLINPUT);
+ if ( rc == WAIT_TIMEOUT ) rc=WaitForMultipleObjectsEx(nCount, pHandles, FALSE, 20, TRUE);
+ return rc;
+}
+
+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 (HIWORD(wParam) == IDCANCEL)
+ {
+ SendDlgItemMessage(hwnd, IDC_PROGRESSBAR, PBM_SETPOS, MIRANDA_PROCESS_WAIT_STEPS, 0);
+ EndDialog(hwnd, 0);
+ }
+ break;
+ }
+ return FALSE;
+}
+
+void ParseCommandLine()
+{
+ char* cmdline = GetCommandLineA();
+ char* p = strstr( cmdline, "/restart:" );
+ if ( p ) {
+ HANDLE hProcess = OpenProcess( SYNCHRONIZE, FALSE, atol( p+9 ));
+ if ( hProcess ) {
+ DialogBoxParam(hMirandaInst, MAKEINTRESOURCE(IDD_WAITRESTART), NULL, WaitForProcessDlgProc, (LPARAM)hProcess);
+ CloseHandle( hProcess );
+ }
+ }
+}
+
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int )
+{
+ DWORD myPid=0;
+ int messageloop=1;
+ HMODULE hUser32, hThemeAPI, hDwmApi, hShFolder = NULL;
+ int result = 0;
+
+ hMirandaInst = hInstance;
+
+ setlocale(LC_ALL, "");
+
+#ifdef _DEBUG
+ _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
+#endif
+
+ hUser32 = GetModuleHandleA("user32");
+ openInputDesktop = (pfnOpenInputDesktop)GetProcAddress (hUser32, "OpenInputDesktop");
+ closeDesktop = (pfnCloseDesktop)GetProcAddress (hUser32, "CloseDesktop");
+ msgWaitForMultipleObjectsEx = (pfnMsgWaitForMultipleObjectsEx)GetProcAddress(hUser32, "MsgWaitForMultipleObjectsEx");
+ animateWindow =(pfnAnimateWindow)GetProcAddress(hUser32, "AnimateWindow");
+ setLayeredWindowAttributes =(pfnSetLayeredWindowAttributes)GetProcAddress(hUser32, "SetLayeredWindowAttributes");
+
+ MyMonitorFromPoint = (pfnMyMonitorFromPoint)GetProcAddress(hUser32, "MonitorFromPoint");
+ MyMonitorFromRect = (pfnMyMonitorFromRect)GetProcAddress(hUser32, "MonitorFromRect");
+ MyMonitorFromWindow = (pfnMyMonitorFromWindow)GetProcAddress(hUser32, "MonitorFromWindow");
+#ifdef _UNICODE
+ MyGetMonitorInfo = (pfnMyGetMonitorInfo)GetProcAddress(hUser32, "GetMonitorInfoW");
+#else
+ MyGetMonitorInfo = (pfnMyGetMonitorInfo)GetProcAddress(hUser32, "GetMonitorInfoA");
+#endif
+
+ hShFolder = GetModuleHandleA("shell32");
+ shGetSpecialFolderPathA = (pfnSHGetSpecialFolderPathA)GetProcAddress(hShFolder,"SHGetSpecialFolderPathA");
+ shGetSpecialFolderPathW = (pfnSHGetSpecialFolderPathW)GetProcAddress(hShFolder,"SHGetSpecialFolderPathW");
+ if (shGetSpecialFolderPathA == NULL)
+ {
+ hShFolder = LoadLibraryA("ShFolder.dll");
+ shGetSpecialFolderPathA = (pfnSHGetSpecialFolderPathA)GetProcAddress(hShFolder,"SHGetSpecialFolderPathA");
+ shGetSpecialFolderPathW = (pfnSHGetSpecialFolderPathW)GetProcAddress(hShFolder,"SHGetSpecialFolderPathW");
+ }
+
+ shAutoComplete = (pfnSHAutoComplete)GetProcAddress(GetModuleHandleA("shlwapi"),"SHAutoComplete");
+
+ if (IsWinVerXPPlus())
+ {
+ hThemeAPI = LoadLibraryA("uxtheme.dll");
+ if (hThemeAPI)
+ {
+ openThemeData = (pfnOpenThemeData)GetProcAddress(hThemeAPI, "OpenThemeData");
+ isThemeBackgroundPartiallyTransparent = (pfnIsThemeBackgroundPartiallyTransparent)GetProcAddress(hThemeAPI, "IsThemeBackgroundPartiallyTransparent");
+ drawThemeParentBackground = (pfnDrawThemeParentBackground)GetProcAddress(hThemeAPI, "DrawThemeParentBackground");
+ drawThemeBackground = (pfnDrawThemeBackground)GetProcAddress(hThemeAPI, "DrawThemeBackground");
+ drawThemeText = (pfnDrawThemeText)GetProcAddress(hThemeAPI, "DrawThemeText");
+ drawThemeTextEx = (pfnDrawThemeTextEx)GetProcAddress(hThemeAPI, "DrawThemeTextEx");
+ getThemeBackgroundContentRect = (pfnGetThemeBackgroundContentRect)GetProcAddress(hThemeAPI ,"GetThemeBackgroundContentRect");
+ getThemeFont = (pfnGetThemeFont)GetProcAddress(hThemeAPI, "GetThemeFont");
+ closeThemeData = (pfnCloseThemeData)GetProcAddress(hThemeAPI, "CloseThemeData");
+ enableThemeDialogTexture = (pfnEnableThemeDialogTexture)GetProcAddress(hThemeAPI, "EnableThemeDialogTexture");
+ setWindowTheme = (pfnSetWindowTheme)GetProcAddress(hThemeAPI, "SetWindowTheme");
+ setWindowThemeAttribute = (pfnSetWindowThemeAttribute)GetProcAddress(hThemeAPI, "SetWindowThemeAttribute");
+ isThemeActive = (pfnIsThemeActive)GetProcAddress(hThemeAPI, "IsThemeActive");
+ 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 (IsWinVerVistaPlus())
+ {
+ hDwmApi = LoadLibraryA("dwmapi.dll");
+ if (hDwmApi)
+ {
+ dwmExtendFrameIntoClientArea = (pfnDwmExtendFrameIntoClientArea)GetProcAddress(hDwmApi,"DwmExtendFrameIntoClientArea");
+ dwmIsCompositionEnabled = (pfnDwmIsCompositionEnabled)GetProcAddress(hDwmApi,"DwmIsCompositionEnabled");
+ }
+ }
+
+ HMODULE hWinSock = GetModuleHandleA("ws2_32");
+ MyGetaddrinfo = (pfnGetaddrinfo)GetProcAddress(hWinSock, "getaddrinfo");
+ MyFreeaddrinfo = (pfnFreeaddrinfo)GetProcAddress(hWinSock, "freeaddrinfo");
+
+ if (bufferedPaintInit) bufferedPaintInit();
+
+ OleInitialize(NULL);
+
+ if (IsWinVer7Plus())
+ CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_ALL, IID_ITaskbarList3, (void**)&pTaskbarInterface);
+
+ InitialiseModularEngine();
+// ParseCommandLine();
+
+ if (LoadDefaultModules()) {
+ NotifyEventHooks(hShutdownEvent,0,0);
+ UnloadDefaultModules();
+
+ result = 1;
+ goto exit;
+ }
+ NotifyEventHooks(hModulesLoadedEvent,0,0);
+
+ // 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();
+ myPid=GetCurrentProcessId();
+ for(;messageloop;) {
+ MSG msg;
+ DWORD rc;
+ BOOL dying=FALSE;
+ rc=MsgWaitForMultipleObjectsExWorkaround(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.
+ UnwindThreadWait();
+ 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=0;
+ }
+ } // while
+ }
+
+exit:
+ UnloadNewPluginsModule();
+ DestroyModularEngine();
+ CloseHandle(hStackMutex);
+ CloseHandle(hMirandaShutdown);
+ CloseHandle(hThreadQueueEmpty);
+ DestroyWindow(hAPCWindow);
+
+ if (pTaskbarInterface)
+ pTaskbarInterface->Release();
+
+ OleUninitialize();
+
+ if (bufferedPaintUninit) bufferedPaintUninit();
+
+ if (hDwmApi) FreeLibrary(hDwmApi);
+ if (hThemeAPI) FreeLibrary(hThemeAPI);
+ if (hShFolder) FreeLibrary(hShFolder);
+
+ return result;
+}
+
+static INT_PTR OkToExit(WPARAM, LPARAM)
+{
+ return NotifyEventHooks(hOkToExitEvent,0,0)==0;
+}
+
+static INT_PTR GetMirandaVersion(WPARAM, LPARAM)
+{
+ TCHAR filename[MAX_PATH];
+ DWORD unused;
+ DWORD verInfoSize;
+ UINT blockSize;
+ PVOID pVerInfo;
+ VS_FIXEDFILEINFO *vsffi;
+ DWORD ver;
+
+ GetModuleFileName(NULL,filename,SIZEOF(filename));
+ verInfoSize=GetFileVersionInfoSize(filename,&unused);
+ pVerInfo=mir_alloc(verInfoSize);
+ GetFileVersionInfo(filename,0,verInfoSize,pVerInfo);
+ VerQueryValue(pVerInfo,_T("\\"),(PVOID*)&vsffi,&blockSize);
+ ver=(((vsffi->dwProductVersionMS>>16)&0xFF)<<24)|
+ ((vsffi->dwProductVersionMS&0xFF)<<16)|
+ (((vsffi->dwProductVersionLS>>16)&0xFF)<<8)|
+ (vsffi->dwProductVersionLS&0xFF);
+ mir_free(pVerInfo);
+ return (INT_PTR)ver;
+}
+
+static INT_PTR GetMirandaVersionText(WPARAM wParam,LPARAM lParam)
+{
+ TCHAR filename[MAX_PATH], *productVersion;
+ DWORD unused;
+ DWORD verInfoSize;
+ UINT blockSize;
+ PVOID pVerInfo;
+
+ GetModuleFileName(NULL,filename,SIZEOF(filename));
+ verInfoSize=GetFileVersionInfoSize(filename,&unused);
+ pVerInfo=mir_alloc(verInfoSize);
+ GetFileVersionInfo(filename,0,verInfoSize,pVerInfo);
+ VerQueryValue(pVerInfo,_T("\\StringFileInfo\\000004b0\\ProductVersion"),(LPVOID*)&productVersion,&blockSize);
+#if defined( _WIN64 )
+ mir_snprintf(( char* )lParam, wParam, "%S x64 Unicode", productVersion );
+#elif defined( _UNICODE )
+ mir_snprintf(( char* )lParam, wParam, "%S Unicode", productVersion );
+#else
+ lstrcpyn((char*)lParam,productVersion,wParam);
+#endif
+ mir_free(pVerInfo);
+ 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<waitObjectCount;i++)
+ if(hWaitObjects[i]==(HANDLE)wParam) break;
+ if(i==waitObjectCount) return 1;
+ waitObjectCount--;
+ MoveMemory(&hWaitObjects[i],&hWaitObjects[i+1],sizeof(HANDLE)*(waitObjectCount-i));
+ MoveMemory(&pszWaitServices[i],&pszWaitServices[i+1],sizeof(char*)*(waitObjectCount-i));
+ return 0;
+}
+
+INT_PTR GetMemoryManagerInterface(WPARAM, LPARAM lParam)
+{
+ struct MM_INTERFACE *mmi = (struct MM_INTERFACE*) lParam;
+ if ( mmi == NULL )
+ return 1;
+
+ mmi->mmi_malloc = mir_alloc;
+ mmi->mmi_realloc = mir_realloc;
+ mmi->mmi_free = mir_free;
+
+ switch( mmi->cbSize ) {
+ case sizeof(struct MM_INTERFACE):
+ mmi->mir_snprintf = mir_snprintf;
+ mmi->mir_sntprintf = mir_sntprintf;
+ mmi->mir_vsnprintf = mir_vsnprintf;
+ mmi->mir_vsntprintf = mir_vsntprintf;
+ mmi->mir_a2u_cp = mir_a2u_cp;
+ mmi->mir_a2u = mir_a2u;
+ mmi->mir_u2a_cp = mir_u2a_cp;
+ mmi->mir_u2a = mir_u2a;
+ // fall through
+
+ case MMI_SIZE_V2:
+ mmi->mmi_calloc = mir_calloc;
+ mmi->mmi_strdup = mir_strdup;
+ mmi->mmi_wstrdup = mir_wstrdup;
+ // fall through
+
+ case MMI_SIZE_V1:
+ break;
+
+ default:
+#if defined( _DEBUG )
+ DebugBreak();
+#endif
+ return 1;
+ }
+
+ return 0;
+}
+
+INT_PTR GetListInterface(WPARAM, LPARAM lParam)
+{
+ struct LIST_INTERFACE *li = (struct LIST_INTERFACE*) lParam;
+ if ( li == NULL )
+ return 1;
+
+ switch(li->cbSize) {
+ case LIST_INTERFACE_V3_SIZE:
+ li->List_Copy = List_Copy;
+ li->List_ObjCopy = List_ObjCopy;
+
+ case LIST_INTERFACE_V2_SIZE:
+ li->List_InsertPtr = List_InsertPtr;
+ li->List_RemovePtr = List_RemovePtr;
+
+ case LIST_INTERFACE_V1_SIZE:
+ li->List_Create = List_Create;
+ li->List_Destroy = List_Destroy;
+ li->List_Find = List_Find;
+ li->List_GetIndex = List_GetIndex;
+ li->List_Insert = List_Insert;
+ li->List_Remove = List_Remove;
+ li->List_IndexOf = List_IndexOf;
+ return 0;
+ }
+ return 1;
+}
+
+INT_PTR GetUtfInterface(WPARAM, LPARAM lParam)
+{
+ struct UTF8_INTERFACE *utfi = (struct UTF8_INTERFACE*) lParam;
+ if ( utfi == NULL )
+ return 1;
+
+ switch( utfi->cbSize ) {
+ case UTF8_INTERFACE_SIZEOF_V1:
+ case UTF8_INTERFACE_SIZEOF_V2:
+ case sizeof( struct UTF8_INTERFACE ):
+ break;
+
+ default:
+ return 1;
+ }
+
+ utfi->utf8_decode = Utf8Decode;
+ utfi->utf8_decodecp = Utf8DecodeCP;
+ utfi->utf8_encode = Utf8Encode;
+ utfi->utf8_encodecp = Utf8EncodeCP;
+ utfi->utf8_encodeW = Utf8EncodeUcs2;
+ if (utfi->cbSize > UTF8_INTERFACE_SIZEOF_V1)
+ utfi->utf8_decodeW = Utf8DecodeUcs2;
+ if (utfi->cbSize > UTF8_INTERFACE_SIZEOF_V2)
+ utfi->utf8_lenW = Ucs2toUtf8Len;
+
+ return 0;
+}
+
+int LoadSystemModule(void)
+{
+ INITCOMMONCONTROLSEX icce = {0};
+ icce.dwSize = sizeof(icce);
+ icce.dwICC = ICC_WIN95_CLASSES | ICC_USEREX_CLASSES;
+ InitCommonControlsEx(&icce);
+
+ if (IsWinVerXPPlus()) {
+ hAPCWindow=CreateWindowEx(0,_T("ComboLBox"),NULL,0, 0,0,0,0, NULL,NULL,NULL,NULL);
+ SetClassLongPtr(hAPCWindow, GCL_STYLE, GetClassLongPtr(hAPCWindow, GCL_STYLE) | CS_DROPSHADOW);
+ DestroyWindow(hAPCWindow);
+ hAPCWindow = NULL;
+ }
+
+ hAPCWindow=CreateWindowEx(0,_T("STATIC"),NULL,0, 0,0,0,0, NULL,NULL,NULL,NULL); // lame
+ SetWindowLongPtr(hAPCWindow,GWLP_WNDPROC,(LONG_PTR)APCWndProc);
+ hStackMutex=CreateMutex(NULL,FALSE,NULL);
+ hMirandaShutdown=CreateEvent(NULL,TRUE,FALSE,NULL);
+ hThreadQueueEmpty=CreateEvent(NULL,TRUE,TRUE,NULL);
+
+ hShutdownEvent=CreateHookableEvent(ME_SYSTEM_SHUTDOWN);
+ hPreShutdownEvent=CreateHookableEvent(ME_SYSTEM_PRESHUTDOWN);
+ hModulesLoadedEvent=CreateHookableEvent(ME_SYSTEM_MODULESLOADED);
+ hOkToExitEvent=CreateHookableEvent(ME_SYSTEM_OKTOEXIT);
+
+ CreateServiceFunction(MS_SYSTEM_FORK_THREAD,ForkThreadService);
+ CreateServiceFunction(MS_SYSTEM_FORK_THREAD_EX,ForkThreadServiceEx);
+ CreateServiceFunction(MS_SYSTEM_THREAD_PUSH,UnwindThreadPush);
+ CreateServiceFunction(MS_SYSTEM_THREAD_POP,UnwindThreadPop);
+ CreateServiceFunction(MS_SYSTEM_TERMINATED,MirandaIsTerminated);
+ CreateServiceFunction(MS_SYSTEM_OKTOEXIT,OkToExit);
+ CreateServiceFunction(MS_SYSTEM_GETVERSION,GetMirandaVersion);
+ CreateServiceFunction(MS_SYSTEM_GETVERSIONTEXT,GetMirandaVersionText);
+ CreateServiceFunction(MS_SYSTEM_WAITONHANDLE,WaitOnHandle);
+ CreateServiceFunction(MS_SYSTEM_REMOVEWAIT,RemoveWait);
+ CreateServiceFunction(MS_SYSTEM_GET_LI,GetListInterface);
+ CreateServiceFunction(MS_SYSTEM_GET_MMI,GetMemoryManagerInterface);
+ CreateServiceFunction(MS_SYSTEM_GET_UTFI,GetUtfInterface);
+ CreateServiceFunction(MS_SYSTEM_GETEXCEPTFILTER,GetExceptionFilter);
+ CreateServiceFunction(MS_SYSTEM_SETEXCEPTFILTER,SetExceptionFilter);
+
+ InitPathUtils();
+ return 0;
+}
diff --git a/src/core/miranda.h b/src/core/miranda.h
new file mode 100644
index 0000000000..850e2a78c8
--- /dev/null
+++ b/src/core/miranda.h
@@ -0,0 +1,370 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM 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.
+*/
+
+#define NEWSTR_ALLOCA(A) (A==NULL)?NULL:strcpy((char*)alloca(strlen(A)+1),A)
+#define NEWTSTR_ALLOCA(A) (A==NULL)?NULL:_tcscpy((TCHAR*)alloca((_tcslen(A)+1)* sizeof(TCHAR)),A)
+
+typedef HMONITOR (WINAPI *pfnMyMonitorFromPoint)(POINT, DWORD);
+extern pfnMyMonitorFromPoint MyMonitorFromPoint;
+
+typedef HMONITOR (WINAPI *pfnMyMonitorFromRect)(LPCRECT, DWORD);
+extern pfnMyMonitorFromRect MyMonitorFromRect;
+
+typedef HMONITOR(WINAPI *pfnMyMonitorFromWindow) (HWND, DWORD);
+extern pfnMyMonitorFromWindow MyMonitorFromWindow;
+
+typedef BOOL(WINAPI *pfnMyGetMonitorInfo) (HMONITOR, LPMONITORINFO);
+extern pfnMyGetMonitorInfo MyGetMonitorInfo;
+
+typedef HRESULT (STDAPICALLTYPE *pfnSHAutoComplete)(HWND,DWORD);
+extern pfnSHAutoComplete shAutoComplete;
+
+typedef HRESULT (STDAPICALLTYPE *pfnSHGetSpecialFolderPathA)(HWND, LPSTR, int, BOOL );
+typedef HRESULT (STDAPICALLTYPE *pfnSHGetSpecialFolderPathW)(HWND, LPWSTR, int, BOOL );
+extern pfnSHGetSpecialFolderPathA shGetSpecialFolderPathA;
+extern pfnSHGetSpecialFolderPathW shGetSpecialFolderPathW;
+
+#ifdef _UNICODE
+#define shGetSpecialFolderPath shGetSpecialFolderPathW
+#else
+#define shGetSpecialFolderPath shGetSpecialFolderPathA
+#endif
+
+typedef HDESK (WINAPI* pfnOpenInputDesktop)(DWORD, BOOL, DWORD);
+extern pfnOpenInputDesktop openInputDesktop;
+
+typedef HDESK (WINAPI* pfnCloseDesktop)(HDESK);
+extern pfnCloseDesktop closeDesktop;
+
+typedef BOOL (WINAPI* pfnAnimateWindow)(HWND, DWORD, DWORD);
+extern pfnAnimateWindow animateWindow;
+
+typedef BOOL (WINAPI * pfnSetLayeredWindowAttributes) (HWND, COLORREF, BYTE, DWORD);
+extern pfnSetLayeredWindowAttributes setLayeredWindowAttributes;
+
+typedef HTHEME ( STDAPICALLTYPE *pfnOpenThemeData )( HWND, LPCWSTR );
+typedef HRESULT ( STDAPICALLTYPE *pfnIsThemeBackgroundPartiallyTransparent )( HTHEME, int, int );
+typedef HRESULT ( STDAPICALLTYPE *pfnDrawThemeParentBackground )( HWND, HDC, const RECT * );
+typedef HRESULT ( STDAPICALLTYPE *pfnDrawThemeBackground )( HTHEME, HDC, int, int, const RECT *, const RECT * );
+typedef HRESULT ( STDAPICALLTYPE *pfnDrawThemeText)( HTHEME, HDC, int, int, LPCWSTR, int, DWORD, DWORD, const RECT *);
+typedef HRESULT ( STDAPICALLTYPE *pfnDrawThemeTextEx)( HTHEME, HDC, int, int, LPCWSTR, int, DWORD, LPRECT, const struct _DTTOPTS * );
+typedef HRESULT ( STDAPICALLTYPE *pfnGetThemeBackgroundContentRect)( HTHEME, HDC, int, int, LPCRECT, LPRECT );
+typedef HRESULT ( STDAPICALLTYPE *pfnGetThemeFont)( HTHEME, HDC, int, int, int, LOGFONT * );
+typedef HRESULT ( STDAPICALLTYPE *pfnCloseThemeData )( HTHEME );
+typedef HRESULT ( STDAPICALLTYPE *pfnEnableThemeDialogTexture )( HWND hwnd, DWORD dwFlags );
+typedef HRESULT ( STDAPICALLTYPE *pfnSetWindowTheme )( HWND, LPCWSTR, LPCWSTR );
+typedef HRESULT ( STDAPICALLTYPE *pfnSetWindowThemeAttribute )( HWND, enum WINDOWTHEMEATTRIBUTETYPE, PVOID, DWORD );
+typedef BOOL ( STDAPICALLTYPE *pfnIsThemeActive )();
+typedef HRESULT (STDAPICALLTYPE *pfnBufferedPaintInit)(void);
+typedef HRESULT (STDAPICALLTYPE *pfnBufferedPaintUninit)(void);
+typedef HANDLE (STDAPICALLTYPE *pfnBeginBufferedPaint)(HDC, RECT *, BP_BUFFERFORMAT, BP_PAINTPARAMS *, HDC *);
+typedef HRESULT (STDAPICALLTYPE *pfnEndBufferedPaint)(HANDLE, BOOL);
+typedef HRESULT (STDAPICALLTYPE *pfnGetBufferedPaintBits)(HANDLE, RGBQUAD **, int *);
+
+extern pfnOpenThemeData openThemeData;
+extern pfnIsThemeBackgroundPartiallyTransparent isThemeBackgroundPartiallyTransparent;
+extern pfnDrawThemeParentBackground drawThemeParentBackground;
+extern pfnDrawThemeBackground drawThemeBackground;
+extern pfnDrawThemeText drawThemeText;
+extern pfnDrawThemeTextEx drawThemeTextEx;
+extern pfnGetThemeBackgroundContentRect getThemeBackgroundContentRect;
+extern pfnGetThemeFont getThemeFont;
+extern pfnCloseThemeData closeThemeData;
+extern pfnEnableThemeDialogTexture enableThemeDialogTexture;
+extern pfnSetWindowTheme setWindowTheme;
+extern pfnSetWindowThemeAttribute setWindowThemeAttribute;
+extern pfnIsThemeActive isThemeActive;
+extern pfnBufferedPaintInit bufferedPaintInit;
+extern pfnBufferedPaintUninit bufferedPaintUninit;
+extern pfnBeginBufferedPaint beginBufferedPaint;
+extern pfnEndBufferedPaint endBufferedPaint;
+extern pfnGetBufferedPaintBits getBufferedPaintBits;
+
+extern ITaskbarList3 * pTaskbarInterface;
+
+typedef HRESULT ( STDAPICALLTYPE *pfnDwmExtendFrameIntoClientArea )( HWND hwnd, const MARGINS *margins );
+typedef HRESULT ( STDAPICALLTYPE *pfnDwmIsCompositionEnabled )( BOOL * );
+
+extern pfnDwmExtendFrameIntoClientArea dwmExtendFrameIntoClientArea;
+extern pfnDwmIsCompositionEnabled dwmIsCompositionEnabled;
+
+typedef INT (STDAPICALLTYPE *pfnGetaddrinfo)(PCSTR pNodeName, PCSTR pServiceName, const ADDRINFOA * pHints, PADDRINFOA * ppResult);
+typedef INT (STDAPICALLTYPE *pfnFreeaddrinfo)(PADDRINFOA pAddrInfo);
+
+extern pfnGetaddrinfo MyGetaddrinfo;
+extern pfnFreeaddrinfo MyFreeaddrinfo;
+
+/**** file.c ***************************************************************************/
+
+void PushFileEvent( HANDLE hContact, HANDLE hdbe, LPARAM lParam );
+
+/**** memory.c *************************************************************************/
+
+#ifdef _STATIC
+void* mir_alloc( size_t );
+void* mir_calloc( size_t );
+void* mir_realloc( void* ptr, size_t );
+void mir_free( void* ptr );
+char* mir_strdup( const char* str );
+WCHAR* mir_wstrdup( const WCHAR* str );
+char* mir_strndup( const char* str, size_t len );
+
+int mir_snprintf(char *buffer, size_t count, const char* fmt, ...);
+int mir_sntprintf(TCHAR *buffer, size_t count, const TCHAR* fmt, ...);
+int mir_vsnprintf(char *buffer, size_t count, const char* fmt, va_list va);
+int mir_vsntprintf(TCHAR *buffer, size_t count, const TCHAR* fmt, va_list va);
+
+WCHAR* mir_a2u_cp(const char* src, int codepage);
+WCHAR* mir_a2u(const char* src);
+char* mir_u2a_cp(const wchar_t* src, int codepage);
+char* mir_u2a( const wchar_t* src);
+#endif
+
+/**** miranda.c ************************************************************************/
+
+extern HINSTANCE hMirandaInst;
+extern pfnExceptionFilter pMirandaExceptFilter;
+
+/**** modules.c ************************************************************************/
+
+void KillModuleEventHooks( HINSTANCE );
+void KillModuleServices( HINSTANCE );
+
+void KillObjectEventHooks( void* pObject );
+void KillObjectServices( void* pObject );
+void KillObjectThreads( void* pObject );
+
+/**** utf.c ****************************************************************************/
+
+char* Utf8Decode( char* str, wchar_t** ucs2 );
+char* Utf8DecodeCP( char* str, int codepage, wchar_t** ucs2 );
+
+wchar_t* Utf8DecodeUcs2( const char* str );
+
+__forceinline char* Utf8DecodeA(const char* src)
+{
+ char* tmp = mir_strdup(src);
+ Utf8Decode(tmp, NULL);
+ return tmp;
+}
+
+
+char* Utf8Encode( const char* str );
+char* Utf8EncodeCP( const char* src, int codepage );
+
+char* Utf8EncodeUcs2( const wchar_t* str );
+
+int Ucs2toUtf8Len(const wchar_t *src);
+
+#if defined( _UNICODE )
+ #define Utf8DecodeT Utf8DecodeUcs2
+ #define Utf8EncodeT Utf8EncodeUcs2
+#else
+ #define Utf8DecodeT Utf8DecodeA
+ #define Utf8EncodeT Utf8Encode
+#endif
+
+/**** langpack.c ***********************************************************************/
+
+int LangPackGetDefaultCodePage();
+int LangPackGetDefaultLocale();
+TCHAR* LangPackPcharToTchar( const char* pszStr );
+char* LangPackTranslateString(struct LangPackMuuid* pUuid, const char *szEnglish, const int W);
+
+unsigned int __fastcall hash(const void * key, unsigned int len);
+
+#pragma optimize( "gt", on )
+__inline unsigned int hashstr(const char * key)
+{
+ if (key == NULL) return 0;
+ const unsigned int len = (unsigned int)strlen((const char*)key);
+ return hash(key, len);
+}
+
+__inline unsigned int hashstr(const wchar_t * key)
+{
+ if (key == NULL) return 0;
+ const unsigned int len = (unsigned int)wcslen((const wchar_t*)key);
+ return hash(key, len * sizeof(wchar_t));
+}
+#pragma optimize( "", on )
+
+/**** path.c ***************************************************************************/
+
+int pathToAbsolute(const char *pSrc, char *pOut, char* base);
+void CreatePathToFile( char* wszFilePath );
+int CreateDirectoryTree(const char *szDir);
+#if defined( _UNICODE )
+ void CreatePathToFileW( WCHAR* wszFilePath );
+ int CreateDirectoryTreeW(const WCHAR *szDir);
+ int pathToAbsoluteW(const TCHAR *pSrc, TCHAR *pOut, TCHAR* base);
+ #define pathToAbsoluteT pathToAbsoluteW
+ #define CreatePathToFileT CreatePathToFileW
+ #define CreateDirectoryTreeT CreateDirectoryTreeW
+#else
+ #define pathToAbsoluteT pathToAbsolute
+ #define CreatePathToFileT CreatePathToFile
+ #define CreateDirectoryTreeT CreateDirectoryTree
+#endif
+
+/**** skin2icons.c *********************************************************************/
+
+HANDLE IcoLib_AddNewIcon( SKINICONDESC* sid );
+HICON IcoLib_GetIcon( const char* pszIconName, bool big );
+HICON IcoLib_GetIconByHandle( HANDLE hItem, bool big );
+HANDLE IcoLib_IsManaged( HICON hIcon );
+int IcoLib_ReleaseIcon( HICON hIcon, char* szIconName, bool big );
+
+/**** skinicons.c **********************************************************************/
+
+HICON LoadSkinProtoIcon( const char* szProto, int status, bool big = false );
+HICON LoadSkinIcon( int idx, bool big = false );
+HANDLE GetSkinIconHandle( int idx );
+
+HICON LoadIconEx(HINSTANCE hInstance, LPCTSTR lpIconName, BOOL bShared);
+int ImageList_AddIcon_NotShared(HIMAGELIST hIml, LPCTSTR szResource);
+int ImageList_ReplaceIcon_NotShared(HIMAGELIST hIml, int iIndex, HINSTANCE hInstance, LPCTSTR szResource);
+
+int ImageList_AddIcon_IconLibLoaded(HIMAGELIST hIml, int iconId);
+int ImageList_AddIcon_ProtoIconLibLoaded(HIMAGELIST hIml, const char* szProto, int iconId);
+int ImageList_ReplaceIcon_IconLibLoaded(HIMAGELIST hIml, int nIndex, HICON hIcon);
+
+void Button_SetIcon_IcoLib(HWND hDlg, int itemId, int iconId, const char* tooltip);
+void Button_FreeIcon_IcoLib(HWND hDlg, int itemId);
+
+void Window_SetIcon_IcoLib(HWND hWnd, int iconId);
+void Window_SetProtoIcon_IcoLib(HWND hWnd, const char* szProto, int iconId);
+void Window_FreeIcon_IcoLib(HWND hWnd);
+
+#define IconLib_ReleaseIcon(hIcon, szName) IcoLib_ReleaseIcon(hIcon, szName, false);
+#define Safe_DestroyIcon(hIcon) if (hIcon) DestroyIcon(hIcon)
+
+/**** clistmenus.c **********************************************************************/
+
+extern HANDLE hMainMenuObject, hContactMenuObject, hStatusMenuObject;
+extern HANDLE hPreBuildMainMenuEvent, hPreBuildContactMenuEvent;
+
+extern const int statusModeList[ MAX_STATUS_COUNT ];
+extern const int skinIconStatusList[ MAX_STATUS_COUNT ];
+extern const int skinIconStatusFlags[ MAX_STATUS_COUNT ];
+
+int TryProcessDoubleClick( HANDLE hContact );
+
+/**** protocols.c ***********************************************************************/
+
+#define OFFSET_PROTOPOS 200
+#define OFFSET_VISIBLE 400
+#define OFFSET_ENABLED 600
+#define OFFSET_NAME 800
+
+extern LIST<PROTOACCOUNT> accounts;
+
+PROTOACCOUNT* __fastcall Proto_GetAccount( const char* accName );
+PROTOACCOUNT* __fastcall Proto_GetAccount( HANDLE hContact );
+PROTOCOLDESCRIPTOR* __fastcall Proto_IsProtocolLoaded( const char* szProtoName );
+
+bool __fastcall Proto_IsAccountEnabled( PROTOACCOUNT* pa );
+bool __fastcall Proto_IsAccountLocked( PROTOACCOUNT* pa );
+
+PROTO_INTERFACE* AddDefaultAccount( const char* szProtoName );
+int FreeDefaultAccount( PROTO_INTERFACE* ppi );
+
+BOOL ActivateAccount( PROTOACCOUNT* pa );
+void EraseAccount( const char* pszProtoName );
+void DeactivateAccount( PROTOACCOUNT* pa, bool bIsDynamic, bool bErase );
+void UnloadAccount( PROTOACCOUNT* pa, bool bIsDynamic, bool bErase );
+void OpenAccountOptions( PROTOACCOUNT* pa );
+
+void LoadDbAccounts( void );
+void WriteDbAccounts( void );
+
+INT_PTR CallProtoServiceInt( HANDLE hContact, const char* szModule, const char* szService, WPARAM, LPARAM );
+INT_PTR CallContactService( HANDLE hContact, const char *szProtoService, WPARAM, LPARAM );
+
+__inline static INT_PTR CallProtoService( const char* szModule, const char* szService, WPARAM wParam, LPARAM lParam )
+{
+ return CallProtoServiceInt( NULL, szModule, szService, wParam, lParam );
+}
+
+/**** utils.c **************************************************************************/
+
+#if defined( _UNICODE )
+ char* __fastcall rtrim(char* str);
+#endif
+TCHAR* __fastcall rtrim(TCHAR* str);
+char* __fastcall ltrim(char* str);
+char* __fastcall ltrimp(char* str);
+__inline char* lrtrim(char* str) { return ltrim(rtrim(str)); };
+__inline char* lrtrimp(char* str) { return ltrimp(rtrim(str)); };
+
+bool __fastcall wildcmp(char * name, char * mask);
+
+void HotkeyToName(TCHAR *buf, int size, BYTE shift, BYTE key);
+WORD GetHotkeyValue( INT_PTR idHotkey );
+
+HBITMAP ConvertIconToBitmap(HICON hIcon, HIMAGELIST hIml, int iconId);
+
+class StrConvUT
+{
+private:
+ wchar_t* m_body;
+
+public:
+ StrConvUT( const char* pSrc ) :
+ m_body( mir_a2u( pSrc )) {}
+
+ ~StrConvUT() { mir_free( m_body ); }
+ operator const wchar_t* () const { return m_body; }
+};
+
+class StrConvAT
+{
+private:
+ char* m_body;
+
+public:
+ StrConvAT( const wchar_t* pSrc ) :
+ m_body( mir_u2a( pSrc )) {}
+
+ ~StrConvAT() { mir_free( m_body ); }
+ operator const char* () const { return m_body; }
+ operator const wchar_t* () const { return ( wchar_t* )m_body; } // type cast to fake the interface definition
+ operator const LPARAM () const { return ( LPARAM )m_body; }
+};
+
+#ifdef _UNICODE
+
+#define StrConvT( x ) StrConvUT( x )
+#define StrConvTu( x ) x
+#define StrConvA( x ) StrConvAT( x )
+#define StrConvU( x ) x
+
+#else
+
+#define StrConvT( x ) x
+#define StrConvTu( x ) StrConvAT( x )
+#define StrConvA( x ) x
+#define StrConvU( x ) StrConvUT( x )
+
+#endif
+
diff --git a/src/core/modules.cpp b/src/core/modules.cpp
new file mode 100644
index 0000000000..c8d173f9a7
--- /dev/null
+++ b/src/core/modules.cpp
@@ -0,0 +1,784 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM 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"
+#include <m_plugins.h>
+
+// list of hooks
+
+static int compareHooks( const THook* p1, const THook* p2 )
+{
+ return strcmp( p1->name, p2->name );
+}
+
+static LIST<THook> hooks( 50, compareHooks );
+
+struct THookToMainThreadItem
+{
+ THook* hook;
+ HANDLE hDoneEvent;
+ WPARAM wParam;
+ LPARAM lParam;
+ int result;
+};
+
+// list of services
+
+struct TService
+{
+ DWORD nameHash;
+ HINSTANCE hOwner;
+ union {
+ MIRANDASERVICE pfnService;
+ MIRANDASERVICEPARAM pfnServiceParam;
+ MIRANDASERVICEOBJ pfnServiceObj;
+ MIRANDASERVICEOBJPARAM pfnServiceObjParam;
+ };
+ int flags;
+ LPARAM lParam;
+ void* object;
+ char name[1];
+};
+
+LIST<TService> services( 100, NumericKeySortT );
+
+typedef struct
+{
+ HANDLE hDoneEvent;
+ WPARAM wParam;
+ LPARAM lParam;
+ int result;
+ const char *name;
+}
+ TServiceToMainThreadItem;
+
+// other static variables
+static BOOL bServiceMode = FALSE;
+static CRITICAL_SECTION csHooks,csServices;
+static DWORD mainThreadId;
+static int hookId = 1;
+static HANDLE hMainThread;
+static HANDLE hMissingService;
+static THook *pLastHook = NULL;
+
+HINSTANCE GetInstByAddress( void* codePtr );
+
+void LangPackDropUnusedItems( void );
+
+void ParseCommandLine(); // core: IDD_WAITRESTART
+int LoadSystemModule(void); // core: m_system.h services
+int LoadNewPluginsModuleInfos(void); // core: preloading plugins
+int LoadNewPluginsModule(void); // core: N.O. plugins
+int LoadSslModule(void);
+int LoadNetlibModule(void); // core: network
+void NetlibInitSsl(void);
+int LoadLangPackModule(void); // core: translation
+int LoadProtocolsModule(void); // core: protocol manager
+int LoadAccountsModule(void); // core: account manager
+int LoadIgnoreModule(void); // protocol filter: ignore
+
+int LoadSendRecvUrlModule(void); //send/recv
+int LoadSendRecvEMailModule(void); //send/recv
+int LoadSendRecvAuthModule(void); //send/recv
+int LoadSendRecvFileModule(void); //send/recv
+
+int LoadContactListModule(void);// ui: clist
+int LoadOptionsModule(void); // ui: options dialog
+int LoadFindAddModule(void); // ui: search/add users
+int LoadSkinIcons(void);
+int LoadSkinSounds(void);
+int LoadSkinHotkeys(void);
+int LoadHelpModule(void); // ui: help stuff
+int LoadUserInfoModule(void); // ui: user info
+int LoadHistoryModule(void); // ui: history viewer
+int LoadAwayMsgModule(void); // ui: setting away messages
+int LoadVisibilityModule(void); // ui: visibility control
+int LoadCLUIModule(void); // ui: CList UI
+int LoadPluginOptionsModule(void); // ui: plugin viewer
+int LoadAddContactModule(void); // ui: authcontrol contacts
+int LoadIdleModule(void); // rnd: report idle information
+int LoadAutoAwayModule(void); // ui: away
+int LoadUserOnlineModule(void); // ui: online alert
+int LoadUtilsModule(void); // ui: utils (has a few window classes, like HyperLink)
+int LoadCLCModule(void); // window class: CLC control
+int LoadButtonModule(void); // window class: button class
+int LoadContactsModule(void); // random: contact
+int LoadFontserviceModule(void); // ui: font manager
+int LoadIcoLibModule(void); // ui: icons manager
+int LoadUpdateNotifyModule(void); // random: update notification
+int LoadServiceModePlugin(void);
+int LoadErrorsModule();
+
+void UnloadUtilsModule(void);
+void UnloadButtonModule(void);
+void UnloadClcModule(void);
+void UnloadContactListModule(void);
+void UnloadEventsModule(void);
+void UnloadIdleModule(void);
+void UnloadLangPackModule(void);
+void UnloadSslModule(void);
+void UnloadNetlibModule(void);
+void UnloadNewPlugins(void);
+void UnloadUpdateNotifyModule(void);
+void UnloadIcoLibModule(void);
+void UnloadSkinSounds(void);
+void UnloadSkinHotkeys(void);
+void UnloadProtocolsModule(void);
+void UnloadAccountsModule(void);
+void UnloadErrorsModule(void);
+
+int LoadIcoTabsModule();
+int LoadHeaderbarModule();
+int LoadDescButtonModule();
+int LoadDefaultModules(void)
+{
+ //load order is very important for these
+ if (LoadSystemModule()) return 1;
+ if (LoadLangPackModule()) return 1; // langpack will be a system module in the new order so this is moved here
+ ParseCommandLine(); // IDD_WAITRESTART need langpack so this is moved here
+ if (LoadUtilsModule()) return 1; //order not important for this, but no dependencies and no point in pluginising
+ if (LoadIcoTabsModule()) return 1;
+ if (LoadHeaderbarModule()) return 1;
+ if (LoadNewPluginsModuleInfos()) return 1;
+
+ // database is available here
+ if (LoadButtonModule()) return 1;
+ if (LoadIcoLibModule()) return 1;
+ if (LoadSkinIcons()) return 1;
+
+// if (LoadErrorsModule()) return 1;
+
+ bServiceMode = LoadServiceModePlugin();
+ switch ( bServiceMode )
+ {
+ case 1: return 0; // stop loading here
+ case 0: break;
+ default: return 1;
+ }
+
+ //this info will be available at LoadNewPluginsModule()
+ INT_PTR *disableDefaultModule=(INT_PTR*)CallService(MS_PLUGINS_GETDISABLEDEFAULTARRAY,0,0);
+
+ if (LoadSkinSounds()) return 1;
+ if (LoadSkinHotkeys()) return 1;
+ if (LoadFontserviceModule()) return 1;
+
+ if (LoadDescButtonModule()) return 1;
+ if (LoadOptionsModule()) return 1;
+ if (LoadNetlibModule()) return 1;
+ if (LoadProtocolsModule()) return 1;
+ LoadDbAccounts(); // retrieves the account array from a database
+ if (LoadContactsModule()) return 1;
+ if (LoadContactListModule()) return 1;
+ if (LoadAddContactModule()) return 1;
+ if (LoadNewPluginsModule()) return 1; // will call Load() on everything, clist will load first
+
+ LangPackDropUnusedItems();
+
+ if (!disableDefaultModule[DEFMOD_SSL]) if (LoadSslModule()) return 1;
+ NetlibInitSsl();
+
+ if (LoadAccountsModule()) return 1;
+
+ //order becomes less important below here
+ if (!disableDefaultModule[DEFMOD_UIFINDADD]) if (LoadFindAddModule()) return 1;
+ if (!disableDefaultModule[DEFMOD_UIUSERINFO]) if (LoadUserInfoModule()) return 1;
+ if (!disableDefaultModule[DEFMOD_SRURL]) if (LoadSendRecvUrlModule()) return 1;
+ if (!disableDefaultModule[DEFMOD_SREMAIL]) if (LoadSendRecvEMailModule()) return 1;
+ if (!disableDefaultModule[DEFMOD_SRAUTH]) if (LoadSendRecvAuthModule()) return 1;
+ if (!disableDefaultModule[DEFMOD_SRFILE]) if (LoadSendRecvFileModule()) return 1;
+ if (!disableDefaultModule[DEFMOD_UIHELP]) if (LoadHelpModule()) return 1;
+ if (!disableDefaultModule[DEFMOD_UIHISTORY]) if (LoadHistoryModule()) return 1;
+ if (!disableDefaultModule[DEFMOD_RNDIDLE]) if (LoadIdleModule()) return 1;
+ if (!disableDefaultModule[DEFMOD_RNDAUTOAWAY]) if (LoadAutoAwayModule()) return 1;
+ if (!disableDefaultModule[DEFMOD_RNDUSERONLINE]) if (LoadUserOnlineModule()) return 1;
+ if (!disableDefaultModule[DEFMOD_SRAWAY]) if (LoadAwayMsgModule()) return 1;
+ if (!disableDefaultModule[DEFMOD_RNDIGNORE]) if (LoadIgnoreModule()) return 1;
+ if (!disableDefaultModule[DEFMOD_UIVISIBILITY]) if (LoadVisibilityModule()) return 1;
+ if (!disableDefaultModule[DEFMOD_UPDATENOTIFY]) if (LoadUpdateNotifyModule()) return 1;
+ return 0;
+}
+
+void UnloadDefaultModules(void)
+{
+ UnloadAccountsModule();
+ UnloadNewPlugins();
+ UnloadProtocolsModule();
+ UnloadSkinSounds();
+ UnloadSkinHotkeys();
+// UnloadErrorsModule();
+ UnloadIcoLibModule();
+ UnloadUtilsModule();
+ UnloadButtonModule();
+ UnloadClcModule();
+ UnloadContactListModule();
+ UnloadEventsModule();
+ UnloadIdleModule();
+ UnloadUpdateNotifyModule();
+ UnloadNetlibModule();
+ UnloadSslModule();
+ UnloadLangPackModule();
+}
+
+int InitialiseModularEngine(void)
+{
+ InitializeCriticalSection(&csHooks);
+ InitializeCriticalSection(&csServices);
+
+ mainThreadId=GetCurrentThreadId();
+ DuplicateHandle(GetCurrentProcess(),GetCurrentThread(),GetCurrentProcess(),&hMainThread,0,FALSE,DUPLICATE_SAME_ACCESS);
+
+ hMissingService = CreateHookableEvent(ME_SYSTEM_MISSINGSERVICE);
+ return 0;
+}
+
+void DestroyModularEngine(void)
+{
+ int i;
+ THook* p;
+ EnterCriticalSection( &csHooks );
+ for( i=0; i < hooks.getCount(); i++ ) {
+ p = hooks[i];
+ if ( p->subscriberCount )
+ mir_free( p->subscriber );
+ DeleteCriticalSection( &p->csHook );
+ mir_free( p );
+ }
+ hooks.destroy();
+ LeaveCriticalSection( &csHooks );
+ DeleteCriticalSection( &csHooks );
+
+ EnterCriticalSection( &csServices );
+ for ( i=0; i < services.getCount(); i++ )
+ mir_free( services[i] );
+
+ services.destroy();
+ LeaveCriticalSection( &csServices );
+ DeleteCriticalSection( &csServices );
+ CloseHandle( hMainThread );
+}
+
+///////////////////////////////HOOKS
+
+HANDLE CreateHookableEvent(const char *name)
+{
+ THook* ret;
+ int idx;
+
+ if ( name == NULL )
+ return NULL;
+
+ EnterCriticalSection( &csHooks );
+ if (( idx = hooks.getIndex(( THook* )name )) != -1 ) {
+ LeaveCriticalSection( &csHooks );
+ return NULL;
+ }
+
+ ret = ( THook* )mir_alloc( sizeof( THook ));
+ strncpy( ret->name, name, sizeof( ret->name )); ret->name[ MAXMODULELABELLENGTH-1 ] = 0;
+ ret->id = hookId++;
+ ret->subscriberCount = 0;
+ ret->subscriber = NULL;
+ ret->pfnHook = NULL;
+ InitializeCriticalSection( &ret->csHook );
+ hooks.insert( ret );
+
+ LeaveCriticalSection( &csHooks );
+ return ( HANDLE )ret;
+}
+
+int DestroyHookableEvent( HANDLE hEvent )
+{
+ int idx;
+ THook* p;
+
+ EnterCriticalSection( &csHooks );
+ if ( pLastHook == ( THook* )hEvent )
+ pLastHook = NULL;
+
+ if (( idx = hooks.getIndex(( THook* )hEvent )) == -1 ) {
+ LeaveCriticalSection(&csHooks);
+ return 1;
+ }
+ p = hooks[idx];
+ if ( p->subscriberCount ) {
+ mir_free( p->subscriber );
+ p->subscriber = NULL;
+ p->subscriberCount = 0;
+ }
+ hooks.remove( idx );
+ DeleteCriticalSection( &p->csHook );
+ mir_free( p );
+
+ LeaveCriticalSection( &csHooks );
+ return 0;
+}
+
+int SetHookDefaultForHookableEvent(HANDLE hEvent, MIRANDAHOOK pfnHook)
+{
+ THook* p = ( THook* )hEvent;
+
+ EnterCriticalSection(&csHooks);
+ if ( hooks.getIndex( p ) != -1 )
+ p->pfnHook = pfnHook;
+ LeaveCriticalSection(&csHooks);
+ return 0;
+}
+
+int CallHookSubscribers( HANDLE hEvent, WPARAM wParam, LPARAM lParam )
+{
+ int i, returnVal = 0;
+ THook* p = ( THook* )hEvent;
+ if ( p == NULL )
+ return -1;
+
+ EnterCriticalSection( &p->csHook );
+
+ // NOTE: We've got the critical section while all this lot are called. That's mostly safe, though.
+ for ( i = 0; i < p->subscriberCount; i++ ) {
+ THookSubscriber* s = &p->subscriber[i];
+ switch ( s->type ) {
+ case 1: returnVal = s->pfnHook( wParam, lParam ); break;
+ case 2: returnVal = s->pfnHookParam( wParam, lParam, s->lParam ); break;
+ case 3: returnVal = s->pfnHookObj( s->object, wParam, lParam ); break;
+ case 4: returnVal = s->pfnHookObjParam( s->object, wParam, lParam, s->lParam ); break;
+ case 5: returnVal = SendMessage( s->hwnd, s->message, wParam, lParam ); break;
+ default: continue;
+ }
+ if ( returnVal )
+ break;
+ }
+
+ // check for no hooks and call the default hook if any
+ if ( p->subscriberCount == 0 && p->pfnHook != 0 )
+ returnVal = p->pfnHook( wParam, lParam );
+
+ LeaveCriticalSection( &p->csHook );
+ return returnVal;
+}
+
+static int checkHook( HANDLE hHook )
+{
+ if ( hHook == NULL )
+ return -1;
+
+ EnterCriticalSection( &csHooks );
+ if ( pLastHook != hHook || !pLastHook ) {
+ if ( hooks.getIndex(( THook* )hHook ) == -1 ) {
+ LeaveCriticalSection( &csHooks );
+ return -1;
+ }
+ pLastHook = ( THook* )hHook;
+ }
+ LeaveCriticalSection( &csHooks );
+ return 0;
+}
+
+static void CALLBACK HookToMainAPCFunc(ULONG_PTR dwParam)
+{
+ THookToMainThreadItem* item = ( THookToMainThreadItem* )dwParam;
+
+ if ( checkHook( item->hook ) == -1 )
+ item->result = -1;
+ else
+ item->result = CallHookSubscribers( item->hook, item->wParam, item->lParam );
+ SetEvent( item->hDoneEvent );
+}
+
+int NotifyEventHooks( HANDLE hEvent, WPARAM wParam, LPARAM lParam )
+{
+ extern HWND hAPCWindow;
+
+ if ( GetCurrentThreadId() != mainThreadId ) {
+ THookToMainThreadItem item;
+
+ item.hDoneEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
+ item.hook = ( THook* )hEvent;
+ item.wParam = wParam;
+ item.lParam = lParam;
+
+ QueueUserAPC( HookToMainAPCFunc, hMainThread, ( ULONG_PTR )&item );
+ PostMessage( hAPCWindow, WM_NULL, 0, 0 ); // let it process APC even if we're in a common dialog
+ WaitForSingleObject( item.hDoneEvent, INFINITE );
+ CloseHandle( item.hDoneEvent );
+ return item.result;
+ }
+
+ return ( checkHook( hEvent ) == -1 ) ? -1 : CallHookSubscribers( hEvent, wParam, lParam );
+}
+
+static HANDLE HookEventInt( int type, const char* name, MIRANDAHOOK hookProc, void* object, LPARAM lParam )
+{
+ int idx;
+ THook* p;
+ HANDLE ret;
+
+ EnterCriticalSection( &csHooks );
+ if (( idx = hooks.getIndex(( THook* )name )) == -1 ) {
+ #ifdef _DEBUG
+ OutputDebugStringA("Attempt to hook: \t");
+ OutputDebugStringA(name);
+ OutputDebugStringA("\n");
+ #endif
+ LeaveCriticalSection(&csHooks);
+ return NULL;
+ }
+
+ p = hooks[ idx ];
+ p->subscriber = ( THookSubscriber* )mir_realloc( p->subscriber, sizeof( THookSubscriber )*( p->subscriberCount+1 ));
+ p->subscriber[ p->subscriberCount ].type = type;
+ p->subscriber[ p->subscriberCount ].pfnHook = hookProc;
+ p->subscriber[ p->subscriberCount ].object = object;
+ p->subscriber[ p->subscriberCount ].lParam = lParam;
+ p->subscriber[ p->subscriberCount ].hOwner = GetInstByAddress( hookProc );
+ p->subscriberCount++;
+
+ ret = ( HANDLE )(( p->id << 16 ) | p->subscriberCount );
+ LeaveCriticalSection( &csHooks );
+ return ret;
+}
+
+HANDLE HookEvent( const char* name, MIRANDAHOOK hookProc )
+{
+ return HookEventInt( 1, name, hookProc, 0, 0 );
+}
+
+HANDLE HookEventParam( const char* name, MIRANDAHOOKPARAM hookProc, LPARAM lParam )
+{
+ return HookEventInt( 2, name, (MIRANDAHOOK)hookProc, 0, lParam );
+}
+
+HANDLE HookEventObj( const char* name, MIRANDAHOOKOBJ hookProc, void* object)
+{
+ return HookEventInt( 3, name, (MIRANDAHOOK)hookProc, object, 0 );
+}
+
+HANDLE HookEventObjParam( const char* name, MIRANDAHOOKOBJPARAM hookProc, void* object, LPARAM lParam )
+{
+ return HookEventInt( 4, name, (MIRANDAHOOK)hookProc, object, lParam );
+}
+
+HANDLE HookEventMessage( const char* name, HWND hwnd, UINT message )
+{
+ int idx;
+ THook* p;
+ HANDLE ret;
+
+ EnterCriticalSection( &csHooks );
+ if (( idx = hooks.getIndex(( THook* )name )) == -1 ) {
+ #ifdef _DEBUG
+ MessageBoxA(NULL,"Attempt to hook non-existant event",name,MB_OK);
+ #endif
+ LeaveCriticalSection(&csHooks);
+ return NULL;
+ }
+
+ p = hooks[ idx ];
+ p->subscriber = ( THookSubscriber* )mir_realloc( p->subscriber, sizeof( THookSubscriber )*( p->subscriberCount+1 ));
+ p->subscriber[ p->subscriberCount ].type = 5;
+ p->subscriber[ p->subscriberCount ].hwnd = hwnd;
+ p->subscriber[ p->subscriberCount ].message = message;
+ p->subscriberCount++;
+
+ ret = ( HANDLE )(( p->id << 16 ) | p->subscriberCount );
+ LeaveCriticalSection( &csHooks );
+ return ret;
+}
+
+int UnhookEvent( HANDLE hHook )
+{
+ int i;
+ THook* p = NULL;
+
+ int hookId = ( int )hHook >> 16;
+ int subscriberId = (( int )hHook & 0xFFFF ) - 1;
+
+ if (hHook == NULL) return 0;
+
+ EnterCriticalSection( &csHooks );
+ for ( i = 0; i < hooks.getCount(); i++ ) {
+ if ( hooks[i]->id == hookId ) {
+ p = hooks[i];
+ break;
+ } }
+
+ if ( p == NULL ) {
+ LeaveCriticalSection( &csHooks );
+ return 1;
+ }
+
+ if ( subscriberId >= p->subscriberCount || subscriberId < 0 ) {
+ LeaveCriticalSection( &csHooks );
+ return 1;
+ }
+
+ p->subscriber[subscriberId].type = 0;
+ p->subscriber[subscriberId].pfnHook = NULL;
+ p->subscriber[subscriberId].hOwner = NULL;
+ while( p->subscriberCount && p->subscriber[p->subscriberCount-1].type == 0 )
+ p->subscriberCount--;
+ if ( p->subscriberCount == 0 ) {
+ if ( p->subscriber ) mir_free( p->subscriber );
+ p->subscriber = NULL;
+ }
+ LeaveCriticalSection( &csHooks );
+ return 0;
+}
+
+void KillModuleEventHooks( HINSTANCE hInst )
+{
+ int i, j;
+
+ EnterCriticalSection(&csHooks);
+ for ( i = hooks.getCount()-1; i >= 0; i-- ) {
+ if ( hooks[i]->subscriberCount == 0 )
+ continue;
+
+ for ( j = hooks[i]->subscriberCount-1; j >= 0; j-- ) {
+ if ( hooks[i]->subscriber[j].hOwner == hInst ) {
+ char szModuleName[ MAX_PATH ];
+ GetModuleFileNameA( hooks[i]->subscriber[j].hOwner, szModuleName, sizeof(szModuleName));
+ Netlib_Logf( NULL, "A hook %08x for event '%s' was abnormally deleted because module '%s' didn't released it",
+ hooks[i]->subscriber[j].pfnHook, hooks[i]->name, szModuleName );
+ UnhookEvent(( HANDLE )(( hooks[i]->id << 16 ) + j + 1 ));
+ if ( hooks[i]->subscriberCount == 0 )
+ break;
+ } } }
+
+ LeaveCriticalSection(&csHooks);
+}
+
+void KillObjectEventHooks( void* pObject )
+{
+ int i, j;
+
+ EnterCriticalSection(&csHooks);
+ for ( i = hooks.getCount()-1; i >= 0; i-- ) {
+ if ( hooks[i]->subscriberCount == 0 )
+ continue;
+
+ for ( j = hooks[i]->subscriberCount-1; j >= 0; j-- ) {
+ if ( hooks[i]->subscriber[j].object == pObject ) {
+ UnhookEvent(( HANDLE )(( hooks[i]->id << 16 ) + j + 1 ));
+ if ( hooks[i]->subscriberCount == 0 )
+ break;
+ } } }
+
+ LeaveCriticalSection(&csHooks);
+}
+
+/////////////////////SERVICES
+
+static __inline TService* FindServiceByName( const char *name )
+{
+ unsigned hash = hashstr( name );
+ return services.find(( TService* )&hash );
+}
+
+static HANDLE CreateServiceInt( int type, const char *name, MIRANDASERVICE serviceProc, void* object, LPARAM lParam)
+{
+ if ( name == NULL ) {
+#ifdef _DEBUG
+ MessageBoxA(0,"Someone tried to create a NULL'd service, see call stack for more info","",0);
+ DebugBreak();
+#endif
+ return NULL;
+ }
+
+ TService tmp;
+ tmp.nameHash = hashstr( name );
+
+ EnterCriticalSection( &csServices );
+
+ if ( services.getIndex( &tmp ) != -1 ) {
+ LeaveCriticalSection( &csServices );
+ return NULL;
+ }
+
+ TService* p = ( TService* )mir_alloc( sizeof( *p ) + strlen( name ));
+ strcpy( p->name, name );
+ p->nameHash = tmp.nameHash;
+ p->pfnService = serviceProc;
+ p->hOwner = GetInstByAddress( serviceProc );
+ p->flags = type;
+ p->lParam = lParam;
+ p->object = object;
+ services.insert( p );
+
+ LeaveCriticalSection( &csServices );
+ return ( HANDLE )tmp.nameHash;
+}
+
+HANDLE CreateServiceFunction( const char *name, MIRANDASERVICE serviceProc )
+{
+ return CreateServiceInt( 0, name, serviceProc, 0, 0 );
+}
+
+HANDLE CreateServiceFunctionParam(const char *name,MIRANDASERVICEPARAM serviceProc,LPARAM lParam)
+{
+ return CreateServiceInt( 1, name, (MIRANDASERVICE)serviceProc, 0, lParam );
+}
+
+HANDLE CreateServiceFunctionObj(const char *name,MIRANDASERVICEOBJ serviceProc,void* object)
+{
+ return CreateServiceInt( 2, name, (MIRANDASERVICE)serviceProc, object, 0 );
+}
+
+HANDLE CreateServiceFunctionObjParam(const char *name,MIRANDASERVICEOBJPARAM serviceProc,void* object,LPARAM lParam)
+{
+ return CreateServiceInt( 3, name, (MIRANDASERVICE)serviceProc, object, lParam );
+}
+
+int DestroyServiceFunction(HANDLE hService)
+{
+ int idx;
+
+ EnterCriticalSection( &csServices );
+ if (( idx = services.getIndex(( TService* )&hService )) != -1 ) {
+ mir_free( services[idx] );
+ services.remove( idx );
+ }
+
+ LeaveCriticalSection(&csServices);
+ return 0;
+}
+
+int ServiceExists(const char *name)
+{
+ if ( name == NULL )
+ return FALSE;
+
+ EnterCriticalSection( &csServices );
+ int ret = FindServiceByName( name ) != NULL;
+ LeaveCriticalSection( &csServices );
+ return ret;
+}
+
+INT_PTR CallService(const char *name,WPARAM wParam,LPARAM lParam)
+{
+ #ifdef _DEBUG
+ if (name==NULL) {
+ MessageBoxA(0,"Someone tried to CallService(NULL,..) see stack trace for details","",0);
+ DebugBreak();
+ return CALLSERVICE_NOTFOUND;
+ }
+ #else
+ if (name==NULL) return CALLSERVICE_NOTFOUND;
+ #endif
+
+ EnterCriticalSection(&csServices);
+ TService *pService = FindServiceByName(name);
+ if (pService==NULL) {
+ LeaveCriticalSection(&csServices);
+ #ifdef _DEBUG
+ //MessageBoxA(NULL,"Attempt to call non-existant service",name,MB_OK);
+ OutputDebugStringA("Missing service called: \t");
+ OutputDebugStringA(name);
+ OutputDebugStringA("\n");
+ #endif
+/* { MISSING_SERVICE_PARAMS params = { name, wParam, lParam };
+ int result = NotifyEventHooks(hMissingService,0,(LPARAM)&params);
+ if (result != 0)
+ return params.lParam;
+ } */
+ return CALLSERVICE_NOTFOUND;
+ }
+
+ MIRANDASERVICE pfnService = pService->pfnService;
+ int flags = pService->flags;
+ LPARAM fnParam = pService->lParam;
+ void* object = pService->object;
+ LeaveCriticalSection(&csServices);
+ switch( flags ) {
+ case 1: return ((MIRANDASERVICEPARAM)pfnService)(wParam,lParam,fnParam);
+ case 2: return ((MIRANDASERVICEOBJ)pfnService)(object,wParam,lParam);
+ case 3: return ((MIRANDASERVICEOBJPARAM)pfnService)(object,wParam,lParam,fnParam);
+ default: return pfnService(wParam,lParam);
+} }
+
+static void CALLBACK CallServiceToMainAPCFunc(ULONG_PTR dwParam)
+{
+ TServiceToMainThreadItem *item = (TServiceToMainThreadItem*) dwParam;
+ item->result = CallService(item->name, item->wParam, item->lParam);
+ SetEvent(item->hDoneEvent);
+}
+
+INT_PTR CallServiceSync(const char *name, WPARAM wParam, LPARAM lParam)
+{
+ extern HWND hAPCWindow;
+
+ if (name==NULL) return CALLSERVICE_NOTFOUND;
+ // the service is looked up within the main thread, since the time it takes
+ // for the APC queue to clear the service being called maybe removed.
+ // even thou it may exists before the call, the critsec can't be locked between calls.
+ if (GetCurrentThreadId() != mainThreadId) {
+ TServiceToMainThreadItem item;
+ item.wParam = wParam;
+ item.lParam = lParam;
+ item.name = name;
+ item.hDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ QueueUserAPC(CallServiceToMainAPCFunc, hMainThread, (ULONG_PTR) &item);
+ PostMessage(hAPCWindow,WM_NULL,0,0); // let this get processed in its own time
+ WaitForSingleObject(item.hDoneEvent, INFINITE);
+ CloseHandle(item.hDoneEvent);
+ return item.result;
+ }
+
+ return CallService(name, wParam, lParam);
+}
+
+int CallFunctionAsync( void (__stdcall *func)(void *), void *arg)
+{
+ extern HWND hAPCWindow;
+ int r = QueueUserAPC(( void (__stdcall *)( ULONG_PTR ))func, hMainThread, ( ULONG_PTR )arg );
+ PostMessage(hAPCWindow,WM_NULL,0,0);
+ return r;
+}
+
+void KillModuleServices( HINSTANCE hInst )
+{
+ int i;
+
+ EnterCriticalSection(&csServices);
+ for ( i = services.getCount()-1; i >= 0; i-- ) {
+ if ( services[i]->hOwner == hInst ) {
+ char szModuleName[ MAX_PATH ];
+ GetModuleFileNameA( services[i]->hOwner, szModuleName, sizeof(szModuleName));
+ Netlib_Logf( NULL, "A service function '%s' was abnormally deleted because module '%s' didn't released it",
+ services[i]->name, szModuleName );
+ DestroyServiceFunction(( HANDLE )services[i]->nameHash );
+ } }
+
+ LeaveCriticalSection(&csServices);
+}
+
+void KillObjectServices( void* pObject )
+{
+ int i;
+
+ EnterCriticalSection(&csServices);
+ for ( i = services.getCount()-1; i >= 0; i-- )
+ if ( services[i]->object == pObject )
+ DestroyServiceFunction(( HANDLE )services[i]->nameHash );
+
+ LeaveCriticalSection(&csServices);
+}
diff --git a/src/core/modules.h b/src/core/modules.h
new file mode 100644
index 0000000000..f40fc885e6
--- /dev/null
+++ b/src/core/modules.h
@@ -0,0 +1,268 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM 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.
+*/
+//Modules Core - Richard
+#ifndef MODULES_H_
+#define MODULES_H_
+
+#ifdef _MSC_VER
+ #pragma warning(disable:4201)
+#endif
+
+/* MAXMODULELABELLENGTH
+The maximum allowed length of a 'name' parameter. Very likely to change with
+restructuring modules.c for performance.
+*/
+#define MAXMODULELABELLENGTH 64
+
+typedef int (*MIRANDAHOOK)(WPARAM,LPARAM);
+typedef int (*MIRANDAHOOKPARAM)(WPARAM,LPARAM,LPARAM);
+typedef int (*MIRANDAHOOKOBJ)(void*,WPARAM,LPARAM);
+typedef int (*MIRANDAHOOKOBJPARAM)(void*,WPARAM,LPARAM,LPARAM);
+
+typedef INT_PTR (*MIRANDASERVICE)(WPARAM,LPARAM);
+typedef INT_PTR (*MIRANDASERVICEPARAM)(WPARAM,LPARAM,LPARAM);
+typedef INT_PTR (*MIRANDASERVICEOBJ)(void*,LPARAM,LPARAM);
+typedef INT_PTR (*MIRANDASERVICEOBJPARAM)(void*,WPARAM,LPARAM,LPARAM);
+
+typedef struct
+{
+ HINSTANCE hOwner;
+ int type;
+ union {
+ struct {
+ union {
+ MIRANDAHOOK pfnHook;
+ MIRANDAHOOKPARAM pfnHookParam;
+ MIRANDAHOOKOBJ pfnHookObj;
+ MIRANDAHOOKOBJPARAM pfnHookObjParam;
+ };
+ void* object;
+ LPARAM lParam;
+ };
+ struct {
+ HWND hwnd;
+ UINT message;
+ };
+ };
+}
+ THookSubscriber;
+
+typedef struct
+{
+ char name[ MAXMODULELABELLENGTH ];
+ int id;
+ int subscriberCount;
+ THookSubscriber* subscriber;
+ MIRANDAHOOK pfnHook;
+ CRITICAL_SECTION csHook;
+}
+ THook;
+
+/**************************hook functions****************************/
+/* CreateHookableEvent
+Adds an named event to the list and returns a handle referring to it, or NULL
+on failure. Will be automatically destroyed on exit, or can be removed from the
+list earlier using DestroyHookableEvent()
+Will fail if the given name has already been used
+*/
+HANDLE CreateHookableEvent(const char *name);
+
+/* DestroyHookableEvent
+Removes the event hEvent from the list of events. All modules hooked to it are
+automatically unhooked. NotifyEventHooks() will fail if called with this hEvent
+again. hEvent must have been returned by CreateHookableEvent()
+Returns 0 on success, or nonzero if hEvent is invalid
+*/
+int DestroyHookableEvent(HANDLE hEvent);
+
+/* NotifyEventHooks
+Calls every module in turn that has hooked hEvent, using the parameters wParam
+and lParam. hEvent must have been returned by CreateHookableEvent()
+Returns 0 on success
+ -1 if hEvent is invalid
+ If one of the hooks returned nonzero to indicate abort, returns that abort
+ value immediately, without calling the rest of the hooks in the chain
+
+Notes on calling NotifyEventHooks() from a thread other than that which owns
+the main Miranda window:
+It works. The call is routed to the main thread and all hook subcribers are
+called in the context of the main thread. The thread which called
+NotifyHookEvents() is paused until all the processing is complete at which
+point it returns with the correct return value.
+This procedure requires more than one wait object so naturally there are
+possibilities for deadlocks, but not many.
+Calling NotifyEventHooks() from other than the main thread will be
+considerably slower than from the main thread, but will consume only slightly
+more actual CPU time, the rest will mostly be spent waiting for the main thread
+to return to the message loop so it can be interrupted neatly.
+*/
+int NotifyEventHooks(HANDLE hEvent,WPARAM wParam,LPARAM lParam);
+
+/* CallHookSubscribers
+Works precisely like NotifyEventHooks, but without switching to the first thread
+It guarantees that the execution time for these events is always tiny
+*/
+
+int CallHookSubscribers( HANDLE hEvent, WPARAM wParam, LPARAM lParam );
+
+/*
+ hEvent : a HANDLE which has been returned by CreateHookableEvent()
+ pfnHook: a function pointer (MIRANDAHOOK) which is called when there are no hooks.
+ Affect: This core service allows hooks to have a 'default' hook which is called
+ when no one has hooked the given event, this allows hook creators to add default
+ processing which is ONLY CALLED when no one else has HookEvent()'d
+ Notes: The return value from pfnHook() is returned to NotifyEventHooks()
+ Returns: 0 on success, non zero on failure
+ Version: 0.3.4+ (2004/09/15)
+*/
+int SetHookDefaultForHookableEvent(HANDLE hEvent, MIRANDAHOOK pfnHook);
+
+/* HookEvent
+Adds a new hook to the chain 'name', to be called when the hook owner calls
+NotifyEventHooks(). Returns NULL if name is not a valid event or a handle
+referring to the hook otherwise. Note that debug builds will warn with a
+MessageBoxA if a hook is attempted on an unknown event. All hooks will be
+automatically destroyed when their parent event is destroyed or the programme
+ends, but can be unhooked earlier using UnhookEvent(). hookProc() is defined as
+ int HookProc(WPARAM wParam,LPARAM lParam)
+where you can substitute your own name for HookProc. wParam and lParam are
+defined by the creator of the event when NotifyEventHooks() is called.
+The return value is 0 to continue processing the other hooks, or nonzero
+to stop immediately. This abort value is returned to the caller of
+NotifyEventHooks() and should not be -1 since that is a special return code
+for NotifyEventHooks() (see above)
+*/
+HANDLE HookEvent(const char *name,MIRANDAHOOK hookProc);
+HANDLE HookEventParam(const char *name, MIRANDAHOOKPARAM hookProc, LPARAM lParam);
+HANDLE HookEventObj(const char *name,MIRANDAHOOKOBJ hookProc, void* object);
+HANDLE HookEventObjParam(const char *name, MIRANDAHOOKOBJPARAM hookProc, void* object, LPARAM lParam);
+
+/* HookEventMessage
+Works as for HookEvent(), except that when the notifier is called a message is
+sent to a window, rather than a function being called.
+Note that SendMessage() is a decidedly slow function so please limit use of
+this function to events that are not called frequently, or to hooks that are
+only installed briefly
+The window procedure is called with the message 'message' and the wParam and
+lParam given to NotifyEventHooks(). The return value of SendMessage() is used
+in the same way as the return value in HookEvent().
+*/
+HANDLE HookEventMessage(const char *name,HWND hwnd,UINT message);
+
+/* UnhookEvent
+Removes a hook from its event chain. It will no longer receive any events.
+hHook must have been returned by HookEvent() or HookEventMessage().
+Returns 0 on success or nonzero if hHook is invalid.
+*/
+int UnhookEvent(HANDLE hHook);
+
+
+/*************************service functions**************************/
+/* CreateServiceFunction
+Adds a new service function called 'name' to the global list and returns a
+handle referring to it. Service function handles are destroyed automatically
+on exit, but can be removed from the list earlier using
+DestroyServiceFunction()
+Returns NULL if name has already been used. serviceProc is defined by the
+caller as
+ int ServiceProc(WPARAM wParam,LPARAM lParam)
+where the creator publishes the meanings of wParam, lParam and the return value
+Service functions must not return CALLSERVICE_NOTFOUND since that would confuse
+callers of CallService().
+*/
+HANDLE CreateServiceFunction(const char *name,MIRANDASERVICE serviceProc);
+
+/* CreateServiceFunctionParam
+Same as CreateServiceFunction - adds new parameter, to pass to service handler function.
+serviceProc is defined by the caller as
+ int ServiceProc(WPARAM wParam,LPARAM lParam,LPARAM fnParam)
+where fnParam does not need to be publicly known. Gives the ability to handle multiple services
+with the same function.
+
+added during 0.7+ (2007/04/24)
+*/
+HANDLE CreateServiceFunctionParam(const char *name,MIRANDASERVICEPARAM serviceProc,LPARAM lParam);
+
+/* CreateServiceFunctionObj
+ CreateServiceFunctionObjParam
+Same as CreateServiceFunction - adds new parameter, an object, to pass to service handler function.
+serviceProc is defined by the caller as
+ int ServiceProc(void* object, WPARAM wParam,LPARAM lParam[,LPARAM fnParam])
+where fnParam does not need to be publicly known. Gives the ability to handle multiple services
+with the same function.
+
+added during 0.7+ (2007/04/24)
+*/
+
+HANDLE CreateServiceFunctionObj(const char *name,MIRANDASERVICEOBJ serviceProc,void* object);
+HANDLE CreateServiceFunctionObjParam(const char *name,MIRANDASERVICEOBJPARAM serviceProc,void* object,LPARAM lParam);
+
+/* DestroyServiceFunction
+Removes the function associated with hService from the global service function
+list. Modules calling CallService() will fail if they try to call this
+service's name. hService must have been returned by CreateServiceFunction().
+Returns 0 on success or non-zero if hService is invalid.
+*/
+int DestroyServiceFunction(HANDLE hService);
+
+/* CallService
+Finds and calls the service function 'name' using the parameters wParam and
+lParam.
+Returns CALLSERVICE_NOTFOUND if no service function called 'name' has been
+created, or the value the service function returned otherwise.
+*/
+#ifdef _WIN64
+ #define CALLSERVICE_NOTFOUND ((INT_PTR)0x8000000000000000)
+#else
+ #define CALLSERVICE_NOTFOUND ((int)0x80000000)
+#endif
+INT_PTR CallService(const char *name,WPARAM wParam,LPARAM lParam);
+
+/* ServiceExists
+Finds if a service with the given name exists
+Returns nonzero if the service was found, and zero if it was not
+*/
+int ServiceExists(const char *name);
+
+/* CallServiceSync
+Calls a given service executed within the context of the main thread
+only useful to multi threaded modules calling thread unsafe services!
+*/
+INT_PTR CallServiceSync(const char *name, WPARAM wParam, LPARAM lParam);
+
+/* CallFunctionAsync
+Calls a given function pointer, it doesn't go thru the core at all, it is
+just a wrapper around QueueUserAPC() and other workarounds to make APC
+work even if there are non APC message loops, this allows plugins who
+need this feature to get it without recoding it themselves.
+
+The function 'func' will always be called from the main thread in idle time even
+if it is invokved from a worker thread, 'arg' must not be on the stack.
+
+Returns nonzero on success, zero on failure
+
+added during 0.3.4+ (2004/08/14)
+*/
+int CallFunctionAsync( void (__stdcall *func)(void *), void *arg);
+
+#endif // MODULES_H_