Does anyone have a working code example showing a call to the Windows Color System function WcsGetDefaultColorProfile to get the default color profile for a specific device? It works for me when I pass null for the pDeviceName parameter, but when I try to pass the device name of a monitor, I always get back an error code of ERROR_FILE_NOT_FOUND.
I would prefer a C# example, but I'll take anything I can get. I can't find any sample code for the newer WCS profile management functions anywhere.
I was running into the same problem, and the reason for your frustration is that the MSDN docs are incorrect (or at best misleading) about the pDeviceName parameter to WcsGetDefaultColorProfile.
The MSDN doc (http://msdn.microsoft.com/en-us/library/dd372247(v=vs.85).aspx) indicates pDeviceName refers to the "name of the device", which for display devices one would assume to be a windows display device name, such as "\.\DISPLAY1", as returned in the DeviceName parameter of the DISPLAY_DEVICE struct from EnumDisplayDevices.
In fact, what it is requiring here is the DeviceKey parameter of the monitor, and specifically the DeviceKey obtained when the EDD_GET_DEVICE_INTERFACE_NAME flag is used in EnumDisplayDevices.
So working code looks like this, assuming szDisplayDeviceName is already set to display device name you care about, e.g., "\.\DISPLAY1":
WCHAR szPath[MAX_PATH];
DISPLAY_DEVICE dd;
dd.cb = sizeof(dd);
if (EnumDisplayDevices(szDisplayDeviceName, 0, &dd, EDD_GET_DEVICE_INTERFACE_NAME))
{
if (WcsGetDefaultColorProfile(WCS_PROFILE_MANAGEMENT_SCOPE_CURRENT_USER,
dd.DeviceKey,
CPT_ICC,
CPST_PERCEPTUAL,
1, // dwProfileID -- doesn't seem to matter what value you use here
MAX_PATH * sizeof(WCHAR),
szPath))
{
PROFILE profile;
profile.cbDataSize = (DWORD)(wcslen(szPath) + 1) * sizeof(WCHAR);
profile.dwType = PROFILE_FILENAME;
profile.pProfileData = (PVOID)szPath;
HPROFILE hProfile = OpenColorProfile(&profile,
PROFILE_READ, FILE_SHARE_READ, OPEN_EXISTING);
// now do something with the profile
}
}
Following up on the answer from Matt M above (thanks!): If you want to match what other apps do, then use the first monitor returned by EnumDisplayDevices as above.
But note that this may return an incorrect (inactive/disabled) monitor in a multi-monitor setup where one or more monitors are disabled but still connected. Of course, Microsoft doesn't document this anywhere, and so a lot of apps including big players like Photoshop are broken in that regard :(
In case you want to do the right thing, you have to call EnumDisplayDevices multiple times until you find the active monitor (flags DISPLAY_DEVICE_ACTIVE and DISPLAY_DEVICE_MULTI_DRIVER in case multiple monitors are associated to the display).
The documentation doesn't make it obvious at all, but from the previous answers I pieced together a complete solution (in the interests of clarity there is no error checking here). Also, this will only return a default as specified by the user, if they've never set a default, you will need to use GetStandardColorSpaceProfile
to get the "other" default.
DISPLAY_DEVICE displayDevice = {};
displayDevice.cb = sizeof(DISPLAY_DEVICE);
// First, find the primary adaptor
std::stringw adaptorName;
DWORD deviceIndex = 0;
while (::EnumDisplayDevicesW(nullptr, deviceIndex++, &displayDevice, EDD_GET_DEVICE_INTERFACE_NAME))
{
if (displayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP &&
displayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
{
adaptorName = displayDevice.DeviceName;
break;
}
}
// Second, find the first active (and attached) monitor
std::string deviceName;
deviceIndex = 0;
while (::EnumDisplayDevicesW(adaptorName, deviceIndex++, &displayDevice, EDD_GET_DEVICE_INTERFACE_NAME))
{
if (displayDevice.StateFlags & DISPLAY_DEVICE_ACTIVE &&
displayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED)
{
deviceName = displayDevice.DeviceKey;
break;
}
}
// Third, find out whether to use the global or user profile
BOOL usePerUserProfiles = FALSE;
WcsGetUsePerUserProfiles(deviceName, CLASS_MONITOR, &usePerUserProfiles);
// Finally, get the profile name
const WCS_PROFILE_MANAGEMENT_SCOPE scope = usePerUserProfiles ? WCS_PROFILE_MANAGEMENT_SCOPE_CURRENT_USER : WCS_PROFILE_MANAGEMENT_SCOPE_SYSTEM_WIDE;
DWORD profileNameLength = 0; // In bytes
WcsGetDefaultColorProfileSize(scope, deviceName, CPT_ICC, CPST_RGB_WORKING_SPACE, 0, &profileNameLength);
wchar_t *const profileName = new wchar_t[profileNameLength / sizeof(wchar_t)];
WcsGetDefaultColorProfile(scope, deviceName, CPT_ICC, CPST_RGB_WORKING_SPACE, 0, profileNameLength, profileName);
// Do something with your profile name
delete[] profileName;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With