Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Круглый стол
  
Правила КС
>> Настройки

Фильтр вопросов
>> Новые вопросы
отслеживать по
>> Новые ответы

Избранное

Страница вопросов
Поиск по КС


Специальные проекты:
>> К л ю к в а
>> Г о л о в о л о м к и

Вопрос №

Задать вопрос
Off-topic вопросы

Помощь

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
 
 11:50 marcello
 11:47 Василий
 
 
Во Флориде и в Королевстве сейчас  11:53[Войти] | [Зарегистрироваться]
Ответ на вопрос № 68224

31-01-2009 13:12
Здравствуйте!
Столкнулся со следующей проблемой -если при вызове  функции DLL ( использующей DataModule Dll c TIdDataBase )  пропал Connect то при вызове FreeLibrary (DllHandle) виснет поток.
Это кратко. Далее опишу развернуто, для тех, кому эта тема близка, и кто в силах посоветовать.


Есть сервис, который по расписанию вызывает функции DLL.
Для каждого задания Сервис создает отдельный поток в котором и выполняет функцию :
Сервис (все стандартно) :

  Th:=TCallDll.Create(true);
        Th.FreeOnTerminate:=True;
// установка параметров потока
        Th.Resume;



Поток ( приведу полностью - чтобы понимать Лог ( ниже) :


unit ThreadCallDll;

interface

uses
  Classes, SysUtils,Activex,  Windows;

type
  TCallDll = class(TThread)
  private
  fNameJob    : string;
  fNameDll    : string;
  fNameFunc  : string;
  fParametr  : string;
  fIdJob      : integer;
    { Private declarations }
  protected
    procedure Execute; override;
 
  public

  property NameJob    :  string read fNameJob write fNameJob;
  property NameDll    :  string read fNameDll write fNameDll;
  property NameFunc  :  string read fNameFunc write fNameFunc;
  property Parametr  :  string read fParametr write fParametr;
  property IdJob      :  integer read fIdJob write fIdJob;
 
  end;
implementation

uses UAboutForm, Umain;


{ CallDll }

procedure TCallDll.Execute;
type
StandartProc = function (aName:String):String ;
var
DLLHandle : THandle;
TestProc : StandartProc;
Rez : string;
begin



  DLLHandle:=LoadLibrary(Pchar(fNameDll));
  if DLLHandle=0 then  begin
    ServiceDP.Log(IntToStr(FIdJob)+' Error Load Dll ' +FNameJob
                  +' DLL : '+FNameDll
                  +' Function: '+ FNameFunc + ' Code:' + IntToStr(GetLastError) );
    fAbout.WriteLogToBase( FIdJob,
      Exit;



end;
try
    CoInitialize(nil);
  @TestProc:=GetProcAddress ( DLLHandle,Pchar(FnameFunc));
  if (@Testproc= nil) then    begin
      ServiceDP.Log(IntToStr(FIdJob)+' Function not found ' +FNameJob
                  +' DLL : '+FNameDll
                  +' Function: '+ FNameFunc);
          Exit;

  end;
  try
  Rez:=  TestProc(FParametr)  ;

  Except
    on E: Exception do  begin


      ServiceDP.Log(IntToStr(FIdJob)+' Error DLL: '+ E.Message+ ' Task: '+FNameJob
                  +' DLL : '+FNameDll
                  +' Function: '+ FNameFunc);

    end;

  end;

  ServiceDP.Log(IntToStr(FIdJob)+' Return from DLL : '+ Rez+ ' Task: '+FNameJob
                  +' DLL : '+FNameDll
                  +' Function: '+ FNameFunc);

  finally
   

      ServiceDP.Log('Before free Library');
      FreeLibrary(DllHandle);


      ServiceDP.Log('Finish');

   
   
end;



Т.е грузится Dll( все функции одного формата - на вход строка - на выходе строка) - вызов функции - завешение потока. все протоколируется.

Ну и кусочек ДЛЛ для примера


library TestDll;

uses
  ShareMem,
  SysUtils,
  Activex,
  Classes,
  dateutils,
  jpeg,
  db,
  windows,
  graphics,
 
  TestDllDataModule in 'TestDllDataModule.pas' {DM_LoadSKD: TDataModule};

{$R *.res}

  function HelloWorld (aName : string):string ;
var
DM : TDM_LoadSKD;
  begin
  try
    try
      DM:=TDM_LoadSKD.Create(nil);

      CoInitialize(nil);
      DM.IBConn.Connected:=true;
      DM.moss_connection.Connected:=true;

      with DM do begin
      // открываем коннекшн работаем с IB и MS SQL
      // все закрыли
      end

// дошли до конца - значит все ок
      Result:='Import from SKD - OK.';
      end; // with dm

    except
        on E: Exception do begin
            Result:=('Error LoadSKD: '+ E.Message );

        end;

    end;

    finally
    if DM<>nil then FreeAndNil(DM);
    end;

  end;




вообщем все замечательно работает, пока в момент работы ДЛЛ не пропадает коннект .

Пример Лога нормальной работы :


  23.01.2009 14:15:28 2 Start task: Import data SKD DLL : TestDLL.dll Function: LoadSKD
  23.01.2009 14:16:10 2 Return from DLL : Import from SKD - OK. Task: Import data SKD DLL : TestDLL.dll Function: LoadSKD
  23.01.2009 14:16:10 2 Finished Task: Import data SKD DLL : TestDLL.dll Function: LoadSKD
  23.01.2009 14:25:28 2 Start task: Import data SKD DLL : TestDLL.dll Function: LoadSKD
  23.01.2009 14:26:12 2 Return from DLL : Import from SKD - OK. Task: Import data SKD DLL : TestDLL.dll Function: LoadSKD
  23.01.2009 14:26:12 2 Finished Task: Import data SKD DLL : TestDLL.dll Function: LoadSKD



если пропал коннект к сети ( к обеим базам (MS SQL - SDAC) InterBase - стандарт Delphi TIbDatabase  и пр.)
то лог такой :


30.01.2009 18:07:56 2 Start task: Import data SKD DLL : TestDLL.dll Function: LoadSKD
  30.01.2009 18:09:21 2 Error DLL: Error reading data from the connection Task: Import data SKD DLL : TestDLL.dll Function: LoadSKD
  30.01.2009 18:09:21 2 Return from DLL : Error LoadSKD: [DBNETLIB][ConnectionRead (recv()).]Общая ошибка сети. Обратитесь к документации по сети. Task: Import data SKD DLL : TestDLL.dll Function: LoadSKD

  30.01.2009 18:09:21 Before free Library



как видно сообщения после ФрииЛайбрери Finisk нет.

Счетчик поток показывает, что действительно поток не завершается..

Т.Е. Длл не фри и в ней застряло. Все это отлаживается под Вистой а работает На Серв2008.

У меня такое впечатление, что компонент доступа к ИБазе, кргда рухает по причине дисконнекта, пытается об этом сказать при помощи ShowMessage .. а так из под Виста+ Сервис такое не проходит... он и висит в ожидании реакции пользователя.

Что посоветуете?
Спасибо всем дочитавшим. :)

[+] Добавить в избранные вопросы

Отслеживать ответы на этот вопрос по RSS

Ответы:


Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице.
Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.

03-02-2009 08:12
Вообще-то на QC даже есть такой отчёт (сейчас вот поиском нашёл, после того, как проблему определили): QC Report #15944. К сожалению, закрыт, как плохо оформленный. Попробуйте составить воспроизводимую демку и отправить на QC.

Кстати, есть например и такой отчёт: QC Report #43714, но это не ваш случай.

03-02-2009 07:59 | Сообщение от автора вопроса
Ну наверное, благодоря активному участию Александра Алексеева, проблема решена.

Ну это же просто ..ОПА! что за компоненты Interbase идут в составе Delphi??
Где написано что нельзя их пользовать в DLL?? убил сегодня день на рытье Инета на эту тему -
проблема есть.. http://www.delphimaster.ru/cgi-bin/forum.pl?id=1215171753&n=0 вот например..
искал на форумах КодеЖир и Ембаркадеро.. как то все обходится...

Большое спасибо разработчикам прекрасного сервера Ибайс и компонетов к нему.

03-02-2009 07:13
>>> Сдалал пакет вместо длл - работает. Не знаю радоваться или печалиться.
Это говорит о том, что модули IB написаны без учёта требований DLL. Поэтому они не могут быть использованы в DLL. У вас два нормальных варианта: 1). найти другой способ связи с БД и 2). использовать пакеты. Плюс вы можете попытаться использовать грязные трюки, типа той же выгрузки DLL, что вы приводили (это может быть не единственной проблемой в IB-модулях).

