所以,我有一个使用WM_COPYDATA的类允许应用程序进行通信。
__next__
发送申请:
type
TMyRec = record
Name: string[255];
Age: integer;
Birthday: TDateTime;
end;
function TAppCommunication.SendRecord(const ARecordToSend: Pointer; const ARecordType: PTypeInfo): Boolean;
var
_Stream: TMemoryStream;
begin
_Stream := TMemoryStream.Create;
try
_Stream.Write(NativeInt(ARecordType), SizeOf(TTypeInfo));
_Stream.Write(NativeInt(ARecordToSend), SizeOf(ARecordToSend));
_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,
integer(FLocalReceiverForm.Handle), integer(@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;
//_ms.Write(_Rec, SizeOf(TMyRec));
//_AppCommunication.SendStreamData(_ms, TCopyDataType.cdtRecord);
_AppCommunication.SendRecord(@_rec, System.TypeInfo(TMyRec));
//_AppCommunication.SendRecord(@_Record, System.TypeInfo(TAttrData));
finally
FreeAndNil(_ms);
FreeAndNil(_AppCommunication);
end;
end;
问题是如果我一起发送TypeInfo和记录,我在读第二个时失败了。如果我单独发送,我可以阅读TypInfo或记录。我该怎么办才能让它发挥作用?
答案 0 :(得分:1)
您不能跨进程边界使用指针,更不用指向RTTI的指针。您不应该将指针发送到TMyRec
(当然不是指针到其RTTI)。您需要发送实际 TMyRec
本身的副本(您已将代码注释掉以完全相同),例如:
type
PMyRec = ^TMyRec;
TMyRec = packed record
Name: string[255];
Age: integer;
Birthday: TDateTime;
end;
function TAppCommunication.SendRecord(const ARecordToSend: Pointer; ARecordSize: Integer): Boolean;
var
_Stream: TMemoryStream;
begin
_Stream := TMemoryStream.Create;
try
_Stream.WriteBuffer(ARecordToSend^, ARecordSize);
_Stream.Position := 0;
Result := SendStreamData(_Stream, TCopyDataType.cdtRecord);
finally
FreeAndNil(_Stream);
end;
end;
...
// need to cast to WPARAM and LPARAM, not Integer...
_SendResponse := SendMessage(_ReceiverHandle, WM_COPYDATA, WPARAM(FLocalReceiverForm.Handle), LPARAM(@ADataToSend));
...
var
_Rec: TMyRec;
_Rec.Name := 'Edijs';
_Rec.Age := 29;
_Rec.Birthday := EncodeDate(1988, 10, 06);
_AppCommunication.SendRecord(@_Rec, SizeOf(_Rec));
procedure TReceiverMainForm.OnAppMessageReceived(const ASender : TPair<HWND, string>; const AReceivedData: TCopyDataStruct; var AResult: integer);
var
_MyRec: PMyRec;
begin
....
else
begin
if AReceivedData.dwData = Ord(TCopyDataType.cdtRecord) then
begin
memLog.Lines.Add('Record received.');
_MyRec := PMyRec(AReceivedData.lpData);
// Use _MyRec^ data as needed...
ShowMessage(_MyRec.Name + ', Age: ' + IntToStr(_MyRec.Age) + ', birthday: ' + DateToStr(_MyRec.Birthday));
end else
memLog.Lines.Add('Unknown data received.');
AResult := -1;
end;
end;
如果您需要在相同的cdtRecord
ID下发送多种类型的记录,则需要在记录数据之前发送实际记录类型名称(而不是其RTTI),例如:
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;
var
_Rec: TMyRec;
_Rec.Name := 'Edijs';
_Rec.Age := 29;
_Rec.Birthday := EncodeDate(1988, 10, 06);
_AppCommunication.SendRecord('TMyRec', @_Rec, SizeOf(_Rec));
procedure TReceiverMainForm.OnAppMessageReceived(const ASender : TPair<HWND, string>; const AReceivedData: TCopyDataStruct; var AResult: integer);
var
_RecType: ShortString;
_RecData: Pointer;
_MyRec: PMyRec;
begin
....
else
begin
if AReceivedData.dwData = Ord(TCopyDataType.cdtRecord) then
begin
memLog.Lines.Add('Record received.');
_RecType := PShortString(AReceivedData.lpData)^;
_RecData := PByte(AReceivedData.lpData)+1+Length(_RecType);
if (_RetType = 'TMyRec') then
begin
_MyRec := PMyRec(_RecData);
// Use _MyRec^ data as needed...
ShowMessage(_MyRec.Name + ', Age: ' + IntToStr(_MyRec.Age) + ', birthday: ' + DateToStr(_MyRec.Birthday));
end
else
...
end else
memLog.Lines.Add('Unknown data received.');
AResult := -1;
end;
end;
否则,您需要使用更复杂的序列化机制,以更一般化的方式识别您的记录类型和字段。