2

首先是 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
    );
4

2 回答 2

5

对于您的问题。

  1. HWND_BROADCAST不是0xFFFF_0xFFFFFFFF
  2. 您必须使用 Marshal.StringToHGlobalUni手动为 LPARAM 值分配内存,然后在调用后使用Marshal.FreeHGlobal释放它。您必须释放此内存,否则它将泄漏。Marshal'd 内存不会被垃圾收集。
  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因为您不知道接收窗口将如何处理传递给它的指针。但是,由于WM_SETTINGCHANGE是内置的 Windows 消息,Windows 将为您处理此指针。

于 2013-11-01T23:45:03.750 回答
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);
于 2013-11-01T23:55:17.100 回答