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#、またはその両方)をどのように変更する必要がありますか?