Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > C++ и Delphi DLL: проблема с потоками


Автор: hvzh 12.4.2011, 10:42
Доброе время суток!
У меня возникла проблема с вызовом функции из паскалевой DLL. Суть проблемы: имеется прога, написанная на VC++ и Delphi DLL, функции которой юзает сишная прога. В одной из паскалевых функций создается поток. Как только сишная прога вызывает эту функцию, происходит отвал. Вот пример тестовой проги:

Код

#include "stdafx.h"
#include <stdio.h>
#include <conio.h>
#include <Windows.h>

typedef bool(__stdcall *SealControllerType)(int);
typedef bool(__stdcall *SealControllerType1)();

int _tmain(int argc, _TCHAR* argv[])
{
    int par = 4;
    SetDllDirectory(TEXT("g:\\"));
    HMODULE hdll = ::LoadLibrary(TEXT("SealController.dll"));
    if(hdll)
    {
        printf("Dll is loaded\n");
        SealControllerType f = (SealControllerType)::GetProcAddress(hdll, "InitController");
        printf("Assa1\n");
        if(!f)
            printf("Can not find function InitController\n");
        else
        {
            printf("Before calling function InitController\n");
            bool s = f(1);  // ВОТ ЗДЕСЬ ОТВАЛИВАЕТСЯ (ВЕРНЕЕ, КОД ИСПОЛНЯЕТСЯ ДО КОНЦА, НО ПРИ СОЗДАНИИ ПОТОКА В ЭТОЙ ФУНКЦИИ ПРОИСХОДИТ ОТВАЛ)
            printf( "InitController: %d\n", s );
        }

        SealControllerType1 g = (SealControllerType1)::GetProcAddress(hdll, "GetControllerStatus");
        if(!f)
            printf("Can not find function GetControllerStatus\n");
        else
        {
            printf("Before calling function GetControllerStatus\n");
            bool s = g();
            printf( "GetControllerStatus: %d\n", s );
        }
        ::FreeLibrary(hdll);
    }
    else 
        printf("DLL not found... Is it exists? Error = %d\n", GetLastError());
    system("PAUSE");
    return 0;
}


Есть ли у кого идеи по поводу того, в чем может быть проблема. Любую дополнительную инфу за исключением паскалевых исходников могу предоставить.

Автор: Dem_max 12.4.2011, 10:59
что значит происходит отвал ???

Автор: hvzh 12.4.2011, 11:01
Цитата(Dem_max @ 12.4.2011,  10:59)
что значит происходит отвал ???

Unhandled exception at 0x002a45f1 in SafeTest.exe: 0xC0000005: Access violation writing location 0x00000004.

Автор: Dem_max 12.4.2011, 11:04
приведи код паскаля этой функции и объявление этой функции для экспорта 

Автор: hvzh 12.4.2011, 11:27
Цитата(Dem_max @ 12.4.2011,  11:04)
приведи код паскаля этой функции и объявление этой функции для экспорта

Существует функция со следующим объявлением:
Код

function InitController(AComNum: Integer): boolean; cdecl;


Последним шагом в ней - создание потока с использованием следующих функций:


Код

unit ZThread;

interface

uses
   SysUtils, Classes, DateUtils;

type
   TCheckStatusThread = class(TThread)
   public
      gLastCheckStatusTime,
      gLastWatchdogPingTime : TDateTime;
      gOldStatusByte1,
      gOldStatusByte2,
      gOldStatusByte3,
      gOldStatusByte4 : Byte;
      procedure Execute; override;
   end;

var
   gCheckStatusThread: TThread = nil;

procedure StartCheckStatusThread;
procedure StopCheckStatusThread;


implementation

uses
  ZapaykaController, FillyUtils;

procedure StartCheckStatusThread;
begin
   if gCheckStatusThread <> nil then
      Exit;
   gCheckStatusThread := TCheckStatusThread.Create(False);
end;


procedure StopCheckStatusThread;
begin
   gCheckStatusThread.Terminate;
end;

{ TCheckStatusThread }

procedure TCheckStatusThread.Execute;
var   b1, b2, i, j: Byte;
begin
  inherited;
  gLastCheckStatusTime := Now;
  while not Terminated do begin
    try
    continue;

    except
    end;
    Sleep(1);
  end;
end;

end.


Этот поток в данный момент ничего не выполняет, но ошибка при его создании тем не менее возникает

