我用delphi调用一个C语言编写的dll,每次都是第一次执行正常,第二次就出错了。但是同样的调用直接用按钮调用就没事!procedure TPrm_Proxy.IdTCPServer_DB_TuxedoExecute(AThread: TIdPeerThread);
Var
  StrRe:String;
  StrArrRe:Array [0..19] of String;
  StrMobileNumber,StrPwd:String;
  Stra,Strb,Strc,Strd:pChar;
  IntRe:integer;  Handle:   THandle;
  Auth:   TMyApp;
begin
   if   not   AThread.Terminated   and   AThread.Connection.Connected   then     //注意这里
    begin
StrRe:=AThread.Connection.ReadLn();
     MemoDealInfo.Lines.Add('--->'+DateTimeToStr(Now)+':收到来自客户端'+ AThread.Connection.Socket.Binding.PeerIP+':'+inttoStr        (AThread.Connection.Socket.Binding.PeerPort)+'的请求信息:'+StrRe);        //拆分客户端传来的(日志、Tuxedo请求)信息A|B|C
        SplitString(StrArrRe,StrRe,'|');        //查看是tuxedo服务请求还是日志存储请求
        if(SameText(StrArrRe[0],'Log')) then
        begin
            try
         DataModule_t.SaveLogInfo(StrArrRe[1],StrToInt(StrArrRe[2]),StrArrRe[3]);
     MemoDealInfo.Lines.Add('<---'+DateTimeToStr(Now)+':已存储日志信息:'+StrRe);
            except
        
           Athread.Connection.DisconnectSocket;
         AThread.Connection.Disconnect;
             Exit;
            end;        
           Athread.Connection.DisconnectSocket; 
         AThread.Connection.Disconnect;
         end; //if log
        if(SameText(StrArrRe[0],'Tuxedo')) then
        begin
            Stra:='13381260003';
            Strb:='001662';
            IntRe:=-9999;
            IntRe:=User_Auth(Stra,Strb) ;//调用dll
        try
                AThread.Connection.WriteLn(inttostr(IntRe));
     MemoDealInfo.Lines.Add('<---'+DateTimeToStr(Now)+':已处理Tuxedo请求:'+inttostr(IntRe));
        except
           Athread.Connection.DisconnectSocket;
         AThread.Connection.Disconnect;
             Exit;
         end;
          Athread.Connection.DisconnectSocket;
          AThread.Connection.Disconnect; 
        end; //if tuxedo
    end;// not   AThread.Terminated 
end;===============================================================================
第2种方法
procedure TPrm_Proxy.Button3Click(Sender: TObject);
var
  Str2,Str3:pChar;
b_ok:integer;
begin    Str2:='13381260003';
    Str3:='001662';
    b_ok:=-9999;
    b_ok:=User_Auth(Str2,Str3) ;  //调用dll
end;
用2种方法每次都成功的,可是第一种方法只有第一次调用会成功,第二次调用,要么就是dll里面的Tpinit失败,或者调用tuxedo服务失败!dll在C里面这么声明的extern "C" _declspec(dllexport) int User_Auth(char * cMobileNumber,char* cPwd);delphi里面静态掉的 function User_Auth(cMobileNumber:pChar;cPwd :pChar  ):integer;cdecl;
   external 'Tuxedo_Auth.dll';    另外,里面用的是indy的IDTCPserver组件,工程里面还有ODAC组件,都是第三方的。现在定位了一天多了,还是一筹莫展,往高手不吝赐教,不然明天还得加班!