По пакетам посмотрите также вот это.

03-02-2009 07:09
>>> По поводу пакета - попробую сейчас - честно говоря не очень понял что это..
Секции initialization и finalization модулей в DLL, а также begin/end в dpr файле DLL выполняются из вызова DllMain. Суть проблемы в том, что далеко не все действия допустимы в DllMain.
Вероятнее всего, у вас как раз таки проблема в том, что сейчас в вашей DLL происходят всяческие плохие вещи. Например, в IBIntf.pas есть вызов FreeIBInstallLibrary из finalization. Я подозреваю, что именно этим вызваны попытки обойти проблемы ранней выгрузкой gds32.dll.

Пакет - это та же DLL, но у которой вся работа из DllMain вынесена в отдельные функции - Initialize и Finalize. Именно поэтому, пакеты не имеют таких проблем.

03-02-2009 07:08

Давайте (временно, только для теста) вы попробуете заменить DLL пакетом. Для этого создайте новый пакет, добавьте к нему новый модуль и впишите в него вашу функцию LoadSKD + слова exports LoadSKD; Далее, собираете пакет (соглашаетесь на вопрос о подключении зависимостей по пакетам), а в главном приложении вместо Load/FreeLibrary вставляете Load/UnloadPackage. Плюс устанавливаем галочку Use run-time packages. ShareMem везде убираем. Остальное вроде бы без изменений.


