diff --git a/L10n/en.template b/L10n/en.template
index 8975a04f..5a60690d 100644
--- a/L10n/en.template
+++ b/L10n/en.template
@@ -109,8 +109,8 @@
 /* Empire rank. [stats.py] */
 "Duke" = "Duke";
 
-/* Configuration setting. [prefs.py] */
-"E:D log file location" = "E:D log file location";
+/* Location of the new Journal file in E:D 2.2. [prefs.py] */
+"E:D journal file location" = "E:D journal file location";
 
 /* Empire rank. [stats.py] */
 "Earl" = "Earl";
diff --git a/README.md b/README.md
index c517dbd7..2da16df2 100644
--- a/README.md
+++ b/README.md
@@ -69,7 +69,7 @@ This app can save a variety of data in a variety of formats:
 
 By default these files will be placed in your Documents folder. Since this app will create a lot of files if you use it for a while you may wish to create a separate folder for the files and tell the app to place them there.
 
-Some options work by reading the Elite: Dangerous game's log files. Normally this app will find the log files but if you find some options greyed-out then adjust the “E:D log file location” setting described [below](#doesnt-track-systems-visited).
+Some options work by reading the Elite: Dangerous game's “journal” files. If you're running this app on a different machine from the Elite: Dangerous game then adjust the “E:D journal file location” setting on the Configuration tab to point to the game's journal files.
 
 ### EDDN
 
