2016-03-28 54 views
-2

我嘗試創建一個程序,它將以編程方式設置Windows顏色管理以歸檔類似f.lux的效果作爲業餘愛好項目。AccessViolationException當嘗試從C#中使用元帥類的指針讀取內存

** 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 
); 

**這是託管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 
); 

問題是,當我試圖讓這也是作爲回報使用Marshal類從WINAPI一個指針的字符串。如使用Marshal.ReadInt32

// 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)); 

GetDefaultColorProfileSize回報TRUE但是當我嘗試訪問它返回的地址(它返回該地址0x0000003e)它拋出這個錯誤

System.AccessViolationException試圖讀取或寫保護的內存。這通常表明其他內存已損壞。

如何能夠讀取該指針處的內存?

我首先嚐試分配的內存由nvoigt

建議從IntPtr SizePointer更改爲IntPtr SizePointer = Marshal.AllocHGlobal(4);

但它仍然拋出同樣的異常

完整的代碼如下這裏。

Enumnerate顯示設備

[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; 
     } 
    } 
+0

我們需要更大膽的文字。 – Dennis

+0

對不起,我現在已經解決了這個問題,使其更具可讀性。 – Suttisak

回答

1

SizePointer是你從未使用過的局部變量。我不知道你期望發生,但這是行不通的。您可能打算使用profileSize

未來,您應該先解決您的警告。它們很重要。


好的,現在你至少傳遞了正確的變量。你還沒有初始化任何東西。你傳遞一個NULL指針給應該寫在那裏的方法。它將無法。我無法想象你實際上從該方法中獲得了TRUE。而從NULL指針讀取顯然會失敗。您需要確保指針實際上指向可以寫入的內存中的一部分。您需要一個DWORD。正如你使用ReadInt32,我假設你在32位。

您需要首先分配內存:

int size = 4; // 4 byte = 32 bit 

IntPtr p = Marshal.AllocHGlobal(size); 

不要忘記稍後釋放它,這不是垃圾收集:

Marshal.FreeHGlobal(p); 
+0

對不起,這是我將代碼複製到StackOverflow並削減一些不重要的代碼行時的拼寫錯誤。我在VS2015中運行的實際代碼已更正。我已經修復了你剛纔提到的錯字。 – Suttisak

+0

如果您發佈虛假代碼,並且告訴我們我們正在回答錯誤的問題,沒有人願意提供幫助,就好像那是我們的錯。坦率地說,我們不關心你的代碼實際上是什麼。我們只關心在我們面前的問題。如果您發佈的代碼與您面前的代碼沒有任何關係,那就是您的問題。請不要發佈虛假代碼。 –

+0

@nvoigt我已經嘗試過,但它仍然拋出異常。返回'TRUE'的WcsGetDefaultColorProfileSize返回out IntPtr SizePointer的指針始終爲「0x0000003e」。當我打開VS中的內存窗口並搜索這個地址。它只顯示?? ?? ?? ??。 – Suttisak