解决方案 »

  1.   

    第一种方法 
    注释这行看看有没有问题 
     IntRe:=User_Auth(Stra,Strb) ;//调用dll 如果没有问题,说明问题出在这行,因为IdTCPServer_DB_TuxedoExecute是个线程回调函数,User_Auth函数引用的资源可能没有考虑线程同步或者资源有冲突,如果有dll的代码研究一下就能判断出来了否则在User_Auth(Stra,Strb)前后加个信号量同步一下线程看看还有没有问题
    WaitForSingleObject如果注释了IntRe:=User_Auth(Stra,Strb) ;//调用dll 依然有问题说明问题不在dll函数上了,检查别的吧
      

  2.   

    顶2楼,2楼提供的调试方法很好,俺也怀疑是同步的问题。。对dll调用使用线程同步再试一试!
      

  3.   

    嗯,我几乎所有的可能性都验证过了,也考虑到了线程同步或者资源冲突的问题,当然没有找到切实可行的办法解决。dll肯定是没有问题的,因为如果不是在IdTCPServer_DB_TuxedoExecute这里执行,它的运行一直都是正常的。我先试着用monkchen 的方法再改改试试。谢谢大家,请继续关注
      

  4.   

    IntRe:=WaitforSingleObject(User_Auth(Stra,Strb),100);我这样修改之后,一次都不成功了~monkchen,我这样写对不??
      

  5.   

    对了,我关掉程序,再执行一次就可以登陆一次。但后面几次一样不行。我不知道关掉程序以及再打开程序,对idtcpserver有什么影响。
      

  6.   

    把MemoDealInfo.Lines.Add...... 全部注释掉试试,这些代码不是线程安全的。
      

  7.   

    又用这种方法调用了,还是不行。看来只要放在线程当中就不行?program Server;{$APPTYPE CONSOLE}uses
      SysUtils,
      Winsock,
      Windows;type
      TParam=record
        TrdId:integer;
        Sckt:TSocket;
      end;  function User_Auth(cMobileNumber:pChar;cPwd :pChar  ):integer;cdecl;
       external 'Tuxedo_Auth.dll';function SplitString(var arstr: array of string; const Source: string; ch: Char): integer;
    var
      i, head: Integer;
    begin
      result := 0;  if Source = '' then
      begin
        arstr[1] := '';
        inc(result);
        exit;
      end;  head := 1;
      for i := 1 to length(Source) do
      begin
        if Source[i] = ch then
        begin
          arstr[result] := copy(Source, head, i - head);
          head := i + 1;
          inc(result);
        end;
      end;
      arstr[result] := copy(Source, head, length(Source) - head + 1);
      inc(result);
    end;
    /////////////////////////////////////////////////////////////////////////////
    //子线程函数
    function ChildThrd(p:Pointer):LongInt;stdcall;
    var
      PkLen:integer;
      ThreadId:integer;
      ASocket:TSocket;
      buf:array[0..63] of char;
      //StrArrRe:Array [0..19] of String;
      r:integer;
      a,b:pChar;
    begin
      Result:=0;
      ThreadId:=TParam(p^).TrdId;
      ASocket:=TParam(p^).Sckt;
      Writeln('Thread '+IntToStr(ThreadId)+' Create');
      PkLen:=1;
      while PkLen>0 do
      begin
        FillChar(buf,SizeOf(buf),0);
        PkLen:=Recv(ASocket,buf,SizeOf(buf),0);  //接收数据
        //-------------------------------------------------
        a:='133########';
        b:='0016##';
        //-------------------------------------------------
        r:=User_Auth(a,b);   //调用dll
        Writeln('result is :' +inttostr(r));
        Write(buf);
        if PkLen>0 then
        begin
          Send(ASocket,buf,PkLen,0);//发送数据
        end;
      end;
      CloseSocket(ASocket); //关闭socket
      Dispose(p);
      Writeln('Thread \'+IntToStr(ThreadId)+' End\');
      Writeln('Socket \'+IntToStr(ASocket)+' DisConnect\');
    end;//主程序
    var
      MyWSA: WSAData;
      Svr,Clt: TSockAddr;
      NameLen:Integer;
      hSocket,s: TSocket;
      TimeOut:integer;
      ThreadCount:integer;
      hThread:Thandle;
      ThreadID:DWord;
      Param:^TParam;   
    begin
      If WSAStartup(MAKEWORD(2,2), MyWSA) <> 0 Then  //初始化
      Begin
        WSACleanup;
        Writeln('WSAStartup() Fail\');
        Exit;
      end;
      hSocket := Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //创建socket
      If hSocket = INVALID_SOCKET Then
      Begin
        WSACleanup;
        Writeln('Socket() Fail\');
        Exit;
      End;
      Svr.sin_family := AF_INET;
      Svr.sin_port := htons(9999); //server端口号为9999
      Svr.sin_addr.S_addr := inet_addr(PChar('127.0.0.1'));//server的ip地址为127.0.0.1
      If Bind(hSocket, Svr, SizeOf(Svr)) = SOCKET_ERROR Then  //绑定socket
      Begin
        CloseSocket(hSocket);
        WSACleanup;
        Writeln('Bind() Fail\');
        Exit;
      end;
      if Listen(hSocket,256) = SOCKET_ERROR Then  //socket开始侦听,最大同时连接数为256个
      begin
        CloseSocket(hSocket);
        WSACleanup;
        Writeln('Listen() Fail\');
        Exit;
      end;
      TimeOut:=3000;
      ThreadCount:=0;
      Writeln('Listening......\');
      while true do
      begin
        NameLen:=SizeOf(Clt);
        s:=Accept(hSocket,@Clt,@NameLen);//接受一个连接
        if s = SOCKET_ERROR Then
        begin
          CloseSocket(hSocket);
          WSACleanup;
          Writeln('Accept() Fail\');
          Exit;
        end
        else
        begin
          Writeln('Socket \'+IntToStr(s)+' Connect\');
          if SetSockOpt(s,SOL_SOCKET,SO_RCVTIMEO,PChar(@TimeOut),SizeOf(TimeOut))=SOCKET_ERROR then //设置接收超时为3秒
          begin
            CloseSocket(s);
            CloseSocket(hSocket);
            WSACleanup;
            Writeln('SetSockOpt() Fail\');
            Exit;
          end;
          if SetSockOpt(s,SOL_SOCKET,SO_SNDTIMEO,PChar(@TimeOut),SizeOf(TimeOut))=SOCKET_ERROR then //设置发送超时为3秒
          begin
            CloseSocket(s);
            CloseSocket(hSocket);
            WSACleanup;
            Writeln('SetSockOpt() Fail\');
            Exit;
          end;
          new(Param);
          Param^.TrdId:=ThreadCount;
          Param^.Sckt:=s;
          hThread:=CreateThread(nil,0,@ChildThrd,Param,0,ThreadID); //创建childthrd子线程
          if hThread=0 then
          begin
            Writeln('CreateThread() Fail\');
          end
          else
          begin
            Inc(ThreadCount); 
          end;
        end;
      end;
      CloseSocket(hSocket); //关闭socket
      WSACleanup;
    end.
      

  8.   

    既然你是动态加载线程,为什么不试试动态加载和释放dll。
      

  9.   

    tpinfo = (TPINIT *)tpalloc("TPINIT", NULL, TPINITNEED(0));
    tpinfo->flags = TPMULTICONTEXTS; //多线程
    需要在初始化tuxedo连接时,指定多线程终于解决问题了,激动
      

  10.   

    tpinfo = (TPINIT *)tpalloc("TPINIT", NULL, TPINITNEED(0));
    tpinfo->flags = TPMULTICONTEXTS; //多线程需要在初始化Tuxedo连接时,指定支持多线程调用。终于解决了,开心!
      

  11.   

    恭喜,呵呵。WaitForSingleObject是API函数,建议查MSDN