@@ -126,13 +126,7 @@ Ensure that you visit the in-game Commodity Market at a station where you intend
 This problem is tracked as [Issue #92](https://github.com/Marginal/EDMarketConnector/issues/92).
 
 ### Doesn't track Systems visited
-This app uses Elite: Dangerous' log files to track the systems and stations that you visit. When looking for the log files, this app assumes:
-
-- That you're running this app and Elite: Dangerous on the same machine.
-- That you're running Elite: Dangerous from Steam, if you have both Steam and non-Steam versions installed.
-- That you're running “Horizons” 64bit, if you have both Horizons and Season 1 installed.
-
-If you find that this app isn't automatically tracking the systems that you visit and/or isn't automatically “updating” on docking (if you have that option selected), or if you're running this app on a different machine from the Elite: Dangerous game then adjust the “E:D log file location” setting on the Configuration tab to point to the game's log files using [this info](https://support.frontier.co.uk/kb/faq.php?id=108) as a guide.
+This app uses Elite: Dangerous' “journal” files to track the systems and stations that you visit. If you're running this app on a different machine from the Elite: Dangerous game, or if you find that this app isn't automatically tracking the systems that you visit and/or isn't automatically “updating” on docking (if you have that option selected), then adjust the “E:D journal file location” setting on the Configuration tab to point to the game's journal files.
 
 Running from source
 --------
diff --git a/config.py b/config.py
index c1baebe7..b51ca4f6 100644
--- a/config.py
+++ b/config.py
@@ -1,7 +1,7 @@
 import numbers
 import sys
 from os import getenv, makedirs, mkdir, pardir
-from os.path import expanduser, dirname, isdir, join, normpath
+from os.path import expanduser, dirname, exists, isdir, join, normpath
 from sys import platform
 
 
@@ -19,14 +19,21 @@ if platform=='darwin':
 
 elif platform=='win32':
     import ctypes
+    from ctypes.wintypes import *
+    import uuid
 
-    CSIDL_PERSONAL = 0x0005
-    CSIDL_LOCAL_APPDATA = 0x001C
-    CSIDL_PROFILE = 0x0028
+    FOLDERID_Documents    = uuid.UUID('{FDD39AD0-238F-46AF-ADB4-6C85480369C7}')
+    FOLDERID_LocalAppData = uuid.UUID('{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}')
+    FOLDERID_Profile      = uuid.UUID('{5E6C858F-0E22-4760-9AFE-EA3317B67173}')
+    FOLDERID_SavedGames   = uuid.UUID('{4C5C32FF-BB9D-43b0-B5B4-2D72E54EAAA4}')
+
+    SHGetKnownFolderPath = ctypes.windll.shell32.SHGetKnownFolderPath
+    SHGetKnownFolderPath.argtypes = [ctypes.c_char_p, DWORD, HANDLE, ctypes.POINTER(ctypes.c_wchar_p)]
+
+    CoTaskMemFree = ctypes.windll.ole32.CoTaskMemFree
+    CoTaskMemFree.argtypes = [ctypes.c_void_p]
 
     # _winreg that ships with Python 2 doesn't support unicode, so do this instead
-    from ctypes.wintypes import *
-
     HKEY_CURRENT_USER       = 0x80000001
     KEY_ALL_ACCESS          = 0x000F003F
     REG_CREATED_NEW_KEY     = 0x00000001
@@ -100,6 +107,8 @@ class Config:
             if not isdir(self.plugin_dir):
                 mkdir(self.plugin_dir)
 
+            self.default_journal_dir = join(NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, True)[0], 'Frontier Developments', 'Elite Dangerous', 'Logs')	# FIXME: check this
+
             self.home = expanduser('~')
 
             self.respath = getattr(sys, 'frozen', False) and normpath(join(dirname(sys.executable), pardir, 'Resources')) or dirname(__file__)
@@ -148,19 +157,25 @@ class Config:
 
         def __init__(self):
 
-            buf = ctypes.create_unicode_buffer(MAX_PATH)
-            ctypes.windll.shell32.SHGetSpecialFolderPathW(0, buf, CSIDL_LOCAL_APPDATA, 0)
+            buf = ctypes.c_wchar_p()
+            SHGetKnownFolderPath(ctypes.create_string_buffer(FOLDERID_LocalAppData.bytes_le), 0, 0, ctypes.byref(buf))
             self.app_dir = join(buf.value, appname)
             if not isdir(self.app_dir):
                 mkdir(self.app_dir)
+            CoTaskMemFree(buf)
             
             self.plugin_dir = join(self.app_dir, 'plugins')
             if not isdir(self.plugin_dir):
                 mkdir(self.plugin_dir)
 
             # expanduser in Python 2 on Windows doesn't handle non-ASCII - http://bugs.python.org/issue13207
-            ctypes.windll.shell32.SHGetSpecialFolderPathW(0, buf, CSIDL_PROFILE, 0)
+            SHGetKnownFolderPath(ctypes.create_string_buffer(FOLDERID_Profile.bytes_le), 0, 0, ctypes.byref(buf))
             self.home = buf.value
+            CoTaskMemFree(buf)
+
+            SHGetKnownFolderPath(ctypes.create_string_buffer(FOLDERID_SavedGames.bytes_le), 0, 0, ctypes.byref(buf))
+            self.default_journal_dir = buf.value
+            CoTaskMemFree(buf)
 
             self.respath = dirname(getattr(sys, 'frozen', False) and sys.executable or __file__)
 
@@ -190,8 +205,9 @@ class Config:
 
             if not self.get('outdir') or not isdir(self.get('outdir')):
                 buf = ctypes.create_unicode_buffer(MAX_PATH)
-                ctypes.windll.shell32.SHGetSpecialFolderPathW(0, buf, CSIDL_PERSONAL, 0)
+                SHGetKnownFolderPath(ctypes.create_string_buffer(FOLDERID_Documents.bytes_le), 0, 0, ctypes.byref(buf))
                 self.set('outdir', buf.value)
+                CoTaskMemFree(buf)
 
         def get(self, key):
             typ  = DWORD()
@@ -253,6 +269,8 @@ class Config:
             if not isdir(self.plugin_dir):
                 mkdir(self.plugin_dir)
 
+            self.default_journal_dir = None
+
             self.home = expanduser('~')
 
             self.respath = dirname(__file__)
diff --git a/monitor.py b/monitor.py
index 5645b660..bb62a33f 100644
--- a/monitor.py
+++ b/monitor.py
@@ -65,7 +65,6 @@ class EDLogs(FileSystemEventHandler):
     def __init__(self):
         FileSystemEventHandler.__init__(self)	# futureproofing - not need for current version of watchdog
         self.root = None
-        self.logdir = self._logdir()	# E:D client's default Logs directory, or None if not found
         self.currentdir = None		# The actual logdir that we're monitoring
         self.logfile = None
         self.observer = None
@@ -88,8 +87,8 @@ class EDLogs(FileSystemEventHandler):
 
     def start(self, root):
         self.root = root
-        logdir = config.get('logdir') or self.logdir
-        if not self.is_valid_logdir(logdir):
+        logdir = config.get('journaldir') or config.default_journal_dir
+        if not logdir or not exists(logdir):
             self.stop()
             return False
 
@@ -101,7 +100,7 @@ class EDLogs(FileSystemEventHandler):
         # File system events are unreliable/non-existent over network drives on Linux.
         # We can't easily tell whether a path points to a network drive, so assume
         # any non-standard logdir might be on a network drive and poll instead.
-        polling = bool(config.get('logdir')) and platform != 'win32'
+        polling = bool(config.get('journaldir')) and platform != 'win32'
         if not polling and not self.observer:
             self.observer = Observer()
             self.observer.daemon = True
@@ -239,114 +238,6 @@ class EDLogs(FileSystemEventHandler):
         else:
             return self.parse_entry(self.event_queue.pop(0))
 
-    def is_valid_logdir(self, path):
-        return self._is_valid_logdir(path)
-
-
-    if platform=='darwin':
-
-        def _logdir(self):
-            # https://support.frontier.co.uk/kb/faq.php?id=97
-            paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, True)
-            if len(paths) and self._is_valid_logdir(join(paths[0], 'Frontier Developments', 'Elite Dangerous', 'Logs')):
-                return join(paths[0], 'Frontier Developments', 'Elite Dangerous', 'Logs')
-            else:
-                return None
-
-        def _is_valid_logdir(self, path):
-            # Apple's SMB implementation is too flaky so assume target machine is OSX
-            return path and isdir(path) and isfile(join(path, pardir, 'AppNetCfg.xml'))
-
-
-    elif platform=='win32':
-
-        def _logdir(self):
-
-            # Try locations described in https://support.elitedangerous.com/kb/faq.php?id=108, in reverse order of age
-            candidates = []
-
-            # Steam and Steam libraries
-            key = HKEY()
-            if not RegOpenKeyEx(HKEY_CURRENT_USER, r'Software\Valve\Steam', 0, KEY_READ, ctypes.byref(key)):
-                valtype = DWORD()
-                valsize = DWORD()
-                if not RegQueryValueEx(key, 'SteamPath', 0, ctypes.byref(valtype), None, ctypes.byref(valsize)) and valtype.value == REG_SZ:
-                    buf = ctypes.create_unicode_buffer(valsize.value / 2)
-                    if not RegQueryValueEx(key, 'SteamPath', 0, ctypes.byref(valtype), buf, ctypes.byref(valsize)):
-                        steampath = buf.value.replace('/', '\\')	# For some reason uses POSIX seperators
-                        steamlibs = [steampath]
-                        try:
-                            # Simple-minded Valve VDF parser
-                            with open(join(steampath, 'config', 'config.vdf'), 'rU') as h:
-                                for line in h:
-                                    vals = line.split()
-                                    if vals and vals[0].startswith('"BaseInstallFolder_'):
-                                        steamlibs.append(vals[1].strip('"').replace('\\\\', '\\'))
-                        except:
-                            pass
-                        for lib in steamlibs:
-                            candidates.append(join(lib, 'steamapps', 'common', 'Elite Dangerous', 'Products'))
-                RegCloseKey(key)
-
-            # Next try custom installation under the Launcher
-            if not RegOpenKeyEx(HKEY_LOCAL_MACHINE,
-                                machine().endswith('64') and
-                                r'SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall' or	# Assumes that the launcher is a 32bit process
-                                r'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall',
-                                0, KEY_READ, ctypes.byref(key)):
-                buf = ctypes.create_unicode_buffer(MAX_PATH)
-                i = 0
-                while True:
-                    size = DWORD(MAX_PATH)
-                    if RegEnumKeyEx(key, i, buf, ctypes.byref(size), None, None, None, None):
-                        break
-
-                    subkey = HKEY()
-                    if not RegOpenKeyEx(key, buf, 0, KEY_READ, ctypes.byref(subkey)):
-                        valtype = DWORD()
-                        valsize = DWORD((len('Frontier Developments')+1)*2)
-                        valbuf = ctypes.create_unicode_buffer(valsize.value / 2)
-                        if not RegQueryValueEx(subkey, 'Publisher', 0, ctypes.byref(valtype), valbuf, ctypes.byref(valsize)) and valtype.value == REG_SZ and valbuf.value == 'Frontier Developments':
-                            if not RegQueryValueEx(subkey, 'InstallLocation', 0, ctypes.byref(valtype), None, ctypes.byref(valsize)) and valtype.value == REG_SZ:
-                                valbuf = ctypes.create_unicode_buffer(valsize.value / 2)
-                                if not RegQueryValueEx(subkey, 'InstallLocation', 0, ctypes.byref(valtype), valbuf, ctypes.byref(valsize)):
-                                    candidates.append(join(valbuf.value, 'Products'))
-                        RegCloseKey(subkey)
-                    i += 1
-                RegCloseKey(key)
-
-            # Standard non-Steam locations
-            programs = ctypes.create_unicode_buffer(MAX_PATH)
-            ctypes.windll.shell32.SHGetSpecialFolderPathW(0, programs, CSIDL_PROGRAM_FILESX86, 0)
-            candidates.append(join(programs.value, 'Frontier', 'Products')),
-
-            applocal = ctypes.create_unicode_buffer(MAX_PATH)
-            ctypes.windll.shell32.SHGetSpecialFolderPathW(0, applocal, CSIDL_LOCAL_APPDATA, 0)
-            candidates.append(join(applocal.value, 'Frontier_Developments', 'Products'))
-
-            for game in ['elite-dangerous-64', 'FORC-FDEV-D-1']:	# Look for Horizons in all candidate places first
-                for base in candidates:
-                    if isdir(base):
-                        for d in listdir(base):
-                            if d.startswith(game) and self._is_valid_logdir(join(base, d, 'Logs')):
-                                return join(base, d, 'Logs')
-
-            return None
-
-        def _is_valid_logdir(self, path):
-            # Assume target machine is Windows
-            return path and isdir(path) and isfile(join(path, pardir, 'AppConfig.xml'))
-
-
-    elif platform=='linux2':
-
-        def _logdir(self):
-            return None
-
-        def _is_valid_logdir(self, path):
-            # Assume target machine is Windows
-            return path and isdir(path) and isfile(join(path, pardir, 'AppConfig.xml'))
-
 
 # singleton
 monitor = EDLogs()
