2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему На страницу 1, 2  След.
 
 exe в Delphi 7, dll Builder 6
Сообщение29.05.2011, 13:34 


01/07/08
836
Киев
Не получается из дельфийской экзешки передать в параметре TMemoryStream в былдеровскую dll. Тестировал на передаче из былдеровской экзешки все катит. Про применение типов PChar и (char *) мне известно. Валится, по моему, дельфийская экзешка на обращении к функции dll не успев войти в dll. Прошу совета. С уважением,

 Профиль  
                  
 
 Re: exe в Delphi 7, dll Builder 6
Сообщение29.05.2011, 13:42 
Заслуженный участник


27/04/09
28128

(Оффтоп)

Мне кажется, людям, которые захотят разобраться, в чём дело, вместо уважения будет полезнее код.

 Профиль  
                  
 
 Re: exe в Delphi 7, dll Builder 6
Сообщение29.05.2011, 14:08 


01/07/08
836
Киев

(Оффтоп)

arseniiv
Не сердитесь на меня, не хочу морочить головы своими описками.
Я описал задачу. Каждый желающий может её смоделировать. Я выкрутился из положения вообще отказавшись от передачи параметров. То есть применил LoadFromFile и SaveToFile. Но хочется передать TMemoryStream через параметр. exe(Delphi) dll(Builder).


С уважением,

 Профиль  
                  
 
 Re: exe в Delphi 7, dll Builder 6
Сообщение30.05.2011, 04:43 
Заслуженный участник


26/07/09
1559
Алматы
2hurtsy
Присоединяюсь к arseniiv'у: приведите ваш код из программы и из библиотеки. Без этого что-либо подсказать не получится -- проблема может быть в чем угодно, начиная от элементарной ошибки набора и заканчивая вопросами общего доступа к памяти. :)

 Профиль  
                  
 
 Re: exe в Delphi 7, dll Builder 6
Сообщение30.05.2011, 13:45 
Заслуженный участник
Аватара пользователя


01/08/06
3131
Уфа
1) Попробуйте в Builder-овской DLL сделать функцию __stdcall, и в API для Delphi также опишите ещё как stdcall;
2) Убедитесь, что в dpr-проекте в Delphi 1-м модулем в списке uses стоит ShareMem, и в Builder'е также убедитесь, что используется менеджер памяти из BorlndMM.dll (не помню, как в билдере это делается).

 Профиль  
                  
 
 Re: exe в Delphi 7, dll Builder 6
Сообщение30.05.2011, 19:25 


01/07/08
836
Киев
Спасибо, worm2.
Добавил, ShareMem и присоединил в билдеровских проектах MEMMGR.LIB. Билдеровская связка работает без изменений, да и делфи без изменений. Слетает в дэльэльке на том ж месте, т.е. при первом обращении к функции TMemoryStreem, в данном случае это Position.
Ниже тексты

// Форма в обоих задачах стандартная TForm с кнопкой Button1
//---------------------------------------------------------------------------

код: [ скачать ] [ спрятать ]
Используется синтаксис C++
#ifndef UnbsH
#define UnbsH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE-managed Components
        TButton *Button1;
        void __fastcall Button1Click(TObject *Sender);
private:        // User declarations
public:         // User declarations
HANDLE hlib;
 typedef int (__stdcall  *LPStartAdjustment)(char *);
    LPStartAdjustment StartAdjustment;
   

        __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

//---Вызывающий модуль Builder--------------------------
код: [ скачать ] [ спрятать ]
Используется синтаксис C++
#include <vcl.h>
#pragma hdrstop

#include "Unbs.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
TMemoryStream *b;

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
 int i,j;
    hlib=LoadLibrary("bdll.dll");
                if(hlib<(HANDLE)HINSTANCE_ERROR)
                {
                ShowMessage("Не найден dll ");
                return ;
                }


   StartAdjustment = (LPStartAdjustment )GetProcAddress(hlib,"StartAdjustment");
        if(!StartAdjustment)
        {
                ShowMessage("нет входа StartAdjustment ");
                        return ;
        }
         if (b==NULL)
         b= new TMemoryStream(); else
         b->Clear();
         b->Position=0;
         i=1;
        j=b->Write(&i,4);
        i+=20;
        j=b->Write(&i,4);
        b->Position=0;

         StartAdjustment((char *)b);
        b->Position=0;
        j=b->Read(&i,4);
        j=b->Read(&i,4);
        b->Clear();
}

//----dll в Builder ------------------------------
код: [ скачать ] [ спрятать ]
Используется синтаксис C++
#pragma argsused
 extern "C"  int   _stdcall _export  StartAdjustment(char * a )

{ int i,j;
 TMemoryStream *b;
 ShowMessage("dll  1");
 b=(TMemoryStream *)a;
 i=  b->Position;
  b->Position=0;
  j=b->Read(&i,4);
  i=i+7;
  b->Position=0;
  ShowMessage("dll  2");
  j=b->Write(&i,4);
  j=b->Read(&i,4);
  i=i+10;
  b->Position=4;
  j=b->Write(&i,4);
   ShowMessage("dll  3");
        return 0;
}

