在Delphi中用字符串连接PChar



我需要构造一个字符串并通过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;

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

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

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

有人知道如何使用PChar吗我试过这些方法,有时有效,但最后总是有东西坏了:

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

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

对于通过引用传递的数据,无法轻松使用PostMessage。原因是PostMessage异步执行,您需要保持正在传递的内存处于活动状态,直到消息的接收者处理完为止。我想这就是您的GetMem代码背后的内容。

显然,这只适用于同一流程。您还会发现,Windows不允许您对任何接收指针的消息使用PostMessage。例如,具有WM_SETTEXTPostMessage总是失败。您只能希望使用用户定义的消息来完成此操作。当然,您还需要解除分配接收消息的代码中的内存。

我假设您使用的是一个用户定义的消息,该消息确实允许使用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试图避免的陷阱。这是一个本地字符串,在处理消息时已被释放

如果你能找到一种不用PostMessage传递字符串就能解决问题的方法,那可能比所有这些复杂度都要好。

请参阅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;

最新更新