implicit_handle(handle_t nvdaControllerInternalBindingHandle)\r
]\r
interface NvdaControllerInternal {\r
- [fault_status,comm_status] getNVDAProcessID();\r
+ [fault_status,comm_status] requestRegistration();\r
[fault_status,comm_status] inputLangChangeNotify();\r
[fault_status,comm_status] typedCharacterNotify();\r
[fault_status,comm_status] displayModelTextChangeNotify();\r
]\r
interface NvdaControllerInternal {\r
\r
-/**\r
- * Gets the process ID of NVDA.\r
- * @param pProcessID memory where the retreaved process ID can be placed.\r
- */\r
- error_status_t __stdcall getNVDAProcessID([out] long* pProcessID); \r
+ error_status_t __stdcall requestRegistration([in,string] const wchar_t* uuidString);\r
\r
/**\r
* Notifies NVDA that the keyboard layout has changed for this thread. \r
http://www.gnu.org/licenses/old-licenses/gpl-2.0.html\r
*/\r
\r
+[strict_context_handle]\r
interface NvdaInProcUtils {\r
+ [fault_status,comm_status] registerNVDAProcess();\r
+ [fault_status,comm_status] unregisterNVDAProcess();\r
[fault_status,comm_status] winword_expandToLine();\r
[fault_status,comm_status] winword_getTextInRange();\r
}\r
]\r
interface NvdaInProcUtils {\r
\r
+ typedef [context_handle] void* nvdaRegistrationHandle_t;\r
+\r
+ error_status_t registerNVDAProcess([in] handle_t bindingHandle, [out] nvdaRegistrationHandle_t* registrationhandle);\r
+ error_status_t unregisterNVDAProcess([in,out] nvdaRegistrationHandle_t* registrationhandle);\r
+\r
error_status_t winword_expandToLine([in] const long windowHandle, [in] const int offset, [out] int* lineStart, [out] int* lineEnd);\r
\r
error_status_t winword_getTextInRange([in] const long windowHandle, [in] const int startOffset, [in] const int endOffset, [in] const long formatConfig, [out] BSTR* text); \r
\r
#include "nvdaControllerInternal.h"\r
\r
-error_status_t __stdcall nvdaControllerInternal_getNVDAProcessID(long* pProcessID) {\r
- *pProcessID=GetCurrentProcessId();\r
- return RPC_S_OK;\r
+error_status_t(__stdcall *_nvdaControllerInternal_requestRegistration)(const wchar_t*);\r
+error_status_t __stdcall nvdaControllerInternal_requestRegistration(const wchar_t* uuidString) {\r
+ return _nvdaControllerInternal_requestRegistration(uuidString);\r
}\r
\r
error_status_t(__stdcall *_nvdaControllerInternal_inputLangChangeNotify)(const long, const unsigned long, const wchar_t*);\r
#include <cstdio>\r
#include <sstream>\r
#include <algorithm>\r
+#include <rpc.h>\r
+#include <sddl.h>\r
#include "nvdaHelperLocal.h"\r
#include "dllImportTableHooks.h"\r
#include "rpcsrv.h"\r
DllImportTableHooks* oleaccHooks = NULL;\r
DllImportTableHooks* uiaCoreHooks = NULL;\r
\r
-handle_t createConnection(int processID) {\r
+typedef struct _RPC_SECURITY_QOS_V5_W {\r
+ unsigned long Version;\r
+ unsigned long Capabilities;\r
+ unsigned long IdentityTracking;\r
+ unsigned long ImpersonationType;\r
+ unsigned long AdditionalSecurityInfoType;\r
+ union \r
+ {\r
+ RPC_HTTP_TRANSPORT_CREDENTIALS_W *HttpCredentials;\r
+ } u;\r
+ void *Sid;\r
+ unsigned int EffectiveOnly;\r
+ void *ServerSecurityDescriptor;\r
+} RPC_SECURITY_QOS_V5_W, *PRPC_SECURITY_QOS_V5_W;\r
+\r
+handle_t createRemoteBindingHandle(wchar_t* uuidString) {\r
RPC_STATUS rpcStatus;\r
- std::wostringstream addr;\r
- addr<<L"ncalrpc:[nvdaHelperRemote_"<<processID<<L"]";\r
+ RPC_WSTR stringBinding;\r
+ if((rpcStatus=RpcStringBindingCompose((RPC_WSTR)uuidString,(RPC_WSTR)L"ncalrpc",NULL,NULL,NULL,&stringBinding))!=RPC_S_OK) {\r
+ fprintf(stderr,"RpcStringBindingCompose failed, rpc code 0X%X\n",rpcStatus);\r
+ return NULL;\r
+ }\r
handle_t bindingHandle;\r
- if((rpcStatus=RpcBindingFromStringBinding((RPC_WSTR)(addr.str().c_str()),&bindingHandle))!=RPC_S_OK) {\r
+ if((rpcStatus=RpcBindingFromStringBinding(stringBinding,&bindingHandle))!=RPC_S_OK) {\r
fprintf(stderr,"Error creating binding handle from string binding, rpc code 0X%X\n",rpcStatus);\r
return NULL;\r
} \r
+ PSECURITY_DESCRIPTOR psd=NULL;\r
+ ULONG size;\r
+ if(!ConvertStringSecurityDescriptorToSecurityDescriptor(L"D:(A;;GA;;;AU)(A;;GA;;;AC)",SDDL_REVISION_1,&psd,&size)) {\r
+ return NULL;\r
+ }\r
+ RPC_SECURITY_QOS_V5_W securityQos={5,0,0,0,0,NULL,NULL,0,psd};\r
+ if(RpcBindingSetAuthInfoEx(bindingHandle,NULL,RPC_C_AUTHN_LEVEL_DEFAULT,RPC_C_AUTHN_DEFAULT,NULL,0,(RPC_SECURITY_QOS*)&securityQos)!=RPC_S_OK) {\r
+ return NULL;\r
+ }\r
return bindingHandle;\r
}\r
\r
-void destroyConnection(handle_t bindingHandle) {\r
- RpcBindingFree(&bindingHandle);\r
-}\r
-\r
bool shouldCancelSendMessage;\r
const UINT CANCELSENDMESSAGE_CHECK_INTERVAL = 400;\r
\r
EXPORTS\r
- createConnection\r
- destroyConnection\r
+ createRemoteBindingHandle\r
cancellableSendMessageTimeout\r
cancelSendMessage\r
_notifySendMessageCancelled\r
nvdaHelperLocal_initialize\r
nvdaHelperLocal_terminate\r
generateBeep\r
+ nvdaInProcUtils_registerNVDAProcess\r
+ nvdaInProcUtils_unregisterNVDAProcess\r
nvdaInProcUtils_winword_expandToLine\r
nvdaInProcUtils_winword_getTextInRange\r
VBuf_createBuffer\r
VBuf_locateControlFieldNodeAtOffset\r
VBuf_locateTextFieldNodeAtOffset\r
VBuf_setSelectionOffsets\r
+ _nvdaControllerInternal_requestRegistration\r
_nvdaControllerInternal_displayModelTextChangeNotify\r
_nvdaControllerInternal_inputLangChangeNotify\r
_nvdaControllerInternal_logMessage\r
#define NVDAHELPERLOCAL_H\r
#include <rpc.h>\r
\r
-handle_t createConnection(int processID);\r
-void destroyConnection(handle_t bindingHandle);\r
+handle_t createRemoteBindingHandle(wchar_t* uuidString);\r
LRESULT cancellableSendMessageTimeout(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam, UINT fuFlags, UINT uTimeout, PDWORD_PTR lpdwResult);\r
void cancelSendMessage();\r
void nvdaHelperLocal_initialize();\r
#include <cstdio>\r
#include <sstream>\r
#include <rpc.h>\r
+#include <sddl.h>\r
#include "nvdaController.h"\r
#include "nvdaControllerInternal.h"\r
#include <common/winIPCUtils.h>\r
\r
using namespace std;\r
\r
+typedef RPC_STATUS(RPC_ENTRY *RpcServerRegisterIf3_functype)(RPC_IF_HANDLE,UUID __RPC_FAR*,RPC_MGR_EPV __RPC_FAR*,unsigned int,unsigned int,unsigned int,RPC_IF_CALLBACK_FN __RPC_FAR*,void __RPC_FAR*);\r
+\r
RPC_IF_HANDLE availableInterfaces[]={\r
nvdaController_NvdaController_v1_0_s_ifspec,\r
nvdaControllerInternal_NvdaControllerInternal_v1_0_s_ifspec\r
\r
RPC_STATUS startServer() {\r
RPC_STATUS status;\r
- //Set the protocol\r
wchar_t desktopSpecificNamespace[64];\r
generateDesktopSpecificNamespace(desktopSpecificNamespace,ARRAYSIZE(desktopSpecificNamespace));\r
- wstringstream endpointStringStream;\r
- endpointStringStream<<L"NvdaCtlr."<<desktopSpecificNamespace;\r
- status=RpcServerUseProtseqEp((RPC_WSTR)L"ncalrpc",RPC_C_PROTSEQ_MAX_REQS_DEFAULT,(RPC_WSTR)(endpointStringStream.str().c_str()),NULL);\r
+ wstring endpointString=L"NvdaCtlr.";\r
+ endpointString+=desktopSpecificNamespace;\r
+ //On Windows 8 the new rpcServerRegisterIf3 must be used along with a security descriptor allowing appContainer access\r
+ HANDLE rpcrt4Handle=GetModuleHandle(L"rpcrt4.dll");\r
+ RpcServerRegisterIf3_functype RpcServerRegisterIf3=(RpcServerRegisterIf3_functype)GetProcAddress((HMODULE)rpcrt4Handle,"RpcServerRegisterIf3");\r
+ PSECURITY_DESCRIPTOR psd=NULL;\r
+ ULONG size;\r
+ if(RpcServerRegisterIf3) {\r
+ if(!ConvertStringSecurityDescriptorToSecurityDescriptor(L"D:(A;;GA;;;AU)(A;;GA;;;AC)",SDDL_REVISION_1,&psd,&size)) {\r
+ return GetLastError();\r
+ }\r
+ if(!psd) return -1;\r
+ }\r
+ status=RpcServerUseProtseqEp((RPC_WSTR)L"ncalrpc",RPC_C_PROTSEQ_MAX_REQS_DEFAULT,(RPC_WSTR)(endpointString.c_str()),psd);\r
//We can ignore the error where the endpoint is already set\r
if(status!=RPC_S_OK&&status!=RPC_S_DUPLICATE_ENDPOINT) {\r
return status;\r
}\r
//Register the interfaces\r
- for(int i=0;i<ARRAYSIZE(availableInterfaces);i++) {\r
- if((status=RpcServerRegisterIf(availableInterfaces[i],NULL,NULL))!=RPC_S_OK) {\r
- return status;\r
+ if(RpcServerRegisterIf3) { //Windows 8\r
+ for(int i=0;i<ARRAYSIZE(availableInterfaces);i++) {\r
+ if((status=RpcServerRegisterIf3(availableInterfaces[i],NULL,NULL,RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH,RPC_C_LISTEN_MAX_CALLS_DEFAULT,0,NULL,psd))!=RPC_S_OK) {\r
+ return status;\r
+ }\r
+ }\r
+ } else { // Pre Windows 8\r
+ for(int i=0;i<ARRAYSIZE(availableInterfaces);i++) {\r
+ if((status=RpcServerRegisterIf(availableInterfaces[i],NULL,NULL))!=RPC_S_OK) {\r
+ return status;\r
+ }\r
}\r
}\r
+ LocalFree(psd);\r
//Start listening\r
if((status=RpcServerListen(1,RPC_C_LISTEN_MAX_CALLS_DEFAULT,TRUE))!=RPC_S_OK) {\r
return status;\r
"textUtils.cpp",\r
],\r
LIBS=[\r
+ "advapi32.lib",\r
"user32",\r
"usp10",\r
"ole32",\r
#include <map>\r
#define WIN32_LEAN_AND_MEAN \r
#include <windows.h>\r
-#include "rpcSrv.h"\r
#include "winword.h"\r
#include "inputLangChange.h"\r
#include "typedCharacter.h"\r
inputLangChange_inProcess_initialize();\r
winword_inProcess_initialize();\r
gdiHooks_inProcess_initialize();\r
- rpcSrv_inProcess_initialize();\r
}\r
\r
void inProcess_terminate() {\r
- rpcSrv_inProcess_terminate();\r
gdiHooks_inProcess_terminate();\r
winword_inProcess_terminate();\r
inputLangChange_inProcess_terminate();\r
#define WIN32_LEAN_AND_MEAN \r
#include <windows.h>\r
#include <shlwapi.h>\r
+#include <sddl.h>\r
#include "log.h"\r
#include "ia2Support.h"\r
#include "apiHook.h"\r
#include "dllmain.h"\r
#include "nvdaHelperRemote.h"\r
#include "inProcess.h"\r
+#include "rpcSrv.h"\r
\r
using namespace std;\r
\r
HINSTANCE tempHandle=NULL;\r
if(!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,(LPCTSTR)dllHandle,&tempHandle)) {\r
LOG_ERROR(L"GetModuleHandleEx failed, GetLastError returned "<<GetLastError());\r
+ ReleaseMutex(threadMutex);\r
return 0;\r
}\r
nhAssert(dllHandle==tempHandle);\r
- //Try to open handles to both the injectionDone event and NVDA's process handle\r
- HANDLE waitHandles[2]={0};\r
- long nvdaProcessID=0;\r
- nvdaControllerInternal_getNVDAProcessID(&nvdaProcessID);\r
- if(nvdaProcessID>0) {\r
- waitHandles[0]=OpenProcess(SYNCHRONIZE,FALSE,nvdaProcessID);\r
- wstringstream s;\r
- s<<L"nvdaHelperRemote_injectionDoneEvent_"<<desktopSpecificNamespace;\r
- waitHandles[1]=OpenEvent(SYNCHRONIZE,FALSE,s.str().c_str());\r
+ //Register for all winEvents in this process.\r
+ inprocWinEventHookID=SetWinEventHook(EVENT_MIN,EVENT_MAX,dllHandle,inproc_winEventCallback,GetCurrentProcessId(),0,WINEVENT_INCONTEXT);\r
+ if(inprocWinEventHookID==0) {\r
+ LOG_ERROR(L"SetWinEventHook failed");\r
}\r
- //As long as we have successfully retreaved handles for NVDA's process and the event, then go on and initialize, wait and terminate.\r
- if(waitHandles[0]&&waitHandles[1]) {\r
- //Register for all winEvents in this process.\r
- inprocWinEventHookID=SetWinEventHook(EVENT_MIN,EVENT_MAX,dllHandle,inproc_winEventCallback,GetCurrentProcessId(),0,WINEVENT_INCONTEXT);\r
- if(inprocWinEventHookID==0) {\r
- LOG_ERROR(L"SetWinEventHook failed");\r
+ //Initialize API hooking\r
+ apiHook_initialize();\r
+//Fore secure mode NVDA process, hook OpenClipboard to disable usage of the clipboard\r
+if(isSecureModeNVDAProcess) real_OpenClipboard=apiHook_hookFunction_safe("USER32.dll",OpenClipboard,fake_OpenClipboard);\r
+ //Initialize in-process subsystems\r
+ inProcess_initialize();\r
+ //Enable all registered API hooks\r
+ apiHook_enableHooks();\r
+ //Initialize our rpc server interfaces and request registration with NVDA\r
+ rpcSrv_initialize();\r
+ //Notify injection_winEventCallback (who started our thread) that we're past initialization\r
+ SetEvent((HANDLE)data);\r
+ //Wait until nvda unregisters\r
+ #ifndef NDEBUG\r
+ Beep(660,75);\r
+ #endif\r
+ // Even though we only registered for in-context winEvents, we may still receive some out-of-context events; e.g. console events.\r
+ // Therefore, we must have a message loop.\r
+ // Otherwise, any out-of-context events will cause major lag which increases over time.\r
+ do {\r
+ // Consume and handle all pending messages.\r
+ MSG msg;\r
+ while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {\r
+ TranslateMessage(&msg);\r
+ DispatchMessage(&msg);\r
}\r
- //Initialize API hooking\r
- apiHook_initialize();\r
- //Fore secure mode NVDA process, hook OpenClipboard to disable usage of the clipboard\r
- if(isSecureModeNVDAProcess) real_OpenClipboard=apiHook_hookFunction_safe("USER32.dll",OpenClipboard,fake_OpenClipboard);\r
- //Initialize in-process subsystems\r
- inProcess_initialize();\r
- //Enable all registered API hooks\r
- apiHook_enableHooks();\r
- //Notify injection_winEventCallback (who started our thread) that we're past initialization\r
- SetEvent((HANDLE)data);\r
- //Wait till either the injection done event is set, or NVDA's process dies\r
- #ifndef NDEBUG\r
- Beep(660,75);\r
- #endif\r
- // Even though we only registered for in-context winEvents, we may still receive some out-of-context events; e.g. console events.\r
- // Therefore, we must have a message loop.\r
- // Otherwise, any out-of-context events will cause major lag which increases over time.\r
- do {\r
- // Consume and handle all pending messages.\r
- MSG msg;\r
- while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {\r
- TranslateMessage(&msg);\r
- DispatchMessage(&msg);\r
- }\r
- } while(MsgWaitForMultipleObjects(2,waitHandles,FALSE,INFINITE,QS_ALLINPUT)==WAIT_OBJECT_0+2);\r
- nhAssert(inprocMgrThreadHandle);\r
- inprocThreadsLock.acquire();\r
- CloseHandle(inprocMgrThreadHandle);\r
- inprocMgrThreadHandle=NULL;\r
- inprocThreadsLock.release();\r
- #ifndef NDEBUG\r
- Beep(1320,75);\r
- #endif\r
- //Unregister and terminate API hooks\r
- apiHook_terminate();\r
- //Terminate all in-process subsystems.\r
- inProcess_terminate();\r
- //Unregister winEvents for this process\r
- if(inprocWinEventHookID) { \r
- UnhookWinEvent(inprocWinEventHookID);\r
- inprocWinEventHookID=0;\r
- }\r
- //Unregister any windows hooks registered so far\r
- killRunningWindowsHooks();\r
- } else {\r
- nhAssert(inprocMgrThreadHandle);\r
- inprocThreadsLock.acquire();\r
- CloseHandle(inprocMgrThreadHandle);\r
- inprocMgrThreadHandle=NULL;\r
- inprocThreadsLock.release();\r
+ } while(MsgWaitForMultipleObjects(1,&nvdaUnregisteredEvent,FALSE,INFINITE,QS_ALLINPUT)==WAIT_OBJECT_0+1);\r
+ nhAssert(inprocMgrThreadHandle);\r
+ inprocThreadsLock.acquire();\r
+ CloseHandle(inprocMgrThreadHandle);\r
+ inprocMgrThreadHandle=NULL;\r
+ inprocThreadsLock.release();\r
+ #ifndef NDEBUG\r
+ Beep(1320,75);\r
+ #endif\r
+ //Terminate our RPC server interfaces\r
+ rpcSrv_terminate();\r
+ //Unregister and terminate API hooks\r
+ apiHook_terminate();\r
+ //Terminate all in-process subsystems.\r
+ inProcess_terminate();\r
+ //Unregister winEvents for this process\r
+ if(inprocWinEventHookID) { \r
+ UnhookWinEvent(inprocWinEventHookID);\r
+ inprocWinEventHookID=0;\r
}\r
- if(waitHandles[0]) CloseHandle(waitHandles[0]);\r
- if(waitHandles[1]) CloseHandle(waitHandles[1]);\r
+ //Unregister any windows hooks registered so far\r
+ killRunningWindowsHooks();\r
//Release and close the thread mutex\r
ReleaseMutex(threadMutex);\r
CloseHandle(threadMutex);\r
HANDLE outprocMgrThreadHandle=NULL;\r
DWORD outprocMgrThreadID=0;\r
BOOL outprocInitialized=FALSE;\r
-HANDLE injectionDoneEvent=NULL;\r
\r
/**\r
* Initializes the out-of-process code for NVDAHelper \r
MessageBox(NULL,L"Error initializing IA2 support",L"nvdaHelperRemote (injection_initialize)",0);\r
return FALSE;\r
}\r
- nhAssert(!injectionDoneEvent);\r
- {\r
- wstringstream s;\r
- s<<L"nvdaHelperRemote_injectionDoneEvent_"<<desktopSpecificNamespace;\r
- injectionDoneEvent=CreateEvent(NULL,TRUE,FALSE,s.str().c_str());\r
- }\r
- nhAssert(injectionDoneEvent);\r
- ResetEvent(injectionDoneEvent);\r
outprocMgrThreadHandle=CreateThread(NULL,0,outprocMgrThreadFunc,NULL,0,&outprocMgrThreadID);\r
outprocInitialized=TRUE;\r
return TRUE;\r
}\r
outprocMgrThreadHandle=NULL;\r
outprocMgrThreadID=0;\r
- nhAssert(injectionDoneEvent);\r
- SetEvent(injectionDoneEvent);\r
- CloseHandle(injectionDoneEvent);\r
- injectionDoneEvent=NULL;\r
outprocInitialized=FALSE;\r
return TRUE;\r
}\r
PathRemoveFileSpec(dllDirectory);\r
generateDesktopSpecificNamespace(desktopSpecificNamespace,ARRAYSIZE(desktopSpecificNamespace));\r
//Initialize some needed RPC binding handles.\r
- wstringstream s;\r
- s<<L"ncalrpc:[NvdaCtlr."<<desktopSpecificNamespace<<L"]";\r
- RpcBindingFromStringBinding((RPC_WSTR)(s.str().c_str()),&nvdaControllerBindingHandle);\r
- RpcBindingFromStringBinding((RPC_WSTR)(s.str().c_str()),&nvdaControllerInternalBindingHandle);\r
+ wstring endpoint=L"NvdaCtlr.";\r
+ endpoint+=desktopSpecificNamespace;\r
+ RPC_WSTR stringBinding;\r
+ RpcStringBindingCompose(NULL,(RPC_WSTR)L"ncalrpc",NULL,(RPC_WSTR)(endpoint.c_str()),NULL,&stringBinding);\r
+ RpcBindingFromStringBinding(stringBinding,&nvdaControllerBindingHandle);\r
+ RpcBindingFromStringBinding(stringBinding,&nvdaControllerInternalBindingHandle);\r
+ RpcStringFree(&stringBinding);\r
} else if(reason==DLL_PROCESS_DETACH) {\r
#ifndef NDEBUG\r
Beep(1760,75);\r
#include <cstdio>\r
#include <sstream>\r
#include <rpc.h>\r
+#include <sddl.h>\r
#include "nvdaControllerInternal.h"\r
#include "log.h"\r
#include "vbufRemote.h"\r
#include "displayModelRemote.h"\r
-#include "nvdaInProcUtils.h"\r
+#include "NvdaInProcUtils.h"\r
+#include "nvdaControllerInternal.h"\r
#include "rpcSrv.h"\r
\r
+typedef RPC_STATUS(RPC_ENTRY *RpcServerRegisterIf3_functype)(RPC_IF_HANDLE,UUID __RPC_FAR*,RPC_MGR_EPV __RPC_FAR*,unsigned int,unsigned int,unsigned int,RPC_IF_CALLBACK_FN __RPC_FAR*,void __RPC_FAR*);\r
+\r
RPC_IF_HANDLE availableInterfaces[]={\r
nvdaInProcUtils_NvdaInProcUtils_v1_0_s_ifspec,\r
displayModelRemote_DisplayModel_v1_0_s_ifspec,\r
free(p);\r
}\r
\r
-void rpcSrv_inProcess_initialize() {\r
+HANDLE nvdaUnregisteredEvent=NULL;\r
+RPC_BINDING_VECTOR* bindingVector;\r
+UUID nvdaInprocUuid;\r
+\r
+RPC_STATUS rpcSrv_initialize() {\r
+ nvdaUnregisteredEvent=CreateEvent(NULL,TRUE,false,NULL);\r
RPC_STATUS status;\r
//Set the protocol\r
- std::wostringstream endPoint;\r
- endPoint<<L"nvdaHelperRemote_"<<GetCurrentProcessId();\r
- status=RpcServerUseProtseqEp((RPC_WSTR)L"ncalrpc",RPC_C_PROTSEQ_MAX_REQS_DEFAULT,(RPC_WSTR)(endPoint.str().c_str()),NULL);\r
+ status=RpcServerUseProtseq((RPC_WSTR)L"ncalrpc",RPC_C_PROTSEQ_MAX_REQS_DEFAULT,NULL);\r
+ //We can ignore the error where the endpoint is already set\r
if(status!=RPC_S_OK&&status!=RPC_S_DUPLICATE_ENDPOINT) {\r
- LOG_ERROR(L"RpcServerUseProtseqEp failed with status "<<status);\r
+ LOG_ERROR(L"Unable to use RPC endPoint. RPC error "<<status); \r
+ return status;\r
+ }\r
+ if((status=RpcServerInqBindings(&bindingVector))!=RPC_S_OK) {\r
+ LOG_ERROR(L"RpcServerInqBindings failed with status "<<status);\r
+ return status;\r
}\r
+ UuidCreate(&nvdaInprocUuid);\r
+ UUID_VECTOR nvdaInprocUuidVector={1,&nvdaInprocUuid};\r
//Register the interfaces\r
for(int i=0;i<ARRAYSIZE(availableInterfaces);++i) {\r
if((status=RpcServerRegisterIfEx(availableInterfaces[i],NULL,NULL,RPC_IF_AUTOLISTEN,RPC_C_LISTEN_MAX_CALLS_DEFAULT,NULL))!=RPC_S_OK) {\r
LOG_ERROR(L"RpcServerRegisterIfEx for interface at index "<<i<<L" failed with status "<<status);\r
+ continue;\r
}\r
+ if((status=RpcEpRegister(availableInterfaces[i],bindingVector,&nvdaInprocUuidVector,(RPC_WSTR)L"NVDAHelperRemote interface"))!=RPC_S_OK) {\r
+ LOG_ERROR(L"RpcEpRegister failed for interface at index "<<i<<L" with status "<<status);\r
+ continue;\r
+ }\r
+ }\r
+ RPC_WSTR uuidString;\r
+ UuidToString(&nvdaInprocUuid,&uuidString);\r
+ RpcBindingSetObject(nvdaControllerInternalBindingHandle,&nvdaInprocUuid);\r
+ if((status=nvdaControllerInternal_requestRegistration((wchar_t*)uuidString))!=RPC_S_OK) {\r
+ LOG_ERROR(L"nvdaControllerInternal_requestRegistration failed with status "<<status);\r
}\r
+ RpcStringFree(&uuidString);\r
+ return status;\r
}\r
\r
-void rpcSrv_inProcess_terminate() {\r
+void rpcSrv_terminate() {\r
RPC_STATUS status;\r
+ CloseHandle(nvdaUnregisteredEvent);\r
+ nvdaUnregisteredEvent=NULL;\r
+ UUID_VECTOR nvdaInprocUuidVector={1,&nvdaInprocUuid};\r
for(int i=0;i<ARRAYSIZE(availableInterfaces);++i) {\r
+ if((status=RpcEpUnregister(availableInterfaces[i],bindingVector,&nvdaInprocUuidVector))!=RPC_S_OK) {\r
+ LOG_ERROR(L"RpcEpUnregister failed for interface at index "<<i<<L" with status "<<status);\r
+ }\r
if((status=RpcServerUnregisterIfEx(availableInterfaces[i],NULL,1))!=RPC_S_OK) {\r
LOG_ERROR(L"RpcServerUnregisterIfEx for interface at index "<<i<<L" failed with status "<<status);\r
}\r
}\r
+ RpcBindingVectorFree(&bindingVector);\r
+}\r
+\r
+error_status_t nvdaInProcUtils_registerNVDAProcess(handle_t bindingHandle, nvdaRegistrationHandle_t* registrationHandle) {\r
+ ResetEvent(nvdaUnregisteredEvent);\r
+ *registrationHandle=&nvdaUnregisteredEvent;\r
+ return RPC_S_OK;\r
+}\r
+\r
+error_status_t nvdaInProcUtils_unregisterNVDAProcess(nvdaRegistrationHandle_t* registrationHandle) {\r
+ SetEvent(nvdaUnregisteredEvent);\r
+ *registrationHandle=NULL;\r
+ return RPC_S_OK;\r
+}\r
+\r
+void __RPC_USER nvdaRegistrationHandle_t_rundown(nvdaRegistrationHandle_t registrationHandle) {\r
+ nvdaInProcUtils_unregisterNVDAProcess(®istrationHandle);\r
}\r
#ifndef RPCSRV_H\r
#define RPCSRV_H\r
\r
-void rpcSrv_inProcess_initialize();\r
-void rpcSrv_inProcess_terminate();\r
+extern HANDLE nvdaUnregisteredEvent;\r
+\r
+RPC_STATUS rpcSrv_initialize();\r
+void rpcSrv_terminate();\r
\r
#endif\r
import os\r
+import sys\r
import _winreg\r
import msvcrt\r
import winKernel\r
\r
from ctypes import *\r
+from ctypes.wintypes import *\r
from comtypes import BSTR\r
import winUser\r
import eventHandler\r
log.debugWarning("Could not find reg value 'Layout Text' for reg key %s"%layoutString)\r
return None\r
\r
+@WINFUNCTYPE(c_long,c_wchar_p)\r
+def nvdaControllerInternal_requestRegistration(uuidString):\r
+ pid=c_long()\r
+ windll.rpcrt4.I_RpcBindingInqLocalClientPID(None,byref(pid))\r
+ pid=pid.value\r
+ if not pid:\r
+ log.error("Could not get process ID for RPC call")\r
+ return -1;\r
+ import appModuleHandler\r
+ mod=appModuleHandler.getAppModuleFromProcessID(pid)\r
+ bindingHandle=c_void_p()\r
+ bindingHandle.value=localLib.createRemoteBindingHandle(uuidString)\r
+ if not bindingHandle: \r
+ log.error("Could not bind to inproc rpc server for pid %d"%pid)\r
+ return -1\r
+ registrationHandle=c_long()\r
+ res=localLib.nvdaInProcUtils_registerNVDAProcess(bindingHandle,byref(registrationHandle))\r
+ if res!=0 or not registrationHandle:\r
+ log.error("Could not register NVDA with inproc rpc server for pid %d, res %d, registrationHandle %s"%(pid,res,registrationHandle))\r
+ windll.rpcrt4.RpcBindingFree(byref(bindingHandle))\r
+ return -1\r
+ mod.helperLocalBindingHandle=bindingHandle\r
+ mod._inprocRegistrationHandle=registrationHandle\r
+ return 0\r
+\r
@WINFUNCTYPE(c_long,c_long,c_long,c_long,c_long,c_long)\r
def nvdaControllerInternal_displayModelTextChangeNotify(hwnd, left, top, right, bottom):\r
import displayModel\r
("nvdaController_speakText",nvdaController_speakText),\r
("nvdaController_cancelSpeech",nvdaController_cancelSpeech),\r
("nvdaController_brailleMessage",nvdaController_brailleMessage),\r
+ ("nvdaControllerInternal_requestRegistration",nvdaControllerInternal_requestRegistration),\r
("nvdaControllerInternal_inputLangChangeNotify",nvdaControllerInternal_inputLangChangeNotify),\r
("nvdaControllerInternal_typedCharacterNotify",nvdaControllerInternal_typedCharacterNotify),\r
("nvdaControllerInternal_displayModelTextChangeNotify",nvdaControllerInternal_displayModelTextChangeNotify),\r
]:\r
try:\r
_setDllFuncPointer(localLib,"_%s"%name,func)\r
- except AttributeError:\r
- log.error("nvdaHelperLocal function pointer for %s could not be found, possibly old nvdaHelperLocal dll"%name)\r
+ except AttributeError as e:\r
+ log.error("nvdaHelperLocal function pointer for %s could not be found, possibly old nvdaHelperLocal dll"%name,exc_info=True)\r
+ raise e\r
localLib.nvdaHelperLocal_initialize()\r
generateBeep=localLib.generateBeep\r
generateBeep.argtypes=[c_char_p,c_float,c_uint,c_ubyte,c_ubyte]\r
#: The ID of the process this appModule is for.\r
#: @type: int\r
self.processID=processID\r
- self.helperLocalBindingHandle=NVDAHelper.localLib.createConnection(processID)\r
if appName is None:\r
appName=getAppNameFromProcessID(processID)\r
#: The application name.\r
#: @type: str\r
self.appName=appName\r
self.processHandle=winKernel.openProcess(winKernel.SYNCHRONIZE,False,processID)\r
+ self.helperLocalBindingHandle=None\r
+ self._inprocRegistrationHandle=None\r
\r
def __repr__(self):\r
return "<%r (appName %r, process ID %s) at address %x>"%(self.appModuleName,self.appName,self.processID,id(self))\r
Subclasses should call the superclass method first.\r
"""\r
winKernel.closeHandle(self.processHandle)\r
- NVDAHelper.localLib.destroyConnection(self.helperLocalBindingHandle)\r
+ if self._inprocRegistrationHandle:\r
+ ctypes.windll.rpcrt4.RpcSsDestroyClientContext(ctypes.byref(self._inprocRegistrationHandle))\r
+ if self.helperLocalBindingHandle:\r
+ ctypes.windll.rpcrt4.RpcBindingFree(ctypes.byref(self.helperLocalBindingHandle))\r
\r
def chooseNVDAObjectOverlayClasses(self, obj, clsList):\r
"""Choose NVDAObject overlay classes for a given NVDAObject.\r
log.info("Using Python version %s"%sys.version)\r
log.info("Using comtypes version %s"%comtypes.__version__)\r
log.debug("Creating wx application instance")\r
+ import appModuleHandler\r
+ log.debug("Initializing appModule Handler")\r
+ appModuleHandler.initialize()\r
import NVDAHelper\r
log.debug("Initializing NVDAHelper")\r
NVDAHelper.initialize()\r
locale.Init(lang,wxLang)\r
except:\r
pass\r
- import appModuleHandler\r
- log.debug("Initializing appModule Handler")\r
- appModuleHandler.initialize()\r
import api\r
import winUser\r
import NVDAObjects.window\r