@@ -107,23 +107,13 @@ def which(self, executable: str, paths: None | list[str] = None) -> None | str:
107107 from DisplayCAL .util_os import dlopen , which
108108elif sys .platform == "win32" :
109109 from DisplayCAL import util_win
110+ from DisplayCAL .mscms import WCSManagerProxy
110111
111112 if sys .getwindowsversion () < (6 ,):
112113 # WCS only available under Vista and later
113114 mscms = None
114115 else :
115- from DisplayCAL .win_handles import (
116- get_handle_name ,
117- get_handle_type ,
118- get_process_handles ,
119- )
120-
121- mscms = util_win ._get_mscms_windll ()
122-
123- win_ver = util_win .win_ver ()
124- win10_1903 = (
125- win_ver [0 ].startswith ("Windows 10" ) and win_ver [2 ] >= "Version 1903"
126- )
116+ mscms = WCSManagerProxy ()
127117
128118
129119if TYPE_CHECKING :
@@ -2363,93 +2353,16 @@ def _wcs_get_display_profile(
23632353 None | str | ICCProfile: The display profile path as a string or
23642354 an ICCProfile object, or None if no profile is found.
23652355 """
2366- buf = ctypes .create_unicode_buffer (256 )
2367- _win10_1903_take_process_handles_snapshot ()
2368- retv = mscms .WcsGetDefaultColorProfile (
2369- scope ,
2370- devicekey ,
2371- profile_type ,
2372- profile_subtype ,
2373- profile_id ,
2374- ctypes .sizeof (buf ), # Bytes
2375- ctypes .byref (buf ),
2356+ prof = mscms .get_default_color_profile (
2357+ scope , devicekey , profile_type , profile_subtype , profile_id
23762358 )
2377- _win10_1903_close_leaked_regkey_handles (devicekey )
2378- if not retv :
2379- raise util_win .get_windows_error (ctypes .windll .kernel32 .GetLastError ())
2380- if buf .value :
2359+ if prof :
23812360 if path_only :
2382- return os .path .join (ICCPROFILES [0 ], buf . value )
2383- return ICCProfile (buf . value , use_cache = use_cache )
2361+ return os .path .join (ICCPROFILES [0 ], prof )
2362+ return ICCProfile (prof , use_cache = use_cache )
23842363 return None
23852364
23862365
2387- def _win10_1903_take_process_handles_snapshot () -> None :
2388- """Take a snapshot of the current process handles under Win10 1903."""
2389- global prev_handles
2390- prev_handles = []
2391- if win10_1903 and DEBUG :
2392- try :
2393- for handle in get_process_handles ():
2394- prev_handles .append (handle .HandleValue )
2395- except OSError as exception :
2396- print ("Couldn't get process handles:" , exception )
2397-
2398-
2399- def _win10_1903_close_leaked_regkey_handles (devicekey : str ) -> None :
2400- """Close leaked registry key handles under Win10 1903.
2401-
2402- Args:
2403- devicekey (str): The device key to match against leaked handles.
2404- """
2405- global prev_handles
2406- if not win10_1903 :
2407- return
2408- # Wcs* methods leak handles under Win10 1903. Get and close them.
2409-
2410- # Extract substring from devicekey for matching handle name, e.g.
2411- # Control\Class\{4d36e96e-e325-11ce-bfc1-08002be10318}
2412- substr = "\\ " .join (devicekey .split ("\\ " )[- 4 :- 1 ])
2413- try :
2414- handles = get_process_handles ()
2415- except OSError as exception :
2416- print ("Couldn't get process handles:" , exception )
2417- return
2418- for handle in handles :
2419- try :
2420- handle_name = get_handle_name (handle )
2421- except OSError as exception :
2422- print (f"Couldn't get name of handle 0x{ handle .HandleValue :x} :" , exception )
2423- handle_name = None
2424- if DEBUG and handle .HandleValue not in prev_handles :
2425- try :
2426- handle_type = get_handle_type (handle )
2427- except OSError as exception :
2428- print (
2429- f"Couldn't get typestring of handle 0x{ handle .HandleValue :x} :" ,
2430- exception ,
2431- )
2432- handle_type = None
2433- print (
2434- "New handle" ,
2435- f"0x{ handle .HandleValue :x} " ,
2436- f"type 0x{ handle .ObjectTypeIndex :02x} { handle_type } " ,
2437- handle_name ,
2438- )
2439- if handle_name and handle_name .endswith (substr ):
2440- print (
2441- "Windows 10" ,
2442- win_ver [2 ].split (" " , 1 )[- 1 ],
2443- f"housekeeping: Closing leaked handle 0x{ handle .HandleValue :x} " ,
2444- handle_name ,
2445- )
2446-
2447- try :
2448- win32api .RegCloseKey (handle .HandleValue )
2449- except pywintypes .error as exception :
2450- print (f"Couldn't close handle 0x{ handle .HandleValue :x} :" , exception )
2451-
2452-
24532366def _winreg_get_display_profile (
24542367 monkey : list ,
24552368 current_user : bool = False ,
@@ -2901,26 +2814,8 @@ def _wcs_set_display_profile(
29012814 Returns:
29022815 bool: True if the profile was set successfully, False otherwise.
29032816 """
2904- # We need to disassociate the profile first in case it's not the default
2905- # so we can make it the default again.
2906- # Note that disassociating the current default profile for a display will
2907- # also set its video card gamma ramps to linear if Windows calibration
2908- # management isn't enabled.
2909- _win10_1903_take_process_handles_snapshot ()
2910- with contextlib .suppress (WindowsError ):
2911- # Disassociate the profile from the device first
2912- mscms .WcsDisassociateColorProfileFromDevice (scope , profile_name , devicekey )
2913- try :
2914- # Associate the profile with the device
2915- retv = mscms .WcsAssociateColorProfileWithDevice (scope , profile_name , devicekey )
2916- except OSError :
2917- retv = None
2918- _win10_1903_close_leaked_regkey_handles (devicekey )
2919- if not retv :
2920- raise util_win .get_windows_error (ctypes .windll .kernel32 .GetLastError ())
2921- monkey = devicekey .split ("\\ " )[- 2 :]
2922- current_user = scope == WCS_PROFILE_MANAGEMENT_SCOPE ["CURRENT_USER" ]
2923- profiles = _winreg_get_display_profiles (monkey , current_user )
2817+ mscms .associate_color_profile_with_device (scope , profile_name , str (devicekey ))
2818+ profiles = mscms .get_device_color_profile_list (scope , str (devicekey ))
29242819 return profile_name in profiles
29252820
29262821
@@ -2949,38 +2844,9 @@ def _wcs_unset_display_profile(
29492844 Returns:
29502845 bool: True if the profile was unset successfully, False otherwise.
29512846 """
2952- # Disassociating a profile will always (regardless of whether or
2953- # not the profile was associated or even exists) result in Windows
2954- # error code 2015 ERROR_PROFILE_NOT_ASSOCIATED_WITH_DEVICE.
2955- # This is probably a Windows bug.
2956- # To have a meaningful return value, we thus check wether the profile that
2957- # should be removed is currently associated, and only fail if it is not,
2958- # or if disassociating it fails for some reason.
2959- monkey = devicekey .split ("\\ " )[- 2 :]
2960- current_user = scope == WCS_PROFILE_MANAGEMENT_SCOPE ["CURRENT_USER" ]
2961- profiles = _winreg_get_display_profiles (monkey , current_user )
2962- _win10_1903_take_process_handles_snapshot ()
2963- try :
2964- # Disassociate the profile from the device
2965- retv = mscms .WcsDisassociateColorProfileFromDevice (
2966- scope , profile_name , devicekey
2967- )
2968- except OSError :
2969- retv = None
2970- _win10_1903_close_leaked_regkey_handles (devicekey )
2971- if not retv :
2972- errcode = ctypes .windll .kernel32 .GetLastError ()
2973- if (
2974- errcode in (ERROR_PROFILE_NOT_ASSOCIATED_WITH_DEVICE , ERROR_SUCCESS )
2975- and profile_name in profiles
2976- ):
2977- # Check if profile is still associated
2978- profiles = _winreg_get_display_profiles (monkey , current_user )
2979- if profile_name not in profiles :
2980- # Successfully disassociated
2981- return True
2982- raise util_win .get_windows_error (errcode )
2983- return True
2847+ mscms .disassociate_color_profile_from_device (scope , profile_name , str (devicekey ))
2848+ profiles = mscms .get_device_color_profile_list (scope , str (devicekey ))
2849+ return profile_name not in profiles
29842850
29852851
29862852def set_display_profile (
0 commit comments