WcsGetDefaultColorProfile的代码示例

时间:2012-11-23 17:49:03

标签: windows winapi color-profile color-management

是否有人有一个工作代码示例显示对Windows Color System函数的调用 WcsGetDefaultColorProfile 以获取特定设备的默认颜色配置文件?当我为pDeviceName参数传递null时,它适用于我,但是当我尝试传递监视器的设备名称时,我总是返回错误代码ERROR_FILE_NOT_FOUND。

我更喜欢C#示例,但我会接受任何我能得到的东西。我无法在任何地方找到任何新的WCS配置文件管理功能的示例代码。

5 个答案:

答案 0 :(得分:5)

我遇到了同样的问题,令人沮丧的原因是MSDN文档对于WcsGetDefaultColorProfile的pDeviceName参数不正确(或者最好是误导)。

MSDN doc(http://msdn.microsoft.com/en-us/library/dd372247(v=vs.85).aspx)表示pDeviceName是指“设备名称”,对于显示设备,人们会认为它是Windows显示设备名称,例如“\。\ DISPLAY1”,如从EnumDisplayDevices中的DISPLAY_DEVICE结构的DeviceName参数返回。

实际上,这里需要的是监视器的DeviceKey参数,特别是在EnumDisplayDevices中使用EDD_GET_DEVICE_INTERFACE_NAME标志时获得的DeviceKey。

所以工作代码看起来像这样,假设szDisplayDeviceName已设置为显示您关心的设备名称,例如“\。\ 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
    }
}

答案 1 :(得分:1)

跟进上面的Matt M的答案(谢谢!):如果你想匹配其他应用程序所做的事情,那么使用EnumDisplayDevices返回的第一个监视器,如上所述。

但请注意,这可能会在多显示器设置中返回不正确(无效/禁用)显示器,其中一个或多个显示器已禁用但仍连接。当然,微软并没有在任何地方记录这一点,所以很多应用程序,包括像Photoshop这样的大型应用程序都在这方面被打破:(

如果您想要做正确的事情,您必须多次调用EnumDisplayDevices,直到找到活动监视器(如果多个监视器与显示器关联,则标记DISPLAY_DEVICE_ACTIVE和DISPLAY_DEVICE_MULTI_DRIVER)。

答案 2 :(得分:1)

尝试将Mark的代码翻译成C#:

SUBTOTAL(5,OFFSET(A1:D1,ROW(A1:D4)-MIN(ROW(A1:D4)),))

答案 3 :(得分:0)

添加以下结构:

public const uint ProfileRead = 1;

public enum FileShare : uint
{
    Read = 1,
    Write = 2,
    Delete = 4
};

public enum CreateDisposition : uint
{
    CreateNew = 1,
    CreateAlways = 2,
    OpenExisting = 3,
    OpenAlways = 4,
    TruncateExisting = 5

};

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public class ProfileFilename
{
    public uint type;
    [MarshalAs(UnmanagedType.LPTStr)]
    public string profileData;
    public uint dataSize;

    public ProfileFilename(string filename)
    {
        type = ProfileFilenameType;
        profileData = filename;
        dataSize = (uint)filename.Length * 2 + 2;
    }
};

[DllImport("mscms.dll", SetLastError = true, EntryPoint = "GetStandardColorSpaceProfileW", CallingConvention = CallingConvention.Winapi)]
static extern bool GetStandardColorSpaceProfile(    uint machineName,
                                                    LogicalColorSpace profileID,
                                                    [MarshalAs(UnmanagedType.LPTStr), In, Out] StringBuilder profileName,
                                                    ref uint size);

[DllImport("mscms.dll", SetLastError = true, EntryPoint = "OpenColorProfileW", CallingConvention = CallingConvention.Winapi)]
    static extern IntPtr OpenColorProfile(  [MarshalAs(UnmanagedType.LPStruct)] ProfileFilename profile,
                                            uint desiredAccess,
                                            FileShare shareMode,
                                            CreateDisposition creationMode);

打开默认配置文件的示例:

public openDefaultColorProfile()
{ 
    StringBuilder profileName = new StringBuilder(256);
    uint size = (uint)profileName.Capacity * 2;
    success = GetStandardColorSpaceProfile(0, LogicalColorSpace.WindowsColorSpace, profileName, ref size);

    ProfileFilename sRGBFilename = new ProfileFilename(profileName.ToString());
    IntPtr hSRGBProfile = OpenColorProfile(sRGBFilename, ProfileRead, FileShare.Read, CreateDisposition.OpenExisting);
}

答案 4 :(得分:0)

文档根本没有显而易见,但从之前的答案中我拼凑了一个完整的解决方案(为了清楚起见,这里没有错误检查)。此外,这只会返回用户指定的默认值,如果他们从未设置默认值,则需要使用GetStandardColorSpaceProfile来获取“其他”默认值。

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;