/* This file is a part of the NVDA project. URL: http://www.nvda-project.org/ Copyright 2006-2010 NVDA contributers. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 2.0, as published by the Free Software Foundation. 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. This license can be found at: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html */ #include #include #include #include #define WIN32_LEAN_AND_MEAN #include #include #include #include #include "ia2Support.h" #include "apiHook.h" #include "nvdaController.h" #include "nvdaControllerInternal.h" #include #include #include "dllmain.h" #include "nvdaHelperRemote.h" #include "inProcess.h" #include "rpcSrv.h" using namespace std; typedef HHOOK(WINAPI *SetWindowsHookEx_funcType)(int,HOOKPROC,HINSTANCE,DWORD); HINSTANCE dllHandle=NULL; wchar_t dllDirectory[MAX_PATH]; wchar_t desktopSpecificNamespace[64]; LockableObject inprocThreadsLock; HANDLE inprocMgrThreadHandle=NULL; HWINEVENTHOOK inprocWinEventHookID=0; map callWndProcHooksByThread; map getMessageHooksByThread; long tlsIndex_inThreadInjectionID=0; bool isProcessExiting=false; bool isSecureModeNVDAProcess=false; SetWindowsHookEx_funcType real_SetWindowsHookExA=NULL; //Code executed in-process //General in-process winEvent callback //Used for all possible winEvents in this process void CALLBACK inproc_winEventCallback(HWINEVENTHOOK hookID, DWORD eventID, HWND hwnd, long objectID, long childID, DWORD threadID, DWORD time) { if(hookID==0) return; //We are not at all interested in out-of-context winEvents, even if they were accidental. if(threadID!=GetCurrentThreadId()) return; //Set windows hooks for this thread if we havn't done so already inprocThreadsLock.acquire(); if((HWINEVENTHOOK)TlsGetValue(tlsIndex_inThreadInjectionID)!=hookID) { TlsSetValue(tlsIndex_inThreadInjectionID,(LPVOID)hookID); HHOOK tempHook; if((tempHook=SetWindowsHookEx(WH_GETMESSAGE,inProcess_getMessageHook,dllHandle,threadID))==0) { LOG_DEBUGWARNING(L"SetWindowsHookEx with WH_GETMESSAGE failed, GetLastError returned "<* hooksByThread=NULL; HOOKPROC ourHookProc=NULL; switch(IdHook) { case WH_GETMESSAGE: hooksByThread=&getMessageHooksByThread; ourHookProc=inProcess_getMessageHook; break; case WH_CALLWNDPROC: hooksByThread=&callWndProcHooksByThread; ourHookProc=inProcess_callWndProcHook; break; default: return res; } //See if we have previously hooked this thread ourselves. //If not then do nothing more. inprocThreadsLock.acquire(); map::iterator i=hooksByThread->find(dwThreadId); if(i!=hooksByThread->end()) { //Unhook our previous hook for this thread and rehook it again, placing our hook before the non-NVDA hook just registered if(UnhookWindowsHookEx(i->second)) { i->second=SetWindowsHookEx(IdHook,ourHookProc,NULL,dwThreadId); } else { i->second=0; } if(i->second==0) { hooksByThread->erase(i); } } inprocThreadsLock.release(); return res; } //Unregisters any current windows hooks void killRunningWindowsHooks() { for(map::iterator i=getMessageHooksByThread.begin();i!=getMessageHooksByThread.end();) { UnhookWindowsHookEx(i->second); getMessageHooksByThread.erase(i++); } for(map::iterator i=callWndProcHooksByThread.begin();i!=callWndProcHooksByThread.end();) { UnhookWindowsHookEx(i->second); callWndProcHooksByThread.erase(i++); } } //A replacement OpenClipboard function to disable the use of the clipboard in a secure mode NVDA process //Simply returns false without calling the original OpenClipboard typedef BOOL(WINAPI *OpenClipboard_funcType)(HWND); OpenClipboard_funcType real_OpenClipboard=NULL; BOOL WINAPI fake_OpenClipboard(HWND hwndOwner) { return false; } //A thread function that runs while NVDA is injected in a process. //Note that a mutex is used to make sure that there is never more than one copy of this thread in a given process at any given time. //I.e. Another copy of NVDA is started while the first is still running. DWORD WINAPI inprocMgrThreadFunc(LPVOID data) { HANDLE threadMutex=NULL; //Create a label for the mutex with the processID encoded so that it only affects this process. { wostringstream mutexNameStream; mutexNameStream<