Skip to content

Commit 5fa29fc

Browse files
authored
Merge pull request electron#11329 from electron/remove-classes-key
fix: Properly cleanup in `removeAsDefaultProtocolClient`
2 parents 69c6a68 + bd4c7a1 commit 5fa29fc

File tree

3 files changed

+107
-6
lines changed

3 files changed

+107
-6
lines changed

atom/browser/browser_win.cc

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -153,15 +153,19 @@ bool Browser::RemoveAsDefaultProtocolClient(const std::string& protocol,
153153

154154
// Main Registry Key
155155
HKEY root = HKEY_CURRENT_USER;
156-
base::string16 keyPath = base::UTF8ToUTF16("Software\\Classes\\" + protocol);
156+
base::string16 keyPath = L"Software\\Classes\\";
157157

158158
// Command Key
159-
base::string16 cmdPath = keyPath + L"\\shell\\open\\command";
159+
base::string16 wprotocol = base::UTF8ToUTF16(protocol);
160+
base::string16 shellPath = wprotocol + L"\\shell";
161+
base::string16 cmdPath = keyPath + shellPath + L"\\open\\command";
160162

161-
base::win::RegKey key;
163+
base::win::RegKey classesKey;
162164
base::win::RegKey commandKey;
163-
if (FAILED(key.Open(root, keyPath.c_str(), KEY_ALL_ACCESS)))
164-
// Key doesn't even exist, we can confirm that it is not set
165+
166+
if (FAILED(classesKey.Open(root, keyPath.c_str(), KEY_ALL_ACCESS)))
167+
// Classes key doesn't exist, that's concerning, but I guess
168+
// we're not the default handler
165169
return true;
166170

167171
if (FAILED(commandKey.Open(root, cmdPath.c_str(), KEY_ALL_ACCESS)))
@@ -179,9 +183,25 @@ bool Browser::RemoveAsDefaultProtocolClient(const std::string& protocol,
179183

180184
if (keyVal == exe) {
181185
// Let's kill the key
182-
if (FAILED(key.DeleteKey(L"shell")))
186+
if (FAILED(classesKey.DeleteKey(shellPath.c_str())))
183187
return false;
184188

189+
// Let's clean up after ourselves
190+
base::win::RegKey protocolKey;
191+
base::string16 protocolPath = keyPath + wprotocol;
192+
193+
if (SUCCEEDED(protocolKey
194+
.Open(root, protocolPath.c_str(), KEY_ALL_ACCESS))) {
195+
protocolKey.DeleteValue(L"URL Protocol");
196+
197+
// Overwrite the default value to be empty, we can't delete it right away
198+
protocolKey.WriteValue(L"", L"");
199+
protocolKey.DeleteValue(L"");
200+
}
201+
202+
// If now empty, delete the whole key
203+
classesKey.DeleteEmptyKey(wprotocol.c_str());
204+
185205
return true;
186206
} else {
187207
return true;

spec/api-app-spec.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,9 +504,34 @@ describe('app module', () => {
504504
'--process-start-args', `"--hidden"`
505505
]
506506

507+
let Winreg
508+
let classesKey
509+
507510
before(function () {
508511
if (process.platform !== 'win32') {
509512
this.skip()
513+
} else {
514+
Winreg = require('winreg')
515+
516+
classesKey = new Winreg({
517+
hive: Winreg.HKCU,
518+
key: '\\Software\\Classes\\'
519+
})
520+
}
521+
})
522+
523+
after(function (done) {
524+
if (process.platform !== 'win32') {
525+
done()
526+
} else {
527+
const protocolKey = new Winreg({
528+
hive: Winreg.HKCU,
529+
key: `\\Software\\Classes\\${protocol}`
530+
})
531+
532+
// The last test leaves the registry dirty,
533+
// delete the protocol key for those of us who test at home
534+
protocolKey.destroy(() => done())
510535
}
511536
})
512537

@@ -534,6 +559,61 @@ describe('app module', () => {
534559
assert.equal(app.isDefaultProtocolClient(protocol, updateExe, processStartArgs), true)
535560
assert.equal(app.isDefaultProtocolClient(protocol), false)
536561
})
562+
563+
it('creates a registry entry for the protocol class', (done) => {
564+
app.setAsDefaultProtocolClient(protocol)
565+
566+
classesKey.keys((error, keys) => {
567+
if (error) {
568+
throw error
569+
}
570+
571+
const exists = !!keys.find((key) => key.key.includes(protocol))
572+
assert.equal(exists, true)
573+
574+
done()
575+
})
576+
})
577+
578+
it('completely removes a registry entry for the protocol class', (done) => {
579+
app.setAsDefaultProtocolClient(protocol)
580+
app.removeAsDefaultProtocolClient(protocol)
581+
582+
classesKey.keys((error, keys) => {
583+
if (error) {
584+
throw error
585+
}
586+
587+
const exists = !!keys.find((key) => key.key.includes(protocol))
588+
assert.equal(exists, false)
589+
590+
done()
591+
})
592+
})
593+
594+
it('only unsets a class registry key if it contains other data', (done) => {
595+
app.setAsDefaultProtocolClient(protocol)
596+
597+
const protocolKey = new Winreg({
598+
hive: Winreg.HKCU,
599+
key: `\\Software\\Classes\\${protocol}`
600+
})
601+
602+
protocolKey.set('test-value', 'REG_BINARY', '123', () => {
603+
app.removeAsDefaultProtocolClient(protocol)
604+
605+
classesKey.keys((error, keys) => {
606+
if (error) {
607+
throw error
608+
}
609+
610+
const exists = !!keys.find((key) => key.key.includes(protocol))
611+
assert.equal(exists, true)
612+
613+
done()
614+
})
615+
})
616+
})
537617
})
538618

539619
describe('getFileIcon() API', () => {

spec/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"send": "^0.14.1",
1919
"temp": "^0.8.3",
2020
"walkdir": "0.0.11",
21+
"winreg": "^1.2.4",
2122
"ws": "^1.1.1",
2223
"yargs": "^6.0.0"
2324
},

0 commit comments

Comments
 (0)