//--------Вызывающий модуль в Delphi--------------------------
код: [ скачать ] [ спрятать ]
Используется синтаксис Delphi
unit Unds;

interface

uses
  ShareMem, Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type

Tpredvar = function(a:PChar):integer; stdcall;



  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
 hlib: THandle;
 rvnstream: TMemoryStream;

  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
c1:Tpredvar;
stat:Integer;
i:Integer;
begin
  rvnstream:= TMemoryStream.Create;
  i:=1;
  rvnstream.Write(i,4);
  i:=100;
  rvnstream.Write(i,4);
  Form1.hlib:=LoadLibrary('bdll.dll');
                if(Form1.hlib=0) then
                begin

                 ShowMessage('Не найден файл bdll');
                 FreeLibrary(Form1.hlib);
                exit ;
                end;

     @c1 := GetProcAddress(Form1.hlib,PChar('StartAdjustment'));
        if(@c1=nil) then
        begin
                ShowMessage('Ошибка вызова  StartAdjustment');

      FreeLibrary(Form1.hlib);
                exit ;
        end;


     rvnstream.Position:=0;
try
  ShowMessage('exe 1');
     stat :=  c1(PChar(rvnstream));
     
except
    ShowMessage('exe break');
   rvnstream.Clear;

   exit;
end;

        ShowMessage('dll  good');
        rvnstream.Position:=0;
        rvnstream.Read(i,4);
        rvnstream.Read(i,4);

   FreeLibrary(Form1.hlib);

   rvnstream.Clear;
end;

end.
 


// С уважением,

 Профиль  
                  
 
 Re: exe в Delphi 7, dll Builder 6
Сообщение31.05.2011, 15:05 
Заслуженный участник
Аватара пользователя


01/08/06
3131
Уфа
Ничего не могу сказать, кроме как предположить несовместимость VCL от D7 и от BCB6.
В таких случаях обычно используют (передают через границу библиотек) интерфейс IStream. На вызывающей стороне можно создать IStream из любого потомка TStream с помощью вспомогательного класса TStreamAdapter. На вызываемой стороне пользуются методами IStream. Этот подход работает, если на вызывающей стороне не делается никаких предположений о структуре объекта, реализующего этот интерфейс, а используются только стандартные методы Read, Write, Seek, SetSize.

 Профиль  
                  
 
 Re: exe в Delphi 7, dll Builder 6
Сообщение31.05.2011, 21:05 


01/07/08
836
Киев
worm2 в сообщении #452229 писал(а):
На вызывающей стороне можно создать IStream из любого потомка TStream с помощью вспомогательного класса TStreamAdapter.


Спасибо, в этой языковой области я только юзер. TMemoryStream потомок TStream, зачем использовать TStreamAdapter? Извините моё непонимание, как связать понятия exe и dll с терминологией вызывающая, вызываемая?
А от менеджера памяти можно отказаться? С уважением,

 Профиль  
                  
 
 Re: exe в Delphi 7, dll Builder 6
Сообщение01.06.2011, 11:14 


01/07/08
836
Киев
worm2 в сообщении #452229 писал(а):
Ничего не могу сказать, кроме как предположить несовместимость VCL от D7 и от BCB6.

Ну да, у них(у классов D7 и BCB6 ) различные наследования, C++ имеет множественное наследование. Да может еще что нибудь, придуманное отцами-создателями языков. Получается, чтобы не было мороки с "завязыванием развязыванием шнурков", использовать LoadFromFile и SaveToFile и забыть про MEMMGR.LIB и ShareMem.pas. Может есть более "эстетичные" решения? С уважением,

 Профиль  
                  
 
 Re: exe в Delphi 7, dll Builder 6
Сообщение01.06.2011, 11:52 


03/10/06
826
Создайте класс в BCB6 от TMemoryStream, и назовите например TMemory_Stream.
В дельфи используйте этот самый TMemory_Stream. Импортиртируйте этот класс из ДЛЛ, в общем.

 Профиль  
                  
 
 Re: exe в Delphi 7, dll Builder 6
Сообщение01.06.2011, 16:18 


01/07/08
836
Киев
Спасибо, модераторам за оформление моих корявых кодов :D :D

yk2ru в сообщении #452554 писал(а):
В дельфи используйте этот самый TMemory_Stream. Импортиртируйте этот класс из ДЛЛ, в общем.


Перспективная идея, в смысле "эстетичности". На Google даже начинающим предлагают. А можно к ней "козу"? Заранее благодарен. С уважением,

 Профиль  
                  
 
 Re: exe в Delphi 7, dll Builder 6
Сообщение01.06.2011, 16:33 
Заслуженный участник
Аватара пользователя