Сдалал пакет вместо длл - работает. Не знаю радоваться или печалиться.

03-02-2009 05:51 | Сообщение от автора вопроса

>>> в длл проходит финализейшн - ДМ - фрее - ок.
Не понял: вот здесь DLL выгружается или нет? Программа виснет на FreeLibrary? Ваше "ок" <- это от ShowMessage? Если да, то где же проблема? Получается, что всё работает?



ок - имел ввиду что срабатывает блок


finally
      if DM<>nil then FreeAndNil(DM);


    end;



а так все по прежнему умирает на freelibrary

начитался в инете - есть такие проблемы с Ибейзом - решений не нашел
многие просто меняют компонент. Получается что (плохой)коннект к Ибейзу в Длл делать нельзя - не выгрузишь потом.

в результате блок finally в dll выгляди так:


finally
      DM.t.Commit;
      DM.IBConn.Close;
   
      Hdl := Windows.GetModuleHandle('gds32.dll'); // вроде как Ibase
      if Hdl <> 0 then
      FreeLibrary(Hdl);
      Hdl := Windows.GetModuleHandle('NETAPI32.dll'); // тоже зачемто советутю
      if Hdl <> 0 then
      FreeLibrary(Hdl);

      if DM<>nil then FreeAndNil(DM);


    end;



я понимаю что это все от лукавого.. в отладчике все что приведено выше выполняется отлично - результата нет.. фриилайбрери на мою длл не проходит. ( хотя и gds и NetApi выгружаются - видно в отладчике )..

По поводу пакета - попробую сейчас - честно говоря не очень понял что это.. счас буду разбираться.
Спасибо за участие.

