Win-specific: Fix some crashes in scan libraries

This commit is contained in:
Abs62 2011-12-17 01:15:33 +04:00
parent 5e49c32b53
commit 0c7a92029b
4 changed files with 246 additions and 190 deletions

View file

@ -86,14 +86,14 @@ static BOOL HookImportFunction(HMODULE hModule, LPCSTR szImportModule, LPCSTR sz
if (bDoHook) {
MEMORY_BASIC_INFORMATION mbi_thunk;
DWORD dwOldProtect;
if( !VirtualQuery(pRealThunk, &mbi_thunk, sizeof(MEMORY_BASIC_INFORMATION)) )
if( VirtualQuery(pRealThunk, &mbi_thunk, sizeof(MEMORY_BASIC_INFORMATION)) != sizeof(MEMORY_BASIC_INFORMATION))
return FALSE;
if( !VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, PAGE_READWRITE, &mbi_thunk.Protect) )
return FALSE;
if (paOrigFuncs)
*paOrigFuncs = (PROC)pRealThunk->u1.Function;
pRealThunk->u1.Function = (DWORD)paHookFuncs;
*paOrigFuncs = (PROC)InterlockedExchange((long *)&(pRealThunk->u1.Function), (long)paHookFuncs);
else
InterlockedExchange((long *)&(pRealThunk->u1.Function), (long)paHookFuncs);
VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, mbi_thunk.Protect, &dwOldProtect);
return TRUE;

View file

@ -3,7 +3,6 @@
#include <windows.h>
BOOL HookAPI(LPCSTR szImportModule, LPCSTR szFunc, PROC paHookFuncs, PROC* paOrigFuncs);
#endif

View file

