Конференция "Corba" » сервис и ADO (многопотоковый COM) [Delphi, Windows]
 
  • truegosha (19.01.07 16:33) [0]
    Объясню название темы моего сообщения. ADO ведь реализовано как COM объект. Поэтому решил обратиться именно сюда, а не в форум по базам. Ошибка очень специфичная. Но может кто сталкивался...
    На Delphi 6 писал службу с использованием API-функций. Служба эта - сервер приложений, среднее звено в трехзвенке. База MSSQL 2000. Служба многопоточная - главный поток, рабочий поток и следящий за рабочим. Рабочий поток создавал так:
    hWorkTread := CreateThread(nil, 0, @ServerProc, @StatusHandle, 0, Dummy);

    Вот процедура рабочего потока:
    procedure ServerProc (Param: Pointer); stdcall;
    var
     WorkThrStuff: TWorkThrStuff;
     client: TSimpleClient;
     cIE: HResult;
    begin
     cIE := CoInitializeEx(nil, COINIT_MULTITHREADED);
     WorkThrStuff := TWorkThrStuff.Create;
     while bWork do
     begin
       if counter = 60 then
       begin
         client := nil;
         WorkThrStuff.RefreshState(client);
         counter := 1;
       end
       else counter := counter + 1;
       Sleep(1000);
     end;
     WorkThrStuff.Destroy;
     if Succeeded(cIE) then CoUninitialize;
    end;

    Вот кусок главного потока, который обрабатывает запросы SCM:
     while Status.dwCurrentState <> SERVICE_STOPPED do
     begin
       if not firsttime then
       begin
         if fdwControl = SERVICE_CONTROL_INTERROGATE then NotifyState
         else if dwSrvCtrlToPend[fdwControl] <> 0 then
         begin
           NotifyPend(fdwControl);
           if dwSrvCtrlToPend[fdwControl] = SERVICE_STOP_PENDING then
           begin
             bWork := false;
             if WaitForSingleObject(hControlTread, INFINITE) <> WAIT_OBJECT_0 then
             begin
               MyMsg[0]:='Остановка выполняется с ошибкой!';
               ReportEvent(EventLog, EVENTLOG_WARNING_TYPE, 0, 0, nil, 1, 0, @MyMsg, nil);
             end
             else
             begin
               CloseHandle(hControlTread);
               hControlTread := 0;
             end;
             if WaitForSingleObject(hWorkTread, INFINITE) <> WAIT_OBJECT_0 then
             begin
               MyMsg[0]:='Остановка выполняется с ошибкой!';
               ReportEvent(EventLog, EVENTLOG_WARNING_TYPE, 0, 0, nil, 1, 0, @MyMsg, nil);
             end
             else
             begin
               CloseHandle(hWorkTread);
               hWorkTread := 0;
             end;
           end;
           if dwSrvPendToState[Status.dwCurrentState] <> 0 then NotifyState;
         end;
       end;
       if bWork and (fdwControl = WORKTHREAD_CRASH) then
       begin
         MyMsg[0]:='Рабочий поток упал! Перезапуск потока!';
         ReportEvent(EventLog, EVENTLOG_ERROR_TYPE, 0, 0, nil, 1, 0, @MyMsg, nil);
         counter := 1;
         hWorkTread := CreateThread(nil, 0, @ServerProc, @StatusHandle, 0, Dummy);
       end;
       if Status.dwCurrentState <> SERVICE_STOPPED then
       begin
         GetQueuedCompletionStatus(g_hIOCP, dwBytesTransferred, fdwCompKey, po, INFINITE);
         fdwControl := dwBytesTransferred;
         firsttime := false;
       end;
     end;

    В рабочем потоке полным-полно ADO компонентов. Причем для каждого клиентского приложения, подключающегося к серверу, в рабочем потоке создается свой поток. Поэтому вызываю CoInitializeEx(nil, COINIT_MULTITHREADED);
    А при выходе из рабочего потока вызываю if Succeeded(cIE) then CoUninitialize;
    На Windows 2000 работает без ошибок. А на XP после остановки службы выдается ошибка в модуле unknown. Как я понимаю, unknown - это интерфейс COM.
    Где-то читал, что CoUninitialize нужно вызывать только для процесса, а не для потоков. Пробовал и так. Вызывал в самом конце программы. Не помогло. Заказчик, как на зло собирается ставить службу на XP.
    Уже все варианты что знал - перебрал. Помогите пожалуйста! Заранее спасибо!
  • tesseract © (21.01.07 13:14) [1]
    > Как я понимаю, unknown - это интерфейс COM.

    iUnknown  - это базовый интерфейс, существует во всем COM-объектах. Попробуй отладчиком посмотреть, где ошибка.
  • Polevi © (23.01.07 08:05) [2]
    попробуй убрать
    if Succeeded(cIE) then CoUninitialize;
  • Сергей М. © (23.01.07 10:41) [3]

    > Рабочий поток создавал так:
    > hWorkTread := CreateThread(


    Нельзя так делать.
    Рано или поздно при таком способе нахватаешь "глюков" по самое нехочу.

    Используй BeginThread().
  • truegosha (24.01.07 10:01) [4]
    Спасибо всем за ответы!
    BeginThread() помогло!!!
 
Конференция "Corba" » сервис и ADO (многопотоковый COM) [Delphi, Windows]
Есть новые Нет новых   [134431   +9][b:0][p:0]