Repository: nvaccess/nvda

Issue:
The shortcut to Explore User Config directory in the start menu cannot open the user config directory
Suspect that this is the regression introduced by #13082 But it needs further investigation.

### Steps to reproduce:
1. Install the latest nvda_snapshot_alpha-24264, 2a6ba8fd;
2. Click "Explore User Config directory" under the NVDA folder of the start menu;

### Actual behavior:
User documents directory is opened.
### Expected behavior:
NVDA user config directory should be opened
### System configuration
#### NVDA installed/portable/running from source:
installed
#### NVDA version:
Latest Alpha version
#### Windows version:
Windows 10 21H2 (x64) build 19044.1348
#### Name and version of other software in use when reproducing the issue:
None
#### Other information about your system:
None
### Other questions
#### Does the issue still occur after restarting your computer?
Yes
#### Have you tried any other versions of NVDA? If so, please report their behaviors.
NVDA2021.2 is normal
#### If NVDA add-ons are disabled, is your problem still occurring?
Yes
#### Does the issue still occur after you run the COM Registration Fixing Tool in NVDA's tools menu?
Yes


Discussion:
Hi,

Confirmed - broke with alpha.24247. @lukaszgo1, any thoughts?

Thanks.

Resolving patch:
diff --git a/source/NVDAHelper.py b/source/NVDAHelper.py
--- a/source/NVDAHelper.py
+++ b/source/NVDAHelper.py
@@ -28,8 +28,6 @@
 import api
 import globalVars
 from logHandler import log
-import time
-import globalVars
 
 versionedLibPath = os.path.join(globalVars.appDir, 'lib')
 if os.environ.get('PROCESSOR_ARCHITEW6432') == 'ARM64':
@@ -459,6 +457,14 @@ def nvdaControllerInternal_installAddonPackageFromPath(addonPath):
 	wx.CallAfter(addonGui.handleRemoteAddonInstall, addonPath)
 	return 0
 
+
+@WINFUNCTYPE(c_long)
+def nvdaControllerInternal_openConfigDirectory():
+	import systemUtils
+	systemUtils.openUserConfigurationDirectory()
+	return 0
+
+
 class RemoteLoader64(object):
 
 	def __init__(self):
@@ -528,6 +534,7 @@ def initialize():
 		("nvdaControllerInternal_vbufChangeNotify",nvdaControllerInternal_vbufChangeNotify),
 		("nvdaControllerInternal_installAddonPackageFromPath",nvdaControllerInternal_installAddonPackageFromPath),
 		("nvdaControllerInternal_drawFocusRectNotify",nvdaControllerInternal_drawFocusRectNotify),
+		("nvdaControllerInternal_openConfigDirectory", nvdaControllerInternal_openConfigDirectory),
 	]:
 		try:
 			_setDllFuncPointer(localLib,"_%s"%name,func)
diff --git a/source/shellapi.py b/source/shellapi.py
--- a/source/shellapi.py
+++ b/source/shellapi.py
@@ -1,4 +1,3 @@
-#shellapi.py
 #A part of NonVisual Desktop Access (NVDA)
 #Copyright (C) 2006-2009 NVDA Contributors <http://www.nvda-project.org/>
 #This file is covered by the GNU General Public License.
@@ -6,6 +5,8 @@
 
 from ctypes import *
 from ctypes.wintypes import *
+from typing import Optional
+
 
 shell32 = windll.shell32
 
@@ -33,10 +34,21 @@ def __init__(self, **kwargs):
 
 SEE_MASK_NOCLOSEPROCESS = 0x00000040
 
-def ShellExecute(hwnd, operation, file, parameters, directory, showCmd):
+
+def ShellExecute(
+		hwnd: Optional[int],
+		operation: Optional[str],
+		file: str,
+		parameters: Optional[str],
+		directory: Optional[str],
+		showCmd: int
+) -> None:
+	if not file:
+		raise RuntimeError("file cannot be None")
 	if shell32.ShellExecuteW(hwnd, operation, file, parameters, directory, showCmd) <= 32:
 		raise WinError()
 
+
 def ShellExecuteEx(execInfo):
 	if not shell32.ShellExecuteExW(byref(execInfo)):
 		raise WinError()
@@ -68,4 +80,4 @@ class SHFILEOPSTRUCT(Structure):
 shell32.SHChangeNotify.argtypes = [c_long, c_uint, c_void_p, c_void_p]
 shell32.SHChangeNotify.restype = None
 def SHChangeNotify(wEventId, uFlags, dwItem1, dwItem2):
-	shell32.SHChangeNotify(wEventId, uFlags, dwItem1, dwItem2)
\ No newline at end of file
+	shell32.SHChangeNotify(wEventId, uFlags, dwItem1, dwItem2)
diff --git a/source/systemUtils.py b/source/systemUtils.py
--- a/source/systemUtils.py
+++ b/source/systemUtils.py
@@ -1,6 +1,6 @@
 # -*- coding: UTF-8 -*-
 # A part of NonVisual Desktop Access (NVDA)
-# Copyright (C) 2020 NV Access Limited, Łukasz Golonka
+# Copyright (C) 2020-2021 NV Access Limited, Łukasz Golonka
 # This file may be used under the terms of the GNU General Public License, version 2 or later.
 # For more details see: https://www.gnu.org/licenses/gpl-2.0.html
 
@@ -24,15 +24,18 @@ def hasSyswow64Dir() -> bool:
 def openUserConfigurationDirectory():
 	"""Opens directory containing config files for the current user"""
 	import globalVars
-	try:
-		# configPath is guaranteed to be correct for NVDA, however it will not exist for NVDA_slave.
-		path = globalVars.appArgs.configPath
-	except AttributeError:
-		import config
-		path = config.getUserDefaultConfigPath()
-		if not path:
-			raise ValueError("no user default config path")
-		config.initConfigPath(path)
+	shellapi.ShellExecute(0, None, globalVars.appArgs.configPath, None, None, winUser.SW_SHOWNORMAL)
+
+
+def openDefaultConfigurationDirectory():
+	"""Opens the directory which would be used to store configuration by default.
+	Used as a fallback when trying to explore user config from the start menu,
+	and NVDA is not running."""
+	import config
+	path = config.getUserDefaultConfigPath()
+	if not path:
+		raise ValueError("no user default config path")
+	config.initConfigPath(path)
 	shellapi.ShellExecute(0, None, path, None, None, winUser.SW_SHOWNORMAL)
 
 


Test patch: