我有一个用Delphi编写的DLL,它应该确定一些值,然后将结果传递回调用DLL的C ++应用程序。
要传递回C ++应用程序的数据是一组四个整数值(但将来也可能有字符串值)。
为了做到这一点,我需要将这些整数值声明为在调用应用程序和DLL之间共享。
在C ++应用程序端,我可以这样做(根据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()
如何在Delphi 2009中执行相同的操作(声明value1-N将存储在共享内存中)?
更新,2012年9月18日:我决定使用命名管道来实现注入的DLL和外部世界的通信。
但在我使用命名管道之前,我需要解决以下问题。
目前,流程如下:
1)DLL被注入遗留应用程序。
2)DLL从遗留应用程序中提取一些数据。
3)卸载DLL。
我需要修改它,以便它像这样工作:
1)DLL被注入遗留应用程序。 2)DLL启动类似
的循环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读取从调用应用程序发送的下一个命令(来自命名管道或任何其他合适的通道)。
3)当调用应用程序发送EXIT命令时,DLL将停止循环。
假设我有以下DLL代码:
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*)
循环的位置(在哪个分支中)?
将其替换为OutputDebugString('DLL THREAD ATTACH')
是否明智?
更新19.09.2012:
我的系统设计发生了变化,现在我通过命名管道将数据从Delphi DLL发送到C#应用程序。
德尔福代码:
打开命名管道:
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;
发送消息:
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#代码,应该读取Delphi应用程序发送的数据:
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();
此代码不起作用 - reader.ReadLine();
不会返回任何内容。
如果我尝试按字节顺序将数据读入char[]
缓冲区,则该缓冲区在读取结束时包含垃圾。
请注意,C#应用程序实际上正在接收SOMETHING,我只是不知道如何从流中提取文本。
我应该如何修改我的代码(Delphi,C#或两者),以便Delphi应用程序发送的文本正确到达C#端?
答案 0 :(得分:1)
Delphi工具链没有内置的功能。
为了在Delphi中执行类似的操作,您需要使用内存映射文件API或其他一些进程间通信(IPC)机制,例如:管道,套接字,Windows消息等。
或者,您只需从Delphi DLL加载C ++ DLL即可。 C ++ DLL可以访问共享数据,Delphi DLL可以调用C ++ DLL中读取和写入共享数据的函数。但是,共享数据实际上非常不适合该任务。使用IPC更合适。
你在问题中没有说清楚的是,这里有两个过程。因此需要IPC。
答案 1 :(得分:1)
在我看来,这个解决方案存在很多问题。将全局变量用作返回机制的想法已经是一个非常糟糕的想法 - 如果多个进程正在运行,则不是线程安全/复杂。值得注意的是,DLL的所有实例都将共享此空间。
我绝对会:
将一个空的结构从C ++传递到Delphi端的Delphi(或者你需要使用缓冲区而不仅仅是指针)或者
将指向字段的指针传递给delphi进程,并允许DLL更新这些指针的值或者
将这些结果存储在DLL中的globals中,并创建单独的FUNCTION调用以从C ++中检索那些值。即int getValueA()