WM_COPYDATA с кавычками и без них дает разные результаты - PullRequest
1 голос
/ 24 сентября 2011

Использование 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;

дает разные результаты, если строки заключены в кавычки / добавлены.используется - строка поставляется чистой, но ее нельзя использовать, если она не заключена в кавычки, так как имена файлов могут содержать пробелы, и это:

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

Ответы [ 3 ]

5 голосов
/ 24 сентября 2011

Я считаю, что @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));
4 голосов
/ 25 сентября 2011

В отдельном, но связанном примечании, вместо использования ParamStr() (в котором есть ряд известных ошибок) для анализа исходной командной строки и восстановления из нее новой строки, вы можете просто использовать GetCommandLine() для вместо исходной командной строки и отправьте ее как есть.

4 голосов
/ 24 сентября 2011

Я думаю, что вы имели в виду copyData.cbdata := 1 * SizeOf(Char) + ... вместо просто 1 + ....

...