Problema con el retorno de una función
Publicado: 02 Jun 2009, 19:06
Hola
He reescrito la función _AdslGetIpLocation() que hice (con ayuda de Chefito) en la librería Adsl.au3 hace algún tiempo, porque Creo que podía mejorarse su rendimiento y esque, tal y como estaba cuando la escribí por primera vez al ejecutarla la aplicación que la contubiera, aún simulando el multihilo (que tanto me gusta) se bloqueaba mientras la función recogía la información que le enviaba el servidor donde se realiza la consulta, (que por cierto, tarda unos segundos) es decir, toda la página que devuelve el servidor.
Eso, en mi opinión no queda bien del todo, pues no es posible ni siquiera cerrar el programa si quisiéramos.
por eso, la he hecho de forma, que también simule el multihilo, en la parte que debe recoger la página resultante de la consulta con un timer. De esta forma si mientras se realiza la consulta queremos interactuar con la aplicación podemos hacerlo.
Además, he incluido en la función un parámetro que permite indicar si se quiere, el tiempo máximo que se esperará para que el servidor entregue la respuesta. Así podemos evitar errores o lags innecesários.
Está todo listo, pero a la hora de probar la función encontré un pequeño problema que no se como arreglar.
Aquí va el código por si quereis hechar un vistazo (será más fácil ver como arreglarlo):
;AdslGetIpLocation():
;Código de ejemplo para ejecutar la función:
El problema que surge con el código de _AdslGetIpLocation() es que En el momento en que se empieza ejecutar el timer que recoge la respuesta del servidor Sigue ejecutándose la función y al no cumplirse ninguno de los case siguientes, llega al final y devuelve 0, mientras que no debería ser así, sinó que una vez ejecutada la línea:
La función debería terminar o pausarse, pero sin retornar nada, pues solo debe retornarse algo en el case 1 o 2.
¿Como puedo arreglar esto?...
No encontré la manera.
En definitiva, lo que quiero es, que la función únicamente retorne algo cuando encuentre la instrucción return.
He modificado el switch por sentencias if, pero el resultado como era de esperar, es el mismo...
Gracias de antemano,
Salu2!
He reescrito la función _AdslGetIpLocation() que hice (con ayuda de Chefito) en la librería Adsl.au3 hace algún tiempo, porque Creo que podía mejorarse su rendimiento y esque, tal y como estaba cuando la escribí por primera vez al ejecutarla la aplicación que la contubiera, aún simulando el multihilo (que tanto me gusta) se bloqueaba mientras la función recogía la información que le enviaba el servidor donde se realiza la consulta, (que por cierto, tarda unos segundos) es decir, toda la página que devuelve el servidor.
Eso, en mi opinión no queda bien del todo, pues no es posible ni siquiera cerrar el programa si quisiéramos.
por eso, la he hecho de forma, que también simule el multihilo, en la parte que debe recoger la página resultante de la consulta con un timer. De esta forma si mientras se realiza la consulta queremos interactuar con la aplicación podemos hacerlo.
Además, he incluido en la función un parámetro que permite indicar si se quiere, el tiempo máximo que se esperará para que el servidor entregue la respuesta. Así podemos evitar errores o lags innecesários.
Está todo listo, pero a la hora de probar la función encontré un pequeño problema que no se como arreglar.
Aquí va el código por si quereis hechar un vistazo (será más fácil ver como arreglarlo):
;AdslGetIpLocation():
Código: Seleccionar todo
#include-once
#include <Constants.au3>
#Include <Array.au3>
#Include <File.au3>
#Include <String.au3>
#Include <Ie.au3>
#Include <Inet.au3>
#Include <Timers.au3>
Global $_DataLocation="", $BuffXHandleWindow
Global $HostLocation="www.ipaddresslocation.org", $ActualMSecond=0
Global $MethodLocation="post", $PathLocation="/ip-address-locator.php"
Global $DataLocation, $UserAgentLocation=True
Global $SockLocation, $PortLocation=80
Global $Timer_DataReceibeLocation, $BuffXAutoPause=0
Func _AdslGetIpLocation($XIp, $XHandleWindow, $XAutoPause=0, $_Ex=0)
Local $LegalCharsAutoPause="0123456789", $Location[4]
Switch($_Ex)
Case 0
$BuffXHandleWindow=$XHandleWindow
$DataLocation="ip="&$XIp
$AutoPauseDiv=StringSplit($XAutoPause, "")
For $I=1 To $AutoPauseDiv[0] Step +1
If StringInStr($LegalCharsAutoPause, $AutoPauseDiv[$I])==0 Then
SetError(1)
Return "Valor de pausa incorrecto"
ExitLoop
EndIf
Next
$XAutoPause=Number($XAutoPause)
If $XAutoPause>0 Then
$BuffXAutoPause=$XAutoPause
$ActualMSecond=0
EndIf
If $XHandleWindow=="" Then
SetError(1)
Return "Debe especificarse un identificador de ventana válido"
EndIf
TCPStartUp()
If $XIp=="" Then
setError(1)
Return "Deve especificarse una dirección ip válida"
EndIf
$IpSplit=StringSplit($XIp, ".")
If $IpSplit[0]<>4 Then
SetError(1)
Return "Debe especificarse una dirección ip válida"
EndIf
For $n=1 To 4
If IsNumber($IpSplit[$n]) Then
SetError(1)
Return $XIp&" no es una dirección ip válida"
EndIf
If (Number($IpSplit[$n])<0 Or Number($IpSplit[$n])>255) Then
SetError(1)
Return $XIp&" no es válido"
EndIf
Next
If $MethodLocation=="" Then
$MethodLocation="GET"
EndIf
$MethodLocation=StringUpper($MethodLocation)
$SVPing=Ping($HostLocation, 2000)
If @Error<>0 Then
SetError(1)
Return "La base de datos no está disponible en este momento"
EndIf
$SockLocation=TCPConnect(TcpNameToIp($HostLocation), $PortLocation)
If $SockLocation==-1 Then
SetError(1)
Return "Error al conectar a la base de datos"
EndIf
If $MethodLocation=="GET" Then
$PathLocation&="?"&$DataLocation
EndIf
TcpSend($SockLocation, $MethodLocation&" "&$PathLocation&" HTTP/1.1"&@CRLF)
TcpSend($SockLocation, "Host: "&$HostLocation&@CRLF)
TcpSend($SockLocation, "Content-Type: application/x-www-form-urlencoded"&@CRLF)
If $MethodLocation=="POST" Then
TcpSend($SockLocation, "Content-length: "&StringLen($DataLocation)&@CRLF)
EndIf
If $UserAgentLocation==True Then
TcpSend($SockLocation, "User-Agent: MSIE"&@CRLF)
EndIf
TcpSend($SockLocation, "Connection: close"&@CRLF&@CRLF)
If $MethodLocation=="POST" Then
TcpSend($SockLocation, $DataLocation)
EndIf
$Timer_DataReceibeLocation=_Timer_SetTimer($XHandleWindow, 0, "_DataReceibeLocationTimer")
Case 1
$posIniCountry=StringInStr($_DataLocation,"IP Country:")+15
$posFinCountry=StringInStr($_DataLocation,"</b>",0,1,$posIniCountry)
$Country=StringMid($_DataLocation,$posIniCountry,$posFinCountry-$posIniCountry)
$posIniContinent=StringInStr($_DataLocation,"IP Continent:",0,1,$posFinCountry)+17
$posFinContinent=StringInStr($_DataLocation,"</b>",0,1,$posIniContinent)
$Continent=StringMid($_DataLocation,$posIniContinent,$posFinContinent-$posIniContinent)
$posIniRegion=StringInStr($_DataLocation,"IP Region:",0,1,$posFinContinent)+14
$posFinRegion=StringInStr($_DataLocation,"</b>",0,1,$posIniRegion)
$Region=StringMid($_DataLocation,$posIniRegion,$posFinRegion-$posIniRegion)
$posIniCity=StringInStr($_DataLocation,"Guessed City:",0,1,$posFinRegion)+17
$posFinCity=StringInStr($_DataLocation,"</b>",0,1,$posIniCity)
$City=StringMid($_DataLocation,$posIniCity,$posFinCity-$posIniCity)
If $Country="" or $Continent="" or $Region="" or $City="" Then
SetError(1)
Return "Error al localizar "&$XIp
EndIf
$Location[0]=$Continent
$Location[1]=$Country
$Location[2]=$Region
$Location[3]=$City
$_DataLocation=""
SetError(0)
Return $Location
Case 2
$_DataLocation=""
SetError(1)
Return "Tiempo de espera para el servidor agotado"
EndSwitch
EndFunc
Func _DataReceibeLocationTimer($hWnd, $Msg, $iIDTimer, $dwTime)
$_DataLocation&=TCPRecv($SockLocation, 128)
If @Error Then
_Timer_KillTimer($BuffXHandleWindow, $Timer_DataReceibeLocation)
TcpCloseSocket($SockLocation)
_AdslGetIpLocation("", "", "", 1)
Return
EndIf
If $BuffXAutoPause>0 Then
If $ActualMSecond>=$BuffXAutoPause Then
_Timer_KillTimer($BuffXHandleWindow, $Timer_DataReceibeLocation)
TcpCloseSocket($SockLocation)
_AdslGetIpLocation("", "", "", 2)
Return
Else
$ActualMSecond+=1
EndIf
EndIf
EndFunc
Código: Seleccionar todo
#Include <Constants.au3>
#Include <EditConstants.au3>
#Include <GUIConstants.au3>
#Include <GUIConstantsEx.au3>
#Include <GuiComboBox.au3>
#Include <ButtonConstants.au3>
#Include <Sound.au3>
#Include <StaticConstants.au3>
#Include <TreeViewConstants.au3>
#Include <WindowsConstants.au3>
#Include <Array.au3>
#Include <File.au3>
#Include <String.au3>
#Include <Misc.au3>
#Include <Timers.au3>
#Include <Ie.au3>
#Include <Inet.au3>
#Include <Word.au3>
#Include <WinAPI.au3>
#Include <F:\herramientas\lib\Adsl.au3>
#Include <F:\herramientas\lib\Sys_Info.au3>
#Include <F:\herramientas\lib\Zip.au3>
Opt("MustDeclareVars", 0)
Opt("TrayAutoPause", 1)
Opt("TrayOnEventMode", 1)
Opt("TrayIconHide", 1)
Opt("TrayMenuMode", 1)
Opt("GUIOnEventMode", 1)
Opt("OnExitFunc", "ExitFile")
Opt("GUIResizeMode", $GUI_DOCKWIDTH+$GUI_DOCKHEIGHT+$GUI_DOCKTOP+$GUI_DOCKLEFT)
Global $CtrlWindowThread, $WindowHandler, $Location
$CtrlWindowThread=_Timer_SetTimer($WindowHandler, 0, "CtrlWindowThread")
GUIDelete()
$WindowHandler=GUICreate("Prueba", 900, 700, -1, -1, BitOR($GUI_SS_DEFAULT_GUI, $WS_MAXIMIZEBOX))
$Location=_AdslGetIpLocation("87.216.218.141", $WindowHandler, 12)
GuiSetState()
While 1
If (Not IsArray($Location) And $Location<>"") Then
Msgbox(0, "", $Location)
ExitLoop
ElseIf IsArray($Location) Then
For $I=1 To 4 Step +1
Msgbox(0, "", $Location[$I])
Next
ExitLoop
EndIf
_ReduceMemory()
Wend
Func CtrlWindowThread($hWnd, $Msg, $iIDTimer, $dwTime)
GuiSetOnEvent($GUI_EVENT_CLOSE, "ExitFile")
GuiSetOnEvent($GUI_EVENT_MAXIMIZE, "GuiMaximize")
GuiSetOnEvent($GUI_EVENT_MINIMIZE, "GuiMinimize")
GuiSetOnEvent($GUI_EVENT_RESTORE, "GuiRestore")
EndFunc
Func _ReduceMemory()
DllCall("psapi.dll", "int", "EmptyWorkingSet", "long", -1)
EndFunc
Func ExitFile()
Exit
EndFunc
Func GuiMaximize()
$WinMaximize=@SW_MAXIMIZE
EndFunc
Func GuiMinimize()
$WinMinimize=@SW_MINIMIZE
EndFunc
Func GuiRestore()
$WinRestore=@SW_RESTORE
EndFunc
Código: Seleccionar todo
$Timer_DataReceibeLocation=_Timer_SetTimer($XHandleWindow, 0, "_DataReceibeLocationTimer")
¿Como puedo arreglar esto?...
No encontré la manera.
En definitiva, lo que quiero es, que la función únicamente retorne algo cuando encuentre la instrucción return.
He modificado el switch por sentencias if, pero el resultado como era de esperar, es el mismo...
Gracias de antemano,
Salu2!