Fix missing remote object error when calling remote function created in preload script (#15444)
* fix: report wrong context error based on contextId * fix: destroyed remote renderer warning is now async
This commit is contained in:
parent
b2e1a93177
commit
a8f2646ba6
5 changed files with 54 additions and 21 deletions
|
@ -152,9 +152,10 @@ const throwRPCError = function (message) {
|
|||
throw error
|
||||
}
|
||||
|
||||
const removeRemoteListenersAndLogWarning = (sender, meta, callIntoRenderer) => {
|
||||
const removeRemoteListenersAndLogWarning = (sender, callIntoRenderer) => {
|
||||
const location = v8Util.getHiddenValue(callIntoRenderer, 'location')
|
||||
let message = `Attempting to call a function in a renderer window that has been closed or released.` +
|
||||
`\nFunction provided here: ${meta.location}`
|
||||
`\nFunction provided here: ${location}`
|
||||
|
||||
if (sender instanceof EventEmitter) {
|
||||
const remoteEvents = sender.eventNames().filter((eventName) => {
|
||||
|
@ -214,14 +215,14 @@ const unwrapArgs = function (sender, contextId, args) {
|
|||
return rendererFunctions.get(objectId)
|
||||
}
|
||||
|
||||
const processId = sender.getProcessId()
|
||||
const callIntoRenderer = function (...args) {
|
||||
if (!sender.isDestroyed() && processId === sender.getProcessId()) {
|
||||
if (!sender.isDestroyed()) {
|
||||
sender._sendInternal('ELECTRON_RENDERER_CALLBACK', contextId, meta.id, valueToMeta(sender, contextId, args))
|
||||
} else {
|
||||
removeRemoteListenersAndLogWarning(this, meta, callIntoRenderer)
|
||||
removeRemoteListenersAndLogWarning(this, callIntoRenderer)
|
||||
}
|
||||
}
|
||||
v8Util.setHiddenValue(callIntoRenderer, 'location', meta.location)
|
||||
Object.defineProperty(callIntoRenderer, 'length', { value: meta.length })
|
||||
|
||||
v8Util.setRemoteCallbackFreer(callIntoRenderer, contextId, meta.id, sender)
|
||||
|
@ -281,6 +282,15 @@ const handleRemoteCommand = function (channel, handler) {
|
|||
})
|
||||
}
|
||||
|
||||
handleRemoteCommand('ELECTRON_BROWSER_WRONG_CONTEXT_ERROR', function (event, contextId, passedContextId, id) {
|
||||
const objectId = [passedContextId, id]
|
||||
if (!rendererFunctions.has(objectId)) {
|
||||
// Do nothing if the error has already been reported before.
|
||||
return
|
||||
}
|
||||
removeRemoteListenersAndLogWarning(event.sender, rendererFunctions.get(objectId))
|
||||
})
|
||||
|
||||
handleRemoteCommand('ELECTRON_BROWSER_REQUIRE', function (event, contextId, moduleName) {
|
||||
const customEvent = eventBinding.createWithSender(event.sender)
|
||||
event.sender.emit('remote-require', customEvent, moduleName)
|
||||
|
|
|
@ -270,9 +270,12 @@ function metaToPlainObject (meta) {
|
|||
}
|
||||
|
||||
function handleMessage (channel, handler) {
|
||||
ipcRenderer.on(channel, (event, passedContextId, ...args) => {
|
||||
ipcRenderer.on(channel, (event, passedContextId, id, ...args) => {
|
||||
if (passedContextId === contextId) {
|
||||
handler(...args)
|
||||
handler(id, ...args)
|
||||
} else {
|
||||
// Message sent to an un-exist context, notify the error to main process.
|
||||
ipcRenderer.send('ELECTRON_BROWSER_WRONG_CONTEXT_ERROR', contextId, passedContextId, id)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ const { closeWindow } = require('./window-helpers')
|
|||
const { resolveGetters } = require('./assert-helpers')
|
||||
|
||||
const { remote, ipcRenderer } = require('electron')
|
||||
const { ipcMain, BrowserWindow } = remote
|
||||
const { expect } = chai
|
||||
|
||||
chai.use(dirtyChai)
|
||||
|
@ -512,4 +513,23 @@ describe('remote module', () => {
|
|||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('remote function in renderer', () => {
|
||||
afterEach(() => {
|
||||
ipcMain.removeAllListeners('done')
|
||||
})
|
||||
|
||||
it('works when created in preload script', (done) => {
|
||||
ipcMain.once('done', () => w.close())
|
||||
const preload = path.join(fixtures, 'module', 'preload-remote-function.js')
|
||||
w = new BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
preload: preload
|
||||
}
|
||||
})
|
||||
w.once('closed', () => done())
|
||||
w.loadURL('about:blank')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
5
spec/fixtures/module/preload-remote-function.js
vendored
Normal file
5
spec/fixtures/module/preload-remote-function.js
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
const { remote, ipcRenderer } = require('electron')
|
||||
remote.getCurrentWindow().rendererFunc = () => {
|
||||
ipcRenderer.send('done')
|
||||
}
|
||||
remote.getCurrentWindow().rendererFunc()
|
|
@ -350,26 +350,21 @@ ipcMain.on('disable-preload-on-next-will-attach-webview', (event, id) => {
|
|||
|
||||
ipcMain.on('try-emit-web-contents-event', (event, id, eventName) => {
|
||||
const consoleWarn = console.warn
|
||||
let warningMessage = null
|
||||
const contents = webContents.fromId(id)
|
||||
const listenerCountBefore = contents.listenerCount(eventName)
|
||||
|
||||
try {
|
||||
console.warn = (message) => {
|
||||
warningMessage = message
|
||||
}
|
||||
contents.emit(eventName, { sender: contents })
|
||||
} finally {
|
||||
console.warn = (warningMessage) => {
|
||||
console.warn = consoleWarn
|
||||
}
|
||||
|
||||
const listenerCountAfter = contents.listenerCount(eventName)
|
||||
|
||||
event.returnValue = {
|
||||
warningMessage,
|
||||
listenerCountBefore,
|
||||
listenerCountAfter
|
||||
}
|
||||
}
|
||||
|
||||
contents.emit(eventName, { sender: contents })
|
||||
})
|
||||
|
||||
ipcMain.on('handle-uncaught-exception', (event, message) => {
|
||||
|
|
Loading…
Reference in a new issue