summaryrefslogtreecommitdiff
path: root/miranda-wine/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'miranda-wine/src/core')
-rw-r--r--miranda-wine/src/core/commonheaders.c2
-rw-r--r--miranda-wine/src/core/commonheaders.h84
-rw-r--r--miranda-wine/src/core/forkthread.h64
-rw-r--r--miranda-wine/src/core/memory.c167
-rw-r--r--miranda-wine/src/core/miranda.c565
-rw-r--r--miranda-wine/src/core/miranda.h48
-rw-r--r--miranda-wine/src/core/modules.c656
-rw-r--r--miranda-wine/src/core/modules.h184
8 files changed, 1770 insertions, 0 deletions
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 <tchar.h>
+#include <malloc.h>
+
+#define _ALPHA_BASE_ 1 // defined for CVS builds
+#define _ALPHA_FUSE_ 1 // defined for fuse powered core
+
+#ifdef _DEBUG
+# define _CRTDBG_MAP_ALLOC
+# include <stdlib.h>
+# include <crtdbg.h>
+#endif
+
+#define _WIN32_WINNT 0x0501
+#define _WIN32_IE 0x0500
+#include <windows.h>
+#include <commctrl.h>
+#include <stdio.h>
+#include <time.h>
+#include <stddef.h>
+#include <process.h>
+#include <io.h>
+#include <string.h>
+#include <direct.h>
+#include "../resource.h"
+#include <win2k.h>
+#include "modules.h"
+#include "miranda.h"
+#include "forkthread.h"
+#include <m_system.h>
+#include <newpluginapi.h>
+#include <m_database.h>
+#include <m_clc.h>
+#include <m_clui.h>
+#include <m_langpack.h>
+#include <m_clist.h>
+#include <m_clistint.h>
+#include <m_netlib.h>
+#include <m_button.h>
+#include <m_protosvc.h>
+#include <m_protomod.h>
+#include <m_protocols.h>
+#include <m_plugins.h>
+#include <m_options.h>
+#include <m_utils.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_utils.h>
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;j<WaitingThreadsCount;j++)
+ QueueUserAPC(DummyAPCFunc,WaitingThreads[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 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), NULL);
+ CloseHandle(hDupHandle);
+
+ if(ntStatus != ERROR_SUCCESS) return 0;
+ return ( void* )dwStartAddress;
+}
+
+int UnwindThreadPush(WPARAM wParam,LPARAM lParam)
+{
+ ResetEvent(hThreadQueueEmpty); // thread list is not empty
+ if (WaitForSingleObject(hStackMutex,INFINITE)==WAIT_OBJECT_0)
+ {
+ HANDLE hThread=0;
+ DuplicateHandle(GetCurrentProcess(),GetCurrentThread(),GetCurrentProcess(),&hThread,THREAD_SET_CONTEXT,FALSE,0);
+ WaitingThreads=mir_realloc(WaitingThreads,sizeof(struct THREAD_WAIT_ENTRY)*(WaitingThreadsCount+1));
+ WaitingThreads[WaitingThreadsCount].hThread=hThread;
+ WaitingThreads[WaitingThreadsCount].dwThreadId=GetCurrentThreadId();
+ WaitingThreads[WaitingThreadsCount].hOwner=GetInstByAddress( GetCurrentThreadEntryPoint() );
+ WaitingThreadsCount++;
+#ifdef _DEBUG
+ {
+ char szBuf[64];
+ mir_snprintf(szBuf,SIZEOF(szBuf),"*** pushing thread (%x)\n",GetCurrentThreadId());
+ OutputDebugStringA(szBuf);
+ }
+#endif
+ ReleaseMutex(hStackMutex);
+ } //if
+ return 0;
+}
+
+int UnwindThreadPop(WPARAM wParam,LPARAM lParam)
+{
+ if (WaitForSingleObject(hStackMutex,INFINITE)==WAIT_OBJECT_0)
+ {
+ DWORD dwThreadId=GetCurrentThreadId();
+ int j;
+ for (j=0;j<WaitingThreadsCount;j++) {
+ if (WaitingThreads[j].dwThreadId == dwThreadId) {
+ CloseHandle(WaitingThreads[j].hThread);
+ WaitingThreadsCount--;
+ if (j<WaitingThreadsCount) memmove(&WaitingThreads[j],&WaitingThreads[j+1],(WaitingThreadsCount-j) * sizeof(struct THREAD_WAIT_ENTRY));
+ if (!WaitingThreadsCount)
+ {
+ mir_free(WaitingThreads);
+ WaitingThreads=NULL;
+ WaitingThreadsCount=0;
+ ReleaseMutex(hStackMutex);
+ SetEvent(hThreadQueueEmpty); // thread list is empty now
+ return 0;
+ } else {
+ WaitingThreads=mir_realloc(WaitingThreads,sizeof(struct THREAD_WAIT_ENTRY)*WaitingThreadsCount);
+ } //if
+ ReleaseMutex(hStackMutex);
+ return 0;
+ } //if
+ } //for
+ ReleaseMutex(hStackMutex);
+ } //if
+ return 1;
+}
+
+int MirandaIsTerminated(WPARAM wParam,LPARAM lParam)
+{
+ return WaitForSingleObject(hMirandaShutdown,0)==WAIT_OBJECT_0;
+}
+
+static void __cdecl compactHeapsThread(void *dummy)
+{
+ 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
+}
+
+static void InsertRegistryKey(void)
+{
+ if(DBGetContactSettingByte(NULL,"_Sys","CreateRegKey",1)) {
+ HKEY hKey;
+ DWORD dw;
+ if(RegCreateKeyExA(HKEY_LOCAL_MACHINE,"SOFTWARE\\Miranda",0,NULL,0,KEY_CREATE_SUB_KEY|KEY_SET_VALUE,NULL,&hKey,&dw)==ERROR_SUCCESS) {
+ char str[MAX_PATH],*str2;
+ GetModuleFileNameA(NULL,str,SIZEOF(str));
+ str2=strrchr(str,'\\');
+ if(str2!=NULL) *str2=0;
+ RegSetValueExA(hKey,"Install_Dir",0,REG_SZ,(PBYTE)str,lstrlenA(str)+1);
+ RegCloseKey(hKey);
+ }
+ }
+}
+
+DWORD CALLBACK APCWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if (msg==WM_NULL) SleepEx(0,TRUE);
+ return DefWindowProc(hwnd,msg,wParam,lParam);
+}
+
+HWND hAPCWindow=NULL;
+void (*SetIdleCallback) (void)=NULL;
+
+static int SystemSetIdleCallback(WPARAM 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 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;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 GetMemoryManagerInterface(WPARAM wParam, LPARAM lParam)
+{
+ struct MM_INTERFACE *mmi = (struct MM_INTERFACE*) lParam;
+ if (mmi || mmi->cbSize == 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 <m_plugins.h>
+
+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;i<hookCount;i++)
+ if(hook[i].subscriberCount) mir_free(hook[i].subscriber);
+ if(hookCount) mir_free(hook);
+ if(serviceCount) mir_free(service);
+ DeleteCriticalSection(&csHooks);
+ DeleteCriticalSection(&csServices);
+ CloseHandle(hMainThread);
+}
+
+
+#if __GNUC__
+#define NOINLINEASM
+#endif
+
+DWORD NameHashFunction(const char *szStr)
+{
+#if defined _M_IX86 && !defined _NUMEGA_BC_FINALCHECK && !defined NOINLINEASM
+ __asm { //this breaks if szStr is empty
+ xor edx,edx
+ xor eax,eax
+ mov esi,szStr
+ mov al,[esi]
+ xor cl,cl
+ lph_top: //only 4 of 9 instructions in here don't use AL, so optimal pipe use is impossible
+ xor edx,eax
+ inc esi
+ xor eax,eax
+ and cl,31
+ mov al,[esi]
+ add cl,5
+ test al,al
+ rol eax,cl //rol is u-pipe only, but pairable
+ //rol doesn't touch z-flag
+ jnz lph_top //5 clock tick loop. not bad.
+
+ xor eax,edx
+ }
+#else
+ DWORD hash=0;
+ int i;
+ int shift=0;
+ for(i=0;szStr[i];i++) {
+ hash^=szStr[i]<<shift;
+ if(shift>24) 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;i++)
+ if(!strcmp(hook[i].name,name)) return i;
+ return -1;
+}
+
+static int FindHookByHashAndName(DWORD Hash, const char *name)
+{
+ int i;
+ for (i=0; i<hookCount; i++)
+ if (hook[i].hookHash==Hash)
+ {
+ if (!strcmp(hook[i].name, name)) return i;
+ }
+ return -1;
+}
+
+HANDLE CreateHookableEvent(const char *name)
+{
+ DWORD Hash = NameHashFunction(name);
+ HANDLE ret;
+
+ EnterCriticalSection(&csHooks);
+ //if(FindHookByName(name)!=-1) {LeaveCriticalSection(&csHooks); return NULL;}
+ if (FindHookByHashAndName(Hash, name) != -1)
+ {
+ LeaveCriticalSection(&csHooks);
+ return NULL;
+ }
+ hook=(THookList*)mir_realloc(hook,sizeof(THookList)*(hookCount+1));
+ strcpy(hook[hookCount].name,name);
+ hook[hookCount].hookHash=Hash;
+ hook[hookCount].subscriberCount=0;
+ hook[hookCount].subscriber=NULL;
+ hook[hookCount].pfnHook=NULL;
+ hookCount++;
+ ret=(HANDLE)hookCount;
+ LeaveCriticalSection(&csHooks);
+ return ret;
+}
+
+int DestroyHookableEvent(HANDLE hEvent)
+{
+ int hookId=(int)hEvent-1;
+ EnterCriticalSection(&csHooks);
+ if(hookId>=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;i<hook[hookId].subscriberCount;i++) {
+ if(hook[hookId].subscriber[i].pfnHook!=NULL) {
+ returnVal=hook[hookId].subscriber[i].pfnHook(wParam,lParam);
+ if( returnVal ) break;
+ }
+ else if(hook[hookId].subscriber[i].hwnd!=NULL) {
+ returnVal=SendMessage(hook[hookId].subscriber[i].hwnd,hook[hookId].subscriber[i].message,wParam,lParam);
+ if( returnVal ) break;
+ }//if
+ }//for
+ // check for no hooks and call the default hook if any
+ if ( hook[hookId].subscriberCount == 0 && hook[hookId].pfnHook != 0 ) returnVal = hook[hookId].pfnHook(wParam,lParam);
+ }
+ LeaveCriticalSection(&csHooks);
+ return returnVal;
+}
+
+static void CALLBACK HookToMainAPCFunc(DWORD dwParam)
+{
+ THookToMainThreadItem *item=(THookToMainThreadItem*)dwParam;
+
+ item->result=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<service[mid].nameHash) {
+ if(last-first<=1) break;
+ last=mid;
+ }
+ else return &service[mid];
+ }
+ return NULL;
+}
+
+static __inline TServiceList *FindServiceByName(const char *name)
+{
+ return FindServiceByHash(NameHashFunction(name));
+}
+
+/* assume critical section csServices is owned */
+static int FindHashForService(DWORD hash, int * shift)
+{
+ int i=0;
+ unsigned int mid = 0;
+ unsigned int min = 0;
+ unsigned int max = serviceCount - 1;
+ if (serviceCount==0) {
+ if (shift) *shift=0;
+ return 0;
+ }
+ if ( serviceCount > 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)&params);
+ 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_