diff --git a/prefs.py b/prefs.py
index 7f460efb..5606e610 100644
--- a/prefs.py
+++ b/prefs.py
@@ -1,7 +1,7 @@
 #!/usr/bin/python
 # -*- coding: utf-8 -*-
 
-from os.path import dirname, expanduser, isdir, join, sep
+from os.path import dirname, expanduser, exists, isdir, join, sep
 from sys import platform
 
 import Tkinter as tk
@@ -191,7 +191,7 @@ class PreferencesDialog(tk.Toplevel):
         configframe.columnconfigure(1, weight=1)
 
         self.logdir = nb.Entry(configframe, takefocus=False)
-        logdir = config.get('logdir') or monitor.logdir
+        logdir = config.get('journaldir') or config.default_journal_dir
         if not logdir:
             pass
         elif logdir.startswith(config.home):
@@ -202,14 +202,14 @@ class PreferencesDialog(tk.Toplevel):
 
         if platform != 'darwin':
             # Apple's SMB implementation is way too flaky - no filesystem events and bogus NULLs
-            nb.Label(configframe, text = _('E:D log file location')+':').grid(columnspan=3, padx=PADX, sticky=tk.W)	# Configuration setting
+            nb.Label(configframe, text = _('E:D journal file location')+':').grid(columnspan=3, padx=PADX, sticky=tk.W)	# Location of the new Journal file in E:D 2.2
             self.logdir.grid(row=10, columnspan=2, padx=(PADX,0), sticky=tk.EW)
             self.logbutton = nb.Button(configframe, text=(platform=='darwin' and _('Change...') or	# Folder selection button on OSX
                                                           _('Browse...')),	# Folder selection button on Windows
-                                       command = lambda:self.filebrowse(_('E:D log file location'), self.logdir))
+                                       command = lambda:self.filebrowse(_('E:D journal file location'), self.logdir))
             self.logbutton.grid(row=10, column=2, padx=PADX, sticky=tk.EW)
