2013-11-01 231 views
2

首先實況爲SendMessageTimeout:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644952%28v=vs.85%29.aspx轉換C++代碼轉換爲C#:SendMessageTimeout()

我有這樣的C++代碼,我想將其轉換爲C#:

LRESULT success = SendMessageTimeout(
    HWND_BROADCAST, 
    WM_SETTINGCHANGE, 
    0, 
    (LPARAM) "Environment", 
    SMTO_ABORTIFHUNG, 
    5000, 
    NULL 
); 

我做什麼在C#中:

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] 
    public static extern IntPtr SendMessageTimeout(
     IntPtr hWnd, 
     uint Msg, 
     UIntPtr wParam, 
     IntPtr lParam, 
     uint fuFlags, 
     uint uTimeout, 
     out UIntPtr lpdwResult 
    ); 

    SendMessageTimeout(
     (IntPtr)0xFFFFFFFF, //HWND_BROADCAST 
     0x001A,    //WM_SETTINGCHANGE 
     (UIntPtr)0, 
     (IntPtr)"Environment", // ERROR_1: can't convert string to IntPtr 
     0x0002,    // SMTO_ABORTIFHUNG 
     5000, 
     out UIntPtr.Zero  // ERROR_2: a static readonly field can not be passed ref or out 
    ); 
+0

查找到編組的C-串VS Marshal.StringToHGlobalUni + FreeHGlobal。對於最後一部分,只需定義一個本地並將其傳入。 – Warty

回答

5

對於你的問題。

  1. HWND_BROADCAST0xFFFF0xFFFFFFFF
  2. 你將不得不使用Marshal.StringToHGlobalUni手動爲LPARAM值分配內存,然後使用Marshal.FreeHGlobal電話後釋放它。你必須釋放這個內存,否則它會泄漏。元帥的記憶不是垃圾收集。
  3. 對於lpdwResult只需創建一個IntPtr變量並將其傳入。您可以忽略它的值。

代碼應該是這樣的:

IntPtr result = IntPtr.Zero; 
IntPtr setting = Marshal.StringToHGlobalUni("Environment"); 

SendMessageTimeout(
    (IntPtr)0xFFFF,  //HWND_BROADCAST 
    0x001A,    //WM_SETTINGCHANGE 
    (UIntPtr)0, 
    (IntPtr)setting, 
    0x0002,    // SMTO_ABORTIFHUNG 
    5000, 
    out result 
); 

Marshal.FreeHGlobal(setting); 

一般來說,你需要釋放你傳遞給一個SendMessage調用,因爲你不知道什麼receving窗口會做內存的時候要小心用你傳給它的指針。由於WM_SETTINGCHANGE是一個內置的Windows消息,因此Windows將爲您處理這個指針。

+1

嗨,這可以防止我必須重新啓動系統才能使更改生效。但我仍然需要重新啓動CMD/Powershell。你碰巧知道一種方法來防止這一點呢? –

5

由於使用了非描述參數類型,SendMessage有點痛苦。必要的,因爲它需要做很多工作。在C語言中是必需的,但不在C#中。你想在這裏做的是利用支持超載的C#語言。 IntPtr參數可以只是引用類型引用,pinvoke編組會將它們正確地轉換爲指針並處理內存管理的麻煩。因此,只要手藝另外一個,就是你想使用它的方式兼容:

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] 
public static extern IntPtr SendMessageTimeout(
    IntPtr hWnd, 
    int Msg, 
    IntPtr wParam, 
    string lParam, 
    int fuFlags, 
    int uTimeout, 
    IntPtr lpdwResult 
); 

現在你可以使用:

SendMessageTimeout((IntPtr)0xffff, 0x001A, IntPtr.Zero, "Environment", 
        2, 5000, IntPtr.Zero);