Конференция "Основная" » TIBataBase и DLL [D7, WinXP]
 
  • Maxick © (13.03.08 08:55) [0]
    Проблема следующего характера: Передовая в ДЛЛ данный объект и поимел проблему: при завершении приложения в главной форме не могу фрикнуть (DB.Free) объект DB=TIBDataBase. Вызывается исключение: Ошибка опирации с указателем. Соответственно, если мне не всвобождать DB (я ее создаю сам), то исключение: "приложение ххх.exe обратилось к адрессу хххх" и т.д.
    Собственно вопрос: с чем это связано и как с тим бороться? Варианты типа "обработай сам это исключение" не хотелось бы слюшать.
  • IntruderLab (13.03.08 09:05) [1]
    как вариант используй CoInitialize() и CoUnInicialize(), ShareMem прописаны в главной форме и в dll
  • Maxick © (13.03.08 10:15) [2]
    IntruderLab, Можно будет и попробовать. Я так понимаю, при передачи объекта (указателя) в длл и происходитв вся эта бодяга. В длл у меня форма и работа с базой (таблицы и т.п.). Форма вызывается модально и после высвобождается, но хвост от TIBDataBase остается. Причем, это единственный обект с такой траблой на моей памяти.
    Текст в длл:

    function xxx(app:TApplication; db: TIBDataBase): boolean; stdcall;
    var
     hdll: TApplication;
    begin
     hdll:= application;
     application:= app;
     DataBase:= db;  
     fmForm:= TfmForm.Create(Application);
     fmForm.ShowModal;
     fmForm.Free;
     application:= hdll;



    Соответственно вызов:

    ...
    DB.Create(self);
    ...
    //тут динамическая загрузка длл
    ...
    xxx(Application,db);
    ...
    //и в событии OnClose главной формы
    db.free;


    Весь фокус еще в том, что если фрикать в процедуре (OnCreate главной формы), где создавалась db (там же и функцию из длл вызывать) то нет проблем совсем.
  • Maxick © (13.03.08 10:17) [3]
    забыл добавить, что при динамической загрузке длл также используется соглашение stdcall.
  • Сергей М. © (13.03.08 10:24) [4]
  • Сергей М. © (13.03.08 10:37) [5]

    > и в событии OnClose главной формы
    > db.free;


    Разве это логично ?

    Уж если объект создан тобой сразу после конструирования формы (OnCreate), то и уничтожать его, очевидно, следует непосредственно перед разрушением этой формы (OnDestroy).


    > DB.Create(self);


    А это что еще за фигня ?
    Разве DB у тебя объявлен как TComponentClass ?
  • Maxick © (13.03.08 11:03) [6]

    > Сергей М. ©   (13.03.08 10:37) [5]


    Я так понял, вы про это:
    "1. В исх.кодах своих exe- и dll-проектов убираешь все касаемое параметра Appl, т.е. передача этого параметра не нужна вообще.

    2. Во всех своих проектах устанавливаешь крыжик
    Project->Options..->Packages->Build With Run-Time Packages
    и после этого полностью ребилдишь эти проекты.

    Все !! Больше никаких телодвижений делать не нужно."
    Прав?
    А про Крейт - дошло :). А про дестрой - пробовал - неканает.
  • Сергей М. © (13.03.08 11:05) [7]

    > Прав?


    Да.


    > про дестрой - пробовал - неканает


    Это же не редиска, чтобы "канать")
  • Maxick © (13.03.08 11:09) [8]
    Ладно, сейчас исходников рядом нет (нахожусь в другом месте, долеко от того компа, где все это делается), попробую - отпишусь.
  • Maxick © (13.03.08 11:17) [9]

    > Сергей М. ©

    Но всеравно не совсем въезжаю - я передаю в длл Application а не ее Handle, т.е. длл полностью привязываю к смоему аплу... Т.о., как здесь: "У твоей dll св-во MainForm объекта Application равно nil.
    Удивись, почеши репу, сделай выводы)" - не соответствует моему случаю. И с чаилдами у меня проблем никогда небыло... уже давно все в длл спихиваю, ну нравится мне так - легче в отладке больших проектов, а также в абгрейдах (патчах) у клиентов.
    Или я что-то не допонимаю? ;)
  • Сергей М. © (13.03.08 11:33) [10]

    > Или я что-то не допонимаю?


    Именно.

    Выполнение указанных в [4] рекомендаций приведет к тому, что у всех взаимодействующих модулей в составе приложения будут едиными (общими) объекты Application и Screen (и еще много чего).

    Суть проста - сборка всех взаимодействующих проектов с упомянутой опцией ведет к использованию ими одного и того же экз-ра пакета vclxx.bpl (и, самое главное, пакета rtlxx.bpl), в котором "живут" такие (весьма важные в дан.случае) глобальные объекты как Application и Screen.
  • Maxick © (13.03.08 12:16) [11]
    Суть понял. Но если, ради интереса, попробовать передавать в DLL помимо Application еще и Screen? Каков будет результат в моем случае? (незнаю почему, точнее не помню, но Screen я довно перестал передавать в ДЛЛ - видимо неувидел в этом нужды... года 3 тому назад было...)
  • Сергей М. © (13.03.08 12:24) [12]

    > еще и Screen? Каков будет результат в моем случае?


    Screen не имеет к твоей проблеме никакого отношения.
  • Maxick © (13.03.08 12:36) [13]
    Значит получается проблема именно в экземплярах (копиях) в памяти процесов. Извините за мою докапываемость, но я хочу понять именно причину. Т.о. смогу не допускать подобных ситуаций в своих прогах. Да и поняв причину - метод решения проблемы становится очевидным.
  • Сергей М. © (13.03.08 13:05) [14]

    > проблема именно в экземплярах (копиях) в памяти процесов


    Ну говоря упрощенно - да.
  • Maxick © (13.03.08 13:26) [15]
    и решение, получается, только одно - исключить размножения экземпляров Application (даже передовая и присваивая Application в ДЛЛ он есть свой). Предлагаемый Вами метод, при создании экземпляра ДЛЛ экзешником не создает отдельный Апл а присваевает ему от ехе, чем исключаются все подобные проблемы. И это единственный выход из данной ситуации. Я все правильно понял? Спасибо вам за помощь. Буду пробовать, в случае неудачи напишу.
  • Maxick © (13.03.08 19:04) [16]

    > Сергей М. ©

    Большое спасибо еще раз, все чудесно заработало без ошибок... пока... дальше посмотрим ;)
  • Maxick © (13.03.08 19:45) [17]

    > Сергей М. ©

    НЕ все протестив дал я предыдущий ответ!
    Оно заработало,т.е. там где были траблы (не меняя код) ушли. Убирая в ДЛЛ аппликашион настает кирдык функции (приложение хххх обратилось по адресу 000000 к.... 00000), при попытке фрикаль "DB" (перенЁс в Он Дестрой) таже бадяжка (приложение ххх обратилось по адресу 00000...). И самое прикольное, можно не фрикать и тогда все функции работают (без убирания в длл апла), но там где (в [2] последняя строка) все чудненько работало - перестало напрочь... пока еще я не проверял/выяснял/эксперементировал - но результат не совсем тот, к которому я готовился. тоесть, при убирании в длл апла (Application, т.е его передачу в ДЛЛ) - DLL не понимает крейта формы...
  • Игорь Шевченко © (13.03.08 23:29) [18]

    > при убирании в длл апла (Application, т.е его передачу в
    > ДЛЛ) - DLL не понимает крейта формы...


    Сам понял чего написал - дай другим понять.
  • Германн © (14.03.08 00:40) [19]

    > Сам понял чего написал - дай другим понять.
    >

    При таком французском ("аппликашион настает кирдык", "при попытке фрикаль "DB"", "таже бадяжка", "можно не фрикать", "без убирания в длл апла")  лучше не надо. Не дай бог мозги расплавятся при попытке понять.
  • Maxick © (14.03.08 08:56) [20]
    Поясню (извините госпада, могу и литературным языком выражаться, если непонятно русскими словами английское когда написано.. :) ):

    > > при убирании в длл апла (Application, т.е его передачу
    > в
    > > ДЛЛ) - DLL не понимает крейта формы...
    >
    >
    > Сам понял чего написал - дай другим понять

    В DLL было:
    function xxx(apl:TApplication; DB: TIBDataBase): boolean; stdcall;


    В DLL стало:
    function xxx(apl:TApplication; DB: TIBDataBase): boolean; stdcall;


    Подчеркнутое и есть в написаном в [17] "апл".
    Вызов в ЕХЕ соответственно тоже исправлен. Т.о. я убрал упоминания в DLL об Application, как рекомендовано в [6]. После чего вызов функции из DLL стал невозможен.
    Но если не убирать передачу Application в DLL (xxx(Aplication,DB);), то фукция вызывается безпроблем.
    Также в событии OnDestroy высвобождение объекта TIBDataBase - DB.Free вызывает Exeption.
    Сразу поправлю написаное в [2]: Читать не DB.Create(self) а DB:= TIBDataBase.Create(Self).
    Надеюсь пояснил всё? Сразу оговорюсь: пока еще я не выяснял, что я сделал не так, т.к. вчера был уже поздний час, и большая усталость. :)
    Если подталкнете в нужном направлении - буду очень признателен!
  • Maxick © (14.03.08 08:57) [21]
    Извините, в DLL Стало
    function xxx(DB: TIBDataBase): boolean; stdcall;

  • Сергей М. © (14.03.08 10:30) [22]

    > Maxick ©   (14.03.08 08:57) [21]
    >
    > в DLL Стало


    Показывай еще как "стало" в ехе - прототип, строка вызова ..
  • Maxick © (14.03.08 11:44) [23]
    В ехе:

    ...OnCreate(Sender...);
    ...
    db:= TIBDataBase.Create(Self);
    ...
    end; //end OnCreate
    ...
    Procedure....
    type
    TFunc = function(db:TIBDataBase):boolean;stdcall;
    var
    xxx: TFunc;
    hdll: THandle;
    begin
    ...
    hdll:=LoadLibrary('zzz.dll');
    @xxx:= GetProcessAddress(hdll,'xxx');
    if xxx(DB)
    then ...
    else begin
    db.free; //Здесь программа обращается по адрессу 0000...
    freeLibrary(hdll);
    Applikation.Terminate;
    exit;
    end; //if else
    freelibrary(hdll);
    end;
    ...
    procedure ...OnDestroy(Sender...);
    ...
    db.Free;


    Естественно я сейчас не копирую с исходников а по памяти и выкидывая имена и всякий ненужный в данном случае код.
  • Сергей М. © (14.03.08 11:52) [24]
    Значит проблема в потрохах самой ф-ции xxx
  • Maxick © (14.03.08 12:16) [25]
    потраха примерно выглядят так:

    function xxx(db: TIBDataBase): boolean; stdcall;
    begin
    DataBase:= db;  
    fmForm:= TfmForm.Create(Application);
    fmForm.ShowModal;
    Result:= var1;//результат принимает значение зависимое от события на форме перед закрытием ее
    fmForm.Free;

    //В самой форме
    tbTable:= TIBTable.Create(Self);
    whith tbTable do
    //Здесь я присваиваю ей Базу данных, транзакцию, датасет, имя таблицы
    ...
    //операции с таблицей, в частности работа с блоб полями через потоки (TStream), и их высвобождение
    ...
    tbTable.Free;
    trTransaction.Free;
    DataBase:= nil;//пробовал и без этого но просто DataBase.Free делать нельзя!
    DataBase.Free //верхнее пояснение и сюда же

  • Сергей М. © (14.03.08 12:19) [26]

    > DataBase:= nil;//пробовал и без этого но просто DataBase.
    > Free делать нельзя!
    > DataBase.Free //верхнее пояснение и сюда же


    Убирай нафих и то и другое.
  • Maxick © (14.03.08 12:29) [27]
    да это я ради эксперемента ставил, но никаких изменений не увидел. А вот ести оставить DataBase.Free то заново придется в exe с DB колупаться (DataBaseName, Open и т.п.). По этому не использую. Вот только и с этими строками и без них вчера пробовал - разницы нуль.
  • Сергей М. © (14.03.08 12:32) [28]

    > и с этими строками и без них вчера пробовал - разницы нуль


    Ну тогда продолжай "колупаться", если "разницы нуль")
  • Maxick © (14.03.08 12:40) [29]
    вот здесь не соглашусь, если выполнить DataBase.Free то придется "колупаться", а если DataBase:= Nil то (покрайней мере проверял до выполнения рекомендаций [4]) в exe компонент DB остается нетронутым (не высвобожденым, с conection = true;).
    Ну это ладно, уберу эти строки. Но я не думаю что в этом проблема,т.к. я использую подобным образом далеко не одну DLL, и эти строки только в одной, а не работают все (которые с формами и используют TIBDataBase) функции из DLLок.
  • Maxick © (14.03.08 12:41) [30]

    > Но я не думаю что в этом проблема

    точнее НЕ в этом :)
  • Сергей М. © (14.03.08 12:48) [31]

    > Maxick ©   (14.03.08 12:40) [29]


    > если выполнить DataBase.Free то


    .. то нефих делать это повторно, как это делаешь ты в своем ехе (смотри свои страдания с "фриканьем")

    Убийство единожды убиенного карается AV-исключением, что ты и имел "удовольствие" прочувтсвовать)
  • Maxick © (14.03.08 12:54) [32]
    > Сергей М. ©   (14.03.08 12:48) [31]

    Я понимаю, что речь идет о

    > db.free; //Здесь программа обращается по адрессу 0000...
    >
    > freeLibrary(hdll);
    > Applikation.Terminate;
    > exit;
    > end; //if else
    > freelibrary(hdll);
    > end;
    > ...
    > procedure ...OnDestroy(Sender...);
    > ...
    > db.Free;


    ?
    Ведь в тексте не просто так я дописал:
    > db.free; //Здесь программа обращается по адрессу 0000...
    и это еще долеко до OnDestroy.
    Когда я писал тот фрагмент сразу подумал, что так и поймете о том, что два раза пытаюсь выполнить Free, но я вас огарчу, в тексте идет:
    if DB<>nil then DB.Free


    Может и не совсем коректно, но до тута программа всеравно не добирается...
  • Сергей М. © (14.03.08 13:04) [33]

    > два раза пытаюсь выполнить Free


    А так оно и есть на самом деле)

    И dll тут вообще ни причем - теми же гряблями ты получишь по тому же лбу, где бы ни находилась ф-ция xxx.


    > но я вас огарчу, в тексте идет: if DB<>nil


    Я не вижу подобной проверки в твоем тексте.

    А даже если бы она и была, то для успешной работы возложенной на эту проверку логики ты обязан обNILить указатель при первом же уничтожении объекта, на который этот указатель ссылается.

    Да и нафих, спрашивается, уничтожать в dll этот объект, если dll не вправе распоряжаться его жизнью, хотя бы по причине того, что объект этот был передан в dll из создавшего его exe во временное пользование ?

    А если так хочится приложить в dll свои шаловливые ручки к уничтожению объекта, то и создавать его изволь в той же dll !
  • Maxick © (14.03.08 13:04) [34]

    > Сергей М. ©

    У меня появилась мысль, что я сделал не так... через пару часов проверю, а то может зря почем раздую проблему..
  • DrPass © (14.03.08 15:37) [35]

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

    У меня тоже. Ты ж передаешь компоненту в библиотеку. uses ShareMem в dpr-файлах приложения и библиотеки написать не забыл?
  • Сергей М. © (14.03.08 15:39) [36]

    > DrPass ©   (14.03.08 15:37) [35]


    За каким лешим ему ШароМем, если он последовал (якобы) рекомендации в [4] ?
  • DrPass © (14.03.08 16:11) [37]

    > За каким лешим ему ШароМем, если он последовал (якобы) рекомендации
    > в [4] ?

    Ну здрасьте. Он же передает TIBDatabase, не так ли? Не знаю, что там за рекомендации в [4], перечитывать весь тот тред неохота, но передача компоненты параметром в DLL - это уже фактически означает необходимость использования "межмодульного" менеджера памяти.
  • Сергей М. © (14.03.08 16:15) [38]

    > передача компоненты параметром в DLL - это уже фактически
    > означает необходимость использования "межмодульного" менеджера
    > памяти


    Вовсе не обязательно.
    Все зависит от конкретной ситуации.
    Но если общий менеджер таки необходим, то BwRTP как раз и организует его (и много чего еще кроме оного)
  • Maxick © (17.03.08 05:59) [39]
    Нашел я свою ошибку. Дело было вовсе не в DB.Free. У меня в некоторых DLL были не модальные вызовы форм, так вот для этого у меня были initdll и donedll. В InitDll было Form1:= TForm1.Create(Application), а в DoneDll: Form1.Free. Вот  DoneDll и вызывало ошибку: "..обратилась по адресу 0000...". Убрав DoneDll все стало работать.
  • Сергей М. © (17.03.08 08:26) [40]

    > а в DoneDll: Form1.Free


    > Убрав DoneDll все стало работать


    Те же фаберже, только вид сбоку - где-то присутствует попытка повторного уничтожения объекта, только в д.сл. этим объектом является объект-форма.
  • Maxick © (17.03.08 09:02) [41]
    По логике вещей - да. Но не вижу где.

    function InitDll():boolean; stdcall;
    begin
    Form1:= TForm1.Create(Application);
    Result:= true;
    end;

    function DoneDll():boolean; stdcall;
    begin
    Form1.Free;
    Result:= true;
    end;

    Function ShowForm(): boolean; stdcall;
    begin
    form1.show;
    Result:= true;
    end;



    Вызыв:
    var//глабальные переменные
    hdll: THandle;
    ..OnCreate(sender);

    begin
    ...
    hdll:=LoadLibrary('zzz.dll');
    @InitDll:= getprocadress(hdll,'InitDll');
    ItitDll;
    ...
    OnDestroy
    DaneDll;
    FreeLibrary(hdll);
    ...
    OnClick (кнопочка на главной форме)
    ShowForm;



    Тоесть все по класической схеме.
  • Сергей М. © (17.03.08 09:26) [42]

    > Form1:= TForm1.Create(Application);


    Application здесь от балды написано ?
    Или ты понимаешь смысл именно такого указания ?
  • Сергей М. © (17.03.08 09:30) [43]
    stdcall тоже от балды указано ?
    Это, конечно, не принципиально, но нельзя же бездумно сдувать чужой код, "заточенный" под чиную специфику)
  • Maxick © (17.03.08 10:08) [44]

    > Form1:= TForm1.Create(Application);

    Сделано для указания родителя, вовсе не бездумно. Мне нужно, чтоб наследовала форма некоторые свойства от Application.
    А по поводу StdCall - это для того, чтоб работали мой длл не только с моим приложением. Теорию я знаю, и бездумно не сдираю чужие коды - этож класика ...
  • Leonid Troyanovsky © (17.03.08 10:13) [45]

    > Maxick ©   (17.03.08 10:08) [44]

    > А по поводу StdCall - это для того, чтоб работали мой длл
    > не только с моим приложением. Теорию я знаю, и бездумно

    Сказка про белого бычка.

    --
    Regards, LVT.
  • Maxick © (17.03.08 10:48) [46]

    > Leonid Troyanovsky ©   (17.03.08 10:13) [45]

    а попробуй без соглашения CtdCall вызвать функцию из DLL написаной на Delphi в С++...
  • Сергей М. © (17.03.08 12:37) [47]

    > Сделано для указания родителя, вовсе не бездумно. Мне нужно,
    >  чтоб наследовала форма некоторые свойства от Application.


    Ни "родительские" ни "наследственные" отношения не имеют к параметру Owner никакого отношения.

    Owner - это владелец, а не "родитель" и тем более не "предок".


    > Теорию я знаю, и бездумно не сдираю чужие коды - этож класика


    Да-да, оно заметно.


    > попробуй без соглашения CtdCall вызвать функцию из DLL написаной
    > на Delphi в С++


    Ну и какой нафих Application в C++ ? И c какой луны там взялся TIBDatabase, который ты вознамерился передать в свою dll ?
 
Конференция "Основная" » TIBataBase и DLL [D7, WinXP]
Есть новые Нет новых   [134483   +44][b:0][p:0.002]