@ -10,18 +10,21 @@
#include "GetWord.h"
#include "HookImportFunction.h"
HANDLE hHookMutex = 0;
typedef BOOL (WINAPI *TextOutANextHook_t)(HDC hdc, int nXStart, int nYStart, LPCSTR lpszString,int cbString);
TextOutANextHook_t TextOutANextHook = NULL;
TextOutANextHook_t TextOutANextHook __attribute__ ((aligned (4))) = NULL;
typedef BOOL (WINAPI *TextOutWNextHook_t)(HDC hdc, int nXStart, int nYStart, LPCWSTR lpszString,int cbString);
TextOutWNextHook_t TextOutWNextHook = NULL;
TextOutWNextHook_t TextOutWNextHook __attribute__ ((aligned (4))) = NULL;
typedef BOOL (WINAPI *ExtTextOutANextHook_t)(HDC hdc, int nXStart, int nYStart, UINT fuOptions, CONST RECT *lprc, LPCSTR lpszString, UINT cbString, CONST INT *lpDx);
ExtTextOutANextHook_t ExtTextOutANextHook = NULL;
ExtTextOutANextHook_t ExtTextOutANextHook __attribute__ ((aligned (4))) = NULL;
typedef BOOL (WINAPI *ExtTextOutWNextHook_t)(HDC hdc, int nXStart, int nYStart, UINT fuOptions, CONST RECT *lprc, LPCWSTR lpszString, UINT cbString, CONST INT *lpDx);
ExtTextOutWNextHook_t ExtTextOutWNextHook = NULL;
ExtTextOutWNextHook_t ExtTextOutWNextHook __attribute__ ((aligned (4))) = NULL;
#define HOOKS_NUM 4
TEverythingParams *CurParams = NULL;
HANDLE installEvent = 0;
volatile long hookCounts[HOOKS_NUM] __attribute__ ((aligned (4))) = { 0, 0, 0, 0 };
CRITICAL_SECTION hookCS;
void ConvertToMatchedWordA(TEverythingParams *TP)
{
@ -105,29 +108,31 @@ static int MyCopyMemory(char *a, const char *b, int len)
static void IterateThroughItems(HWND WND, HMENU menu, POINT *p)
{
int count = GetMenuItemCount(menu);
RECT rec;
MENUITEMINFO info;
int i;
int count = GetMenuItemCount(menu);
for (i=0; i<count; i++) {
if (GetMenuItemRect(WND, menu, i, &rec) && (rec.left<=p->x) && (p->x<=rec.right) && (rec.top<=p->y) && (p->y<=rec.bottom)) {
ZeroMemory(&info, sizeof(info));
info.cbSize = sizeof(info);
info.fMask = MIIM_TYPE | MIIM_SUBMENU;
info.cch = 256;
info.dwTypeData = malloc(256);
if(info.dwTypeData != NULL) {
GetMenuItemInfo(menu, i, TRUE, &info);
if (info.cch>0) {
info.fMask = MIIM_STRING | MIIM_SUBMENU;
if( !GetMenuItemInfo(menu, i, TRUE, &info) )
break;
if (info.cch > 0 && info.cch < 255) {
char buf[256];
ZeroMemory(buf, sizeof(buf));
info.cch += 1;
info.dwTypeData = buf;
info.fMask = MIIM_STRING | MIIM_SUBMENU;
if( GetMenuItemInfo(menu, i, TRUE, &info) ) {
if( info.cch > 255 )
CurParams->WordLen = 255;
else
break;
CurParams->WordLen = info.cch;
CurParams->Unicode = FALSE;
CurParams->WordLen = MyCopyMemory(CurParams->MatchedWordA, info.dwTypeData, CurParams->WordLen);
CurParams->WordLen = MyCopyMemory(CurParams->MatchedWordA, buf, CurParams->WordLen + 1);
CurParams->BeginPos = 0;
}
free(info.dwTypeData);
}
break;
}
@ -136,23 +141,26 @@ static void IterateThroughItems(HWND WND, HMENU menu, POINT *p)
static void GetWordTextOutHook (TEverythingParams *TP)
{
DWORD wso;
EnterCriticalSection(&hookCS);
CurParams = TP;
ScreenToClient(TP->WND, &(TP->Pt));
if (TP->Pt.y<0) {
char buffer[256];
HMENU menu;
HMENU menu=NULL;
char buffer2[256];
int n, n2;
ZeroMemory(buffer, sizeof(buffer));
ZeroMemory(buffer2, sizeof(buffer2));
GetWindowText(TP->WND, buffer, sizeof(buffer)-1);
if( ( n = GetWindowText(TP->WND, buffer, sizeof(buffer)-1) ) > 0 ) {
SetWindowText(TP->WND, "");
GetWindowText(TP->WND, buffer2, sizeof(buffer2)-1);
if (buffer2[0]) { // MDI window.
if ( ( n2 = GetWindowText(TP->WND, buffer2, sizeof(buffer2)-1) ) > 0 ) { // MDI window.
char *p = strstr(buffer, buffer2);
if (p) {
if (p == buffer) { // FWS_PREFIXTITLE
strcpy(buffer, buffer+strlen(buffer2));
if( n > n2 && n - n2 < (int)sizeof( buffer ) )
memmove( buffer, buffer + n2, n - n2 + 1 );
// strncpy(buffer, buffer+strlen(buffer2), sizeof(buffer)-1);
} else {
*p = '\0';
}
@ -161,8 +169,9 @@ DWORD wso;
CurParams->Active = TRUE;
SetWindowText(TP->WND, buffer);
CurParams->Active = FALSE;
}
menu = GetMenu(TP->WND);
if (menu) {
if (menu && IsMenu( menu ) ) {
ClientToScreen(TP->WND, &(TP->Pt));
IterateThroughItems(TP->WND, menu, &(TP->Pt));
}
@ -179,11 +188,8 @@ DWORD wso;
CurParams->Active = FALSE;
}
}
wso=WaitForSingleObject(hHookMutex, 10000);
CurParams = NULL;
if (wso == WAIT_OBJECT_0 || wso == WAIT_ABANDONED) {
ReleaseMutex(hHookMutex);
}
LeaveCriticalSection(&hookCS);
}
char* ExtractFromEverything(HWND WND, POINT Pt, int *BeginPos)
@ -347,45 +353,58 @@ static void IsInsidePointW(const HDC DC, int X, int Y, LPCWSTR Str, int Count)
BOOL WINAPI TextOutACallbackProc(HDC hdc, int nXStart, int nYStart, LPCSTR lpszString, int cbString)
{
DWORD wso;
wso = WaitForSingleObject(hHookMutex, 0);
if (wso == WAIT_OBJECT_0 || wso == WAIT_ABANDONED) {
BOOL res = FALSE;
WaitForSingleObject(installEvent, INFINITE);
InterlockedIncrement(hookCounts + 0);
if(TryEnterCriticalSection(&hookCS)) {
if (CurParams && CurParams->Active)
IsInsidePointA(hdc, nXStart, nYStart, lpszString, cbString);
ReleaseMutex(hHookMutex);
LeaveCriticalSection(&hookCS);
}
return TextOutANextHook(hdc, nXStart, nYStart, lpszString, cbString);
if(TextOutANextHook)
res = TextOutANextHook(hdc, nXStart, nYStart, lpszString, cbString);
InterlockedDecrement(hookCounts + 0);
return res;
}
BOOL WINAPI TextOutWCallbackProc(HDC hdc, int nXStart, int nYStart, LPCWSTR lpszString, int cbString)
{
DWORD wso;
wso = WaitForSingleObject(hHookMutex, 0);
if (wso == WAIT_OBJECT_0 || wso == WAIT_ABANDONED) {
BOOL res = FALSE;
WaitForSingleObject(installEvent, INFINITE);
InterlockedIncrement(hookCounts + 1);
if(TryEnterCriticalSection(&hookCS)) {
if (CurParams && CurParams->Active)
IsInsidePointW(hdc, nXStart, nYStart, lpszString, cbString);
ReleaseMutex(hHookMutex);
LeaveCriticalSection(&hookCS);
}
return TextOutWNextHook(hdc, nXStart, nYStart, lpszString, cbString);
if(TextOutWNextHook)
res = TextOutWNextHook(hdc, nXStart, nYStart, lpszString, cbString);
InterlockedDecrement(hookCounts + 1);
return res;
}
BOOL WINAPI ExtTextOutACallbackProc(HDC hdc, int nXStart, int nYStart, UINT fuOptions, CONST RECT *lprc, LPCSTR lpszString, UINT cbString, CONST INT *lpDx)
{
DWORD wso;
wso = WaitForSingleObject(hHookMutex, 0);
if (wso == WAIT_OBJECT_0 || wso == WAIT_ABANDONED) {
BOOL res = FALSE;
WaitForSingleObject(installEvent, INFINITE);
InterlockedIncrement(hookCounts + 2);
if(TryEnterCriticalSection(&hookCS)) {
if (CurParams && CurParams->Active)
IsInsidePointA(hdc, nXStart, nYStart, lpszString, cbString);
ReleaseMutex(hHookMutex);
LeaveCriticalSection(&hookCS);
}
return ExtTextOutANextHook(hdc, nXStart, nYStart, fuOptions, lprc, lpszString, cbString, lpDx);
if(ExtTextOutANextHook)
res = ExtTextOutANextHook(hdc, nXStart, nYStart, fuOptions, lprc, lpszString, cbString, lpDx);
InterlockedDecrement(hookCounts + 2);
return res;
}
BOOL WINAPI ExtTextOutWCallbackProc(HDC hdc, int nXStart, int nYStart, UINT fuOptions, CONST RECT *lprc, LPCWSTR lpszString, UINT cbString, CONST INT *lpDx)
{
DWORD wso;
wso = WaitForSingleObject(hHookMutex, 0);
if (wso == WAIT_OBJECT_0 || wso == WAIT_ABANDONED) {
BOOL res = FALSE;
WaitForSingleObject(installEvent, INFINITE);
InterlockedIncrement(hookCounts + 3);
if(TryEnterCriticalSection(&hookCS)) {
if (CurParams && CurParams->Active)
{
if ( fuOptions & ETO_GLYPH_INDEX )
@ -397,18 +416,24 @@ DWORD wso;
// Here we have to decode glyph indices back to chars. We do this
// by tedious and ineffective iteration.
//
x = GetFontUnicodeRanges( hdc, 0 );
if(x != 0) ranges = malloc(x);
if(ranges == NULL) {
ReleaseMutex(hHookMutex);
return ExtTextOutWNextHook(hdc, nXStart, nYStart, fuOptions, lprc, lpszString, cbString, lpDx);
LeaveCriticalSection(&hookCS);
if(ExtTextOutWNextHook)
res = ExtTextOutWNextHook(hdc, nXStart, nYStart, fuOptions, lprc, lpszString, cbString, lpDx);
InterlockedDecrement(hookCounts + 3);
return res;
}
x = GetFontUnicodeRanges( hdc, ranges );
if(x == 0) {
free(ranges);
ReleaseMutex(hHookMutex);
return ExtTextOutWNextHook(hdc, nXStart, nYStart, fuOptions, lprc, lpszString, cbString, lpDx);
LeaveCriticalSection(&hookCS);
if(ExtTextOutWNextHook)
res = ExtTextOutWNextHook(hdc, nXStart, nYStart, fuOptions, lprc, lpszString, cbString, lpDx);
InterlockedDecrement(hookCounts + 3);
return res;
}
// Render up all available chars into one ridiculously big string
@ -419,14 +444,17 @@ DWORD wso;
if(allChars == NULL || allIndices == NULL) {
if(allChars != NULL) free(allChars);
if(allIndices != NULL) free(allIndices);
ReleaseMutex(hHookMutex);
return ExtTextOutWNextHook(hdc, nXStart, nYStart, fuOptions, lprc, lpszString, cbString, lpDx);
free(ranges);
LeaveCriticalSection(&hookCS);
if(ExtTextOutWNextHook)
res = ExtTextOutWNextHook(hdc, nXStart, nYStart, fuOptions, lprc, lpszString, cbString, lpDx);
InterlockedDecrement(hookCounts + 3);
return res;
}
ptr = allChars;
for( x = 0; x < ranges->cRanges; ++x )
{
for( x = 0; x < ranges->cRanges; ++x ) {
WCHAR c = ranges->ranges[ x ].wcLow;
unsigned y = ranges->ranges[ x ].cGlyphs;
@ -444,19 +472,16 @@ DWORD wso;
restoredString = malloc( cbString * sizeof( WCHAR ) );
if(restoredString != NULL) {
for( x = 0; x < cbString; ++x )
{
for( x = 0; x < cbString; ++x ) {
unsigned y;
WORD idx = lpszString[ x ];
for( y = 0; y < ranges->cGlyphsSupported; ++y )
if ( allIndices[ y ] == idx )
{
if ( allIndices[ y ] == idx ) {
restoredString[ x ] = allChars[ y ];
break;
}
if ( y == ranges->cGlyphsSupported )
{
if ( y == ranges->cGlyphsSupported ) {
// Not found
restoredString[ x ] = L'?';
}
@ -474,15 +499,36 @@ DWORD wso;
IsInsidePointW( hdc, nXStart, nYStart, restoredString, cbString );
free( restoredString );
}
}
else
else // fuOptions & ETO_GLYPH_INDEX
IsInsidePointW(hdc, nXStart, nYStart, lpszString, cbString);
}
ReleaseMutex(hHookMutex);
LeaveCriticalSection(&hookCS);
}
return ExtTextOutWNextHook(hdc, nXStart, nYStart, fuOptions, lprc, lpszString, cbString, lpDx);
if(ExtTextOutWNextHook)
res = ExtTextOutWNextHook(hdc, nXStart, nYStart, fuOptions, lprc, lpszString, cbString, lpDx);
InterlockedDecrement(hookCounts + 3);
return res;
}
void WaitForAllHooks()
{
HANDLE hTimer;
LARGE_INTEGER waitTime;
waitTime.LowPart = 50000000; // 5 s
waitTime.HighPart = 0;
waitTime.QuadPart = -waitTime.QuadPart; // RelativeTime
hTimer = CreateWaitableTimer(NULL, TRUE, NULL);
if(hTimer)
SetWaitableTimer(hTimer, &waitTime, 0, NULL, NULL, FALSE);
while((hookCounts[0] > 0 || hookCounts[1] > 0 || hookCounts[2] > 0 || hookCounts[3] > 0) &&
(!hTimer || WaitForSingleObject(hTimer, 0) != WAIT_OBJECT_0)) {
SwitchToThread();
}
if(hTimer)
CloseHandle(hTimer);
}
static void InstallTextOutHooks()
@ -495,25 +541,26 @@ static void InstallTextOutHooks()
HookAPI("gdi32.dll", "ExtTextOutA", (PROC)ExtTextOutACallbackProc, (PROC*)&ExtTextOutANextHook);
if (ExtTextOutWNextHook==NULL)
HookAPI("gdi32.dll", "ExtTextOutW", (PROC)ExtTextOutWCallbackProc, (PROC*)&ExtTextOutWNextHook);
SetEvent(installEvent);
}
static void UninstallTextOutHooks()
{
if (TextOutANextHook) {
HookAPI("gdi32.dll", "TextOutA", (PROC)TextOutANextHook, NULL);
TextOutANextHook=NULL;
// TextOutANextHook=NULL;
}
if (TextOutWNextHook) {
HookAPI("gdi32.dll", "TextOutW", (PROC)TextOutWNextHook, NULL);
TextOutWNextHook=NULL;
// TextOutWNextHook=NULL;
}
if (ExtTextOutANextHook) {
HookAPI("gdi32.dll", "ExtTextOutA", (PROC)ExtTextOutANextHook, NULL);
ExtTextOutANextHook=NULL;
// ExtTextOutANextHook=NULL;
}
if (ExtTextOutWNextHook) {
HookAPI("gdi32.dll", "ExtTextOutW", (PROC)ExtTextOutWNextHook, NULL);
ExtTextOutWNextHook=NULL;
// ExtTextOutWNextHook=NULL;
}
}
@ -541,28 +588,20 @@ BOOL APIENTRY DllMain (HINSTANCE hInst /* Library instance handle. */ ,
DWORD reason /* Reason this function is being called. */ ,
LPVOID reserved /* Not used. */ )
{
DWORD wso;
switch (reason)
{
case DLL_PROCESS_ATTACH:
if(hHookMutex==0) {
hHookMutex = CreateMutex(NULL, FALSE, "GoldenDictTextOutHookMutex");
if(hHookMutex==0)
return(FALSE);
}
if((installEvent = CreateEvent(0, TRUE, FALSE, 0)) == 0)
return FALSE;
InitializeCriticalSection(&hookCS);
InstallTextOutHooks();
break;
case DLL_PROCESS_DETACH:
UninstallTextOutHooks();
if(hHookMutex) {
wso = WaitForSingleObject(hHookMutex, 5000);
if (wso == WAIT_OBJECT_0 || wso == WAIT_ABANDONED) {
ReleaseMutex(hHookMutex);
CloseHandle(hHookMutex);
hHookMutex=0;
}
}
WaitForAllHooks();
CloseHandle(installEvent);
DeleteCriticalSection(&hookCS);
break;
case DLL_THREAD_ATTACH:

View file

@ -8,7 +8,7 @@ const int REQUEST_MESSAGE_INTERVAL = 500;
const int WM_MY_SHOW_TRANSLATION = WM_USER + 301;
HINSTANCE g_hInstance = NULL;
HANDLE hSynhroMutex = 0, hHookMutex = 0;
HANDLE hSynhroMutex = 0;
HINSTANCE hGetWordLib = 0;
UINT_PTR TimerID = 0;
typedef void (*GetWordProc_t)(TCurrentMode *);
@ -16,6 +16,7 @@ GetWordProc_t GetWordProc = NULL;
GDDataStruct gds;
UINT uGdAskMessage;
WCHAR Buffer[256];
DWORD ourProcessID;
static HWND GetWindowFromPoint(POINT pt)
{
@ -108,8 +109,34 @@ DWORD wso;
wso = WaitForSingleObject(hSynhroMutex, 0);
if (wso == WAIT_OBJECT_0 || wso == WAIT_ABANDONED) {
KillTimer(0, nTimerid);
if ((GlobalData->LastWND!=0)&&(GlobalData->LastWND == GetWindowFromPoint(GlobalData->LastPt))) {
TimerID = 0;
while( 1 ) {
POINT curPt;
HWND targetWnd;
DWORD winProcessID = 0;
if( !GetCursorPos( &curPt ) )
break;
if( ( targetWnd = GetWindowFromPoint( curPt ) ) == NULL )
break;
GetWindowThreadProcessId( targetWnd, &winProcessID );
if( winProcessID != ourProcessID ) {
char className[64];
if( !GetClassName( targetWnd, className, sizeof(className) ) )
break;
if( lstrcmpi( className, "ConsoleWindowClass" ) != 0 )
break;
}
if( GlobalData == NULL || GlobalData->LastWND != targetWnd ||
GlobalData->LastPt.x != curPt.x || GlobalData->LastPt.y != curPt.y)
break;
SendWordToServer();
break;
}
ReleaseMutex(hSynhroMutex);
}
@ -118,13 +145,17 @@ DWORD wso;
LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
DWORD wso;
if ((nCode == HC_ACTION) && ((wParam == WM_MOUSEMOVE) || (wParam == WM_NCMOUSEMOVE)) && (GlobalData != NULL)) {
wso = WaitForSingleObject(hSynhroMutex, 0);
if (wso == WAIT_OBJECT_0 || wso == WAIT_ABANDONED) {
HWND WND;
TCHAR wClassName[64];
if(TimerID) {
KillTimer(0, TimerID);
TimerID = 0;
}
WND = GetWindowFromPoint(((PMOUSEHOOKSTRUCT)lParam)->pt);
if(WND == NULL) {
@ -151,9 +182,9 @@ DWORD wso;
}
if(GlobalData->LastPt.x!=((PMOUSEHOOKSTRUCT)lParam)->pt.x || GlobalData->LastPt.y!=((PMOUSEHOOKSTRUCT)lParam)->pt.y || GlobalData->LastWND != WND) {
TimerID = SetTimer(0, TimerID, MOUSEOVER_INTERVAL, TimerFunc);
GlobalData->LastWND = WND;
GlobalData->LastPt = ((PMOUSEHOOKSTRUCT)lParam)->pt;
TimerID = SetTimer(0, TimerID, MOUSEOVER_INTERVAL, TimerFunc);
}
ReleaseMutex(hSynhroMutex);
}
@ -166,7 +197,6 @@ DLLIMPORT void ActivateTextOutSpying (int Activate)
// After call SetWindowsHookEx(), when you move mouse to a application's window,
// this dll will load into this application automatically. And it is unloaded
// after call UnhookWindowsHookEx().
DWORD wso;
if(GlobalData == NULL) return;
if (Activate) {
if (GlobalData->g_hHookMouse != NULL) return;
@ -174,15 +204,13 @@ DWORD wso;
}
else {
if (GlobalData->g_hHookMouse == NULL) return;
WaitForSingleObject(hSynhroMutex, 2000);
UnhookWindowsHookEx(GlobalData->g_hHookMouse);
wso = WaitForSingleObject(hSynhroMutex, 4*MOUSEOVER_INTERVAL);
if (wso == WAIT_OBJECT_0 || wso == WAIT_ABANDONED) {
if (TimerID) {
if (KillTimer(0, TimerID))
KillTimer(0, TimerID);
TimerID=0;
}
ReleaseMutex(hSynhroMutex);
}
GlobalData->g_hHookMouse = NULL;
}
}
@ -196,15 +224,13 @@ BOOL APIENTRY DllMain (HINSTANCE hInst /* Library instance handle. */ ,
{
case DLL_PROCESS_ATTACH:
g_hInstance = hInst;
ourProcessID = GetCurrentProcessId();
if(hSynhroMutex==0) {
hSynhroMutex = CreateMutex(NULL, FALSE, "GoldenDictTextOutSpyMutex");
if(hSynhroMutex==0) {
return(FALSE);
}
}
if(hHookMutex==0) {
hHookMutex = CreateMutex(NULL, FALSE, "GoldenDictTextOutHookMutex");
}
ThTypes_Init();
uGdAskMessage = RegisterWindowMessage(GD_MESSAGE_NAME);
FindGetPhysicalCursorPos();
@ -214,7 +240,7 @@ BOOL APIENTRY DllMain (HINSTANCE hInst /* Library instance handle. */ ,
// if(hSynhroMutex) WaitForSingleObject(hSynhroMutex, INFINITE);
if(hSynhroMutex) WaitForSingleObject(hSynhroMutex, 2000);
if (TimerID) {
if (KillTimer(0, TimerID))
KillTimer(0, TimerID);
TimerID=0;
}
if(hSynhroMutex) {
@ -224,19 +250,11 @@ BOOL APIENTRY DllMain (HINSTANCE hInst /* Library instance handle. */ ,
}
{
MSG msg ;
while (PeekMessage (&msg, 0, WM_TIMER, WM_TIMER, PM_REMOVE)) {}
while (PeekMessage (&msg, 0, WM_TIMER, WM_TIMER, PM_REMOVE));
}
if ((hGetWordLib != 0)&&(hGetWordLib != (HINSTANCE)(-1))) {
FreeLibrary(hGetWordLib);
}
if(hHookMutex) {
DWORD wso = WaitForSingleObject(hHookMutex, 5000);
if (wso == WAIT_OBJECT_0 || wso == WAIT_ABANDONED) {
ReleaseMutex(hHookMutex);
CloseHandle(hHookMutex);
hHookMutex=0;
}
}
Thtypes_End();
break;