Вопрос передачи данных между DLL и приложением, где данные представлены в виде массива Variant, является актуальным для разработчиков, использующих Delphi и Pascal. В данной статье мы рассмотрим, как решить эту задачу, используя Windows API функцию "SendMessage" с WM_COPYDATA.
Проблема
Разработчик столкнулся с необходимостью передать массив Variant из DLL в приложение. Попытки использовать SendMessage с WM_COPYDATA не увенчались успехом. Это связано с тем, что WM_COPYDATA предназначен для передачи непрерывного блока данных, в то время как массив Variant в Delphi не обязательно будет структурирован таким образом.
Решение
Для решения проблемы необходимо сериализовать массив Variant перед его передачей. Однако, если приложение и DLL используют одинаковую версию RTL и передача происходит внутри одного процесса, можно передать Variant как указатель.
Пример кода для отправки данных
procedure SendData(AppHandle: HWND);
var
V: Variant;
begin
V := VarArrayOf([1, 'Some Text', 123.45, True]);
// Размер данных Variant в байтах
copyDataStruct.cbData := SizeOf(TVariantPtr) + VarArraySize(V) * SizeOf(Pointer);
copyDataStruct.lpData := @V;
copyDataStruct.dwData := copyDataStruct.cbData; // Чтобы получить правильный размер в принятой стороне
SendMessage(AppHandle, WM_COPYDATA, WPARAM(AppHandle), LPARAM(@copyDataStruct));
end;
Пример кода для приема данных
procedure WMCopyData(var Msg: TWMCopyData);
var
V: PVariant;
i: Integer;
begin
if (Msg.CopyDataStruct.dwData <> 0) then
begin
SetLength(V, (Msg.CopyDataStruct.cbData - SizeOf(Pointer)) div SizeOf(Pointer));
Move(Msg.CopyDataStruct.lpData^, V[0], Msg.CopyDataStruct.cbData);
// Работа с массивом Variant
for i := Low(V) to High(V) do
Case VType(V[i]) of
varTypeBoolean: // Обработка булевых значений
varTypeCurrency: // Обработка валютных значений
varTypeDate: // Обработка дат
varTypeDispatch: // Обработка диспетчеров
varTypeError: // Обработка ошибок
varTypeInteger: // Обработка целых чисел
varTypeNull: // Обработка пустых значений
varTypeSingle: // Обработка одиночных чисел
varTypeString: // Обработка строк
varTypeUserDefinedType: // Обработка пользовательских типов
varTypeUnknown: // Обработка неизвестных типов
varTypeVariant: // Обработка общих значений
// Добавьте соответствующие обработчики для каждого типа данных
end;
// Освобождение памяти
SetLength(V, 0);
end;
end;
Альтернативное решение
В качестве альтернативы можно использовать кастомное сообщение вместо WM_COPYDATA:
const
WM_MYCUSTOMMSG = WM_USER + 100;
procedure SendCustomData(AppHandle: HWND; const AData: PVariant);
begin
SendMessage(AppHandle, WM_MYCUSTOMMSG, 0, LPARAM(AData));
end;
procedure WMCustomData(var Msg: TMessage);
var
V: PVariant;
begin
if (Msg.Msg = WM_MYCUSTOMMSG) then
begin
V := PVariant(Msg.LParam);
// Работа с Variant
end;
end;
Заключение
Передача массива Variant через SendMessage с WM_COPYDATA требует понимания структуры данных Variant и правильной сериализации массива перед передачей. Важно также корректно обработать данные на стороне получателя. Использование кастомного сообщения может упростить процесс и избежать необходимости в сериализации данных.
Вопрос связан с передачей массива данных Variant через Windows API функцию 'SendMessage' с WM_COPYDATA для обмена данными между DLL и приложением на Delphi.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS