0

そのため、WM_COPYDATA を使用してアプリケーションが通信できるようにするクラスがあります。

type
  TMyRec = record
    Name: string[255]; // I want just string
    Age: integer;
    Birthday: TDateTime;
  end;

function TAppCommunication.SendRecord(const ARecordType: ShortString; const ARecordToSend: Pointer; ARecordSize: Integer): Boolean;
var
  _Stream: TMemoryStream;
begin
  _Stream := TMemoryStream.Create;
  try
    _Stream.WriteBuffer(ARecordType, 1 + Length(ARecordType));
    _Stream.WriteBuffer(ARecordToSend^, ARecordSize);
    _Stream.Position := 0;
    Result := SendStreamData(_Stream, TCopyDataType.cdtRecord);
  finally
    FreeAndNil(_Stream);
  end;
end;

function TAppCommunication.SendStreamData(const AStream: TMemoryStream;
  const ADataType: TCopyDataType): Boolean;
var
  _CopyDataStruct: TCopyDataStruct;
begin
  Result := False;

  if AStream.Size = 0 then
    Exit;

  _CopyDataStruct.dwData := integer(ADataType);
  _CopyDataStruct.cbData := AStream.Size;
  _CopyDataStruct.lpData := AStream.Memory;

  Result := SendData(_CopyDataStruct);
end;

function TAppCommunication.SendData(const ADataToSend: TCopyDataStruct)
  : Boolean;
var
  _SendResponse: integer;
  _ReceiverHandle: THandle;
begin
  Result := False;

  _ReceiverHandle := GetRemoteReceiverHandle;
  if (_ReceiverHandle = 0) then
    Exit;

  _SendResponse := SendMessage(_ReceiverHandle, WM_COPYDATA,
    WPARAM(FLocalReceiverForm.Handle), LPARAM(@ADataToSend));

  Result := _SendResponse <> 0;
end;

送信者アプリケーション:

procedure TSenderMainForm.BitBtn1Click(Sender: TObject);
var
  _AppCommunication: TAppCommunication;
  _ms: TMemoryStream;
  _Rec: TMyRec;
  _Record: TAttrData;
begin
  _AppCommunication := TAppCommunication.Create('LocalReceiverName', OnAppMessageReceived);
  _ms := TMemoryStream.Create;
  try
    _AppCommunication.SetRemoteReceiverName('LocalReceiverNameServer');
    _AppCommunication.SendString('ąčęėįšųūž123');
    _AppCommunication.SendInteger(998);
    _AppCommunication.SendDouble(0.95);

    _Rec.Name := 'Edijs';
    _Rec.Age := 29;
    _Rec.Birthday := EncodeDate(1988, 10, 06);
    _Record.Len := 1988;
    _AppCommunication.SendRecord(TTypeInfo(System.TypeInfo(TMyRec)^).Name, @_Rec, SizeOf(_Rec));
  finally
    FreeAndNil(_ms);
    FreeAndNil(_AppCommunication);
  end;
end;

受信アプリ:

procedure TReceiverMainForm.OnAppMessageReceived(const ASender
  : TPair<HWND, string>; const AReceivedData: TCopyDataStruct;
  var AResult: integer);
var
  _MyRec: TMyRec;
  _RecType: ShortString;
  _RecData: Pointer;
begin
  ...
  else
  begin
    if (AReceivedData.dwData) = Ord(TCopyDataType.cdtRecord) then
    begin
    _RecType := PShortString(AReceivedData.lpData)^;
      _RecData := PByte(AReceivedData.lpData)+1+Length(_RecType);
      if (_RecType = TTypeInfo(System.TypeInfo(TMyRec)^).Name) then
      begin
        _MyRec := TMyRec(_RecData^);
        ShowMessage(_MyRec.Name + ', Age: ' + IntToStr(_MyRec.Age) + ', birthday: ' +
          DateToStr(_MyRec.Birthday));
      end;
    end;
    AResult := -1;
  end;
end;

問題は、 inに変更Name: string[255];するとクラッシュが発生することです。どうすればこれを克服できますか?すべてのレコードを編集して文字列を別のものに変更したくはありません。また、すべての種類のレコードを送信する関数が 1 つ必要です (私の考えでは、オブジェクトは含まれません)。Name: string;TMyRec

EDITED : Remy から提供された回答を使用し、いくつかの調整を行ったので、SendRecord 関数を 1 つだけ使用して任意の種類のレコードを送信できます。

function TAppCommunication.SendRecord(const ARecordToSend, ARecordTypInfo: Pointer): Boolean;
var
  _Stream: TMemoryStream;
  _RType: TRTTIType;
  _RFields: TArray<TRttiField>;
  i: Integer;
begin
  _Stream := TMemoryStream.Create;
  try
    _RType := TRTTIContext.Create.GetType(ARecordTypInfo);

    _Stream.WriteString(_RType.ToString);
    _RFields := _RType.GetFields;
    for i := 0 to High(_RFields) do
    begin
      if _RFields[i].FieldType.TypeKind = TTypeKind.tkUString then
        _Stream.WriteString(_RFields[i].GetValue(ARecordToSend).ToString)
      else if _RFields[i].FieldType.TypeKind = TTypeKind.tkInteger then
        _Stream.WriteInteger(_RFields[i].GetValue(ARecordToSend).AsType<integer>)
      else if _RFields[i].FieldType.TypeKind = TTypeKind.tkFloat then
        _Stream.WriteDouble(_RFields[i].GetValue(ARecordToSend).AsType<Double>)
    end;
    _Stream.Position := 0;
    Result := SendStreamData(_Stream, TCopyDataType.cdtRecord);
  finally
    FreeAndNil(_Stream);
  end;
end;

送信者:

_AppCommunication.SendRecord(@_Rec, System.TypeInfo(TMyRec));
4

1 に答える 1