03-02-2009 03:38
>>> в длл проходит финализейшн - ДМ - фрее - ок.
Не понял: вот здесь DLL выгружается или нет? Программа виснет на FreeLibrary? Ваше "ок" <- это от ShowMessage? Если да, то где же проблема? Получается, что всё работает?

>>> Я так думаю ( почти уверен) проблема в компоненте IBConn: TIBDatabase - хотя он стандартный от Delphi.
Вообще-то IBConn должен удаляться вместе с экземпляром TDM_LoadSKD в LoadSKD - ДО вызова FreeLibrary.

Давайте (временно, только для теста) вы попробуете заменить DLL пакетом. Для этого создайте новый пакет, добавьте к нему новый модуль и впишите в него вашу функцию LoadSKD + слова exports LoadSKD; Далее, собираете пакет (соглашаетесь на вопрос о подключении зависимостей по пакетам), а в главном приложении вместо Load/FreeLibrary вставляете Load/UnloadPackage. Плюс устанавливаем галочку Use run-time packages. ShareMem везде убираем. Остальное вроде бы без изменений.

03-02-2009 02:50 | Сообщение от автора вопроса
Все лишнее убрал.
Теперь dll выглядит так:


library TestDll;


uses
  ShareMem,
  SysUtils,

 
  TestDllDataModule in 'TestDllDataModule.pas' {DM_LoadSKD: TDataModule};

{$R *.res}


  function LoadSKD(aParam: String):string;


var
  DM : TDM_LoadSKD;
  begin
    try
    try
      DM:=TDM_LoadSKD.Create(nil);
      DM.IBConn.Connected:=true;
      DM.moss_connection.Connected:=true;

    except
        on E: Exception do begin
            Result:=('Error LoadSKD: '+ E.Message );

        end;

    end;

    finally
      if DM<>nil then FreeAndNil(DM);


    end;


    end;




  exports
LoadSKD;

begin
end.



Ни каких действий по выгрузке не выполнятся. А надо?
Честно говоря - это первая моя ДЛЛ. Но где то читал- можно ниче не далать:
begin
end
и все.

ДатаМодуле Длл:



nit TestDllDataModule;

interface

uses
  SysUtils, Classes, DB, IBCustomDataSet, IBQuery, IBDatabase, MemDS, DBAccess,
  MSAccess;

type
  TDM_LoadSKD = class(TDataModule)
    IBConn: TIBDatabase;
    t: TIBTransaction;
    moss_connection: TMSConnection;
   
 
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  DM_LoadSKD: TDM_LoadSKD;

implementation

{$R *.dfm}




end.



Два конекшена к Ibase и Ms Sql (sdac)

в настройках IBConn: TIBDatabase; задаю несуществующий сервер ( имя)

соответственно слетает по ессепшену при коннекте. Сообщение типа " не найден сервер" - возвращается в вызывающую программу, в длл проходит финализейшн - ДМ - фрее - ок.

На фреелайбрери бряк - встает.. по ф7 уходит на begin в длл после export и на немпо ф7 виснет.
Я так думаю ( почти уверен) проблема в компоненте IBConn: TIBDatabase - хотя он стандартный от Delphi.

Если в Длл поменять местами конекшены , т.е. вначале пытаться приконнектится к несуществующему MsSql серверу через Sdac - все работает и обрабатывается на ура, и Длл выгружается. Похоже компонент Ibase что не хочет освобождать.

03-02-2009 02:13
>>> Ну бряк в сервисе на freelibrary - ничего не дает - вообще это функция из kernel32. Что там Алесандр хочет увидеть - непонятно.
FreeLibrary выгружает библиотеку. При выгрузке библиотеки выполняется DllMain с DLL_PROCESS_DETACH. Это приводит к выполнению кода финализации библиотеки. Вашей библиотеки. А не какого-то кода из kernel32.
Поэтому я и попросил вас встать на FreeLibrary и нажать F7 - Delphi должна была остановиться на какой-то секции finalization в вашей DLL. Вам следует пройти по шагам и посмотреть, где у вас завис происходит. Разумеется, вам нужно запускать на отладку вашу DLL, а не exe-файл. Но можно также подключить отладочную информацию (опция Include TD32 debug info) в DLL и exe - тогда без разницы, что запускать, главное, чтобы Delphi нашла связь между exe/DLL и исходниками.
Также можно попробовать поставить бряк явно на DoneUnits в system.pas в DLL (разумеется, для этого надо включить Use Debug DCUs).