-            if monitor.logdir:
-                nb.Button(configframe, text=_('Default'), command=self.logdir_reset, state = monitor.logdir and tk.NORMAL or tk.DISABLED).grid(column=2, padx=PADX, pady=(5,0), sticky=tk.EW)	# Appearance theme and language setting
+            if config.default_journal_dir:
+                nb.Button(configframe, text=_('Default'), command=self.logdir_reset, state = config.get('journaldir') and tk.NORMAL or tk.DISABLED).grid(column=2, padx=PADX, pady=(5,0), sticky=tk.EW)	# Appearance theme and language setting
 
         if platform == 'win32':
             ttk.Separator(configframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=PADX, pady=PADY*8, sticky=tk.EW)
@@ -308,7 +308,7 @@ class PreferencesDialog(tk.Toplevel):
 
     def outvarchanged(self):
         logdir = self.logdir.get().startswith('~') and join(config.home, self.logdir.get()[2:]) or self.logdir.get()
-        logvalid = monitor.is_valid_logdir(logdir)
+        logvalid = logdir and exists(logdir)
 
         local = self.out_bpc.get() or self.out_td.get() or self.out_csv.get() or self.out_ship_eds.get() or self.out_ship_coriolis.get()
         self.out_auto_button['state']   = local and logvalid and tk.NORMAL or tk.DISABLED