01/08/06
3131
Уфа
hurtsy в сообщении #452390 писал(а):
TMemoryStream потомок TStream, зачем использовать TStreamAdapter?
Дело в том, что TMemoryStream в Delphi и TMemoryStream в Builder'е — две разные вещи (хотя я надеялся, что одинаковые, но, по-видимому, ошибался). И даже в разных версиях Delphi — это разные вещи, их нельзя заменять. В разных языках программирования используются разные, не совместимые друг с другом библиотеки классов, и даже сами внутренние представления классов могут различаться. IStream же — универсальный (и даже кроссплатформенный) интерфейс, им можно пользоваться для взаимодействия. TStreamAdapter умеет делать IStream из любого потомка TStream, а пользоваться IStream можно напрямую, не делая из него TStream.
Конечно, не обязательно идти по этому пути. Другие варианты Вам также предложили.

hurtsy писал(а):
Извините моё непонимание, как связать понятия exe и dll с терминологией вызывающая, вызываемая?
Функция, находящаяся в EXE, вызывает функцию, находящуюся в DLL. Значит, в EXE — вызывающая, в DLL — вызываемая.

hurtsy писал(а):
А от менеджера памяти можно отказаться?
Вероятно, в Вашем случае можно не пользоваться общим менеджером памяти, а использовать стандартные (в DLL — свой, в EXE — свой). Но в более сложных случаях (например, если Вы хотите передавать параметры типа AnsiString) он обязателен.

 Профиль  
                  
 
 Re: exe в Delphi 7, dll Builder 6
Сообщение01.06.2011, 17:15 


03/10/06
826
hurtsy в сообщении #452636 писал(а):
А можно к ней "козу"?

Было: импорт класса в Дельфи из VS C++.

В Дельфи:
Код:
TMyClass = class(TObject)
public
  procedure ResetError; virtual; stdcall; abstract;
  { functions returning info parameters }
  function Error:        DWORD; virtual; stdcall; abstract;
  function Name:         Pchar;   virtual; stdcall; abstract;
// ... other functions
end;

function CreateTMyClassObject(szName: PCHAR): TMyClass; stdcall; external 'MyDLL.dll';
procedure DestroyTMyClassObject(obj: TMyClass); stdcall; external 'MyDLL.dll';


В VC++ в '*.H' файле:
Код:
class TMyClass {
protected:
  DWORD fError;
// ...
public: 
  TMyClass (PCHAR szName_);
  ~TMyClass(void);
  virtual void  _stdcall ResetError(void);
  // functions returning info parameters
  virtual DWORD  _stdcall Error(void);
  virtual PCHAR  _stdcall Name(void);
// ... other functions
};


В VC++ в '*.C' файле:
Код:
extern "C" {
__declspec(dllexport) TMyClass * _stdcall CreateTMyClassObject(PCHAR szName)
{
  return new TMyClass(szName);
}

__declspec(dllexport) void _stdcall DestroyTMyClassObject(TMyClass * obj)
{
  delete obj; 
}

}  // extern "C"


В VC++ в '*.DEF' файле:
Код:
LIBRARY MYDLL
EXETYPE WINDOWS
EXPORTS
  CreateTMyClassObject
  DestroyTMyClassObject


Попробуйте приспособить это к связке Дельфи/CBuilder.

 Профиль  
                  
 
 Re: exe в Delphi 7, dll Builder 6
Сообщение04.06.2011, 23:28 


01/07/08
836
Киев
worm2 в сообщении #451934 писал(а):
Убедитесь, что в dpr-проекте в Delphi 1-м модулем в списке uses стоит ShareMem,


С Вашей помощью, я вроде лучше стал понимать работу с интерфейсами. Не могли бы Вы ещё обьяснить странности с использованием ShareMem. Я создал пустую форму. В Unit1 в список uses вставил первым ShareMem. Получается пустая форма без ничего лишнего лишнего. Если бы форма была квадратная а цвет черным, получается программная реализация квадрата Малевича. При закрытие формы печальное сообщение об ошибке. Убираем ShareMem и все работает штатно. Как это понимать. С уважением,

 Профиль  
                  
 
 Re: exe в Delphi 7, dll Builder 6
Сообщение06.06.2011, 12:07 
Заслуженный участник


26/07/09
1559
Алматы
2hurtsy
Падение delphi-программ, использующих sharemem, при выходе -- типичная проблема. В интернете подробно разобрано. :)

Насчет вашего кода. Я даже и предположить не мог, что вы попытаетесь указатель именно на сам объект передать. Во-первых, промежуточная передача через файл -- не так уж и некрасиво; по-крайней мере, менеджер памяти вроде sharemem тоже использует файлы, ну не настоящие конечно... Во-вторых, у TMemoryStream есть свойство Memory (если не ошибаюсь). Вот оно-то хранит именно указатель на сам буфер с данными и его (указатель) можно передавать. Честно говоря, я не знаю, как именно происходит выделение этого буфера по-умолчанию, вполне возможно, что в связке одна программа+одна библиотека необходимости в дополнительных ухищрениях по обеспечению общего доступа к памяти возникнуть не должно, т.е. может быть sharemem (или другой аналогичный менеджер, коих в интеренет опять-же предостаточно) даже и не понадобится...

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 21 ]  На страницу 1, 2  След.

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group