И посмотрите ещё Несколько причин, чтобы не делать ничего страшного в своей DllMain + пройдитесь по всем ссылкам.

03-02-2009 01:18 | Сообщение от автора вопроса
Ну бряк в сервисе на freelibrary - ничего не дает - вообще это функция из kernel32. Что там Алесандр хочет увидеть - непонятно.

Упростил задачу : форма,  на ней кнопка - нет сервисов и потоков, есть просто ДЛЛ.


procedure TForm1.Button1Click(Sender: TObject);
type
StandartProc = function (aName:String):String ;
var
DLLHandle : THandle;
TestProc : StandartProc;
begin



  DLLHandle:=LoadLibrary('TestDll');
  if DLLHandle=0 then  begin
    if GetLastError = ERROR_DLL_NOT_FOUND
    then ShowMessage('Ошибка загрузки DLL');
    Exit;



end;
try
  @TestProc:=GetProcAddress ( DLLHandle,'LoadSKD');
  if (@Testproc= nil) then    begin
      ShowMessage('Ошибка имени функции DLL');
      Exit;

  end;
  ShowMessage(TestProc('14'));

finally
    FreeLibrary(DllHandle);
    ShowMessage('ok');
end;




end;



жму кнопку - если сеть не отрывать - все ок.
если в процессе обработки отключить сеть. из длл возвращается по ексепшн сообщение ошибки ..


Error LoadSKD: [DBNETLIB][ConnectionRead (recv()).]Общая ошибка сети. Обратитесь к документации по сети.


по брейк на фрилайбрери стает.. и дальше что по ф7, что по ф8 уходит в никуда..


02-02-2009 11:33 | Комментарий к предыдущим ответам
Не уверен что под вистой в сервисе бряк сработает ( сервис в 0 сессии, из него даже иконку в таск бар не ставится и шоу мессадж не проходит).. да и честно не большой мастер отлаживать сервисы, но попробую. Спасибо.

02-02-2009 08:03 | Вопрос к автору: запрос дополнительной информации
В чём проблема поставить бряк на FreeLibrary и посмотреть под отладчиком на чём встаёт?

Добавьте свое cообщение

Вашe имя:  [Войти]
Ваш адрес (e-mail):На Королевстве все адреса защищаются от спам-роботов
контрольный вопрос:
Раз дощечка, два дощечка будет лесенка. Раз словечко, два словечко, будет ЧТО?
в качестве ответа на вопрос или загадку следует давать только одно слово в именительном падеже и именно в такой форме, как оно используется в оригинале.
Надоело отвечать на странные вопросы? Зарегистрируйтесь на сайте.
Тип сообщения:
Текст:
Жирный шрифт  Наклонный шрифт  Подчеркнутый шрифт  Выравнивание по центру  Список  Заголовок  Разделительная линия  Код  Маленький шрифт  Крупный шрифт  Цитирование блока текста  Строчное цитирование
  • вопрос Круглого стола № XXX

  • вопрос № YYY в тесте № XXX Рыцарской Квинтаны

  • сообщение № YYY в теме № XXX Базарной площади
  • обсуждение темы № YYY Базарной площади
  •  
     Правила оформления сообщений на Королевстве

    Страница избранных вопросов Круглого стола.
      
    Время на сайте: GMT минус 5 часов

    Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
    Функция может не работать в некоторых версиях броузеров.

    Хостинг предоставлен компанией DOTNETPARK (ASP.NET, MS SQL hosting)  

     
    © При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

    Яндекс цитирования