Merge pull request #45763 from twangboy/win_fix_path_rehash

Fix rehash function in win_path.py
This commit is contained in:
Nicole Thomas 2018-02-15 15:05:15 -05:00 committed by GitHub
commit edcb64de76
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 97 additions and 51 deletions

View file

@ -29,8 +29,8 @@ Values/Entries are name/data pairs. There can be many values in a key. The
# When production windows installer is using Python 3, Python 2 code can be removed
# Import _future_ python libs first & before any other code
from __future__ import absolute_import
from __future__ import unicode_literals
from __future__ import absolute_import, unicode_literals
# Import python libs
import sys
import logging
@ -38,7 +38,6 @@ from salt.ext.six.moves import range # pylint: disable=W0622,import-error
# Import third party libs
try:
import win32gui
import win32api
import win32con
import pywintypes
@ -48,6 +47,7 @@ except ImportError:
# Import salt libs
import salt.utils
import salt.utils.win_functions
from salt.exceptions import CommandExecutionError
PY2 = sys.version_info[0] == 2
@ -68,7 +68,7 @@ def __virtual__():
if not HAS_WINDOWS_MODULES:
return (False, 'reg execution module failed to load: '
'One of the following libraries did not load: '
+ 'win32gui, win32con, win32api')
'win32con, win32api, pywintypes')
return __virtualname__
@ -193,11 +193,7 @@ def broadcast_change():
salt '*' reg.broadcast_change
'''
# https://msdn.microsoft.com/en-us/library/windows/desktop/ms644952(v=vs.85).aspx
_, res = win32gui.SendMessageTimeout(
win32con.HWND_BROADCAST, win32con.WM_SETTINGCHANGE, 0, 0,
win32con.SMTO_ABORTIFHUNG, 5000)
return not bool(res)
return salt.utils.win_functions.broadcast_setting_change('Environment')
def list_keys(hive, key=None, use_32bit_registry=False):

View file

@ -16,14 +16,13 @@ from salt.ext.six.moves import map
# Third party libs
try:
from win32con import HWND_BROADCAST, WM_SETTINGCHANGE
from win32api import SendMessage
HAS_WIN32 = True
except ImportError:
HAS_WIN32 = False
# Import salt libs
import salt.utils
import salt.utils.win_functions
# Settings
log = logging.getLogger(__name__)
@ -47,7 +46,15 @@ def _normalize_dir(string):
def rehash():
'''
Send a WM_SETTINGCHANGE Broadcast to Windows to refresh the Environment variables
Send a WM_SETTINGCHANGE Broadcast to Windows to refresh the Environment
variables for new processes.
.. note::
This will only affect new processes that aren't launched by services. To
apply changes to the path to services, the host must be restarted. The
``salt-minion``, if running as a service, will not see changes to the
environment until the system is restarted. See
`MSDN Documentation <https://support.microsoft.com/en-us/help/821761/changes-that-you-make-to-environment-variables-do-not-affect-services>`_
CLI Example:
@ -55,7 +62,7 @@ def rehash():
salt '*' win_path.rehash
'''
return bool(SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 'Environment'))
return salt.utils.win_functions.broadcast_setting_change('Environment')
def get_path():

View file

@ -3,9 +3,10 @@
Various functions to be used by windows during start up and to monkey patch
missing functions in other modules
'''
from __future__ import absolute_import
from __future__ import absolute_import, unicode_literals
import platform
import re
import ctypes
# Import Salt Libs
from salt.exceptions import CommandExecutionError
@ -17,6 +18,7 @@ try:
import win32api
import win32net
import win32security
from win32con import HWND_BROADCAST, WM_SETTINGCHANGE, SMTO_ABORTIFHUNG
HAS_WIN32 = True
except ImportError:
HAS_WIN32 = False
@ -210,3 +212,72 @@ def escape_for_cmd_exe(arg):
return meta_map[char]
return meta_re.sub(escape_meta_chars, arg)
def broadcast_setting_change(message='Environment'):
'''
Send a WM_SETTINGCHANGE Broadcast to all Windows
Args:
message (str):
A string value representing the portion of the system that has been
updated and needs to be refreshed. Default is ``Environment``. These
are some common values:
- "Environment" : to effect a change in the environment variables
- "intl" : to effect a change in locale settings
- "Policy" : to effect a change in Group Policy Settings
- a leaf node in the registry
- the name of a section in the ``Win.ini`` file
See lParam within msdn docs for
`WM_SETTINGCHANGE <https://msdn.microsoft.com/en-us/library/ms725497%28VS.85%29.aspx>`_
for more information on Broadcasting Messages.
See GWL_WNDPROC within msdn docs for
`SetWindowLong <https://msdn.microsoft.com/en-us/library/windows/desktop/ms633591(v=vs.85).aspx>`_
for information on how to retrieve those messages.
.. note::
This will only affect new processes that aren't launched by services. To
apply changes to the path or registry to services, the host must be
restarted. The ``salt-minion``, if running as a service, will not see
changes to the environment until the system is restarted. Services
inherit their environment from ``services.exe`` which does not respond
to messaging events. See
`MSDN Documentation <https://support.microsoft.com/en-us/help/821761/changes-that-you-make-to-environment-variables-do-not-affect-services>`_
for more information.
CLI Example:
... code-block:: python
import salt.utils.win_functions
salt.utils.win_functions.broadcast_setting_change('Environment')
'''
# Listen for messages sent by this would involve working with the
# SetWindowLong function. This can be accessed via win32gui or through
# ctypes. You can find examples on how to do this by searching for
# `Accessing WGL_WNDPROC` on the internet. Here are some examples of how
# this might work:
#
# # using win32gui
# import win32con
# import win32gui
# old_function = win32gui.SetWindowLong(window_handle, win32con.GWL_WNDPROC, new_function)
#
# # using ctypes
# import ctypes
# import win32con
# from ctypes import c_long, c_int
# user32 = ctypes.WinDLL('user32', use_last_error=True)
# WndProcType = ctypes.WINFUNCTYPE(c_int, c_long, c_int, c_int)
# new_function = WndProcType
# old_function = user32.SetWindowLongW(window_handle, win32con.GWL_WNDPROC, new_function)
broadcast_message = ctypes.create_unicode_buffer(message)
user32 = ctypes.WinDLL('user32', use_last_error=True)
result = user32.SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
broadcast_message, SMTO_ABORTIFHUNG,
5000, 0)
return result == 1

