Jak wysłać łańcuch znaków z jednej instancji mojego programu Delphi do drugiej?
Jaki jest najlepszy i najłatwiejszy sposób na wysłanie ciągu znaków z jednej instancji mojego programu do innej instancji mojego programu? Program odbierający musi wykonać procedurę, używając otrzymanego ciągu jako parametru.
Zacząłem czytać o DDE, ale się pogubiłem. Jakie inne opcje mam i jaki jest najprostszy sposób na wdrożenie tego?
8 answers
Używaj nazwanych rur, ale polecam nazwane elementy rur Russella Libby ' ego. Istnieje komponent TPipeClient i tpipeserver.
[[1]}od (2013-10-04) Francoise Piette i [email protected] zaktualizowano ten kod źródłowy do kompilacji z Delphi 7 do XE5 (wcześniejsze wersje mogą kompilować się jednak niesprawdzone) i umieścić go tutaj: http://www.overbyte.be/frame_index.html?redirTo=/blog_source_code.htmlTe 2 komponenty sprawiają, że korzystanie z nazwanych rur jest niezwykle łatwe i nazwane rury doskonale nadają się do komunikacji międzyprocesowej (IPC).
Jego strona jest tutaj . Szukaj " rury.zip". Opis ze źródła to: / / Opis: Zestaw komponentów klienckich i serwerowych o nazwie pipe dla Delphi, a także / / komponent przekierowujący konsolowy pipe.
Russell pomógł mi również w Experts-Exchange z użyciem starszej wersji tego komponentu do pracy w aplikacji konsolowej do wysyłania / odbierania wiadomości przez nazwane rury. To może pomóc jako przewodnik w getting you up i działa z wykorzystaniem jego komponentów. Pamiętaj, że w aplikacji lub usłudze VCL nie musisz pisać własnej pętli wiadomości, tak jak to zrobiłem w tej aplikacji konsolowej.
program CmdClient;
{$APPTYPE CONSOLE}
uses
Windows, Messages, SysUtils, Pipes;
type
TPipeEventHandler = class(TObject)
public
procedure OnPipeSent(Sender: TObject; Pipe: HPIPE; Size: DWORD);
end;
procedure TPipeEventHandler.OnPipeSent(Sender: TObject; Pipe: HPIPE; Size: DWORD);
begin
WriteLn('On Pipe Sent has executed!');
end;
var
lpMsg: TMsg;
WideChars: Array [0..255] of WideChar;
myString: String;
iLength: Integer;
pcHandler: TPipeClient;
peHandler: TPipeEventHandler;
begin
// Create message queue for application
PeekMessage(lpMsg, 0, WM_USER, WM_USER, PM_NOREMOVE);
// Create client pipe handler
pcHandler:=TPipeClient.CreateUnowned;
// Resource protection
try
// Create event handler
peHandler:=TPipeEventHandler.Create;
// Resource protection
try
// Setup clien pipe
pcHandler.PipeName:='myNamedPipe';
pcHandler.ServerName:='.';
pcHandler.OnPipeSent:=peHandler.OnPipeSent;
// Resource protection
try
// Connect
if pcHandler.Connect(5000) then
begin
// Dispatch messages for pipe client
while PeekMessage(lpMsg, 0, 0, 0, PM_REMOVE) do DispatchMessage(lpMsg);
// Setup for send
myString:='the message I am sending';
iLength:=Length(myString) + 1;
StringToWideChar(myString, wideChars, iLength);
// Send pipe message
if pcHandler.Write(wideChars, iLength * 2) then
begin
// Flush the pipe buffers
pcHandler.FlushPipeBuffers;
// Get the message
if GetMessage(lpMsg, pcHandler.WindowHandle, 0, 0) then DispatchMessage(lpMsg);
end;
end
else
// Failed to connect
WriteLn('Failed to connect to ', pcHandler.PipeName);
finally
// Show complete
Write('Complete...');
// Delay
ReadLn;
end;
finally
// Disconnect event handler
pcHandler.OnPipeSent:=nil;
// Free event handler
peHandler.Free;
end;
finally
// Free pipe client
pcHandler.Free;
end;
end.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-26 14:02:28
Używam nazwanych rur do tego, to było najłatwiejsze, jakie znalazłem. Wyślę kod, kiedy wrócę z pracy.
Oto artykuł jak go używać w delphi: http://www.delphi3000.com/articles/article_2918.asp?SK=
Jest na to milion rozwiązań, wszystkie wydają się denerwujące. Fajki są najlepsze, jakie do tej pory znalazłem. Oto kod, przepraszam za opóźnienie. Powinieneś też sprawdzić bibliotekę fajek wspomnianą przez Micka. The thing I ' ve zrobione tutaj było dość szybkim eksperymentem. Należy pamiętać, że został on wykonany w Delphi 2009.unit PetriW.Pipes;
interface
uses
Windows,
Classes,
Forms,
SyncObjs,
SysUtils
;
type
TPBPipeServerReceivedDataEvent = procedure(AData: string) of object;
TPBPipeServer = class
private
type
TPBPipeServerThread = class(TThread)
private
FServer: TPBPipeServer;
protected
public
procedure Execute; override;
property Server: TPBPipeServer read FServer;
end;
private
FOnReceivedData: TPBPipeServerReceivedDataEvent;
FPath: string;
FPipeHandle: THandle;
FShutdownEvent: TEvent;
FThread: TPBPipeServerThread;
protected
public
constructor Create(APath: string);
destructor Destroy; override;
property Path: string read FPath;
property OnReceivedData: TPBPipeServerReceivedDataEvent read FOnReceivedData write FOnReceivedData;
end;
TPBPipeClient = class
private
FPath: string;
protected
public
constructor Create(APath: string);
destructor Destroy; override;
property Path: string read FPath;
procedure SendData(AData: string); overload;
class procedure SendData(APath, AData: string); overload;
end;
implementation
const
PIPE_MESSAGE_SIZE = $20000;
{ TPipeServer }
constructor TPBPipeServer.Create(APath: string);
begin
FPath := APath;
FShutdownEvent := TEvent.Create(nil, True, False, '');
FPipeHandle := CreateNamedPipe(
PWideChar(FPath),
PIPE_ACCESS_DUPLEX or FILE_FLAG_OVERLAPPED,
PIPE_TYPE_MESSAGE or PIPE_READMODE_MESSAGE or PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
SizeOf(Integer),
PIPE_MESSAGE_SIZE,
NMPWAIT_USE_DEFAULT_WAIT,
nil
);
if FPipeHandle = INVALID_HANDLE_VALUE then
RaiseLastOSError;
FThread := TPBPipeServerThread.Create(true);
FThread.FreeOnTerminate := false;
FThread.FServer := self;
FThread.Resume;
end;
destructor TPBPipeServer.Destroy;
begin
FShutdownEvent.SetEvent;
FreeAndNil(FThread);
CloseHandle(FPipeHandle);
FreeAndNil(FShutdownEvent);
inherited;
end;
{ TPipeServer.TPipeServerThread }
procedure TPBPipeServer.TPBPipeServerThread.Execute;
var
ConnectEvent, ReadEvent: TEvent;
events: THandleObjectArray;
opconnect, opread: TOverlapped;
Signal: THandleObject;
buffer: TBytes;
bytesRead, error: Cardinal;
begin
inherited;
//SetThreadName('TPBPipeServer.TPBPipeServerThread');
ConnectEvent := TEvent.Create(nil, False, False, '');
try
setlength(events, 2);
events[1] := Server.FShutdownEvent;
FillMemory(@opconnect, SizeOf(TOverlapped), 0);
opconnect.hEvent := ConnectEvent.Handle;
while not Terminated do
begin
ConnectNamedPipe(Server.FPipeHandle, @opconnect);
events[0] := ConnectEvent;
THandleObject.WaitForMultiple(events, INFINITE, False, Signal);
if Signal = ConnectEvent then
try
// successful connect!
ReadEvent := TEvent.Create(nil, True, False, '');
try
FillMemory(@opread, SizeOf(TOverlapped), 0);
opread.hEvent := ReadEvent.Handle;
setlength(buffer, PIPE_MESSAGE_SIZE);
if not ReadFile(Server.FPipeHandle, buffer[0], PIPE_MESSAGE_SIZE, bytesRead, @opread) then
begin
error := GetLastError;
if error = ERROR_IO_PENDING then
begin
if not GetOverlappedResult(Server.FPipeHandle, opread, bytesRead, True) then
error := GetLastError
else
error := ERROR_SUCCESS;
end;
if error = ERROR_BROKEN_PIPE then
// ignore, but discard data
bytesRead := 0
else if error = ERROR_SUCCESS then
// ignore
else
RaiseLastOSError(error);
end;
if (bytesRead > 0) and Assigned(Server.OnReceivedData) then
Server.OnReceivedData(TEncoding.Unicode.GetString(buffer, 0, bytesRead));
// Set result to 1
PInteger(@buffer[0])^ := 1;
if not WriteFile(Server.FPipeHandle, buffer[0], SizeOf(Integer), bytesRead, @opread) then
begin
error := GetLastError;
if error = ERROR_IO_PENDING then
begin
if not GetOverlappedResult(Server.FPipeHandle, opread, bytesRead, True) then
error := GetLastError
else
error := ERROR_SUCCESS;
end;
if error = ERROR_BROKEN_PIPE then
// ignore
else if error = ERROR_SUCCESS then
// ignore
else
RaiseLastOSError(error);
end;
finally
FreeAndNil(ReadEvent);
end;
finally
DisconnectNamedPipe(Server.FPipeHandle);
end
else if Signal = Server.FShutdownEvent then
begin
// server is shutting down!
Terminate;
end;
end;
finally
FreeAndNil(ConnectEvent);
end;
end;
{ TPBPipeClient }
constructor TPBPipeClient.Create(APath: string);
begin
FPath := APath;
end;
destructor TPBPipeClient.Destroy;
begin
inherited;
end;
class procedure TPBPipeClient.SendData(APath, AData: string);
var
bytesRead: Cardinal;
success: Integer;
begin
if not CallNamedPipe(PWideChar(APath), PWideChar(AData), length(AData) * SizeOf(Char), @success, SizeOf(Integer), bytesRead, NMPWAIT_USE_DEFAULT_WAIT) then
RaiseLastOSError;
end;
procedure TPBPipeClient.SendData(AData: string);
var
bytesRead: Cardinal;
success: boolean;
begin
if not CallNamedPipe(PWideChar(FPath), PWideChar(AData), length(AData) * SizeOf(Char), @success, SizeOf(Integer), bytesRead, NMPWAIT_USE_DEFAULT_WAIT) then
RaiseLastOSError;
end;
end.
Oto jak coś wysyłam:
TPBPipeClient.SendData('\\.\pipe\pipe server E5DE3B9655BE4885ABD5C90196EF0EC5', 'HELLO');
Oto jak coś przeczytałem:
procedure TfoMain.FormCreate(Sender: TObject);
begin
PipeServer := TPBPipeServer.Create('\\.\pipe\pipe server E5DE3B9655BE4885ABD5C90196EF0EC5');
PipeServer.OnReceivedData := PipeDataReceived;
end;
procedure TfoMain.PipeDataReceived(AData: string);
begin
if AData = 'HELLO' then
// do something, but note that you're not in the main thread, you're in the pipe server thread
end;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-04 19:43:36
Dla bardzo krótkich wiadomości, WM_COPYDATA jest prawdopodobnie najłatwiejszy. Poza tym istnieje sugestia PetriW o nazwanych rurach lub gniazdach.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-04 17:29:18
Patrz JclAppInstances w JCL .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-06 09:05:52
Spójrz na ZeroMQ. Jeśli masz myśli za architekturą może radykalnie zmienić sposób myślenia. O ile miałem przeglądarkę, To mają biblioteki dla wielu języków programowania, w tym Delphi. Ale nie miałem okazji spróbować.
Oto Delphi port biblioteki.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-02 14:02:33
Sprawdź Cromis.IPC , wewnętrznie używa nazwanych pipes, ale zapewnia znacznie łatwiejsze API i jest kompatybilny z najnowszymi wersjami Delphi.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-26 12:58:07
Proponuję TMappedFile-bardziej wydajny niż nazwane rury.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-20 15:03:55
Używam InterAppComm i jest bardzo dobry.
Wysyła dane między dwoma lub więcej aplikacjami. Może wysyłać ciągi, liczby całkowite i inne typy danych.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-02 09:35:19