首页 文章

将数据从Delphi DLL传递到C应用程序

提问于
浏览
0

我有一个用Delphi编写的DLL,它应该确定一些值,然后将结果传递回C app,后者调用DLL .

要传递回C app的数据是一组四个整数值(但将来也可能有字符串值) .

为了做到这一点,我需要将这些整数值声明为在调用应用程序和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[] 缓冲区,则该缓冲区在读取结束时包含垃圾 .

请注意,SOMETHING实际上是由C#应用程序接收的,我只是不知道如何从流中提取文本 .

我应该如何修改我的代码(Delphi,C#或两者),以便Delphi应用程序发送的文本正确到达C#端?

2 回答

  • 1

    Delphi工具链没有内置的功能 .

    为了在Delphi中执行类似的操作,您需要使用内存映射文件API或其他一些进程间通信(IPC)机制,例如:管道,套接字,Windows消息等

    或者,您只需从Delphi DLL加载C DLL即可 . C DLL可以访问共享数据,Delphi DLL可以调用读取和写入共享数据的C DLL中的函数 . 但是,共享数据实际上非常不适合该任务 . 使用IPC更合适 .

    你在这个问题中没有说清楚的是,这里有两个过程 . 因此需要IPC .

  • 1

    在我看来,这个解决方案存在很多问题 . 将全局变量用作返回机制的想法已经是一个非常糟糕的想法 - 如果多个进程正在运行,则不是线程安全/复杂 . 值得注意的是,DLL的所有实例都将共享此空间 .

    我肯定会:

    • 将一个空结构从C语言传递给delphi,Delphi端填充(或者你需要使用缓冲区而不是指针)或者

    • 将指向字段的指针传递给delphi进程,并允许DLL更新这些指针的值

    • 将这些结果存储在DLL中的globals中,并创建单独的FUNCTION调用以从C中检索值 . 即int getValueA()

相关问题