2013-11-01 225 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);