# HG changeset patch # User Steve Dower # Date 1441640372 25200 # Mon Sep 07 08:39:32 2015 -0700 # Node ID 3bba545f4893413124c68b163e28f9699d2ad082 # Parent 738e227d089185c7de853b969d60469a8ca04610 Issue #8232: webbrowser.open incomplete on Windows. Patch by Brandon Milam and Steve Dower diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py --- a/Lib/webbrowser.py +++ b/Lib/webbrowser.py @@ -495,10 +495,30 @@ # if sys.platform[:3] == "win": + class WindowsDefault(BaseBrowser): + # Windows Default opening arguments. + + cmd = "" + newwindow = "" + newtab = "" + def open(self, url, new=0, autoraise=True): + # Format the command for optional arguments and add the url. + if self.cmd: + cmd = self.cmd + if new == 1: + args = self.newwindow + " " + url + elif new == 2: + args = self.newtab + " " + url + else: + args = url + else: + cmd = url + args = None + try: - os.startfile(url) + os.startfile(cmd, "open", args) except OSError: # [Error 22] No application is associated with the specified # file for this operation: '' @@ -506,19 +526,108 @@ else: return True + + # Windows Sub-Classes for commonly used browsers. + + class InternetExplorer(WindowsDefault): + """Launcher class for Internet Explorer browser""" + + cmd = "iexplore.exe" + newwindow = "" + newtab = "" + + + class WinChrome(WindowsDefault): + """Launcher class for windows specific Google Chrome browser""" + + cmd = "chrome.exe" + newwindow = "-new-window" + newtab = "-new-tab" + + + class WinFirefox(WindowsDefault): + """Launcher class for windows specific Firefox browser""" + + cmd = "firefox.exe" + newwindow = "-new-window" + newtab = "-new-tab" + + + class WinOpera(WindowsDefault): + """Launcher class for windows specific Opera browser""" + + cmd = "opera" + newwindow = "" + newtab = "" + + + class WinSeaMonkey(WindowsDefault): + """Launcher class for windows specific SeaMonkey browser""" + + cmd = "seamonkey" + newwinow = "" + newtab = "" + + _tryorder = [] _browsers = {} - # First try to use the default Windows browser + # First try to use the default Windows browser. register("windows-default", WindowsDefault) - # Detect some common Windows browsers, fallback to IE - iexplore = os.path.join(os.environ.get("PROGRAMFILES", "C:\\Program Files"), - "Internet Explorer\\IEXPLORE.EXE") - for browser in ("firefox", "firebird", "seamonkey", "mozilla", - "netscape", "opera", iexplore): - if shutil.which(browser): - register(browser, None, BackgroundBrowser(browser)) + def find_windows_browsers(): + """ Access the windows registry to determine + what browsers are on the system. + """ + + import winreg + HKLM = winreg.HKEY_LOCAL_MACHINE + subkey = r'Software\Clients\StartMenuInternet' + read32 = winreg.KEY_READ | winreg.KEY_WOW64_32KEY + read64 = winreg.KEY_READ | winreg.KEY_WOW64_64KEY + key32 = winreg.OpenKey(HKLM, subkey, access=read32) + key64 = winreg.OpenKey(HKLM, subkey, access=read64) + + # Return a list of browsers found in the registry + # Check if there are any different browsers in the + # 32 bit location instead of the 64 bit location. + browsers = [] + i = 0 + while True: + try: + browsers.append(winreg.EnumKey(key32, i)) + except EnvironmentError: + break + i += 1 + + i = 0 + while True: + try: + browsers.append(winreg.EnumKey(key64, i)) + except EnvironmentError: + break + i += 1 + + winreg.CloseKey(key32) + winreg.CloseKey(key64) + + return browsers + + # Detect some common windows browsers + for browser in find_windows_browsers(): + browser = browser.lower() + if "iexplore" in browser: + register("iexplore", None, InternetExplorer("iexplore")) + elif "chrome" in browser: + register("chrome", None, WinChrome("chrome")) + elif "firefox" in browser: + register("firefox", None, WinFirefox("firefox")) + elif "opera" in browser: + register("opera", None, WinOpera("opera")) + elif "seamonkey" in browser: + register("seamonkey", None, WinSeaMonkey("seamonkey")) + else: + register(browser, None, WindowsDefault(browser)) # # Platform support for MacOS diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -17,6 +17,9 @@ Library ------- +- Issue #8232: webbrowser.open incomplete on Windows. Patch by Brandon Milam + and Steve Dower + - Issue #22241: timezone.utc name is now plain 'UTC', not 'UTC-00:00'. - Issue #23517: fromtimestamp() and utcfromtimestamp() methods of diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -10526,7 +10526,7 @@ #ifdef MS_WINDOWS /* AC 3.5: change to path_t? but that might change exceptions */ PyDoc_STRVAR(win32_startfile__doc__, -"startfile(filepath [, operation])\n\ +"startfile(filepath [, operation [, arguments]])\n\ \n\ Start a file with its associated application.\n\ \n\ @@ -10582,10 +10582,11 @@ PyObject *ofilepath; char *filepath; char *operation = NULL; - wchar_t *wpath, *woperation; + char *arguments = NULL; + wchar_t *wpath, *woperation, *warguments; HINSTANCE rc; - PyObject *unipath, *uoperation = NULL; + PyObject *unipath, *uoperation = NULL, *uarguments = NULL; if(!check_ShellExecute()) { /* If the OS doesn't have ShellExecute, return a @@ -10594,8 +10595,8 @@ "startfile not available on this platform"); } - if (!PyArg_ParseTuple(args, "U|s:startfile", - &unipath, &operation)) { + if (!PyArg_ParseTuple(args, "U|sz:startfile", + &unipath, &operation, &arguments)) { PyErr_Clear(); goto normal; } @@ -10610,6 +10611,16 @@ } } + if (arguments) { + uarguments = PyUnicode_DecodeASCII(arguments, + strlen(arguments), NULL); + if (!uarguments) { + PyErr_Clear(); + arguments = NULL; + goto normal; + } + } + wpath = PyUnicode_AsUnicode(unipath); if (wpath == NULL) goto normal; @@ -10620,13 +10631,21 @@ } else woperation = NULL; + if (uarguments) { + warguments = PyUnicode_AsUnicode(uarguments); + if (warguments == NULL) + goto normal; + } + else + warguments = NULL; Py_BEGIN_ALLOW_THREADS rc = Py_ShellExecuteW((HWND)0, woperation, wpath, - NULL, NULL, SW_SHOWNORMAL); + warguments, NULL, SW_SHOWNORMAL); Py_END_ALLOW_THREADS Py_XDECREF(uoperation); + Py_XDECREF(uarguments); if (rc <= (HINSTANCE)32) { win32_error_object("startfile", unipath); return NULL;