将C ++代码转换为C#:SendMessageTimeout()

时间:2013-11-01 23:14:34

标签: c# c++ sendmessage

首先发送SendMessageTimeout的文档:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644952%28v=vs.85%29.aspx

我有这个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
    );

2 个答案:

答案 0 :(得分:5)

对于你的问题。

  1. HWND_BROADCAST 0xFFFF而不是0xFFFFFFFF
  2. 您必须使用Marshal.StringToHGlobalUni手动为LPARAM值分配内存,然后使用Marshal.FreeHGlobal在通话后释放它。你必须释放这个记忆,否则它会泄漏。 Marshal的记忆不是垃圾收集。
  3. 对于lpdwResult,只需创建一个IntPtr变量并将其传入。您可以忽略其值。
  4. 代码应该是这样的:

    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调用的内存时需要小心,因为您不知道接收窗口将对您传递给它的指针执​​行什么操作。由于WM_SETTINGCHANGE是内置的Windows消息,因此Windows将为您处理此指针。

答案 1 :(得分:5)

SendMessage由于它使用的非描述参数类型而有点痛苦。必要的是因为它需要做很多工作。在C语言中是必需的,但在C#中则不然。你想要做的是利用支持重载的C#语言。 IntPtr参数可以只是引用类型引用,pinvoke marshaller会正确地将它们转换为指针并处理内存管理的麻烦。因此,只需制作另一个与您想要使用它的方式兼容的产品:

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