Автор: Dem_max 12.4.2011, 11:31
у тебя паскалевская функция экспортируется как __cdecl, а ты в сишной проге пытаешься ее импортировать как __stdcall, вот и получаешь свой эксепшн.

Автор: hvzh 12.4.2011, 11:36
Цитата(Dem_max @ 12.4.2011,  11:31)
у тебя паскалевская функция экспортируется как __cdecl, а ты в сишной проге пытаешься ее импортировать как __stdcall, вот и получаешь свой эксепшн.

Сорри, это рудимент, поскольку пробовались и __cdecl и __stdcall. На данный момент и там, и там __stdcall

Автор: Dem_max 12.4.2011, 11:47
тогда я не вижу паскалевского кода с функцией InitController

Автор: GremlinProg 12.4.2011, 11:49
в принципе, можно отладить паскалевскую библиотеку и посмотреть, что там не так,
а вот по коду придерусь только пожалуй к этому:
Цитата(hvzh @  12.4.2011,  13:27 Найти цитируемый пост)

procedure TCheckStatusThread.Execute;
var   b1, b2, i, j: Byte;
begin
  inherited;
  gLastCheckStatusTime := Now;
  while not Terminated do begin
    try
    continue;
    except
    end;
    Sleep(1);
  end;
end;

разве унаследованный TThread.Execute не поднимает исключение, может все же убрать эту строку?

Автор: hvzh 12.4.2011, 11:51
Цитата(Dem_max @ 12.4.2011,  11:47)
тогда я не вижу паскалевского кода с функцией InitController

Вот полный кусок кода:
Код

 function InitController(AComNum: Integer): boolean; stdcall; export;
begin
  Result := False;
  gController.COMPortNum := AComNum;
  gController.SaveFluidLog := False;
  gController.SaveCMDLog := False;
  Result := gController.OpenCOMPort;
end;

function TcntrZapayka.OpenCOMPort: boolean;
begin
   Result := False;
   try
      CloseCOMPort;
      if not InitCOMPort(FCOMPortNum, cS_COM9600) then
         Exit;
      StartCheckStatusThread;
   except
      on e: Exception do
         raise EZapaykaController.Create('InitCOMPort function error: ' + e.Message);
   end;
   Result := True;
end;


Слетает при вызове StartCheckStatusThread в функции OpenCOMPort

Автор: Dem_max 12.4.2011, 12:03
Это жесткий код тоже, грохать поток вместо того чтобы корректно его завершить.
Код

procedure StopCheckStatusThread;
begin
   gCheckStatusThread.Terminate;
end;

Автор: hvzh 12.4.2011, 12:07
Код паскалевый писал не я, доступа ко всему коду нет, так что отладиться не могу

Автор: Dem_max 12.4.2011, 12:09
Тогда бессмыслено искать ошибки в закрытом коде

Автор: hvzh 12.4.2011, 12:13
GremlinProg, 
inherited убрал он, все равно Access violation

Автор: Alca 12.4.2011, 12:18
Цитата

Это жесткий код тоже, грохать поток вместо того чтобы корректно его завершить.код Pascal/Delphi
Цитата

procedure StopCheckStatusThread;
begin
   gCheckStatusThread.Terminate;
end;


VCL-вский метод класса TThread как раз это и делает, т.е. ставить флаг завершения работы потока (это не апишная функция ::TerminateThread).
Название подобрано неудачно

Автор: hvzh 12.4.2011, 13:01
Даже вот так работать не хочет:
Код


procedure TCheckStatusThread.Execute;
begin
   Exit;
end;


и 

Код
 
procedure TCheckStatusThread.Execute;
begin
   while not Terminated do
     continue;
   Exit;
end;

 Поток-то вообще ничего не делает, а как только стартует, то сразу отваливается...

Автор: GremlinProg 13.4.2011, 06:59
возможно проблема в интерпретации типа bool/boolean в разных IDE,
либо в разности выравнивания их в стековом фрейме,
попробуй избавиться от bool/boolean, заменив их на виндовый BOOL в определениях функций с обеих сторон: экспорт/импорт

Автор: Dem_max 13.4.2011, 08:08
тогда уж заменить на DWORD значение, хотя проблем с парой bool - boolean нету. 

Автор: borisbn 13.4.2011, 10:39
hvzh, ты же сам "отваливаешь" dll-ку
Цитата(hvzh @  12.4.2011,  10:42 Найти цитируемый пост)
        ::FreeLibrary(hdll);


Автор: Dem_max 13.4.2011, 11:27
мда, хитрый косяк.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)