2012-11-19 75 views
2

我需要構造一個字符串並通過PostMessage發送它,即。Concat PChar在Delphi中的字符串

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)); 

OR

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

什麼是「某些東西不能工作」和「總是在最後突破」是什麼意思?你有什麼具體的問題?你爲什麼使用'PChar'和'GetMem'呢? (IOW,你爲什麼要混合這些類型呢?) –

+1

PostMessaging字符串的一個問題是,在目標線程/窗口收到字符串之前,字符串往往會被破壞 - PostMessage只是傳遞指針,它對字符串的refCount一無所知,所以不會增加它。 –

+0

@MartinJames這就是爲什麼問題中的代碼用'GetMem'分配緩衝區的原因。 –

回答

7

你不能輕易使用PostMessage與按引用傳遞數據。原因是PostMessage異步執行,並且您需要保留您傳遞的內存,直到郵件已由其收件人處理。我想這就是你的GetMem代碼的背後。

顯然這隻適用於相同的過程。而且您還會發現Windows不會讓您使用PostMessage來接收指針的任何消息。例如,PostMessageWM_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避免的陷阱。這是一個本地字符串,它在處理消息時已被釋放。

如果您可以找到解決問題的方法,而不使用PostMessage來傳遞字符串,那麼這可能比所有這些複雜性更可取。

+0

這是一個很好的例子,爲什麼它支付將代碼分成小的功能部分。通過在消息發佈代碼旁邊混合GetMem /緩衝區複製代碼,重新編寫代碼變得更加困難。但將關注點分離爲單獨功能的瑣碎手段,突然變得容易。當然,後見之明總會讓人更容易看到正確的功能分解。但對於這些問題,請始終保持活力,並且注意更好地考慮代碼。 –

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;