0

考虑WM_SETTEXT可用于通过老式 Win32 API 设置另一个窗口的文本的消息。在 .NET 中可能有多种方法可以做到这一点,我知道有两种方法:

[DllImport("USER32", EntryPoint = "SendMessage", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, string lParam);

SendMessage(handle, WM_SETTEXT, IntPtr.Zero, "Magic String");

 

[DllImport("USER32", EntryPoint = "SendMessage", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

IntPtr textPointer = Marshal.StringToCoTaskMemUni("Magic String");
SendMessage(handle, WM_SETTEXT, IntPtr.Zero, textPointer);
Marshal.FreeCoTaskMem(textPointer);

第一个在 dll 导入的声明中使用字符串并让 .NET 处理它。第二个使用 anIntPtr并显式创建一个指针 usingMarshal.StringToCoTaskMemUni然后释放 using Marshal.FreeCoTaskMem。据我所知,这两种方法都很有效。

请注意,我通常会使用前者(事实上,我多年前作为 VB6 程序员曾经这样做过),但我在另一篇 StackOverflow 帖子的评论中遇到了后者,并且很好奇前者是否是另一个需要压制的坏习惯。

我还看到了第一个示例的变体,char[]在声明中使用数组并传入StringBuilder

我的问题很简单——哪种(如果有的话)是正确的做法?例如,SendMessageWin32 调用无论如何都只接受指针,因此“某些东西”必须在幕后为第一个版本创建指针,如果是这样,它是否会进行清理,或者最好是冗长并使用显式分配和指针的释放。

4

1 回答 1

2

当您声明 的参数时string,p/invoke 编组器将在幕后将其编组为指向以空字符结尾的字符数组的指针。编组器将处理所有内存分配和释放。你可以用一个IntPtr参数自己做,但最终结果是一样的。

您选择哪一个取决于您是否计划将SendMessage声明用于您发送的任何其他消息。

  • 如果你只调用SendMessageWM_SETTEXT,那么你声明它接收一个string参数。
  • 如果您还用于SendMessage发送其他消息,则可以将参数声明为IntPtr并手动执行编组。
  • 还有一个选择是声明多个重载变体,以便您可以使调用的代码SendMessage对程序员尽可能方便。

现在,让我们选择最后一个选项。假设您需要发送WM_GETTEXT以及WM_SETTEXT. 因为WM_SETTEXT您需要将字符串数据从托管传递到本机,所以您更喜欢string. 对于WM_GETTEXT,您需要提供一个缓冲区,以便本机代码可以填写窗口文本。这意味着您要使用StringBuilder. 因此,声明两个重载,一个接收string和一个接收StringBuilder。前者用于WM_SETTEXT,后者用于WM_GETTEXT

于 2013-10-27T09:25:28.447 回答