2

文字列を作成して 経由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));

また

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

2 に答える 2

7

PostMessage参照渡しのデータを簡単に使用することはできません。その理由は、PostMessage非同期で実行されるため、メッセージが受信者によって処理されるまで、渡すメモリを維持する必要があるためです。GetMemそれがあなたのコードの背後にあるものだと思います。

明らかに、これは同じプロセス内でのみ機能します。PostMessageまた、Windows では、ポインターを受け取るメッセージのいずれにも使用できないことがわかります。たとえば、PostMessagewith は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。これは、メッセージが処理されるまでに割り当てが解除されたローカル文字列です。

文字列を渡さずに問題を解決する方法を見つけることができればPostMessage、この複雑さよりも望ましいかもしれません。

于 2012-11-19T20:27:13.477 に答える
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;
于 2012-11-19T20:43:01.967 に答える