I have a DLL, written in Delphi, which should determine some values and then pass the results back to the C++ app, which called the DLL.
The data to be passed back to the C++ app, is a set of four integer values (but in future there may be string values as well).
In order to do this, I need to declare those integer values as being shared between calling application and the DLL.
At the C++ application side, I can do this like this (according to http://msdn.microsoft.com/en-us/library/h90dkhs0%28v=vs.80%29.aspx ):
#pragma data_seg(".SHARED")
int value1;
int value2;
// ...
int valueN;
#pragma data_seg()
How can I do the same thing (declare that value1-N are to be stored in the shared memory) in Delphi 2009?
Update, 18.09.2012: I decided to use named pipes for implementing communication of the injected DLL and the outer world.
But before I can use named pipes, I need to solve following problem.
At the moment, the process looks like this:
1) The DLL is injected into the legacy application.
2) The DLL extracts some data from the legacy application.
3) The DLL is unloaded.
I need to modify it so that it works like this:
1) The DLL is injected into the legacy application. 2) The DLL starts a loop like
bool running = true;
while (running)
{
command = receiveCommandFromInvokingApp();
if ("GET_COORDINATES".equals(command))
{
// Read coordinates of some cell in the grid
// Then communicate it via some channel to the outside world
}
else if ("READ_CELL_VALUE")
{
// Read value of some cell in the grid
// Then communicate it via some channel to the outside world
}
else if ("EXIT")
{
// Close the communication channel
// Perform cleanup work
running = false;
}
// Sleep for, say, 500 milliseconds in order to avoid 100 % CPU usage
}
receiveCommandFromInvokingApp reads next command sent from the invoking application (from named pipe or any other suitable channel).
3) When the invoking application sends the EXIT command, the DLL stops the loop.
Let's say I have following DLL code:
procedure DllMain(reason: integer) ;
begin
if reason = DLL_PROCESS_DETACH then
OutputDebugString('DLL PROCESS DETACH')
else if reason = DLL_THREAD_ATTACH then
OutputDebugString('DLL THREAD ATTACH')
else if reason = DLL_THREAD_DETACH then
OutputDebugString('DLL THREAD DETACH')
else if reason = DLL_PROCESS_ATTACH then
OutputDebugString('DLL_PROCESS_ATTACH')
end;
end; (*DllMain*)
Where (in what branch) should the loop be put?
Is it sensible to put it instead of OutputDebugString('DLL THREAD ATTACH')
?
Update 19.09.2012:
The design of my system changed and now I am sending data from Delphi DLL to a C# application via a named pipe.
Delphi code:
Opening a named pipe:
function OpenNamedPipe() : THandle;
var
hPipe : THandle;
name : string;
connectResult : LongBool;
begin
name := '\\.\pipe\delphi-to-cpp';
hPipe := CreateNamedPipe(PChar(name),
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE or PIPE_READMODE_MESSAGE or PIPE_NOWAIT,
PIPE_UNLIMITED_INSTANCES,
4096 ,
4096 ,
4096 ,
NIL);
if (hPipe = INVALID_HANDLE_VALUE) then
begin
OutputDebugString(PChar('Invalid pipe handle: ' + IntToStr(GetLastError)));
OutputDebugString(PChar(SysErrorMessage(GetLastError)));
end;
OutputDebugString(PChar('OpenNamedPipe, 1'));
connectResult := ConnectNamedPipe(hPipe, NIL);
OutputDebugString(PChar('connectResult: ' + BoolToStr(connectResult)));
OutputDebugString(PChar(SysErrorMessage(GetLastError)));
OpenNamedPipe := hPipe;
end;
Sending messages:
procedure SendMessageToNamedPipe(hPipe:THandle; msg:string);
var
dwWrite : DWORD;
lpNumberOfBytesWritten : LongBool;
MsgLength: DWORD;
MsgW : PWideChar;
begin
MsgW := PWideChar(msg);
MsgLength := lstrlenW(MsgW) * SizeOf(WideChar);
lpNumberOfBytesWritten := WriteFile(hPipe, MsgW, MsgLength, dwWrite, NIL);
if not lpNumberOfBytesWritten then
begin
OutputDebugString(PChar('Sending error: ' + SysErrorMessage(GetLastError)));
end
else
begin
OutputDebugString(PChar('Message sent, dwWrite: ' + IntToStr(dwWrite)));
end;
end;
C# code, which should read the data sent by the Delphi application:
NamedPipeClientStream pipeClient = new NamedPipeClientStream(".", "delphi-to-cpp",
PipeDirection.InOut);
new NamedPipeClientStream(".", "delphi-to-cpp",
PipeDirection.InOut);
Debug.WriteLine("Before pipeClient.Connect");
this.IsRunning = true;
pipeClient.Connect(5000);
StreamReader reader = new StreamReader(pipeClient, Encoding.Unicode);
while (this.IsRunning && pipeClient.IsConnected)
{
string message = reader.ReadLine();
Thread.Sleep(250);
}
reader.Close();
This code doesn't work - reader.ReadLine();
doesn't return anything.
If I try to read the data bytewise into a char[]
buffer, that buffer contains garbage at the end of reading.
Note that SOMETHING is actually being received by the C# application, I just don't know how to extract the text from the stream.
How should I modify my code (Delphi, C# or both) so that the text sent by the Delphi application correctly arrives at C# side?