2014 dxdy logo

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

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




На страницу 1, 2  След.
 
 exe в Delphi 7, dll Builder 6
Сообщение29.05.2011, 13:34 
Не получается из дельфийской экзешки передать в параметре TMemoryStream в былдеровскую dll. Тестировал на передаче из былдеровской экзешки все катит. Про применение типов PChar и (char *) мне известно. Валится, по моему, дельфийская экзешка на обращении к функции dll не успев войти в dll. Прошу совета. С уважением,

 
 
 
 Re: exe в Delphi 7, dll Builder 6
Сообщение29.05.2011, 13:42 

(Оффтоп)

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

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

(Оффтоп)

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


С уважением,

 
 
 
 Re: exe в Delphi 7, dll Builder 6
Сообщение30.05.2011, 04:43 
2hurtsy
Присоединяюсь к arseniiv'у: приведите ваш код из программы и из библиотеки. Без этого что-либо подсказать не получится -- проблема может быть в чем угодно, начиная от элементарной ошибки набора и заканчивая вопросами общего доступа к памяти. :)

 
 
 
 Re: exe в Delphi 7, dll Builder 6
Сообщение30.05.2011, 13:45 
Аватара пользователя
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 
Спасибо, 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 
Аватара пользователя
Ничего не могу сказать, кроме как предположить несовместимость VCL от D7 и от BCB6.
В таких случаях обычно используют (передают через границу библиотек) интерфейс IStream. На вызывающей стороне можно создать IStream из любого потомка TStream с помощью вспомогательного класса TStreamAdapter. На вызываемой стороне пользуются методами IStream. Этот подход работает, если на вызывающей стороне не делается никаких предположений о структуре объекта, реализующего этот интерфейс, а используются только стандартные методы Read, Write, Seek, SetSize.

 
 
 
 Re: exe в Delphi 7, dll Builder 6
Сообщение31.05.2011, 21:05 
worm2 в сообщении #452229 писал(а):
На вызывающей стороне можно создать IStream из любого потомка TStream с помощью вспомогательного класса TStreamAdapter.


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

 
 
 
 Re: exe в Delphi 7, dll Builder 6
Сообщение01.06.2011, 11:14 
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 
Создайте класс в BCB6 от TMemoryStream, и назовите например TMemory_Stream.
В дельфи используйте этот самый TMemory_Stream. Импортиртируйте этот класс из ДЛЛ, в общем.

 
 
 
 Re: exe в Delphi 7, dll Builder 6
Сообщение01.06.2011, 16:18 
Спасибо, модераторам за оформление моих корявых кодов :D :D

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


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

 
 
 
 Re: exe в Delphi 7, dll Builder 6
Сообщение01.06.2011, 16:33 
Аватара пользователя
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 
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 
worm2 в сообщении #451934 писал(а):
Убедитесь, что в dpr-проекте в Delphi 1-м модулем в списке uses стоит ShareMem,


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

 
 
 
 Re: exe в Delphi 7, dll Builder 6
Сообщение06.06.2011, 12:07 
2hurtsy
Падение delphi-программ, использующих sharemem, при выходе -- типичная проблема. В интернете подробно разобрано. :)

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

 
 
 [ Сообщений: 21 ]  На страницу 1, 2  След.


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group