Передача данных из Delphi DLL в приложение C ++

У меня есть DLL, написанная на Delphi, которая должна определить некоторые значения и затем передать результаты обратно в приложение C ++, которое называется DLL.

Данные, которые должны быть переданы обратно в приложение 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()

Как я могу сделать то же самое (объявить, что значение 1-N должно храниться в общей памяти) в Delphi 2009?

Обновление, 18.09.2012: Я решил использовать именованные каналы для реализации связи внедренной 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 # через именованный канал.

Код 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;

Код 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 #?

0

Решение

Набор инструментов Delphi не имеет встроенной возможности.

Чтобы сделать что-то подобное в Delphi, вам нужно использовать API-интерфейс для отображения файла памяти или какой-либо другой механизм межпроцессного взаимодействия (IPC), например, трубы, розетки, сообщения Windows и т. д.

Или вы можете просто загрузить C ++ DLL из вашей Delphi DLL. DLL C ++ может получить доступ к общим данным, а ваша Delphi DLL может вызывать функции в C ++ DLL, которые читают и записывают общие данные. Тем не менее, общие данные действительно очень не подходят для этой задачи. Использование IPC более уместно.

В вопросе вы не совсем ясно дали понять, что здесь есть два процесса. Отсюда и необходимость в МПК.

1

Другие решения

На мой взгляд, с этим решением все в порядке. Идея использования глобальных переменных в качестве механизма возврата уже является довольно плохой идеей — она ​​не безопасна для потоков / не сложна, если запущено несколько процессов. Также стоит отметить, что все экземпляры DLL будут совместно использовать это пространство.

Я бы определенно либо:

  1. Передайте пустую структуру из C ++ в delphi, которую заполняет сторона Delphi (или вам нужно использовать строки, а не только указатели) ИЛИ

  2. Передайте указатели на поля процессу delphi и дайте DLL возможность обновить значения в этих указателях ИЛИ

  3. Сохраните эти результаты в глобальных переменных в DLL и создайте отдельные вызовы FUNCTION для получения значений из C ++. То есть int getValueA ()

1

По вопросам рекламы [email protected]