Problème Hardu : DLL + gestin de réseau

Programmation d'applications complexes
Avatar de l’utilisateur
Progi1984
Messages : 2659
Inscription : mar. 14/déc./2004 13:56
Localisation : France > Rennes
Contact :

Problème Hardu : DLL + gestin de réseau

Message par Progi1984 »

Salut à tous, on a un petit problème :p

Voilà, le code suivant permet de rapporter le contenu d'un fichier PHP afin de pouvoir se coonceter à un BD de type free n'acceptant pas les requetes externes. Mais le pb est le code d'utilsiation bugge à 4637 !

On peut déjà vous dire que cela ne vient pas du thread !


La DLL à compiler en bkdb.dll :

Code : Tout sélectionner

Enumeration
  #File
EndEnumeration

#INTERNET_FLAG_RELOAD = $80000000
#INTERNET_DEFAULT_HTTP_PORT = 80
#INTERNET_SERVICE_HTTP = 3
#HTTP_QUERY_FLAG_NUMBER = $20000000
#HTTP_QUERY_CONTENT_LENGTH = 5
#HTTP_QUERY_STATUS_CODE = 19
#HTTP_STATUS_OK = 200
#INTERNET_OPEN_TYPE_DIRECT = 1
  
Enumeration
  #INITIALISED
  #RUNNING
  #FINISHED_OK
  #NO_NETWORK
  #CONNECTION_FAILED
  #REQUEST_ERROR
  #SYSTEM_ERROR
EndEnumeration


Enumeration
  #OK
  #THREAD_ALREADY_RUNNING
EndEnumeration

Global URL.s, domain.s, result.s, server.s, state.l
  
  

ProcedureDLL.s BKDB_GetResult()
  ProcedureReturn result
EndProcedure


ProcedureDLL.l BKDB_GetState()
  ProcedureReturn state
EndProcedure


ProcedureDLL BKDB_Init(serverAddress.s)
  server = serverAddress
  state = #INITIALISED
  result = ""
EndProcedure