View file

@ -20,49 +20,13 @@ from tests.support.mock import (
import salt.modules.win_path as win_path
class MockWin32API(object):
'''
Mock class for win32api
'''
def __init__(self):
pass
@staticmethod
def SendMessage(*args):
'''
Mock method for SendMessage
'''
return [args[0]]
class MockWin32Con(object):
'''
Mock class for win32con
'''
HWND_BROADCAST = 1
WM_SETTINGCHANGE = 1
def __init__(self):
pass
@skipIf(NO_MOCK, NO_MOCK_REASON)
class WinPathTestCase(TestCase, LoaderModuleMockMixin):
'''
Test cases for salt.modules.win_path
'''
def setup_loader_modules(self):
return {win_path: {'win32api': MockWin32API,
'win32con': MockWin32Con,
'SendMessage': MagicMock,
'HWND_BROADCAST': MagicMock,
'WM_SETTINGCHANGE': MagicMock}}
def test_rehash(self):
'''
Test to rehash the Environment variables
'''
self.assertTrue(win_path.rehash())
return {win_path: {}}
def test_get_path(self):
'''

View file

@ -12,6 +12,7 @@ from tests.support.mock import (
# Import Salt Libs
import salt.utils.win_functions as win_functions
import salt.utils
@skipIf(NO_MOCK, NO_MOCK_REASON)
@ -51,3 +52,10 @@ class WinFunctionsTestCase(TestCase):
encoded = win_functions.escape_argument('C:\\Some Path\\With Spaces')
self.assertEqual(encoded, '^"C:\\Some Path\\With Spaces^"')
@skipIf(not salt.utils.is_windows(), 'WinDLL only available on Windows')
def test_broadcast_setting_change(self):
'''
Test to rehash the Environment variables
'''
self.assertTrue(win_functions.broadcast_setting_change())