0

Delphiで記述されたDLLがあります。これは、いくつかの値を決定し、その結果をDLLと呼ばれるC++アプリに返す必要があります。

C ++アプリに返されるデータは、4つの整数値のセットです(ただし、将来的には文字列値も存在する可能性があります)。

これを行うには、これらの整数値を呼び出し元のアプリケーションと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')ですか?

2012年9月19日更新:

システムの設計が変更され、名前付きパイプを介してDelphi DLLからC#アプリケーションにデータを送信しています。

Delphiコード:

名前付きパイプを開く:

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;

Delphiアプリケーションによって送信されたデータを読み取る必要があるC#コード:

  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#アプリケーションによって受信されていることに注意してください。ストリームからテキストを抽出する方法がわかりません。

Delphiアプリケーションによって送信されたテキストがC#側に正しく到着するように、コード(Delphi、C#、またはその両方)をどのように変更する必要がありますか?

4

2 に答える 2

1

私の意見では、この解決策には多くの間違いがあります。戻りメカニズムとして使用されるグローバル変数のアイデアは、すでにかなり悪いアイデアです。複数のプロセスが実行されている場合、スレッドセーフ/複雑ではありません。DLLのすべてのインスタンスがこのスペースを共有することにも注意してください。

私は間違いなくどちらかです:

  1. 空の構造体をC++からDelphiに渡し、Delphi側が入力します(または、ポインタだけでなくバッファを使用する必要がある文字列)または

  2. フィールドへのポインタをデルファイプロセスに渡し、DLLがこれらのポインタの値を更新できるようにします。または

  3. これらの結果をグローバルにDLLに格納し、C++から値を取得するための個別のFUNCTION呼び出しを作成します。つまり、int getValueA()

于 2012-09-17T11:14:23.440 に答える
1

Delphi ツールチェーンには、その機能が組み込まれていません。

Delphi で同様のことを行うには、メモリ マップド ファイル API、またはパイプ、ソケット、Windows メッセージなどの他のプロセス間通信 (IPC) メカニズムを使用する必要があります。

または、Delphi DLL から C++ DLL を単純にロードすることもできます。C++ DLL は共有データにアクセスでき、Delphi DLL は共有データを読み書きする C++ DLL 内の関数を呼び出すことができます。ただし、共有データは実際にはこのタスクにはあまり適していません。IPC を使用する方が適切です。

質問で明確にしなかったのは、ここには2つのプロセスがあるということです。したがって、IPC が必要です。

于 2012-09-17T11:11:11.010 に答える