ProcedureDLL BKDB_CheckError(value, sMessage.s, terminate)
  If value = 0
      MessageRequester("Error : ", sMessage, #PB_MessageRequester_Ok)
      If terminate
          End
      EndIf
  EndIf
EndProcedure


ProcedureDLL BKDB_Main()
  FileName.s = "CacheFile.txt"
  
  If URLDownloadToFile_(#Null, URL, FileName, #Null, #Null) <> 0
      dwordSize = 4
      hInet = InternetOpen_("Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7.8) Gecko/20050511 Firefox/1.0.4", #INTERNET_OPEN_TYPE_DIRECT, #Null, #Null, 0)
      ; BKDB_CheckError(hInet, "Internet connection not available.", #TRUE)
      If hInet = 0 
        state = #NO_NETWORK
        ProcedureReturn result
      EndIf
      hURL = InternetOpenUrl_(hInet, URL, #Null, 0, #INTERNET_FLAG_RELOAD, 0)
      ; BKDB_CheckError(hURL, "InternetOpenUrl_() failed", #TRUE)
      If hURL = 0 
        state = #CONNECTION_FAILED
        ProcedureReturn result
      EndIf      
      hInetCon = InternetConnect_(hInet, Domain, #INTERNET_DEFAULT_HTTP_PORT, #Null, #Null, #INTERNET_SERVICE_HTTP, 0, 0)
      ; BKDB_CheckError(hInetCon, "Unable to connect to " + Domain, #TRUE)
      If hInetCon = 0 
        state = #CONNECTION_FAILED
        ProcedureReturn result
      EndIf      
      hHttpOpenRequest = HttpOpenRequest_(hInetCon, "HEAD", RemoveString(URL, "http://" + Domain + "/"), "http/1.0", #Null, 0, #INTERNET_FLAG_RELOAD, 0)
      ; BKDB_CheckError(hHttpOpenRequest, "Http open request to " + Domain + " failed", #TRUE)
       If hHttpOpenRequest = 0 
        state = #CONNECTION_FAILED
        ProcedureReturn result
      EndIf      
      ; BKDB_CheckError(HttpSendRequest_(hHttpOpenRequest, #NULL, 0, 0, 0), "Http send request to " + Domain + " failed.", #TRUE)
      res = HttpSendRequest_(hHttpOpenRequest, #Null, 0, 0, 0)
      If res = 0 
        state = #CONNECTION_FAILED
        ProcedureReturn result
      EndIf    
      ; BKDB_CheckError(HttpQueryInfo_(hHttpOpenRequest, #HTTP_QUERY_FLAG_NUMBER | #HTTP_QUERY_STATUS_CODE, @sCode, @dwordSize, @lpdwIndex), "Http query failed.", #FALSE)
      res = HttpQueryInfo_(hHttpOpenRequest, #HTTP_QUERY_FLAG_NUMBER | #HTTP_QUERY_STATUS_CODE, @sCode, @dwordSize, @lpdwIndex)
      If res = 0 
        state = #REQUEST_ERROR
      EndIf    
      ; BKDB_CheckError(sCode = #HTTP_STATUS_OK, "Status code query failed.", #FALSE)
      If sCode <> #HTTP_STATUS_OK
         state = #REQUEST_ERROR
      EndIf
      ; BKDB_CheckError(HttpQueryInfo_(hHttpOpenRequest, #HTTP_QUERY_FLAG_NUMBER | #HTTP_QUERY_CONTENT_LENGTH, @sCode, @dwordSize, @lpdwIndex), "CONTENT_LENGTH query failed.", #FALSE)
      res = HttpQueryInfo_(hHttpOpenRequest, #HTTP_QUERY_FLAG_NUMBER | #HTTP_QUERY_CONTENT_LENGTH, @sCode, @dwordSize, @lpdwIndex)
      If res = 0 
        state = #REQUEST_ERROR
      EndIf    
      If sCode
          DataBufferLength = sCode
        Else
          DataBufferLength = 4096
      EndIf
      *DataBuffer = AllocateMemory(DataBufferLength)
      ; BKDB_CheckError(*DataBuffer, "Not enough memory.", #TRUE)
      If *DataBuffer = 0 
        state = #SYSTEM_ERROR
        ProcedureReturn result
      EndIf    
      ; BKDB_CheckError(CreateFile(0, FileName), "Unable to create file.", #TRUE)
      res = CreateFile(0, FileName)
      If res = 0 
        state = #SYSTEM_ERROR
        ProcedureReturn result
      EndIf 
               
      Repeat
        ; BKDB_CheckError(InternetReadFile_(hURL, *DataBuffer, DataBufferLength, @Bytes), "Download failed.", #TRUE)
        res = InternetReadFile_(hURL, *DataBuffer, DataBufferLength, @Bytes)
        If res = 0 
          state = #SYSTEM_ERROR
          ProcedureReturn result
        EndIf 

        If Bytes
            WriteData(*DataBuffer, Bytes)
        EndIf
      Until Bytes=0
      CloseFile(0)
      FreeMemory(*DataBuffer)
      InternetCloseHandle_(hInetCon)
      InternetCloseHandle_(hURL)
      InternetCloseHandle_(hInet)
  EndIf

  If ReadFile(#File, FileName)
      *Buffer = AllocateMemory(Lof())
      ReadData(*Buffer, Lof())
      CloseFile(#File)
      DeleteFile(FileName)
  EndIf
  
  result = PeekS(*Buffer)
  FreeMemory(*Buffer)

  state = #FINISHED_OK
  ProcedureReturn result
EndProcedure


ProcedureDLL.l BKDB_Run(command.s)
  ; Cancel the command if a thread is already running
  If state = #RUNNING 
    ProcedureReturn #THREAD_ALREADY_RUNNING
  EndIf

  result = ""
  state = #RUNNING
  
  URL.s = server + "/" + command
  domain.s = RemoveString(Left(URL, FindString(URL, "/", 8) - 1), "http://")
  ThreadID = CreateThread(@BKDB_Main(), 0)
  ProcedureReturn #OK
EndProcedure


ProcedureDLL.l BKDB_RunNoThread(command.s)
  ; Cancel the command if a thread is already running
  If state = #RUNNING 
    ProcedureReturn #THREAD_ALREADY_RUNNING
  EndIf
  
  result = ""
  state = #RUNNING
  
  URL.s = server + "/" + command
  domain.s = RemoveString(Left(URL, FindString(URL, "/", 8) - 1), "http://")
  BKDB_Main()
  ProcedureReturn #OK
EndProcedure
Code d'utilisation :

Code : Tout sélectionner

If OpenLibrary(0, "BKDB.DLL")


CallFunction(0,"BKDB_Init","http://repeatuntil.free.fr/")

CallFunction(0,"BKDB_RunNoThread","BKDB.php?opt=setValue&value=" + Str(Random(100)))
Repeat
  ia=ia+1
  resultat=CallFunction(0,"BKDB_GetResult")
  Debug Str(ia)+":"+Str(resultat)
Until False
EndIf
Dernière modification par Progi1984 le mar. 20/sept./2005 21:37, modifié 1 fois.
LeCyb
Messages : 273
Inscription : dim. 26/déc./2004 20:49

Message par LeCyb »

Moi ce que je peux te dire c'est que String + Thread ça fait pas bon ménage dans PB.

J'ai aussi plusieurs applications qui n'attendent que le thread-safe dans PB (normalement pour la v4).
Perso je préfère attendre que de devoir me casser la tête puis de tout devoir retransformer pour la v4.
Vive le thread-safe !
Avatar de l’utilisateur
Progi1984
Messages : 2659
Inscription : mar. 14/déc./2004 13:56
Localisation : France > Rennes
Contact :

Message par Progi1984 »

Personne pour m'aider ?
Dr. Dri
Messages : 2527
Inscription : ven. 23/janv./2004 18:10

Message par Dr. Dri »

bah attend la version 4... c'est tout ce qu'il y a à faire...

Dri
Avatar de l’utilisateur
Progi1984
Messages : 2659
Inscription : mar. 14/déc./2004 13:56
Localisation : France > Rennes
Contact :

Message par Progi1984 »

Je souhaiterais faire une mise au point du pb : cela ne vient pas du thread !

c'est un probleme que surement quelqu'un pourrait comprendre.......
Dr. Dri
Messages : 2527
Inscription : ven. 23/janv./2004 18:10

Message par Dr. Dri »

tu utilises des chaines a la fois dans ton thread et dans le reste du programmes ? si oué, ne cherche pas plus loin. elles partagent le même buffer et cela crée des conflits. La version 4 y remédiera

Dri
repeatuntil
Messages : 7
Inscription : mer. 21/sept./2005 21:20

Message par repeatuntil »

Je travaille avec Progi sur cette petite librairie. Comme progi l'a dit, cela n'a rien a voir avec les threads ! Dans son code poste plus haut, on ne se sert a AUCUN MOMENT du thread. Pour etre plus clair, voici le code SANS thread.
Le premier code sert a creer la dll, le deuxieme sert a l'appeler. Si vous tournez le deuxieme code (boucle infinie), ca plante au bout de plusieurs milliers de boucle, alors qu'on ne fait qu'appeler une routine qui retourne une chaine de caractere !!! La question est pourquoi ?????????

Le code pour creer la dll (sans thread donc) :

Code : Tout sélectionner

Enumeration
  #File
EndEnumeration

#INTERNET_FLAG_RELOAD = $80000000
#INTERNET_DEFAULT_HTTP_PORT = 80
#INTERNET_SERVICE_HTTP = 3
#HTTP_QUERY_FLAG_NUMBER = $20000000
#HTTP_QUERY_CONTENT_LENGTH = 5
#HTTP_QUERY_STATUS_CODE = 19
#HTTP_STATUS_OK = 200
#INTERNET_OPEN_TYPE_DIRECT = 1
 
Enumeration
  #INITIALISED
  #RUNNING
  #FINISHED_OK
  #NO_NETWORK
  #CONNECTION_FAILED
  #REQUEST_ERROR
  #SYSTEM_ERROR
EndEnumeration


Enumeration
  #OK
  #THREAD_ALREADY_RUNNING
EndEnumeration

Global URL.s, domain.s, result.s, server.s, state.l
 
 

ProcedureDLL.s BKDB_GetResult()
  ProcedureReturn result
EndProcedure


ProcedureDLL.l BKDB_GetState()
  ProcedureReturn state
EndProcedure


ProcedureDLL BKDB_Init(serverAddress.s)
  server = serverAddress
  state = #INITIALISED
  result = ""
EndProcedure


ProcedureDLL BKDB_CheckError(value, sMessage.s, terminate)
  If value = 0
      MessageRequester("Error : ", sMessage, #PB_MessageRequester_Ok)
      If terminate
          End
      EndIf
  EndIf
EndProcedure


ProcedureDLL BKDB_Main()
  FileName.s = "CacheFile.txt"
 
  If URLDownloadToFile_(#Null, URL, FileName, #Null, #Null) <> 0
      dwordSize = 4
      hInet = InternetOpen_("Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.7.8) Gecko/20050511 Firefox/1.0.4", #INTERNET_OPEN_TYPE_DIRECT, #Null, #Null, 0)
      ; BKDB_CheckError(hInet, "Internet connection not available.", #TRUE)
      If hInet = 0
        state = #NO_NETWORK
        ProcedureReturn result
      EndIf
      hURL = InternetOpenUrl_(hInet, URL, #Null, 0, #INTERNET_FLAG_RELOAD, 0)
      ; BKDB_CheckError(hURL, "InternetOpenUrl_() failed", #TRUE)
      If hURL = 0
        state = #CONNECTION_FAILED
        ProcedureReturn result
      EndIf     
      hInetCon = InternetConnect_(hInet, Domain, #INTERNET_DEFAULT_HTTP_PORT, #Null, #Null, #INTERNET_SERVICE_HTTP, 0, 0)
      ; BKDB_CheckError(hInetCon, "Unable to connect to " + Domain, #TRUE)
      If hInetCon = 0
        state = #CONNECTION_FAILED
        ProcedureReturn result
      EndIf     
      hHttpOpenRequest = HttpOpenRequest_(hInetCon, "HEAD", RemoveString(URL, "http://" + Domain + "/"), "http/1.0", #Null, 0, #INTERNET_FLAG_RELOAD, 0)
      ; BKDB_CheckError(hHttpOpenRequest, "Http open request to " + Domain + " failed", #TRUE)
       If hHttpOpenRequest = 0
        state = #CONNECTION_FAILED
        ProcedureReturn result
      EndIf     
      ; BKDB_CheckError(HttpSendRequest_(hHttpOpenRequest, #NULL, 0, 0, 0), "Http send request to " + Domain + " failed.", #TRUE)
      res = HttpSendRequest_(hHttpOpenRequest, #Null, 0, 0, 0)
      If res = 0
        state = #CONNECTION_FAILED
        ProcedureReturn result
      EndIf   
      ; BKDB_CheckError(HttpQueryInfo_(hHttpOpenRequest, #HTTP_QUERY_FLAG_NUMBER | #HTTP_QUERY_STATUS_CODE, @sCode, @dwordSize, @lpdwIndex), "Http query failed.", #FALSE)
      res = HttpQueryInfo_(hHttpOpenRequest, #HTTP_QUERY_FLAG_NUMBER | #HTTP_QUERY_STATUS_CODE, @sCode, @dwordSize, @lpdwIndex)
      If res = 0
        state = #REQUEST_ERROR
      EndIf   
      ; BKDB_CheckError(sCode = #HTTP_STATUS_OK, "Status code query failed.", #FALSE)
      If sCode <> #HTTP_STATUS_OK
         state = #REQUEST_ERROR
      EndIf
      ; BKDB_CheckError(HttpQueryInfo_(hHttpOpenRequest, #HTTP_QUERY_FLAG_NUMBER | #HTTP_QUERY_CONTENT_LENGTH, @sCode, @dwordSize, @lpdwIndex), "CONTENT_LENGTH query failed.", #FALSE)
      res = HttpQueryInfo_(hHttpOpenRequest, #HTTP_QUERY_FLAG_NUMBER | #HTTP_QUERY_CONTENT_LENGTH, @sCode, @dwordSize, @lpdwIndex)
      If res = 0
        state = #REQUEST_ERROR
      EndIf   
      If sCode
          DataBufferLength = sCode
        Else
          DataBufferLength = 4096
      EndIf
      *DataBuffer = AllocateMemory(DataBufferLength)
      ; BKDB_CheckError(*DataBuffer, "Not enough memory.", #TRUE)
      If *DataBuffer = 0
        state = #SYSTEM_ERROR
        ProcedureReturn result
      EndIf   
      ; BKDB_CheckError(CreateFile(0, FileName), "Unable to create file.", #TRUE)
      res = CreateFile(0, FileName)
      If res = 0
        state = #SYSTEM_ERROR
        ProcedureReturn result
      EndIf
               
      Repeat
        ; BKDB_CheckError(InternetReadFile_(hURL, *DataBuffer, DataBufferLength, @Bytes), "Download failed.", #TRUE)
        res = InternetReadFile_(hURL, *DataBuffer, DataBufferLength, @Bytes)
        If res = 0
          state = #SYSTEM_ERROR
          ProcedureReturn result
        EndIf

        If Bytes
            WriteData(*DataBuffer, Bytes)
        EndIf
      Until Bytes=0
      CloseFile(0)
      FreeMemory(*DataBuffer)
      InternetCloseHandle_(hInetCon)
      InternetCloseHandle_(hURL)
      InternetCloseHandle_(hInet)
  EndIf

  If ReadFile(#File, FileName)
      *Buffer = AllocateMemory(Lof())
      ReadData(*Buffer, Lof())
      CloseFile(#File)
      DeleteFile(FileName)
  EndIf
 
  result = PeekS(*Buffer)
  FreeMemory(*Buffer)

  state = #FINISHED_OK
  ProcedureReturn result
EndProcedure


ProcedureDLL.l BKDB_RunNoThread(command.s)
  ; Cancel the command if a thread is already running
  If state = #RUNNING
    ProcedureReturn #THREAD_ALREADY_RUNNING
  EndIf
 
  result = ""
  state = #RUNNING
 
  URL.s = server + "/" + command
  domain.s = RemoveString(Left(URL, FindString(URL, "/", 8) - 1), "http://")
  BKDB_Main()
  ProcedureReturn #OK
EndProcedure
Le code pour appeler cette dll, et qui plante :

Code : Tout sélectionner

If OpenLibrary(0, "BKDB.DLL")


CallFunction(0,"BKDB_Init","http://repeatuntil.free.fr/")

CallFunction(0,"BKDB_RunNoThread","BKDB.php?opt=setValue&value=" + Str(Random(100)))
Repeat
  ia=ia+1
  resultat=CallFunction(0,"BKDB_GetResult")
  Debug Str(ia)+":"+Str(resultat)
Until False
EndIf
Merci pour l'aide !!
LeCyb
Messages : 273
Inscription : dim. 26/déc./2004 20:49

Message par LeCyb »

Je pense que y'a déjà un soucis au niveau de l'allocation du buffer car tu prends "sCode" comme taille de buffer alors que dans le cas d'une chaîne "sCode" est la taille sans le zéro terminal.
Donc tu devrais avoir plutôt "DataBufferLength = sCode + 1".

Sinon dans l'ensemble tu fais des retour de procédure dans tous les sens sans libérer aucun buffer.
Idem pour les fichiers.
Idem pour les Handles.

Tu fais un PeekS(*Buffer) alors que tu ne sais pas si ce buffer se termine par zéro. Là faut allouer + 1 ou vérifier le dernier byte.

Sinon chez moi ça plante pas mais tu devrais mettre un Delay(1) dans ta boucle c'est plus rapide à l'exécution.
Vive le thread-safe !
repeatuntil
Messages : 7
Inscription : mer. 21/sept./2005 21:20

Message par repeatuntil »

Merci pour cette reponse. Mais en fait on a reussi a reproduire ce bug avec un code HYPER simple. Et ca plante aussi :
http://purebasic.hmt-forum.com/viewtopic.php?t=3647

On dirait un bug de purebasic ???
Répondre