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/modules.c | 656 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 656 insertions(+) create mode 100644 miranda-wine/src/core/modules.c (limited to 'miranda-wine/src/core/modules.c') 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); +} -- cgit v1.2.3