@@ -366,12 +366,12 @@ class PreferencesDialog(tk.Toplevel):
     def logdir_reset(self):
         self.logdir['state'] = tk.NORMAL	# must be writable to update
         self.logdir.delete(0, tk.END)
-        if not monitor.logdir:
-            pass
-        elif monitor.logdir.startswith(config.home):
-            self.logdir.insert(0, '~' + monitor.logdir[len(config.home):])
+        if not config.default_journal_dir:
+            pass	# Can't reset
+        elif config.default_journal_dir.startswith(config.home):
+            self.logdir.insert(0, '~' + config.default_journal_dir[len(config.home):])
         else:
-            self.logdir.insert(0, monitor.logdir)
+            self.logdir.insert(0, config.default_journal_dir)
         self.logdir['state'] = 'readonly'
         self.outvarchanged()
 
@@ -456,10 +456,10 @@ class PreferencesDialog(tk.Toplevel):
         config.set('edsm_apikey',   self.edsm_apikey.get().strip())
 
         logdir = self.logdir.get().startswith('~') and join(config.home, self.logdir.get()[2:]) or self.logdir.get()
-        if monitor.logdir and logdir.lower() == monitor.logdir.lower():
-            config.set('logdir', '')	# default location
+        if config.default_journal_dir and logdir.lower() == config.default_journal_dir.lower():
+            config.set('journaldir', '')	# default location
         else:
-            config.set('logdir', logdir)
+            config.set('journaldir', logdir)
         if platform in ['darwin','win32']:
             config.set('hotkey_code', self.hotkey_code)
             config.set('hotkey_mods', self.hotkey_mods)