1

使用 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 - 字符串是干净的,但如果没有引用,则不可用,因为文件名可以有空格,并且:

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'궳獧
4

3 回答 3

5

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

WM_COPYDATA我认为,您接收消息的应用程序被lpData视为以空字符结尾的字符串。如果数据格式错误,那么您将遇到缓冲区溢出。我相信这正是您的示例中正在发生的事情,但事实证明它是良性的。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));
于 2011-09-24T19:42:26.250 回答
4

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

于 2011-09-24T18:20:43.960 回答
4

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

于 2011-09-25T16:20:45.557 回答