Repository navigation
Ensure IAccessible2 remains available in Firefox after restarting NVDA on Windows 10 Creaters update, register ISimpleDOM proxy to allow math in Google Chrome without Firefox installed, and Allow the user to get back a virtualBuffer when restarting NVDA with a Firefox document in focus #7535
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
7c0e258
70a88f5
d6ee83a
730fd5f
fe71f7c
2aed84c
2e6ad21
b8a9177
dbb9ab2
b42ffa6
952dfe3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| <?xml version="1.0" encoding="UTF-8" standalone="yes"?> | ||
| <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> | ||
| <assemblyIdentity type="win32" name="%proxyName%" version="1.0.0.0" /> | ||
| <file name="%proxyName%.dll"> | ||
| <comInterfaceProxyStub name="%proxyName%" proxyStubClsid32="%proxyClsid%" iid="%proxyClsid%" /> | ||
| </file> | ||
| </assembly> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,14 +16,13 @@ Import('env') | |
|
|
||
| idlFile=env.Command("ia2.idl","#/miscDeps/include/ia2/ia2.idl",Copy("$TARGET","$SOURCE")) | ||
|
|
||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. extra new line |
||
| tlbFile,headerFile,iidSourceFile,proxySourceFile,dlldataSourceFile=env.TypeLibrary(source=idlFile) | ||
|
|
||
| proxyDll=env.SharedLibrary( | ||
| target='IAccessible2Proxy', | ||
| proxyDll=env.COMProxyDll( | ||
| target='IAccessible2proxy', | ||
| source=[iidSourceFile,proxySourceFile,dlldataSourceFile], | ||
| LIBS=['rpcrt4','oleaut32','ole32'], | ||
| CPPDEFINES=[env['CPPDEFINES'],'WIN32','REGISTER_PROXY_DLL'], | ||
| LINKFLAGS=[env['LINKFLAGS'],'/export:DllGetClassObject,private','/export:DllCanUnloadNow,private'], | ||
| proxyClsid="{62d295fe-2062-4369-a010-4f59b5e32d5e}" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where does this |
||
| ) | ||
|
|
||
| Return(['proxyDll','tlbFile','headerFile','iidSourceFile','proxySourceFile','dlldataSourceFile']) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,167 @@ | ||
| /* | ||
| This file is a part of the NVDA project. | ||
| URL: http://www.nvda-project.org/ | ||
| Copyright 2006-2010 NVDA contributers. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The years listed are wrong. This also doesn't match the format we have on the wiki: https://github.com/nvaccess/nvda/wiki/Copyright-headers |
||
| 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 <cstdio> | ||
| #include <cwchar> | ||
| #include <string> | ||
| #include <locale> | ||
| #include <codecvt> | ||
| #include <vector> | ||
| #define WIN32_LEAN_AND_MEAN | ||
| #define CINTERFACE | ||
| #include <windows.h> | ||
| #include <objbase.h> | ||
| #include <rpcproxy.h> | ||
| #include <common/log.h> | ||
| #include "dllmain.h" | ||
| #include "COMProxyRegistration.h" | ||
|
|
||
| using namespace std; | ||
|
|
||
| typedef void(RPC_ENTRY *LPFNGETPROXYDLLINFO)(ProxyFileInfo***, CLSID**); | ||
|
|
||
| const wchar_t* StringCLSID_StandardMarshaler=L"{00020424-0000-0000-C000-000000000046}"; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. perhaps you could add a comment to this line? Is there a reference for this value? |
||
|
|
||
| COMProxyRegistration_t* registerCOMProxy(wchar_t* dllPath) { | ||
| LOG_DEBUG(L"Registering proxy "<<dllPath); | ||
| int res; | ||
| // Fetch the CLSID for the standard marshaler which will be used to unregister PS CLSIDs later | ||
| CLSID clsid_standardMarshaler; | ||
| if((res=IIDFromString(StringCLSID_StandardMarshaler,&clsid_standardMarshaler))!=S_OK) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would prefer to see these kind of checks split into two lines: |
||
| LOG_ERROR(L"Could not get clsid for standard marshaler"); | ||
| return nullptr; | ||
| } | ||
| // Generate a new unique CLSID to use for class object registration | ||
| CLSID regClsid={0}; | ||
| if((res=CoCreateGuid(®Clsid))!=S_OK) { | ||
| LOG_ERROR(L"Unable to generate registration CLSID"); | ||
| return nullptr; | ||
| } | ||
| // load the proxy dll | ||
| wchar_t absDllPath[MAX_PATH]={0}; | ||
| wsprintf(absDllPath,L"%s\\%s",dllDirectory,dllPath); | ||
| HMODULE dllHandle=LoadLibrary(absDllPath); | ||
| if(dllHandle==NULL) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nullptr |
||
| LOG_ERROR(L"LoadLibrary failed for "<<dllPath); | ||
| return nullptr; | ||
| } | ||
| // look up the GetProxyDllInfo function on the proxy dll | ||
| LPFNGETPROXYDLLINFO Dll_GetProxyDllInfo=(LPFNGETPROXYDLLINFO)GetProcAddress(dllHandle,"GetProxyDllInfo"); | ||
| if(Dll_GetProxyDllInfo==NULL) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nullptr |
||
| LOG_ERROR(L"GetProxyDllInfo function not found in "<<dllPath); | ||
| FreeLibrary(dllHandle); | ||
| return nullptr; | ||
| } | ||
| // Fetch the proxy information from the dll (interface IIDs and the proxy stub CLSID) | ||
| CLSID* pProxyClsid=NULL; | ||
| ProxyFileInfo** pProxyInfo=NULL; | ||
| Dll_GetProxyDllInfo(&pProxyInfo,&pProxyClsid); | ||
| if(!pProxyClsid||!pProxyInfo) { | ||
| LOG_ERROR(L"Could not fetch proxy information from "<<dllPath); | ||
| FreeLibrary(dllHandle); | ||
| return nullptr; | ||
| } | ||
| // Create and activate an activation context using the manifest in the proxy dll | ||
| // to temporarily register the proxy dll's class object | ||
| ACTCTX actCtx={0}; | ||
| actCtx.cbSize=sizeof(actCtx); | ||
| actCtx.dwFlags=ACTCTX_FLAG_HMODULE_VALID|ACTCTX_FLAG_RESOURCE_NAME_VALID; | ||
| actCtx.lpResourceName=MAKEINTRESOURCE(2); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what is 2? |
||
| actCtx.hModule=dllHandle; | ||
| HANDLE hActCtx=CreateActCtx(&actCtx); | ||
| if(hActCtx==NULL) { | ||
| LOG_ERROR(L"Could not create activation context for "<<dllPath); | ||
| FreeLibrary(dllHandle); | ||
| return nullptr; | ||
| } | ||
| ULONG_PTR actCtxCookie; | ||
| if(!ActivateActCtx(hActCtx,&actCtxCookie)) { | ||
| LOG_ERROR(L"Error activating activation context for "<<dllPath); | ||
| ReleaseActCtx(hActCtx); | ||
| FreeLibrary(dllHandle); | ||
| return nullptr; | ||
| } | ||
| // Fetch the class object (which will come from the proxy dll) | ||
| IUnknown* ClassObjPunk=NULL; | ||
| res=CoGetClassObject(*pProxyClsid,CLSCTX_INPROC_SERVER,nullptr,IID_IUnknown,(void**)&ClassObjPunk); | ||
| // From here we no longer need the activation context | ||
| DeactivateActCtx(0,actCtxCookie); | ||
| ReleaseActCtx(hActCtx); | ||
| if(res!=S_OK) { | ||
| LOG_ERROR(L"Error fetching class object for "<<dllPath<<L", code "<<res); | ||
| FreeLibrary(dllHandle); | ||
| return nullptr; | ||
| } | ||
| // Re-register the class object with COM now that the activation context is gone. | ||
| // Keeping the class object available to COM, with COM also handling the life time of the proxy dll now | ||
| DWORD dwCookie; | ||
| res=CoRegisterClassObject(regClsid,ClassObjPunk,CLSCTX_INPROC_SERVER,REGCLS_MULTIPLEUSE,&dwCookie); | ||
| ClassObjPunk->lpVtbl->Release(ClassObjPunk); | ||
| if(res!=S_OK) { | ||
| LOG_ERROR(L"Error registering class object for "<<dllPath<<L", code "<<res); | ||
| FreeLibrary(dllHandle); | ||
| return nullptr; | ||
| } | ||
| COMProxyRegistration_t* reg= new COMProxyRegistration_t(); | ||
| reg->dllPath=dllPath; | ||
| reg->classObjectRegistrationCookie=dwCookie; | ||
| // For all interfaces the proxy dll supports, register its CLSID as their proxy stub CLSID | ||
| ProxyFileInfo** tempInfoPtr=pProxyInfo; | ||
| while(*tempInfoPtr) { | ||
| ProxyFileInfo& fileInfo=**tempInfoPtr; | ||
| for(unsigned short idx=0;idx<fileInfo.TableSize;++idx) { | ||
| IID iid=*(fileInfo.pStubVtblList[idx]->header.piid); | ||
| CLSID clsidBackup={0}; | ||
| wstring_convert<codecvt_utf8_utf16<wchar_t>> converter; | ||
| wstring name=converter.from_bytes(fileInfo.pNamesArray[idx]); | ||
| // Fetch the old CLSID for this interface if one is set, so we can replace it on deregistration. | ||
| // If not set, then we'll use the standard marshaler clsid on deregistration. | ||
| if((res=CoGetPSClsid(iid,&clsidBackup))!=S_OK) { | ||
| clsidBackup=clsid_standardMarshaler; | ||
| } else { | ||
| LOG_DEBUG(L"Backed up existing clsid for interface "<<name); | ||
| } | ||
| if((res=CoRegisterPSClsid(iid,regClsid))!=S_OK) { | ||
| LOG_ERROR(L"Unable to register interface "<<name<<L" with proxy stub "<<dllPath<<L", code "<<res); | ||
| continue; | ||
| } | ||
| reg->psClsidBackups.push_back({name,iid,clsidBackup}); | ||
| LOG_DEBUG(L"Registered interface "<<name); | ||
| } | ||
| ++tempInfoPtr; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there some docs you can point to on ProxyFileInfo? I'm a little nervous about this code. So |
||
| } | ||
| // We can now safely free the proxy dll. COM will keep it loaded or re-load it if needed | ||
| FreeLibrary(dllHandle); | ||
| LOG_DEBUG(L"Done registering proxy "<<dllPath); | ||
| return reg; | ||
| } | ||
|
|
||
| bool unregisterCOMProxy(COMProxyRegistration_t* reg) { | ||
| if(!reg) return false; | ||
| HRESULT res; | ||
| LOG_DEBUG(L"Unregistering proxy "<<(reg->dllPath)); | ||
| for(auto& backup: reg->psClsidBackups) { | ||
| if((res=CoRegisterPSClsid(backup.iid,backup.clsid))!=S_OK) { | ||
| LOG_ERROR(L"Error registering backup PSClsid for interface "<<(backup.name)<<L" from "<<(reg->dllPath)<<L", code "<<res); | ||
| } | ||
| LOG_DEBUG(L"Unregistered interface "<<(backup.name)); | ||
| } | ||
| if((res=CoRevokeClassObject((DWORD)(reg->classObjectRegistrationCookie)))!=S_OK) { | ||
| LOG_ERROR(L"Error unregistering class object from "<<(reg->dllPath)<<L", code "<<res); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For this (and the other error case on line 156) should the function exit early, why is it ok to continue to |
||
| } | ||
| LOG_DEBUG(L"Done unregistering proxy "<<(reg->dllPath)); | ||
| delete reg; | ||
| return true; | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| /* | ||
| This file is a part of the NVDA project. | ||
| URL: http://www.nvda-project.org/ | ||
| Copyright 2006-2010 NVDA contributers. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See copyright headers https://github.com/nvaccess/nvda/wiki/Copyright-headers |
||
| 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 | ||
| */ | ||
|
|
||
| #ifndef NVDAHELPER_COMPROXYREGISTRATION | ||
| #define NVDAHELPER_COMPROXYREGISTRATION | ||
|
|
||
| #include <string> | ||
| #include <locale> | ||
| #include <codecvt> | ||
| #include <vector> | ||
| #define WIN32_LEAN_AND_MEAN | ||
| #include <windows.h> | ||
| #include <objbase.h> | ||
|
|
||
| // Tracks information about a COM interface registered in-process | ||
| typedef struct { | ||
| // The name of the interface (for debugging) | ||
| std::wstring name; | ||
| // The unique identifier of the interface | ||
| IID iid; | ||
| // The CLSID of the original class object that handled creating / proxying of this interface. | ||
| // Used when unregistering, so we can put things back the way they were | ||
| CLSID clsid; | ||
| } PSClsidBackup_t; | ||
|
|
||
| // Represents the registration of a COM proxy dll and its interfaces. | ||
| // this can be used for later unregistration of the COM proxy dll | ||
| typedef struct { | ||
| // The path to the dll (for debugging) | ||
| std::wstring dllPath; | ||
| // The cookie returned by CoRegisterClassObject, for later unregistration via CoRevokeClassObject | ||
| ULONG_PTR classObjectRegistrationCookie; | ||
| // Information for all the interfaces registered for this proxy dll via CoRegisterPSClsid | ||
| std::vector<PSClsidBackup_t> psClsidBackups; | ||
| } COMProxyRegistration_t; | ||
|
|
||
| /* Registers a COM proxy dll and all its interfaces for this process so that they can be marshalled to/from other processes | ||
| @param dllPath the relative path to the proxy dll (relative from this dll) | ||
| @return registration data which can be later passed to UnregisterCOMProxy. | ||
| */ | ||
| COMProxyRegistration_t* registerCOMProxy(wchar_t* dllPath); | ||
|
|
||
| /* Unregisters a COM proxy dll originally registered with registerCOMProxy | ||
| @param reg the registration data returned by registerCOMProxy. | ||
| @return true if successful, false otherwise | ||
| */ | ||
| bool unregisterCOMProxy(COMProxyRegistration_t* reg); | ||
|
|
||
| #endif | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand this code right, I think the last part of this example result should be:
{0xab, 0xcd, 0xab, 0xcd, 0xef, 0x12, 0x34, 0x56}