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

convert C++ code to C#: SendMessageTimeout()

首先为SendMessageTimeout编写文档:
http://msdn.microsoft.com/zh-cn/library/windows/desktop/ms644952(v = vs.85).aspx

我有这个C代码,我想将其转换为C#:

1
2
3
4
5
6
7
8
9
LRESULT success = SendMessageTimeout(
    HWND_BROADCAST,
    WM_SETTINGCHANGE,
    0,
    (LPARAM)"Environment",
    SMTO_ABORTIFHUNG,
    5000,
    NULL
);

我在C#中所做的工作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    [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
    );


SendMessage由于使用了非描述符参数类型而有些痛苦。必要的,因为它需要完成许多工作。使用C语言是必需的,但不是使用C#。您在这里要做的是利用支持重载的C#语言。 IntPtr参数只能是引用类型引用,pinvoke编组器会将它们正确转换为指针,并解决了内存管??理的麻烦。因此,只需制作另一个与您要使用的方式兼容的方式即可:

1
2
3
4
5
6
7
8
9
10
[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
);

现在您可以使用:

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

针对您的问题。

  • HWND_BROADCAST是0xFFFF而不是0xFFFFFFFF
  • 您将必须使用Marshal.StringToHGlobalUni手动为LPARAM值分配内存,然后在调用之后使用Marshal.FreeHGlobal释放内存。您必须释放此内存,否则它将泄漏。元帅的内存不会被垃圾回收。
  • 对于lpdwResult,只需创建一个IntPtr变量并将其传递。您可以忽略其值。
  • 代码应如下所示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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将为您处理此指针。