带引号和不带引号的 WM_COPYDATA 会产生不同的结果

发布于 2024-12-06 10:57:08 字数 1109 浏览 1 评论 0原文

使用 WM_COPYDATA 通过 Delphi XE 将命令行参数传递到另一个应用程序实例,如下所示:

function DAppInstance.SendParamsToPrevInstance(AWindowHandle: THandle): Boolean;
var
  copyData: TCopyDataStruct;
  cmdParams : string;
  i : integer;
begin
  cmdParams := '';
  for i := 1 to ParamCount do
    cmdParams := cmdParams + ParamStr(i); //#1
  //cmdParams := cmdParams + '"' + ParamStr(i) + '" '; //#2
  //cmdParams := cmdParams + format('"%s" ', [ParamStr(i)]); //#3
  //cmdParams := cmdParams + format('%s;', [ParamStr(i)]); //#4

  copyData.lpData := pchar(cmdParams);
  copyData.cbData := 1 + (bytelength(cmdParams));
  copyData.dwData := WaterMark;  //ID for APP

  result := SendMessage(AWindowHandle, 
    WM_COPYDATA, 
    Application.Handle, 
    LPARAM(@copyData)) = 1;
end;

如果引用/附加字符串,则会产生不同的结果。

如果使用 #1 - 字符串是干净的,但如果不加引号则不可用,因为文件名可以有空格,并且 this:

C:\Users\MX4399\Research\delphi\instance\doc with spaces.doc

最后将被视为 3 个参数,同时使用 #2 引用字符串或附加任何内容 (# 3、#4) 原因

"C:\Users\MX4399\Research\delphi\instance\doc with spaces.doc"'#$FF00'궳獧

Using WM_COPYDATA to pass command line params to another app instance with Delphi XE as follows:

function DAppInstance.SendParamsToPrevInstance(AWindowHandle: THandle): Boolean;
var
  copyData: TCopyDataStruct;
  cmdParams : string;
  i : integer;
begin
  cmdParams := '';
  for i := 1 to ParamCount do
    cmdParams := cmdParams + ParamStr(i); //#1
  //cmdParams := cmdParams + '"' + ParamStr(i) + '" '; //#2
  //cmdParams := cmdParams + format('"%s" ', [ParamStr(i)]); //#3
  //cmdParams := cmdParams + format('%s;', [ParamStr(i)]); //#4

  copyData.lpData := pchar(cmdParams);
  copyData.cbData := 1 + (bytelength(cmdParams));
  copyData.dwData := WaterMark;  //ID for APP

  result := SendMessage(AWindowHandle, 
    WM_COPYDATA, 
    Application.Handle, 
    LPARAM(@copyData)) = 1;
end;

yields different results if the strings are quoted / appended to.

if #1 is used - the string comes in clean but is not usable if not quoted as filenames can have spaces and this:

C:\Users\MX4399\Research\delphi\instance\doc with spaces.doc

will be see as 3 paramaters in the end, while using #2 to quote the strings, or appending anything (#3, #4) causes

"C:\Users\MX4399\Research\delphi\instance\doc with spaces.doc"'#$FF00'궳獧

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

猛虎独行 2024-12-13 10:57:09

我相信@TOndrej 已经发现了问题的主要原因。然而,我认为你还有第二个更微妙的错误。

我认为,接收 WM_COPYDATA 消息的应用程序会将 lpData 视为以 null 结尾的字符串。如果数据格式错误,那么缓冲区就会溢出。我相信这正是您的示例中发生的情况,但事实证明它是良性的。 WM_COPYDATA 的编组仅复制 cbData 中指定的缓冲区大小。你必须确保你没有阅读超出它的内容。恶意应用程序可能会向您发送包含数据的 WM_COPYDATA 消息,迫使您执行此操作。相反,我建议您在阅读时使用cbData

因此,要发送您编写的字符串:

copyData.lpData := PChar(cmdParams);
copyData.cbData := ByteLength(cmdParams))
copyData.dwData := WaterMark; 

然后,当您收到它时,您会分配一个缓冲区并根据cbData 的值复制到该缓冲区。

SetString(cmdParams, PChar(copyData.lpData), copyData.cbData div SizeOf(Char));

I believe that @TOndrej has spotted the main cause of the problem. However, I think you have a second more subtle bug.

Your app which receives the WM_COPYDATA message is, I think, treating lpData as a null-terminated string. If the data is malformed then you will have a buffer overrun. I believe that is exactly what is happening in your examples but it just turns out to be benign. The marshalling of WM_COPYDATA copies just the size of buffer specified in cbData. You must make sure you don't read beyond it. A malicious app could send you a WM_COPYDATA message with data to make you do just that. Instead I recommend you use cbData when reading.

So to send the string you write:

copyData.lpData := PChar(cmdParams);
copyData.cbData := ByteLength(cmdParams))
copyData.dwData := WaterMark; 

And then when you receive it you allocate a buffer and copy to that buffer based on the value of cbData.

SetString(cmdParams, PChar(copyData.lpData), copyData.cbData div SizeOf(Char));
独享拥抱 2024-12-13 10:57:09

我认为您的意思是 copyData.cbdata := 1 * SizeOf(Char) + ... 而不仅仅是 1 + ...

I think you meant copyData.cbdata := 1 * SizeOf(Char) + ... instead of just 1 + ....

情绪操控生活 2024-12-13 10:57:09

在一个单独但相关的注释中,您可以只使用 ParamStr() (它本身有许多已知的错误)来解析原始命令行并从中重建一个新字符串,而不是使用 < code>GetCommandLine() 来获取原始命令行并按原样发送。

On a separate but related note, rather then using ParamStr() (which itself has a number of known bugs) to parse the original command-line and rebuild a new string from it, you could just use GetCommandLine() to get the original command-line instead and send it as-is.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文