summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/Mir_core/mir_core.def2
-rw-r--r--plugins/Mir_core/mir_core_10.vcxproj15
-rw-r--r--plugins/Mir_core/mir_core_10.vcxproj.filters3
-rw-r--r--plugins/Mir_core/miranda.cpp319
-rw-r--r--plugins/Mir_core/miranda.h4
-rw-r--r--plugins/Mir_core/modules.cpp146
-rw-r--r--plugins/Mir_core/threads.cpp372
7 files changed, 477 insertions, 384 deletions
diff --git a/plugins/Mir_core/mir_core.def b/plugins/Mir_core/mir_core.def
index 7d998c0d14..e0cefde13b 100644
--- a/plugins/Mir_core/mir_core.def
+++ b/plugins/Mir_core/mir_core.def
@@ -124,3 +124,5 @@ db_set_utf @120
db_set_w @121
db_set_ws @122
UnloadCoreModule @123
+Thread_SetName @124
+
diff --git a/plugins/Mir_core/mir_core_10.vcxproj b/plugins/Mir_core/mir_core_10.vcxproj
index 68b4adf4d8..6600013e1a 100644
--- a/plugins/Mir_core/mir_core_10.vcxproj
+++ b/plugins/Mir_core/mir_core_10.vcxproj
@@ -43,6 +43,7 @@
<ClCompile Include="modules.cpp" />
<ClCompile Include="path.cpp" />
<ClCompile Include="sha1.cpp" />
+ <ClCompile Include="threads.cpp" />
<ClCompile Include="utf.cpp" />
<ClCompile Include="utils.cpp" />
</ItemGroup>
@@ -124,6 +125,13 @@
</AdditionalLibraryDirectories>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
</Link>
+ <CustomBuildStep>
+ <Command>
+ </Command>
+ </CustomBuildStep>
+ <PostBuildEvent>
+ <Command>copy /Y $(IntDir)$(TargetName).lib $(SolutionDir)\lib</Command>
+ </PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
@@ -185,6 +193,13 @@
</AdditionalLibraryDirectories>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
</Link>
+ <CustomBuildStep>
+ <Command>
+ </Command>
+ </CustomBuildStep>
+ <PostBuildEvent>
+ <Command>copy /Y $(IntDir)$(TargetName).lib $(SolutionDir)\lib</Command>
+ </PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
diff --git a/plugins/Mir_core/mir_core_10.vcxproj.filters b/plugins/Mir_core/mir_core_10.vcxproj.filters
index 1aca9fda03..27b6a42604 100644
--- a/plugins/Mir_core/mir_core_10.vcxproj.filters
+++ b/plugins/Mir_core/mir_core_10.vcxproj.filters
@@ -46,6 +46,9 @@
<ClCompile Include="db.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="threads.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="commonheaders.h">
diff --git a/plugins/Mir_core/miranda.cpp b/plugins/Mir_core/miranda.cpp
index 910b204292..b059e11cb7 100644
--- a/plugins/Mir_core/miranda.cpp
+++ b/plugins/Mir_core/miranda.cpp
@@ -29,326 +29,10 @@ HWND hAPCWindow = NULL;
int InitPathUtils(void);
void (*RecalculateTime)(void);
-HANDLE hStackMutex, hThreadQueueEmpty;
int hLangpack = 0;
HINSTANCE hInst = 0;
-/////////////////////////////////////////////////////////////////////////////////////////
-// exception handling
-
-static DWORD __cdecl sttDefaultFilter(DWORD, EXCEPTION_POINTERS*)
-{
- return EXCEPTION_EXECUTE_HANDLER;
-}
-
-pfnExceptionFilter pMirandaExceptFilter = sttDefaultFilter;
-
-MIR_CORE_DLL(pfnExceptionFilter) GetExceptionFilter()
-{
- return pMirandaExceptFilter;
-}
-
-MIR_CORE_DLL(pfnExceptionFilter) SetExceptionFilter(pfnExceptionFilter pMirandaExceptFilter)
-{
- pfnExceptionFilter oldOne = pMirandaExceptFilter;
- if (pMirandaExceptFilter != 0)
- pMirandaExceptFilter = pMirandaExceptFilter;
- return oldOne;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// thread support functions
-
-struct THREAD_WAIT_ENTRY
-{
- DWORD dwThreadId; // valid if hThread isn't signalled
- HANDLE hThread;
- HINSTANCE hOwner;
- void* pObject;
- //PVOID addr;
-};
-
-static LIST<THREAD_WAIT_ENTRY> threads(10, NumericKeySortT);
-
-struct FORK_ARG {
- HANDLE hEvent;
- pThreadFunc threadcode;
- pThreadFuncEx threadcodeex;
- void *arg, *owner;
-};
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// forkthread - starts a new thread
-
-void __cdecl forkthread_r(void * arg)
-{
- struct FORK_ARG * fa = (struct FORK_ARG *) arg;
- void (*callercode)(void*)=fa->threadcode;
- void * cookie=fa->arg;
- Thread_Push(( HINSTANCE)callercode);
- SetEvent(fa->hEvent);
- __try
- {
- callercode(cookie);
- }
- __except(pMirandaExceptFilter(GetExceptionCode(), GetExceptionInformation()))
- {
- }
-
- SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
- Thread_Pop();
- return;
-}
-
-MIR_CORE_DLL(UINT_PTR) forkthread( void (__cdecl *threadcode)(void*), unsigned long stacksize, void *arg)
-{
- UINT_PTR rc;
- struct FORK_ARG fa;
- fa.hEvent=CreateEvent(NULL, FALSE, FALSE, NULL);
- fa.threadcode=threadcode;
- fa.arg=arg;
- rc=_beginthread(forkthread_r, stacksize, &fa);
- if ((UINT_PTR)-1L != rc)
- WaitForSingleObject(fa.hEvent, INFINITE);
-
- CloseHandle(fa.hEvent);
- return rc;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// forkthreadex - starts a new thread with the extended info and returns the thread id
-
-unsigned __stdcall forkthreadex_r(void * arg)
-{
- struct FORK_ARG *fa = (struct FORK_ARG *)arg;
- pThreadFuncEx threadcode = fa->threadcodeex;
- pThreadFuncOwner threadcodeex = (pThreadFuncOwner)fa->threadcodeex;
- void *cookie = fa->arg;
- void *owner = fa->owner;
- unsigned long rc = 0;
-
- Thread_Push((HINSTANCE)threadcode, fa->owner);
- SetEvent(fa->hEvent);
- __try
- {
- if (owner)
- rc = threadcodeex(owner, cookie);
- else
- rc = threadcode(cookie);
- }
- __except(pMirandaExceptFilter(GetExceptionCode(), GetExceptionInformation()))
- {
- }
-
- SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
- Thread_Pop();
- return rc;
-}
-
-MIR_CORE_DLL(UINT_PTR) forkthreadex(
- void *sec,
- unsigned stacksize,
- unsigned (__stdcall *threadcode)(void*),
- void* owner,
- void *arg,
- unsigned *thraddr)
-{
- UINT_PTR rc;
- struct FORK_ARG fa = { 0 };
- fa.threadcodeex = threadcode;
- fa.arg = arg;
- fa.owner = owner;
- fa.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- rc = _beginthreadex(sec, stacksize, forkthreadex_r, (void *)&fa, 0, thraddr);
- if (rc)
- WaitForSingleObject(fa.hEvent, INFINITE);
-
- CloseHandle(fa.hEvent);
- return rc;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// APC and mutex functions
-
-static void __stdcall DummyAPCFunc(ULONG_PTR)
-{
- /* called in the context of thread that cleared it's APC queue */
- return;
-}
-
-static int MirandaWaitForMutex(HANDLE hEvent)
-{
- for (;;) {
- // will get WAIT_IO_COMPLETE for QueueUserAPC() which isnt a result
- DWORD rc = MsgWaitForMultipleObjectsEx(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;
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-static void CALLBACK KillAllThreads(HWND, UINT, UINT_PTR, DWORD)
-{
- if ( MirandaWaitForMutex(hStackMutex)) {
- for (int j=0; j < threads.getCount(); j++) {
- THREAD_WAIT_ENTRY* p = threads[j];
- char szModuleName[ MAX_PATH ];
- GetModuleFileNameA(p->hOwner, szModuleName, sizeof(szModuleName));
- TerminateThread(p->hThread, 9999);
- CloseHandle(p->hThread);
- mir_free(p);
- }
-
- threads.destroy();
-
- ReleaseMutex(hStackMutex);
- SetEvent(hThreadQueueEmpty);
- }
-}
-
-MIR_CORE_DLL(void) KillObjectThreads(void* owner)
-{
- if (owner == NULL)
- return;
-
- WaitForSingleObject(hStackMutex, INFINITE);
-
- HANDLE* threadPool = (HANDLE*)alloca(threads.getCount()*sizeof(HANDLE));
- int threadCount = 0;
-
- for (int j = threads.getCount(); j--;) {
- THREAD_WAIT_ENTRY* p = threads[j];
- if (p->pObject == owner)
- threadPool[ threadCount++ ] = p->hThread;
- }
- ReleaseMutex(hStackMutex);
-
- // is there anything to kill?
- if (threadCount > 0) {
- if ( WaitForMultipleObjects(threadCount, threadPool, TRUE, 5000) == WAIT_TIMEOUT) {
- // forcibly kill all remaining threads after 5 secs
- WaitForSingleObject(hStackMutex, INFINITE);
- for (int j = threads.getCount()-1; j >= 0; j--) {
- THREAD_WAIT_ENTRY* p = threads[j];
- if (p->pObject == owner) {
- TerminateThread(p->hThread, 9999);
- CloseHandle(p->hThread);
- threads.remove(j);
- mir_free(p);
- }
- }
- ReleaseMutex(hStackMutex);
- }
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-MIR_CORE_DLL(void) Thread_Wait(void)
-{
- // acquire the list and wake up any alertable threads
- if ( MirandaWaitForMutex(hStackMutex)) {
- int j;
- for (j=0; j < threads.getCount(); j++)
- QueueUserAPC(DummyAPCFunc, threads[j]->hThread, 0);
- ReleaseMutex(hStackMutex);
- }
-
- // give all unclosed threads 5 seconds to close
- SetTimer(NULL, 0, 5000, KillAllThreads);
-
- // wait til the thread list is empty
- MirandaWaitForMutex(hThreadQueueEmpty);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-typedef LONG (WINAPI *pNtQIT)(HANDLE, LONG, PVOID, ULONG, PULONG);
-#define ThreadQuerySetWin32StartAddress 9
-
-static void* GetCurrentThreadEntryPoint()
-{
- LONG ntStatus;
- HANDLE hDupHandle, hCurrentProcess;
- DWORD_PTR dwStartAddress;
-
- pNtQIT NtQueryInformationThread = (pNtQIT)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "NtQueryInformationThread" );
- if(NtQueryInformationThread == NULL) return 0;
-
- hCurrentProcess = GetCurrentProcess();
- if(!DuplicateHandle(hCurrentProcess, GetCurrentThread(), hCurrentProcess, &hDupHandle, THREAD_QUERY_INFORMATION, FALSE, 0)){
- SetLastError(ERROR_ACCESS_DENIED);
- return NULL;
- }
- ntStatus = NtQueryInformationThread(hDupHandle, ThreadQuerySetWin32StartAddress, &dwStartAddress, sizeof(DWORD_PTR), NULL);
- CloseHandle(hDupHandle);
-
- if(ntStatus != ERROR_SUCCESS) return 0;
- return ( void* )dwStartAddress;
-}
-
-MIR_CORE_DLL(INT_PTR) Thread_Push(HINSTANCE hInst, void* pOwner)
-{
- ResetEvent(hThreadQueueEmpty); // thread list is not empty
- if ( WaitForSingleObject(hStackMutex, INFINITE) == WAIT_OBJECT_0) {
- THREAD_WAIT_ENTRY* p = (THREAD_WAIT_ENTRY*)mir_calloc(sizeof(THREAD_WAIT_ENTRY));
-
- DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &p->hThread, 0, FALSE, DUPLICATE_SAME_ACCESS);
- p->dwThreadId = GetCurrentThreadId();
- p->pObject = pOwner;
- if (pluginListAddr.getIndex(hInst) != -1)
- p->hOwner = hInst;
- else
- p->hOwner = GetInstByAddress(( hInst != NULL ) ? (PVOID)hInst : GetCurrentThreadEntryPoint());
-
- threads.insert(p);
-
- ReleaseMutex(hStackMutex);
- }
- return 0;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-MIR_CORE_DLL(INT_PTR) Thread_Pop()
-{
- if ( WaitForSingleObject(hStackMutex, INFINITE) == WAIT_OBJECT_0) {
- DWORD dwThreadId = GetCurrentThreadId();
- for (int j=0; j < threads.getCount(); j++) {
- THREAD_WAIT_ENTRY* p = threads[j];
- if (p->dwThreadId == dwThreadId) {
- SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
- CloseHandle(p->hThread);
- threads.remove(j);
- mir_free(p);
-
- if ( !threads.getCount()) {
- threads.destroy();
- ReleaseMutex(hStackMutex);
- SetEvent(hThreadQueueEmpty); // thread list is empty now
- return 0;
- }
-
- ReleaseMutex(hStackMutex);
- return 0;
- }
- }
- ReleaseMutex(hStackMutex);
- }
- return 1;
-}
+HANDLE hStackMutex, hThreadQueueEmpty;
/////////////////////////////////////////////////////////////////////////////////////////
// module init
@@ -378,6 +62,7 @@ static void LoadCoreModule(void)
hAPCWindow = CreateWindowEx(0, _T("STATIC"), NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
SetWindowLongPtr(hAPCWindow, GWLP_WNDPROC, (LONG_PTR)APCWndProc);
hStackMutex = CreateMutex(NULL, FALSE, NULL);
+ hThreadQueueEmpty = CreateEvent(NULL, TRUE, TRUE, NULL);
#ifdef WIN64
HMODULE mirInst = GetModuleHandleA("miranda64.exe");
diff --git a/plugins/Mir_core/miranda.h b/plugins/Mir_core/miranda.h
index 65140260c1..71c0804fd1 100644
--- a/plugins/Mir_core/miranda.h
+++ b/plugins/Mir_core/miranda.h
@@ -43,6 +43,7 @@ int InitPathUtils(void);
extern HINSTANCE hInst;
extern HWND hAPCWindow;
+extern HANDLE hStackMutex, hThreadQueueEmpty;
/**** modules.cpp **********************************************************************/
@@ -68,6 +69,8 @@ struct THookSubscriber
};
};
+#define HOOK_SECRET_SIGNATURE 0xDEADBABA
+
struct THook
{
char name[ MAXMODULELABELLENGTH ];
@@ -75,6 +78,7 @@ struct THook
int subscriberCount;
THookSubscriber* subscriber;
MIRANDAHOOK pfnHook;
+ DWORD secretSignature;
CRITICAL_SECTION csHook;
};
diff --git a/plugins/Mir_core/modules.cpp b/plugins/Mir_core/modules.cpp
index f451a70f60..bd8636ccb8 100644
--- a/plugins/Mir_core/modules.cpp
+++ b/plugins/Mir_core/modules.cpp
@@ -109,17 +109,18 @@ MIR_CORE_DLL(HANDLE) CreateHookableEvent(const char *name)
return NULL;
}
- THook* ret = (THook*)mir_alloc(sizeof(THook));
- strncpy(ret->name, name, sizeof(ret->name)); ret->name[ MAXMODULELABELLENGTH-1 ] = 0;
- ret->id = hookId++;
- ret->subscriberCount = 0;
- ret->subscriber = NULL;
- ret->pfnHook = NULL;
- InitializeCriticalSection(&ret->csHook);
- hooks.insert(ret);
+ THook* newItem = (THook*)mir_alloc(sizeof(THook));
+ strncpy(newItem->name, name, sizeof(newItem->name)); newItem->name[ MAXMODULELABELLENGTH-1 ] = 0;
+ newItem->id = hookId++;
+ newItem->subscriberCount = 0;
+ newItem->subscriber = NULL;
+ newItem->pfnHook = NULL;
+ newItem->secretSignature = HOOK_SECRET_SIGNATURE;
+ InitializeCriticalSection(&newItem->csHook);
+ hooks.insert(newItem);
LeaveCriticalSection(&csHooks);
- return (HANDLE)ret;
+ return (HANDLE)newItem;
}
MIR_CORE_DLL(int) DestroyHookableEvent(HANDLE hEvent)
@@ -135,6 +136,7 @@ MIR_CORE_DLL(int) DestroyHookableEvent(HANDLE hEvent)
}
THook* p = hooks[idx];
+ p->secretSignature = 0;
if (p->subscriberCount) {
mir_free(p->subscriber);
p->subscriber = NULL;
@@ -223,38 +225,44 @@ MIR_CORE_DLL(int) CallHookSubscribers(HANDLE hEvent, WPARAM wParam, LPARAM lPara
return returnVal;
}
-static int checkHook(HANDLE hHook)
+static bool checkHook(HANDLE hHook)
{
- if (hHook == NULL)
- return -1;
-
- EnterCriticalSection(&csHooks);
- if (pLastHook != hHook || !pLastHook) {
- if (hooks.getIndex((THook*)hHook) == -1) {
- LeaveCriticalSection(&csHooks);
- return -1;
- }
- pLastHook = (THook*)hHook;
+ THook* p = (THook*)hHook;
+ if (p == NULL)
+ return false;
+
+ bool ret;
+ __try
+ {
+ if (p->secretSignature != HOOK_SECRET_SIGNATURE)
+ ret = false;
+ else if (p->subscriberCount == 0)
+ ret = false;
+ else
+ ret = true;
}
- LeaveCriticalSection(&csHooks);
- return 0;
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ret = false;
+ }
+
+ return ret;
}
static void CALLBACK HookToMainAPCFunc(ULONG_PTR dwParam)
{
THookToMainThreadItem* item = (THookToMainThreadItem*)dwParam;
-
- if (checkHook(item->hook) == -1)
- item->result = -1;
- else
- item->result = CallHookSubscribers(item->hook, item->wParam, item->lParam);
+ item->result = CallHookSubscribers(item->hook, item->wParam, item->lParam);
SetEvent(item->hDoneEvent);
}
MIR_CORE_DLL(int) NotifyEventHooks(HANDLE hEvent, WPARAM wParam, LPARAM lParam)
{
+ if ( !checkHook(hEvent))
+ return -1;
+
if ( GetCurrentThreadId() == mainThreadId)
- return (checkHook(hEvent) == -1) ? -1 : CallHookSubscribers(hEvent, wParam, lParam);
+ return CallHookSubscribers(hEvent, wParam, lParam);
mir_ptr<THookToMainThreadItem> item;
item->hDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
@@ -267,11 +275,8 @@ MIR_CORE_DLL(int) NotifyEventHooks(HANDLE hEvent, WPARAM wParam, LPARAM lParam)
static HANDLE HookEventInt(int type, const char* name, MIRANDAHOOK hookProc, void* object, LPARAM lParam)
{
- int idx;
- THook* p;
- HANDLE ret;
-
EnterCriticalSection(&csHooks);
+ int idx;
if ((idx = hooks.getIndex((THook*)name)) == -1) {
#ifdef _DEBUG
OutputDebugStringA("Attempt to hook: \t");
@@ -282,7 +287,7 @@ static HANDLE HookEventInt(int type, const char* name, MIRANDAHOOK hookProc, voi
return NULL;
}
- p = hooks[ idx ];
+ THook* p = hooks[ idx ];
p->subscriber = (THookSubscriber*)mir_realloc(p->subscriber, sizeof(THookSubscriber)*(p->subscriberCount+1));
p->subscriber[ p->subscriberCount ].type = type;
p->subscriber[ p->subscriberCount ].pfnHook = hookProc;
@@ -291,7 +296,7 @@ static HANDLE HookEventInt(int type, const char* name, MIRANDAHOOK hookProc, voi
p->subscriber[ p->subscriberCount ].hOwner = GetInstByAddress(hookProc);
p->subscriberCount++;
- ret = (HANDLE)((p->id << 16) | p->subscriberCount);
+ HANDLE ret = (HANDLE)((p->id << 16) | p->subscriberCount);
LeaveCriticalSection(&csHooks);
return ret;
}
@@ -318,11 +323,9 @@ MIR_CORE_DLL(HANDLE) HookEventObjParam(const char* name, MIRANDAHOOKOBJPARAM hoo
MIR_CORE_DLL(HANDLE) HookEventMessage(const char* name, HWND hwnd, UINT message)
{
- int idx;
- THook* p;
- HANDLE ret;
-
EnterCriticalSection(&csHooks);
+
+ int idx;
if ((idx = hooks.getIndex((THook*)name)) == -1) {
#ifdef _DEBUG
MessageBoxA(NULL, "Attempt to hook non-existant event", name, MB_OK);
@@ -331,34 +334,34 @@ MIR_CORE_DLL(HANDLE) HookEventMessage(const char* name, HWND hwnd, UINT message)
return NULL;
}
- p = hooks[ idx ];
+ THook* p = hooks[ idx ];
p->subscriber = (THookSubscriber*)mir_realloc(p->subscriber, sizeof(THookSubscriber)*(p->subscriberCount+1));
p->subscriber[ p->subscriberCount ].type = 5;
p->subscriber[ p->subscriberCount ].hwnd = hwnd;
p->subscriber[ p->subscriberCount ].message = message;
p->subscriberCount++;
- ret = (HANDLE)((p->id << 16) | p->subscriberCount);
+ HANDLE ret = (HANDLE)((p->id << 16) | p->subscriberCount);
LeaveCriticalSection(&csHooks);
return ret;
}
MIR_CORE_DLL(int) UnhookEvent(HANDLE hHook)
{
- int i;
- THook* p = NULL;
+ if (hHook == NULL)
+ return 0;
int hookId = (int)hHook >> 16;
int subscriberId = ((int)hHook & 0xFFFF) - 1;
- if (hHook == NULL) return 0;
-
EnterCriticalSection(&csHooks);
- for (i = 0; i < hooks.getCount(); i++) {
+
+ THook* p = NULL;
+ for (int i = 0; i < hooks.getCount(); i++)
if (hooks[i]->id == hookId) {
p = hooks[i];
break;
- } }
+ }
if (p == NULL) {
LeaveCriticalSection(&csHooks);
@@ -385,35 +388,36 @@ MIR_CORE_DLL(int) UnhookEvent(HANDLE hHook)
MIR_CORE_DLL(void) KillModuleEventHooks(HINSTANCE hInst)
{
- int i, j;
-
EnterCriticalSection(&csHooks);
- for (i = hooks.getCount()-1; i >= 0; i--) {
+
+ for (int i = hooks.getCount()-1; i >= 0; i--) {
if (hooks[i]->subscriberCount == 0)
continue;
- for (j = hooks[i]->subscriberCount-1; j >= 0; j--) {
- if (hooks[i]->subscriber[j].hOwner == hInst) {
- char szModuleName[ MAX_PATH ];
- GetModuleFileNameA(hooks[i]->subscriber[j].hOwner, szModuleName, sizeof(szModuleName));
- UnhookEvent((HANDLE)((hooks[i]->id << 16) + j + 1));
- if (hooks[i]->subscriberCount == 0)
- break;
- } } }
+ for (int j = hooks[i]->subscriberCount-1; j >= 0; j--) {
+ if (hooks[i]->subscriber[j].hOwner != hInst)
+ continue;
+
+ char szModuleName[ MAX_PATH ];
+ GetModuleFileNameA(hooks[i]->subscriber[j].hOwner, szModuleName, sizeof(szModuleName));
+ UnhookEvent((HANDLE)((hooks[i]->id << 16) + j + 1));
+ if (hooks[i]->subscriberCount == 0)
+ break;
+ }
+ }
LeaveCriticalSection(&csHooks);
}
MIR_CORE_DLL(void) KillObjectEventHooks(void* pObject)
{
- int i, j;
-
EnterCriticalSection(&csHooks);
- for (i = hooks.getCount()-1; i >= 0; i--) {
+
+ for (int i = hooks.getCount()-1; i >= 0; i--) {
if (hooks[i]->subscriberCount == 0)
continue;
- for (j = hooks[i]->subscriberCount-1; j >= 0; j--) {
+ for (int j = hooks[i]->subscriberCount-1; j >= 0; j--) {
if (hooks[i]->subscriber[j].object == pObject) {
UnhookEvent((HANDLE)((hooks[i]->id << 16) + j + 1));
if (hooks[i]->subscriberCount == 0)
@@ -551,12 +555,14 @@ static void CALLBACK CallServiceToMainAPCFunc(ULONG_PTR dwParam)
MIR_CORE_DLL(INT_PTR) CallServiceSync(const char *name, WPARAM wParam, LPARAM lParam)
{
- if (name == NULL) return CALLSERVICE_NOTFOUND;
+ 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)
- return CallService(name, wParam, lParam);
+ return CallService(name, wParam, lParam);
mir_ptr<TServiceToMainThreadItem> item;
item->wParam = wParam;
@@ -576,12 +582,14 @@ MIR_CORE_DLL(int) CallFunctionAsync(void (__stdcall *func)(void *), void *arg)
MIR_CORE_DLL(void) KillModuleServices(HINSTANCE hInst)
{
EnterCriticalSection(&csServices);
+
for (int i = services.getCount()-1; i >= 0; i--) {
if (services[i]->hOwner == hInst) {
char szModuleName[ MAX_PATH ];
GetModuleFileNameA(services[i]->hOwner, szModuleName, sizeof(szModuleName));
DestroyServiceFunction((HANDLE)services[i]->nameHash);
- } }
+ }
+ }
LeaveCriticalSection(&csServices);
}
@@ -589,6 +597,7 @@ MIR_CORE_DLL(void) KillModuleServices(HINSTANCE hInst)
MIR_CORE_DLL(void) KillObjectServices(void* pObject)
{
EnterCriticalSection(&csServices);
+
for (int i = services.getCount()-1; i >= 0; i--)
if (services[i]->object == pObject)
DestroyServiceFunction((HANDLE)services[i]->nameHash);
@@ -613,23 +622,26 @@ int InitialiseModularEngine(void)
void DestroyModularEngine(void)
{
EnterCriticalSection(&csHooks);
+
for (int i=0; i < hooks.getCount(); i++) {
THook* p = hooks[i];
- if (p->subscriberCount)
+ if (p->subscriberCount)
mir_free(p->subscriber);
DeleteCriticalSection(&p->csHook);
mir_free(p);
}
hooks.destroy();
+
LeaveCriticalSection(&csHooks);
DeleteCriticalSection(&csHooks);
EnterCriticalSection(&csServices);
+
for (int j=0; j < services.getCount(); j++)
mir_free(services[j]);
-
services.destroy();
+
LeaveCriticalSection(&csServices);
- DeleteCriticalSection(&csServices);
+ DeleteCriticalSection(&csServices);
CloseHandle(hMainThread);
}
diff --git a/plugins/Mir_core/threads.cpp b/plugins/Mir_core/threads.cpp
new file mode 100644
index 0000000000..68fb526f5d
--- /dev/null
+++ b/plugins/Mir_core/threads.cpp
@@ -0,0 +1,372 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2012 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "commonheaders.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// APC and mutex functions
+
+static void __stdcall DummyAPCFunc(ULONG_PTR)
+{
+ /* called in the context of thread that cleared it's APC queue */
+ return;
+}
+
+static int MirandaWaitForMutex(HANDLE hEvent)
+{
+ for (;;) {
+ // will get WAIT_IO_COMPLETE for QueueUserAPC() which isnt a result
+ DWORD rc = MsgWaitForMultipleObjectsEx(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;
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// exception handling
+
+static DWORD __cdecl sttDefaultFilter(DWORD, EXCEPTION_POINTERS*)
+{
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+
+pfnExceptionFilter pMirandaExceptFilter = sttDefaultFilter;
+
+MIR_CORE_DLL(pfnExceptionFilter) GetExceptionFilter()
+{
+ return pMirandaExceptFilter;
+}
+
+MIR_CORE_DLL(pfnExceptionFilter) SetExceptionFilter(pfnExceptionFilter pMirandaExceptFilter)
+{
+ pfnExceptionFilter oldOne = pMirandaExceptFilter;
+ if (pMirandaExceptFilter != 0)
+ pMirandaExceptFilter = pMirandaExceptFilter;
+ return oldOne;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// thread support functions
+
+struct THREAD_WAIT_ENTRY
+{
+ DWORD dwThreadId; // valid if hThread isn't signalled
+ HANDLE hThread;
+ HINSTANCE hOwner;
+ void* pObject;
+ //PVOID addr;
+};
+
+static LIST<THREAD_WAIT_ENTRY> threads(10, NumericKeySortT);
+
+struct FORK_ARG {
+ HANDLE hEvent;
+ pThreadFunc threadcode;
+ pThreadFuncEx threadcodeex;
+ void *arg, *owner;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// forkthread - starts a new thread
+
+void __cdecl forkthread_r(void * arg)
+{
+ struct FORK_ARG * fa = (struct FORK_ARG *) arg;
+ void (*callercode)(void*)=fa->threadcode;
+ void * cookie=fa->arg;
+ Thread_Push(( HINSTANCE)callercode);
+ SetEvent(fa->hEvent);
+ __try
+ {
+ callercode(cookie);
+ }
+ __except(pMirandaExceptFilter(GetExceptionCode(), GetExceptionInformation()))
+ {
+ }
+
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
+ Thread_Pop();
+ return;
+}
+
+MIR_CORE_DLL(UINT_PTR) forkthread( void (__cdecl *threadcode)(void*), unsigned long stacksize, void *arg)
+{
+ UINT_PTR rc;
+ struct FORK_ARG fa;
+ fa.hEvent=CreateEvent(NULL, FALSE, FALSE, NULL);
+ fa.threadcode=threadcode;
+ fa.arg=arg;
+ rc=_beginthread(forkthread_r, stacksize, &fa);
+ if ((UINT_PTR)-1L != rc)
+ WaitForSingleObject(fa.hEvent, INFINITE);
+
+ CloseHandle(fa.hEvent);
+ return rc;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// forkthreadex - starts a new thread with the extended info and returns the thread id
+
+unsigned __stdcall forkthreadex_r(void * arg)
+{
+ struct FORK_ARG *fa = (struct FORK_ARG *)arg;
+ pThreadFuncEx threadcode = fa->threadcodeex;
+ pThreadFuncOwner threadcodeex = (pThreadFuncOwner)fa->threadcodeex;
+ void *cookie = fa->arg;
+ void *owner = fa->owner;
+ unsigned long rc = 0;
+
+ Thread_Push((HINSTANCE)threadcode, fa->owner);
+ SetEvent(fa->hEvent);
+ __try
+ {
+ if (owner)
+ rc = threadcodeex(owner, cookie);
+ else
+ rc = threadcode(cookie);
+ }
+ __except(pMirandaExceptFilter(GetExceptionCode(), GetExceptionInformation()))
+ {
+ }
+
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
+ Thread_Pop();
+ return rc;
+}
+
+MIR_CORE_DLL(UINT_PTR) forkthreadex(
+ void *sec,
+ unsigned stacksize,
+ unsigned (__stdcall *threadcode)(void*),
+ void* owner,
+ void *arg,
+ unsigned *thraddr)
+{
+ UINT_PTR rc;
+ struct FORK_ARG fa = { 0 };
+ fa.threadcodeex = threadcode;
+ fa.arg = arg;
+ fa.owner = owner;
+ fa.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ rc = _beginthreadex(sec, stacksize, forkthreadex_r, (void *)&fa, 0, thraddr);
+ if (rc)
+ WaitForSingleObject(fa.hEvent, INFINITE);
+
+ CloseHandle(fa.hEvent);
+ return rc;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+MIR_CORE_DLL(void) KillObjectThreads(void* owner)
+{
+ if (owner == NULL)
+ return;
+
+ WaitForSingleObject(hStackMutex, INFINITE);
+
+ HANDLE* threadPool = (HANDLE*)alloca(threads.getCount()*sizeof(HANDLE));
+ int threadCount = 0;
+
+ for (int j = threads.getCount(); j--;) {
+ THREAD_WAIT_ENTRY* p = threads[j];
+ if (p->pObject == owner)
+ threadPool[ threadCount++ ] = p->hThread;
+ }
+ ReleaseMutex(hStackMutex);
+
+ // is there anything to kill?
+ if (threadCount > 0) {
+ if ( WaitForMultipleObjects(threadCount, threadPool, TRUE, 5000) == WAIT_TIMEOUT) {
+ // forcibly kill all remaining threads after 5 secs
+ WaitForSingleObject(hStackMutex, INFINITE);
+ for (int j = threads.getCount()-1; j >= 0; j--) {
+ THREAD_WAIT_ENTRY* p = threads[j];
+ if (p->pObject == owner) {
+ TerminateThread(p->hThread, 9999);
+ CloseHandle(p->hThread);
+ threads.remove(j);
+ mir_free(p);
+ }
+ }
+ ReleaseMutex(hStackMutex);
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static void CALLBACK KillAllThreads(HWND, UINT, UINT_PTR, DWORD)
+{
+ if ( MirandaWaitForMutex(hStackMutex)) {
+ for (int j=0; j < threads.getCount(); j++) {
+ THREAD_WAIT_ENTRY* p = threads[j];
+ char szModuleName[ MAX_PATH ];
+ GetModuleFileNameA(p->hOwner, szModuleName, sizeof(szModuleName));
+ TerminateThread(p->hThread, 9999);
+ CloseHandle(p->hThread);
+ mir_free(p);
+ }
+
+ threads.destroy();
+
+ ReleaseMutex(hStackMutex);
+ SetEvent(hThreadQueueEmpty);
+ }
+}
+
+MIR_CORE_DLL(void) Thread_Wait(void)
+{
+ // acquire the list and wake up any alertable threads
+ if ( MirandaWaitForMutex(hStackMutex)) {
+ for (int j=0; j < threads.getCount(); j++)
+ QueueUserAPC(DummyAPCFunc, threads[j]->hThread, 0);
+ ReleaseMutex(hStackMutex);
+ }
+
+ // give all unclosed threads 5 seconds to close
+ SetTimer(NULL, 0, 5000, KillAllThreads);
+
+ // wait til the thread list is empty
+ MirandaWaitForMutex(hThreadQueueEmpty);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+typedef LONG (WINAPI *pNtQIT)(HANDLE, LONG, PVOID, ULONG, PULONG);
+#define ThreadQuerySetWin32StartAddress 9
+
+static void* GetCurrentThreadEntryPoint()
+{
+ LONG ntStatus;
+ HANDLE hDupHandle, hCurrentProcess;
+ DWORD_PTR dwStartAddress;
+
+ pNtQIT NtQueryInformationThread = (pNtQIT)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "NtQueryInformationThread" );
+ if(NtQueryInformationThread == NULL) return 0;
+
+ hCurrentProcess = GetCurrentProcess();
+ if(!DuplicateHandle(hCurrentProcess, GetCurrentThread(), hCurrentProcess, &hDupHandle, THREAD_QUERY_INFORMATION, FALSE, 0)){
+ SetLastError(ERROR_ACCESS_DENIED);
+ return NULL;
+ }
+ ntStatus = NtQueryInformationThread(hDupHandle, ThreadQuerySetWin32StartAddress, &dwStartAddress, sizeof(DWORD_PTR), NULL);
+ CloseHandle(hDupHandle);
+
+ if(ntStatus != ERROR_SUCCESS) return 0;
+ return ( void* )dwStartAddress;
+}
+
+MIR_CORE_DLL(INT_PTR) Thread_Push(HINSTANCE hInst, void* pOwner)
+{
+ ResetEvent(hThreadQueueEmpty); // thread list is not empty
+ if ( WaitForSingleObject(hStackMutex, INFINITE) == WAIT_OBJECT_0) {
+ THREAD_WAIT_ENTRY* p = (THREAD_WAIT_ENTRY*)mir_calloc(sizeof(THREAD_WAIT_ENTRY));
+
+ DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &p->hThread, 0, FALSE, DUPLICATE_SAME_ACCESS);
+ p->dwThreadId = GetCurrentThreadId();
+ p->pObject = pOwner;
+ if (pluginListAddr.getIndex(hInst) != -1)
+ p->hOwner = hInst;
+ else
+ p->hOwner = GetInstByAddress(( hInst != NULL ) ? (PVOID)hInst : GetCurrentThreadEntryPoint());
+
+ threads.insert(p);
+
+ ReleaseMutex(hStackMutex);
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+MIR_CORE_DLL(INT_PTR) Thread_Pop()
+{
+ if ( WaitForSingleObject(hStackMutex, INFINITE) == WAIT_OBJECT_0) {
+ DWORD dwThreadId = GetCurrentThreadId();
+ for (int j=0; j < threads.getCount(); j++) {
+ THREAD_WAIT_ENTRY* p = threads[j];
+ if (p->dwThreadId == dwThreadId) {
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
+ CloseHandle(p->hThread);
+ threads.remove(j);
+ mir_free(p);
+
+ if ( !threads.getCount()) {
+ threads.destroy();
+ ReleaseMutex(hStackMutex);
+ SetEvent(hThreadQueueEmpty); // thread list is empty now
+ return 0;
+ }
+
+ ReleaseMutex(hStackMutex);
+ return 0;
+ }
+ }
+ ReleaseMutex(hStackMutex);
+ }
+ return 1;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+const DWORD MS_VC_EXCEPTION=0x406D1388;
+
+#pragma pack(push,8)
+typedef struct tagTHREADNAME_INFO
+{
+ DWORD dwType; // Must be 0x1000.
+ LPCSTR szName; // Pointer to name (in user addr space).
+ DWORD dwThreadID; // Thread ID (-1=caller thread).
+ DWORD dwFlags; // Reserved for future use, must be zero.
+} THREADNAME_INFO;
+#pragma pack(pop)
+
+MIR_CORE_DLL(void) Thread_SetName(DWORD dwThreadID, const char *szThreadName)
+{
+ THREADNAME_INFO info;
+ info.dwType = 0x1000;
+ info.szName = szThreadName;
+ info.dwThreadID = dwThreadID;
+ info.dwFlags = 0;
+
+ __try
+ {
+ RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+}