用Delphi中的字符串Concat PChar

时间:2012-11-19 20:09:17

标签: string delphi pointers delphi-2010

我需要构建一个字符串并通过PostMessage发送,即

FileName := String_1 + String_2 + String_3;
PostMessage(FWndHandle, WM_BLA_BLA, NotifyData^.Action, LParam(FileName));

但有些东西不起作用。另外,FileName是PChar。代码如下所示:

var
   FileName : PChar;
   Directory_Str : String;
   AnotherString : String;
begin
    // Get memory for filename and fill it with data
    GetMem(FileName, NotifyData^.FileNameLength + SizeOf(WideChar));
    Move(NotifyData^.FileName, Pointer(FileName)^, NotifyData^.FileNameLength);
    PWord(Cardinal(FileName) + NotifyData^.FileNameLength)^ := 0;

    // TODO: Contact string before sending message
    // FileName := AnotherString + Directory_Str + FileName;

    PostMessage(FWndHandle, WM_BLA_BLA, NotifyData^.Action, LParam(FileName));

    ...
end;

现在我需要在调用FileName之前联系另一个字符串到变量PostMessage,即。

FileName := AnotherString + Directory_Str + FileName;
PostMessage(FWndHandle, WM_BLA_BLA, NotifyData^.Action, LParam(FileName));

如果FileName是一个字符串,这将起作用,这不是这里的情况。

任何人都知道如何使用PChar做到这一点?我尝试过这些方法,有时可以使用,但最后总会出现问题:

StrPCopy(FileName, FDirectory + String(FileName));

OR

FileName := PChar(AnotherString + Directory_Str + FileName);

2 个答案:

答案 0 :(得分:7)

您不能轻易地将PostMessage用于通过引用传递的数据。原因是PostMessage异步执行,并且您需要保留正在传递的内存,直到其收件人处理了该消息。我想这就是你的GetMem代码背后的内容。

显然这仅适用于同一过程。而且您还会发现Windows不允许您使用PostMessage来获取任何接收指针的消息。例如,PostMessage WM_SETTEXT始终失败。您只能希望使用用户定义的消息来执行此操作。当然,您需要在接收消息的代码中释放内存。

我将假设您使用的用户定义消息允许发送带有PostMessage的字符串。在这种情况下,您已经有了解决方案。使用字符串变量进行连接,然后使用答案中的第一个代码块。

虽然你可以这样做得更清洁:

function HeapAllocatedPChar(const Value: string): PChar;
var
  bufferSize: Integer;
begin
  bufferSize := (Length(Value)+1)*SizeOf(Char);
  GetMem(Result, bufferSize);
  Move(PChar(Value)^, Result^, bufferSize);
end;

procedure PostString(Window: HWND; Msg: UINT; wParam: WPARAM; 
  const Value: string);
var
  P: PChar;
begin
  P := HeapAllocatedPChar(Value);
  if not PostMessage(Window, Msg, wParam, LPARAM(P)) then
    FreeMem(P);
end;

你可以这样称呼这个程序:

PostString(FWndHandle, WM_BLA_BLA, NotifyData^.Action, FDirectory + FileName);

您当前的代码失败,原因是:

  1. 当您致电StrPCopy时,您不会为较长的字符串分配任何内存。
  2. 当你写PChar(AnotherString + Directory_Str + FileName)时,你会陷入GetMem试图避免的陷阱。这是一个本地字符串,在处理消息时已经解除分配。
  3. 如果您可以找到一种解决问题的方法而不使用PostMessage来传递字符串,那么这可能比所有这些复杂性更可取。

答案 1 :(得分:6)

请参阅David的答案,了解您的代码失败的原因。

我总是定义一个用于通过PostMessage操作分发字符串的类。 没有泄漏的风险,并且可以通过更多信息轻松扩展。

Type
  TMyMessage = class
    msg : String;
    Constructor Create(aMessage : String);
  end;


// Sending the message
var
  myMsg : TMyMessage;
...
myMsg := TMyMessage.Create('A message');

if not PostMessage(someHandle,WM_something,WParam(myMsg),0)
then begin
  myMsg.free;
  ... Take care of this condition if PostMessage fails !!
end;  

// Receiving the message

procedure TSomeForm.GetMessage(var msg : TMessage);
var
  aMsg : TMyMessage;
begin
  ...
  aMsg := TMyMessage(msg.WParam);
  try
    ...
    // Do something with the message
  finally
    aMsg.Free;
  end;
end;