I try to create a program that will programatically set Windows Color Management to archive an effect like f.lux as a hobby project.
**The definition of WINAPI WcsGetDefaultColorProfileSize
. **
BOOL WINAPI WcsGetDefaultColorProfileSize(
_In_ WCS_PROFILE_MANAGEMENT_SCOPE profileManagementScope,
_In_opt_ PCWSTR pDeviceName,
_In_ COLORPROFILETYPE cptColorProfileType,
_In_ COLORPROFILESUBTYPE cpstColorProfileSubType,
_In_ DWORD dwProfileID,
_Out_ PDWORD pcbProfileName
);
**This is the signature of managed WcsGetDefaultColorProfileSize
. **
[DllImport("Mscms.dll", EntryPoint = "WcsGetDefaultColorProfileSize", CharSet = CharSet.Unicode)]
private static extern bool GetDefaultColorProfileSize(
WCS_PROFILE_MANAGEMENT_SCOPE profileManagementScope,
[MarshalAs(UnmanagedType.LPWStr), In] string pDeviceName,
COLORPROFILETYPE cptColorProfileType,
COLORPROFILESUBTYPE cpstColorProfileSubType,
Int32 dwProfileID,
out IntPtr pcbProfileSize
);
The problem is when I try to get the string which is return as a pointer from WINAPI using Marshal class. Like this
// Need to get the size of ICC profile file first
GetDefaultColorProfileSize(
WCS_PROFILE_MANAGEMENT_SCOPE.WCS_PROFILE_MANAGEMENT_SCOPE_CURRENT_USER,
monitor_name.DeviceKey,
COLORPROFILETYPE.CPT_ICC,
COLORPROFILESUBTYPE.CPST_RGB_WORKING_SPACE,
1,
out SizePointer);
System.Diagnostics.Debug.WriteLine("Size is " + Marshal.ReadInt32(SizePointer));
the GetDefaultColorProfileSize
return TRUE
but when I try to access the address it return (It return this address 0x0000003e) using Marshal.ReadInt32
It throw this error
System.AccessViolationException Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
How can I able to read the memory at that pointer?
I try to allocate the memory first as suggesting by nvoigt
Changing from IntPtr SizePointer
to IntPtr SizePointer = Marshal.AllocHGlobal(4);
But it still throw the same exception
[DllImport("User32.dll")]
private static extern bool EnumDisplayDevices(
string lpDevice, int iDevNum,
ref DISPLAY_DEVICE lpDisplayDevice, int dwFlags);
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAY_DEVICE
{
public int cb;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string DeviceName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceString;
public int StateFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceID;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceKey;
public DISPLAY_DEVICE(int flags) {
cb = 0;
StateFlags = flags;
DeviceName = new string((char)32, 32);
DeviceString = new string((char)32, 128);
DeviceID = new string((char)32, 128);
DeviceKey = new string((char)32, 128);
cb = Marshal.SizeOf(this);
}
}
enum WCS_PROFILE_MANAGEMENT_SCOPE
{
WCS_PROFILE_MANAGEMENT_SCOPE_SYSTEM_WIDE = 0,
WCS_PROFILE_MANAGEMENT_SCOPE_CURRENT_USER
}
enum COLORPROFILETYPE
{
CPT_ICC = 0x0001,
CPT_DMP,
CPT_CAMP,
CPT_GMMP
}
enum COLORPROFILESUBTYPE
{
CPST_NONE = 0x0000,
CPST_RGB_WORKING_SPACE = 0x0001,
CPST_PERCEPTUAL = 0x0002,
CPST_ABSOLUTE_COLORIMETRIC = 0x0004,
CPST_RELATIVE_COLORIMETRIC = 0x0008,
CPST_SATURATION = 0x0010,
CPST_CUSTOM_WORKING_SPACE = 0x0020
}
[DllImport("Mscms.dll", EntryPoint = "WcsGetDefaultColorProfileSize", CharSet = CharSet.Unicode)]
private static extern bool GetDefaultColorProfileSize(
WCS_PROFILE_MANAGEMENT_SCOPE profileManagementScope,
[MarshalAs(UnmanagedType.LPWStr), In] string pDeviceName,
COLORPROFILETYPE cptColorProfileType,
COLORPROFILESUBTYPE cpstColorProfileSubType,
Int32 dwProfileID,
out IntPtr pcbProfileSize
);
[DllImport("Mscms.dll", EntryPoint = "WcsGetDefaultColorProfile" , CharSet =CharSet.Unicode, SetLastError =true)]
private unsafe static extern bool GetDefaultColorProfile(WCS_PROFILE_MANAGEMENT_SCOPE profileManagementScope,
[MarshalAs(UnmanagedType.LPWStr), In] string pDeviceName,
COLORPROFILETYPE cptColorProfileType,
COLORPROFILESUBTYPE cpstColorProfileSubType,
Int32 dwProfileID,
Int32 cbProfileName,
out IntPtr pProfileName);
[DllImport("Mscms.dll", EntryPoint = "WcsSetUsePerUserProfiles", CharSet = CharSet.Unicode)]
private static extern bool SetUsePerUserProfiles([MarshalAs(UnmanagedType.LPWStr), In]string pDeviceName, Int32 dwDeviceClass, bool usePerUserProfiles);
[DllImport("Mscms.dll", EntryPoint = "WcsGetUsePerUserProfiles", CharSet = CharSet.Unicode)]
private static extern bool GetUsePerUserProfiles([MarshalAs(UnmanagedType.LPWStr), In]string pDeviceName, Int32 dwDeviceClass, out bool pUsePerUserProfiles);
public unsafe static void GetProfile() {
DISPLAY_DEVICE lpDisplayDevice = new DISPLAY_DEVICE(0); // OUT
DISPLAY_DEVICE monitor_name = new DISPLAY_DEVICE(0); // OUT
int devNum = 0;
while (EnumDisplayDevices(null, devNum, ref lpDisplayDevice, 0)) {
int devNum2 = 0;
while (EnumDisplayDevices(lpDisplayDevice.DeviceName, devNum2, ref monitor_name, 0)) {
IntPtr SizePointer;
// Need to get the size of ICC profile file first
GetDefaultColorProfileSize(
WCS_PROFILE_MANAGEMENT_SCOPE.WCS_PROFILE_MANAGEMENT_SCOPE_CURRENT_USER,
monitor_name.DeviceKey,
COLORPROFILETYPE.CPT_ICC,
COLORPROFILESUBTYPE.CPST_RGB_WORKING_SPACE,
1,
out SizePointer);
System.Diagnostics.Debug.WriteLine("Size is " + Marshal.ReadInt32(SizePointer));
// Try to get a location of ICC profile file.
// Not Implement Yet
break;
}
break;
}
}
Your SizePointer
is a local variable that you never used. I don't know what you expect to happen, but this is not going to work. You probably meant to use profileSize
.
In the future, you should fix your warnings first. They are important.
Okay, now you are at least passing the correct variable. You still have not initialized it to anything. You are passing a NULL pointer to a method that is supposed to write there. It won't be able to. I cannot imagine you actually got a TRUE
back from that method. And reading from a NULL pointer will obviously fail. You need to make sure that pointer actually points to a part in memory that can be written to.
You need a DWORD. As you are using ReadInt32
, I'll assume you are on 32bit.
You need to allocate memory first:
int size = 4; // 4 byte = 32 bit
IntPtr p = Marshal.AllocHGlobal(size);
Don't forget to free it later, this is not garbage collected:
Marshal.FreeHGlobal(p);
User contributions licensed under CC BY-SA 3.0