From cb4a46e7fbe62d788e66ed6121c717a2d22a4d7c Mon Sep 17 00:00:00 2001 From: watcherhd Date: Thu, 21 Apr 2011 14:14:52 +0000 Subject: svn.miranda.im is moving to a new home! git-svn-id: http://miranda-plugins.googlecode.com/svn/trunk@7 e753b5eb-9565-29b2-b5c5-2cc6f99dfbcb --- miranda-wine/src/core/commonheaders.c | 2 + miranda-wine/src/core/commonheaders.h | 84 +++++ miranda-wine/src/core/forkthread.h | 64 ++++ miranda-wine/src/core/memory.c | 167 +++++++++ miranda-wine/src/core/miranda.c | 565 +++++++++++++++++++++++++++++ miranda-wine/src/core/miranda.h | 48 +++ miranda-wine/src/core/modules.c | 656 ++++++++++++++++++++++++++++++++++ miranda-wine/src/core/modules.h | 184 ++++++++++ 8 files changed, 1770 insertions(+) create mode 100644 miranda-wine/src/core/commonheaders.c create mode 100644 miranda-wine/src/core/commonheaders.h create mode 100644 miranda-wine/src/core/forkthread.h create mode 100644 miranda-wine/src/core/memory.c create mode 100644 miranda-wine/src/core/miranda.c create mode 100644 miranda-wine/src/core/miranda.h create mode 100644 miranda-wine/src/core/modules.c create mode 100644 miranda-wine/src/core/modules.h (limited to 'miranda-wine/src/core') diff --git a/miranda-wine/src/core/commonheaders.c b/miranda-wine/src/core/commonheaders.c new file mode 100644 index 0000000..95b2201 --- /dev/null +++ b/miranda-wine/src/core/commonheaders.c @@ -0,0 +1,2 @@ +#include "commonheaders.h" + diff --git a/miranda-wine/src/core/commonheaders.h b/miranda-wine/src/core/commonheaders.h new file mode 100644 index 0000000..a08783f --- /dev/null +++ b/miranda-wine/src/core/commonheaders.h @@ -0,0 +1,84 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2006 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. +*/ + +#if defined( UNICODE ) && !defined( _UNICODE ) +# define _UNICODE +#endif + +#include +#include + +#define _ALPHA_BASE_ 1 // defined for CVS builds +#define _ALPHA_FUSE_ 1 // defined for fuse powered core + +#ifdef _DEBUG +# define _CRTDBG_MAP_ALLOC +# include +# include +#endif + +#define _WIN32_WINNT 0x0501 +#define _WIN32_IE 0x0500 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../resource.h" +#include +#include "modules.h" +#include "miranda.h" +#include "forkthread.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/miranda-wine/src/core/forkthread.h b/miranda-wine/src/core/forkthread.h new file mode 100644 index 0000000..154584f --- /dev/null +++ b/miranda-wine/src/core/forkthread.h @@ -0,0 +1,64 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2006 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. + +*/ +unsigned long forkthread ( + void (__cdecl *threadcode)(void*), + unsigned long stacksize, + void *arg +); + +unsigned long forkthreadex( + void *sec, + unsigned stacksize, + unsigned (__stdcall *threadcode)(void*), + void *arg, + unsigned cf, + unsigned *thraddr +); + diff --git a/miranda-wine/src/core/memory.c b/miranda-wine/src/core/memory.c new file mode 100644 index 0000000..7c55939 --- /dev/null +++ b/miranda-wine/src/core/memory.c @@ -0,0 +1,167 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2006 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 = mir_alloc( strlen( str )+1 ); + if ( p ) + strcpy( p, str ); + return p; + } + return NULL; +} + +/******************************************************************************/ + +WCHAR* mir_wstrdup( const WCHAR* str ) +{ + if ( str != NULL ) { + WCHAR* p = mir_alloc( sizeof( WCHAR )*( wcslen( str )+1 )); + if ( p ) + wcscpy( p, str ); + return p; + } + return NULL; +} diff --git a/miranda-wine/src/core/miranda.c b/miranda-wine/src/core/miranda.c new file mode 100644 index 0000000..f003ecf --- /dev/null +++ b/miranda-wine/src/core/miranda.c @@ -0,0 +1,565 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2006 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 "../modules/database/dblists.h" + +int InitialiseModularEngine(void); +void DestroyingModularEngine(void); +void DestroyModularEngine(void); +int UnloadNewPluginsModule(void); + +HINSTANCE GetInstByAddress( void* codePtr ); + +DWORD (WINAPI *MyMsgWaitForMultipleObjectsEx)(DWORD,CONST HANDLE*,DWORD,DWORD,DWORD); +static DWORD MsgWaitForMultipleObjectsExWorkaround(DWORD nCount, const HANDLE *pHandles, + DWORD dwMsecs, DWORD dwWakeMask, DWORD dwFlags); + +static 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 hStackMutex,hMirandaShutdown,hThreadQueueEmpty; + +struct THREAD_WAIT_ENTRY { + DWORD dwThreadId; // valid if hThread isn't signalled + HANDLE hThread; + HINSTANCE hOwner; +}; + +struct THREAD_WAIT_ENTRY *WaitingThreads=NULL; +int WaitingThreadsCount=0; + +struct FORK_ARG { + HANDLE hEvent; + void (__cdecl *threadcode)(void*); + unsigned (__stdcall *threadcodeex)(void*); + void *arg; +}; + +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,0); + SetEvent(fa->hEvent); + __try { + callercode(cookie); + } __finally { + CallService(MS_SYSTEM_THREAD_POP,0,0); + } + return; +} + +unsigned long forkthread ( + void (__cdecl *threadcode)(void*), + unsigned long stacksize, + void *arg +) +{ + unsigned long 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 ((unsigned long)-1L != rc) { + WaitForSingleObject(fa.hEvent,INFINITE); + } //if + CloseHandle(fa.hEvent); + return rc; +} + +unsigned __stdcall forkthreadex_r(void * arg) +{ + struct FORK_ARG *fa=(struct FORK_ARG *)arg; + unsigned (__stdcall * threadcode) (void *)=fa->threadcodeex; + void *cookie=fa->arg; + unsigned long rc; + + CallService(MS_SYSTEM_THREAD_PUSH,0,0); + SetEvent(fa->hEvent); + __try { + rc=threadcode(cookie); + } __finally { + CallService(MS_SYSTEM_THREAD_POP,0,0); + } + return rc; +} + +unsigned long forkthreadex( + void *sec, + unsigned stacksize, + unsigned (__stdcall *threadcode)(void*), + void *arg, + unsigned cf, + unsigned *thraddr +) +{ + unsigned long rc; + struct FORK_ARG fa; + fa.threadcodeex=threadcode; + fa.arg=arg; + 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 void __stdcall DummyAPCFunc(DWORD dwArg) +{ + /* 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 hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + if ( MirandaWaitForMutex( hStackMutex )) { + int j; + for ( j=0; j < WaitingThreadsCount; j++ ) { + char szModuleName[ MAX_PATH ]; + GetModuleFileNameA( WaitingThreads[j].hOwner, szModuleName, sizeof(szModuleName)); + Netlib_Logf( NULL, "Thread %08x was abnormally terminated because module '%s' didn't released it", + WaitingThreads[j].hThread, szModuleName ); + TerminateThread( WaitingThreads[j].hThread, 9999 ); + } + + ReleaseMutex(hStackMutex); + SetEvent(hThreadQueueEmpty); +} } + +static void UnwindThreadWait(void) +{ + // acquire the list and wake up any alertable threads + if ( MirandaWaitForMutex(hStackMutex) ) { + int j; + for (j=0;jmessage) { + case WM_MOUSEACTIVATE: + case WM_MOUSEMOVE: + case WM_CHAR: + { + dwEventTime = GetTickCount(); + } + } +} + +static int SystemGetIdle(WPARAM 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 ( MyMsgWaitForMultipleObjectsEx != NULL ) + return MyMsgWaitForMultipleObjectsEx(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; +} + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +{ + DWORD myPid=0; + int messageloop=1; + +#ifdef _DEBUG + _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); +#endif + + if (InitialiseModularEngine()) + { + NotifyEventHooks(hShutdownEvent,0,0); + UnloadNewPluginsModule(); + DestroyModularEngine(); + return 1; + } + InsertRegistryKey(); + NotifyEventHooks(hModulesLoadedEvent,0,0); + MyMsgWaitForMultipleObjectsEx=(DWORD (WINAPI *)(DWORD,CONST HANDLE*,DWORD,DWORD,DWORD))GetProcAddress(GetModuleHandleA("user32"),"MsgWaitForMultipleObjectsEx"); + 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 + && GetClassLong(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); + DestroyingModularEngine(); + // 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 + } + UnloadNewPluginsModule(); + DestroyModularEngine(); + CloseHandle(hStackMutex); + CloseHandle(hMirandaShutdown); + CloseHandle(hThreadQueueEmpty); + DestroyWindow(hAPCWindow); + return 0; +} + +static int SystemShutdownProc(WPARAM wParam,LPARAM lParam) +{ + return 0; +} + +static int OkToExit(WPARAM wParam,LPARAM lParam) +{ + return NotifyEventHooks(hOkToExitEvent,0,0)==0; +} + +static int GetMirandaVersion(WPARAM wParam,LPARAM lParam) +{ + char filename[MAX_PATH]; + DWORD unused; + DWORD verInfoSize; + UINT blockSize; + PVOID pVerInfo; + VS_FIXEDFILEINFO *vsffi; + DWORD ver; + + GetModuleFileNameA(NULL,filename,SIZEOF(filename)); + verInfoSize=GetFileVersionInfoSizeA(filename,&unused); + pVerInfo=mir_alloc(verInfoSize); + GetFileVersionInfoA(filename,0,verInfoSize,pVerInfo); + VerQueryValueA(pVerInfo,"\\",(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)ver; +} + +static int GetMirandaVersionText(WPARAM wParam,LPARAM lParam) +{ + char filename[MAX_PATH],*productVersion; + DWORD unused; + DWORD verInfoSize; + UINT blockSize; + PVOID pVerInfo; + + GetModuleFileNameA(NULL,filename,SIZEOF(filename)); + verInfoSize=GetFileVersionInfoSizeA(filename,&unused); + pVerInfo=mir_alloc(verInfoSize); + GetFileVersionInfoA(filename,0,verInfoSize,pVerInfo); + VerQueryValueA(pVerInfo,"\\StringFileInfo\\000004b0\\ProductVersion",(void*)&productVersion,&blockSize); + #if defined( _UNICODE ) + mir_snprintf(( char* )lParam, wParam, "%s Unicode", productVersion ); + #else + lstrcpynA((char*)lParam,productVersion,wParam); + #endif + mir_free(pVerInfo); + return 0; +} + +int 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 RemoveWait(WPARAM wParam,LPARAM lParam) +{ + int i; + + for(i=0;icbSize == sizeof(struct MM_INTERFACE)) + { + mmi->mmi_malloc = mir_alloc; + mmi->mmi_realloc = mir_realloc; + mmi->mmi_free = mir_free; + return 0; + } + return 1; +} + +int GetListInterface(WPARAM wParam, LPARAM lParam) +{ + struct LIST_INTERFACE *li = (struct LIST_INTERFACE*) lParam; + if (li || li->cbSize == sizeof(struct LIST_INTERFACE)) + { + 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 LoadSystemModule(void) +{ + InitCommonControls(); + + hAPCWindow=CreateWindowEx(0,_T("STATIC"),NULL,0, 0,0,0,0, NULL,NULL,NULL,NULL); // lame + SetWindowLong(hAPCWindow,GWL_WNDPROC,(LONG)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); + + HookEvent(ME_SYSTEM_SHUTDOWN,SystemShutdownProc); + + 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); + return 0; +} diff --git a/miranda-wine/src/core/miranda.h b/miranda-wine/src/core/miranda.h new file mode 100644 index 0000000..af80535 --- /dev/null +++ b/miranda-wine/src/core/miranda.h @@ -0,0 +1,48 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2006 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. +*/ + +/**** memory.c *************************************************************************/ + +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 ); + +#if defined( _UNICODE ) + #define mir_tstrdup mir_wstrdup +#else + #define mir_tstrdup mir_strdup +#endif + +/**** utf.c ****************************************************************************/ + +void Utf8Decode( char* str, wchar_t** ucs2 ); + +/**** langpack.c ***********************************************************************/ + +int LangPackGetDefaultCodePage(); +int LangPackGetDefaultLocale(); +TCHAR* LangPackPcharToTchar( const char* pszStr ); +char* LangPackTranslateString(const char *szEnglish, const int W); diff --git a/miranda-wine/src/core/modules.c b/miranda-wine/src/core/modules.c new file mode 100644 index 0000000..dd180fe --- /dev/null +++ b/miranda-wine/src/core/modules.c @@ -0,0 +1,656 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2006 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 + +typedef struct { + MIRANDAHOOK pfnHook; + HINSTANCE hOwner; + HWND hwnd; + UINT message; +} THookSubscriber; + +typedef struct { + char name[MAXMODULELABELLENGTH]; + DWORD hookHash; + int subscriberCount; + THookSubscriber *subscriber; + MIRANDAHOOK pfnHook; +} THookList; + +typedef struct { + char name[MAXMODULELABELLENGTH]; + DWORD nameHash; + HINSTANCE hOwner; + MIRANDASERVICE pfnService; +} TServiceList; + +typedef struct { + int hookId; + HANDLE hDoneEvent; + WPARAM wParam; + LPARAM lParam; + int result; +} THookToMainThreadItem; + +typedef struct { + HANDLE hDoneEvent; + WPARAM wParam; + LPARAM lParam; + int result; + const char *name; +} TServiceToMainThreadItem; + +static THookList *hook; +static TServiceList *service; +static int hookCount,serviceCount; +static CRITICAL_SECTION csHooks,csServices; +static DWORD mainThreadId; +static HANDLE hMainThread; +static HANDLE hMissingService; + +HINSTANCE GetInstByAddress( void* codePtr ); + +int LoadSystemModule(void); // core: m_system.h services +int LoadNewPluginsModuleInfos(void); // core: preloading plugins +int LoadNewPluginsModule(void); // core: N.O. plugins +int LoadNetlibModule(void); // core: network +int LoadLangPackModule(void); // core: translation +int LoadProtocolsModule(void); // core: protocol 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 LoadSkinModule(void); // ui: skin +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 + +static int LoadDefaultModules(void) +{ + int *disableDefaultModule = 0; + + //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 'ere + if(LoadUtilsModule()) return 1; //order not important for this, but no dependencies and no point in pluginising + if(LoadNewPluginsModuleInfos()) return 1; + if(LoadProtocolsModule()) return 1; + if(LoadSkinModule()) return 1; + if(LoadButtonModule()) return 1; + if(LoadOptionsModule()) return 1; + 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 + + //this info will be available at LoadNewPluginsModule() + disableDefaultModule=(int*)CallService(MS_PLUGINS_GETDISABLEDEFAULTARRAY,0,0); + if(!disableDefaultModule[DEFMOD_PROTOCOLNETLIB]) if(LoadNetlibModule()) 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_UIPLUGINOPTS]) if(LoadPluginOptionsModule()) return 1; + return 0; +} + +int InitialiseModularEngine(void) +{ + hookCount=serviceCount=0; + hook=NULL; + service=NULL; + InitializeCriticalSection(&csHooks); + InitializeCriticalSection(&csServices); + + mainThreadId=GetCurrentThreadId(); + DuplicateHandle(GetCurrentProcess(),GetCurrentThread(),GetCurrentProcess(),&hMainThread,THREAD_SET_CONTEXT,FALSE,0); + + hMissingService = CreateHookableEvent(ME_SYSTEM_MISSINGSERVICE); + return LoadDefaultModules(); +} + +void DestroyingModularEngine(void) +{ + return; +} + +void DestroyModularEngine(void) +{ + int i; + for(i=0;i24) hash^=(szStr[i]>>(32-shift))&0x7F; + shift=(shift+5)&0x1F; + } + return hash; +#endif +} + +///////////////////////////////HOOKS + +static int FindHookByName(const char *name) +{ + int i; + + for(i=0;i=hookCount || hookId<0) {LeaveCriticalSection(&csHooks); return 1;} + if(hook[hookId].name[0]==0) {LeaveCriticalSection(&csHooks); return 1;} + hook[hookId].name[0]=0; + if(hook[hookId].subscriberCount) { + mir_free(hook[hookId].subscriber); + hook[hookId].subscriber=NULL; + hook[hookId].subscriberCount=0; + } + LeaveCriticalSection(&csHooks); + return 0; +} + +int SetHookDefaultForHookableEvent(HANDLE hEvent, MIRANDAHOOK pfnHook) +{ + int hookId = (int) hEvent - 1; + if ( hookId < 0 || hookId >= hookCount ) return 1; + EnterCriticalSection(&csHooks); + hook[hookId].pfnHook = pfnHook; + LeaveCriticalSection(&csHooks); + return 0; +} + +static int CallHookSubscribers(int hookId,WPARAM wParam,LPARAM lParam) +{ + int i,returnVal=0; + + EnterCriticalSection(&csHooks); + if(hookId>=hookCount || hookId<0 || hook[hookId].name[0]==0) returnVal=-1; + else { + //NOTE: We've got the critical section while all this lot are called. That's mostly safe, though. + for(i=0;iresult=CallHookSubscribers(item->hookId,item->wParam,item->lParam); + SetEvent(item->hDoneEvent); + return; +} + +int NotifyEventHooks(HANDLE hEvent,WPARAM wParam,LPARAM lParam) +{ + extern HWND hAPCWindow; + + if(GetCurrentThreadId()!=mainThreadId) { + THookToMainThreadItem item; + + item.hDoneEvent=CreateEvent(NULL,FALSE,FALSE,NULL); + item.hookId=(int)hEvent-1; + item.wParam=wParam; + item.lParam=lParam; + + QueueUserAPC(HookToMainAPCFunc,hMainThread,(DWORD)&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; + } + else + return CallHookSubscribers((int)hEvent-1,wParam,lParam); +} + +HANDLE HookEvent(const char *name,MIRANDAHOOK hookProc) +{ + int hookId; + HANDLE ret; + + EnterCriticalSection(&csHooks); + hookId=FindHookByName(name); + if(hookId==-1) { +#ifdef _DEBUG + OutputDebugStringA("Attempt to hook: \t"); + OutputDebugStringA(name); + OutputDebugStringA("\n"); +#endif + LeaveCriticalSection(&csHooks); + return NULL; + } + hook[hookId].subscriber=(THookSubscriber*)mir_realloc(hook[hookId].subscriber,sizeof(THookSubscriber)*(hook[hookId].subscriberCount+1)); + hook[hookId].subscriber[hook[hookId].subscriberCount].pfnHook = hookProc; + hook[hookId].subscriber[hook[hookId].subscriberCount].hOwner = GetInstByAddress(hookProc); + hook[hookId].subscriber[hook[hookId].subscriberCount].hwnd = NULL; + hook[hookId].subscriberCount++; + + ret=(HANDLE)((hookId<<16)|hook[hookId].subscriberCount); + LeaveCriticalSection(&csHooks); + return ret; +} + +HANDLE HookEventMessage(const char *name,HWND hwnd,UINT message) +{ + int hookId; + HANDLE ret; + + EnterCriticalSection(&csHooks); + hookId=FindHookByName(name); + if(hookId==-1) { +#ifdef _DEBUG + MessageBoxA(NULL,"Attempt to hook non-existant event",name,MB_OK); +#endif + LeaveCriticalSection(&csHooks); + return NULL; + } + hook[hookId].subscriber=(THookSubscriber*)mir_realloc(hook[hookId].subscriber,sizeof(THookSubscriber)*(hook[hookId].subscriberCount+1)); + hook[hookId].subscriber[hook[hookId].subscriberCount].pfnHook=NULL; + hook[hookId].subscriber[hook[hookId].subscriberCount].hwnd=hwnd; + hook[hookId].subscriber[hook[hookId].subscriberCount].message=message; + hook[hookId].subscriberCount++; + ret=(HANDLE)((hookId<<16)|hook[hookId].subscriberCount); + LeaveCriticalSection(&csHooks); + return ret; +} + +int UnhookEvent(HANDLE hHook) +{ + int hookId=(int)hHook>>16; + int subscriberId=((int)hHook&0xFFFF)-1; + + EnterCriticalSection(&csHooks); + if(hookId>=hookCount || hookId<0) {LeaveCriticalSection(&csHooks); return 1;} + if(hook[hookId].name[0]==0) {LeaveCriticalSection(&csHooks); return 1;} + if(subscriberId>=hook[hookId].subscriberCount || subscriberId<0) {LeaveCriticalSection(&csHooks); return 1;} + hook[hookId].subscriber[subscriberId].pfnHook=NULL; + hook[hookId].subscriber[subscriberId].hwnd=NULL; + while(hook[hookId].subscriberCount && hook[hookId].subscriber[hook[hookId].subscriberCount-1].pfnHook==NULL && hook[hookId].subscriber[hook[hookId].subscriberCount-1].hwnd==NULL) + hook[hookId].subscriberCount--; + if (hook[hookId].subscriberCount==0) { + if(hook[hookId].subscriber) mir_free(hook[hookId].subscriber); + hook[hookId].subscriber=NULL; + } + LeaveCriticalSection(&csHooks); + return 0; +} + +void KillModuleEventHooks( HINSTANCE hInst ) +{ + int i, j; + + EnterCriticalSection(&csHooks); + for ( i = hookCount-1; i >= 0; i-- ) { + if ( hook[i].subscriberCount == 0 ) + continue; + + for ( j = hook[i].subscriberCount-1; j >= 0; j-- ) { + if ( hook[i].subscriber[j].hOwner == hInst ) { + char szModuleName[ MAX_PATH ]; + GetModuleFileNameA( hook[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", + hook[i].subscriber[j].pfnHook, hook[i].name, szModuleName ); + UnhookEvent(( HANDLE )(( i << 16 ) + j + 1 )); + if ( hook[i].subscriberCount == 0 ) + break; + } } } + + LeaveCriticalSection(&csHooks); +} + +/////////////////////SERVICES + +static __inline TServiceList *FindServiceByHash(DWORD hash) +{ + int first,last,mid; + + if(serviceCount==0) return NULL; + first=0; last=serviceCount-1; + if(hash>=service[last].nameHash) { + if(hash==service[last].nameHash) return &service[last]; + return NULL; + } + for(;;) { + mid=(first+last)>>1; + if(hash>service[mid].nameHash) { + if(last-first<=1) break; + first=mid; + } + else if(hash 0 && hash > service[serviceCount - 1].nameHash) { + if (shift) *shift = 0; + return serviceCount; + } + if ( serviceCount > 2 ) + { + for ( ; (max - min) > 1 ; ) + { + mid = ( min + max ) >> 1; + if ( hash > service[mid].nameHash ) min = mid; + else if ( hash < service[mid].nameHash ) max = mid; + else return -1; + } // for + i = mid - 1; + } + /* its O(N) but we might reduce it to M=(log2 N), then looking for the hash is only O(2) */ + for(; i < serviceCount ; i++) { + if ( hash <= service[i].nameHash ) break; + } + return i; +} + +HANDLE CreateServiceFunction(const char *name,MIRANDASERVICE serviceProc) +{ + DWORD hash; + int i; + int shift = 1; +#ifdef _DEBUG + if (name==NULL) { + MessageBoxA(0,"Someone tried to create a NULL'd service, see call stack for more info","",0); + DebugBreak(); + return NULL; + } +#else + if (name==NULL) return NULL; +#endif + hash=NameHashFunction(name); + EnterCriticalSection(&csServices); + i=FindHashForService(hash,&shift); + if (i==-1) { + LeaveCriticalSection(&csServices); + return NULL; + } + service=(TServiceList*)mir_realloc(service,sizeof(TServiceList)*(serviceCount+1)); + if ( serviceCount > 0 && shift) MoveMemory(service+i+1,service+i,sizeof(TServiceList)*(serviceCount-i)); + strncpy(service[i].name,name,sizeof(service[i].name)); + service[i].nameHash = hash; + service[i].pfnService = serviceProc; + service[i].hOwner = GetInstByAddress( serviceProc ); + serviceCount++; + LeaveCriticalSection(&csServices); + return (HANDLE)hash; +} + +int DestroyServiceFunction(HANDLE hService) +{ + TServiceList *pService; + int i; + + EnterCriticalSection(&csServices); + pService=FindServiceByHash((DWORD)hService); + if(pService==NULL) {LeaveCriticalSection(&csServices); return 1;} + i=(int)(pService-service); + MoveMemory(service+i,service+i+1,sizeof(TServiceList)*(--serviceCount-i)); + LeaveCriticalSection(&csServices); + return 0; +} + +int ServiceExists(const char *name) +{ + int ret; + EnterCriticalSection(&csServices); + ret=FindServiceByName(name)!=NULL; + LeaveCriticalSection(&csServices); + return ret; +} + +int CallService(const char *name,WPARAM wParam,LPARAM lParam) +{ + TServiceList *pService; + MIRANDASERVICE pfnService; + +#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); + 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)¶ms); + if (result != 0) + return params.lParam; + } */ + return CALLSERVICE_NOTFOUND; + } + pfnService=pService->pfnService; + LeaveCriticalSection(&csServices); + return ((int (*)(WPARAM,LPARAM))pfnService)(wParam,lParam); +} + +static void CALLBACK CallServiceToMainAPCFunc(DWORD dwParam) +{ + TServiceToMainThreadItem *item = (TServiceToMainThreadItem*) dwParam; + item->result = CallService(item->name, item->wParam, item->lParam); + SetEvent(item->hDoneEvent); +} + +int 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, (DWORD) &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 = 0; + r=QueueUserAPC((void (__stdcall *)(DWORD))func,hMainThread,(DWORD)arg); + PostMessage(hAPCWindow,WM_NULL,0,0); + return r; +} + +void KillModuleServices( HINSTANCE hInst ) +{ + int i; + + EnterCriticalSection(&csServices); + for ( i = serviceCount-1; i >= 0; i-- ) { + if ( service[i].hOwner == hInst ) { + char szModuleName[ MAX_PATH ]; + GetModuleFileNameA( service[i].hOwner, szModuleName, sizeof(szModuleName)); + Netlib_Logf( NULL, "A service function '%s' was abnormally deleted because module '%s' didn't released it", + service[i].name, szModuleName ); + DestroyServiceFunction(( HANDLE )service[i].nameHash ); + } } + + LeaveCriticalSection(&csServices); +} diff --git a/miranda-wine/src/core/modules.h b/miranda-wine/src/core/modules.h new file mode 100644 index 0000000..4e488d3 --- /dev/null +++ b/miranda-wine/src/core/modules.h @@ -0,0 +1,184 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2006 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_ + +/* 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 (*MIRANDASERVICE)(WPARAM,LPARAM); + +/**************************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); + +/* + 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); + +/* 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); + +/* 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. +*/ +#define CALLSERVICE_NOTFOUND ((int)0x80000000) +int 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 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_ -- cgit v1.2.3