Seite 1 von 2
Schnelles URLEncode mit WinAPI
Verfasst: 24.10.2007 13:06
von WernerZ
Hi!
Ich brauche dringend ein URLEncode, das mit der aktuellen PB-Version läuft und so maschinennahe wie möglich ist.
Die in PB programmierten URLEncodes, die ich so finden konnte, sind unendlich langsam und legen den Computer Minuten lang lahm, wenn es um richtig lange Strings geht und genau solche habe ich aber.
Da ich mit der WinAPI bisher null Erfahrung habe, meine Bitte:
Kann mir bitte jemand anhand eines Codebeispiels verraten, wie ich die URLEncode-Funktion, die es angeblich in der WinAPI gibt, konkret aufrufe?
PS: Alternativ wäre natürlich auch eine selbstgebaute ASM-Bibliotheksfunktion denkbar - aber auch da konnte ich nichts finden, das mit PB4 läuft.
Danke!
Verfasst: 24.10.2007 13:53
von WernerZ
In der WinAPI heisst die Funktion offenbar UrlEscapeA, soviel habe ich schon mal rausgefunden. Ein erster Versuch produziert zwar keinen Fehler, aber ist auch nicht sehr aktiv:
String$ = "test=blabla@123"
If OpenLibrary(0, "shlwapi.dll")
CallFunction(0, "UrlEscapeA", @String$, 0, 0, 0)
CloseLibrary(0)
EndIf
Debug String$
Ich habe leider keine Erfahrung mit der API - irgendwo hockt da sicher ein schwerer Denkfehler.
Ich habe jetzt ein Beispiel für die Nutzung von UrlEscape gefunden, allerdings nicht in PB:
'//URL Encode Demo
strEncodedURL = Space$(MAX_PATH)
ret = UrlEscape(strURL, strEncodedURL, MAX_PATH, URL_DONT_SIMPLIFY)
If ret = 0 Then
strEncodedURL = Left$(strEncodedURL, MAX_PATH)
MsgBox "Encoded URL : " & vbCrLf & strEncodedURL
End If
Offensichtlich ist der erste übergebene String die Quelle und der zweite String das Ziel nach der Kodierung, in PB könnte es daher so ähnlich aussehen:
String1$ = "test=blabla@-+123"
If OpenLibrary(0, "shlwapi.dll")
String2$ = " "
ret = CallFunction(0,"UrlEscape", String1$, String2$, 30, #URL_DONT_SIMPLIFY)
Debug ret
Debug String1$
Debug String2$
CloseLibrary(0)
EndIf
Wie genau sind die Strings zu übergeben? Wie gesagt, ist der erste String ein Input, der zweite sollte ev. ein Zeiger sein @String2$ ??
Mit oder ohne @s bei beiden Strings ist das Ergebnis derzeit immer das gleiche: String1 ist nachher unverändert und String2 bleibt leer.
Der Rückgabewert ret ist 0, was ja an sich ein gutes Zeichen sein sollte.
Verfasst: 24.10.2007 15:25
von AND51
Sind die PB Codes denn wirklich so lahm?
Muss es denn unbedingt API sein und nichts anderes?
Welche Zeichen müssen denn ersetzt werden? Alle oder nur bestimmte Zeichen, wie sie auch vom Browser ersetzt werden?
Wenn nämlich zum Beispiel a-z A-Z 0-9 nicht encodiert werden brauchen, dann reicht es doch, wenn du mit einer Schleife und
ReplaceString() rangehst.
Code folgt gleich.
Edit:Code: Alles auswählen
Procedure.s url_encode(text$)
Protected n
text$=ReplaceString(text$, "%", "%25")
For n=1 To 255
If Not (n = '%' Or (n >= '0' And n <= '9') Or (n >= 'A' And n <= 'Z') Or (n >= 'a' And n <= 'z')) And FindString(text$, Chr(n), 1)
text$=ReplaceString(text$, Chr(n), "%"+RSet(Hex(n), 2, "0"))
EndIf
Next
ProcedureReturn text$
EndProcedure
Debug url_encode("a-z A-Z 0-9 dürfen%nicht ersetzt werden!!!")
Ersetzt alles außer alphanumerische Zeichen (a-z A-Z 0-9). Meinste die API kann das so viel schneller, obwohl (vielleicht) nur derselbe Code hintersteckt?
Verfasst: 24.10.2007 15:34
von edel
WernerZ hat geschrieben:
Offensichtlich ist der erste übergebene String die Quelle und der zweite String das Ziel nach der Kodierung, in PB könnte es daher so ähnlich aussehen:
Raten bringt dich so garantiert nicht weiter, schau dir mal
die Dokumentation des Befehls an :
http://66.102.9.104/search?q=cache:MXy9 ... cd=1&gl=de
Verfasst: 24.10.2007 15:37
von AND51
Hab dein Edit nicht gesehen, WenerZ. Vielleicht schaust du dir ja doch nochmal mein Beispiel an.
Es ist übrigens kein Problem, meine Prozedur so umzustricken, dass ihr ein Pointer statt der String selbst übergeben wird. Und statt ProcedureReturn könnte meine Prozedur das Ergebnis auch irgendwo hin-pointern.
Verfasst: 24.10.2007 15:40
von WernerZ
AND51 hat geschrieben:Sind die PB Codes denn wirklich so lahm?
Muss es denn unbedingt API sein und nichts anderes?
Welche Zeichen müssen denn ersetzt werden? Alle oder nur bestimmte Zeichen, wie sie auch vom Browser ersetzt werden?
Wenn nämlich zum Beispiel a-z A-Z 0-9 nicht encodiert werden brauchen, dann reicht es doch, wenn du mit einer Schleife und
ReplaceString() rangehst.
Code folgt gleich.
Edit:Code: Alles auswählen
Procedure.s url_encode(text$)
Protected n
text$=ReplaceString(text$, "%", "%25")
For n=1 To 255
If Not (n = '%' Or (n >= '0' And n <= '9') Or (n >= 'A' And n <= 'Z') Or (n >= 'a' And n <= 'z')) And FindString(text$, Chr(n), 1)
text$=ReplaceString(text$, Chr(n), "%"+RSet(Hex(n), 2, "0"))
EndIf
Next
ProcedureReturn text$
EndProcedure
Debug url_encode("a-z A-Z 0-9 dürfen%nicht ersetzt werden!!!")
Ersetzt alles außer alphanumerische Zeichen (a-z A-Z 0-9). Meinste die API kann das so viel schneller, obwohl (vielleicht) nur derselbe Code hintersteckt?
Danke! Aber mit einem Code in ähnlicher Form hab ich's schon probiert und auch andere Versionen, die so in den Foren kursieren.
Das Problem ist, dass ich sehr große Mengen POSTen (und vorher kodieren) muss. In der Realität bedeutet das, dass der Rechner bei rund 250kB minutenlang praktisch blockiert ist (schwankt natürlich stark mit der Rechnerleistung, aber bei meinem Notebook sinds mehr als 2 Minuten - und wie gesagt, der Rechner ist derweil unbedienbar).
Verfasst: 24.10.2007 15:44
von AND51
Dann müsstest du den Code manuell mit Hilfe eines Pointers durchgehen (parsen) und jedes unerwünsche Zeichen ersetzen. Es dürfte vermutlich um einiges schneller sein, den Code linear auf alle zeichen zu prüfen, als jedes Zeichen zu suchen und zu ersetzen.
Edit: Lass bei meinem Code mal das FindString() weg. Denn ReplaceString() hat ja schon ein FindString() eingebaut, sonst könnte er ja keine Strings suchen, um sie zu ersetzen. Das dürfte meinen Code noch etwas schneller machen.
Außerdem ist es nicht nötig, einen Parallelthread im englsichen Forum zu eröffnen, denn dadurch fühlen sich beide Boards etwas vor den Kopf gestoßen, wenn beide dir eine Lösung präsentieren und du nur eines (oder im Endeffekt keines) von beiden annimmst......
Verfasst: 24.10.2007 15:45
von WernerZ
edel hat geschrieben:WernerZ hat geschrieben:
Offensichtlich ist der erste übergebene String die Quelle und der zweite String das Ziel nach der Kodierung, in PB könnte es daher so ähnlich aussehen:
Raten bringt dich so garantiert nicht weiter, schau dir mal
die Dokumentation des Befehls an :
http://66.102.9.104/search?q=cache:MXy9 ... cd=1&gl=de
Danke!
Für den Code habe ich ja ein Beispiel gefunden und kenne die Parameter des API-Befehls - mein Problem ist eher die Umsetzung in PB, bzw. die Parameterübergabe und -rückgabe.
Verfasst: 24.10.2007 16:11
von WernerZ
AND51 hat geschrieben:Dann müsstest du den Code manuell mit Hilfe eines Pointers durchgehen (parsen) und jedes unerwünsche Zeichen ersetzen. Es dürfte vermutlich um einiges schneller sein, den Code linear auf alle zeichen zu prüfen, als jedes Zeichen zu suchen und zu ersetzen.
Edit: Lass bei meinem Code mal das FindString() weg. Denn ReplaceString() hat ja schon ein FindString() eingebaut, sonst könnte er ja keine Strings suchen, um sie zu ersetzen. Das dürfte meinen Code noch etwas schneller machen.
Außerdem ist es nicht nötig, einen Parallelthread im englsichen Forum zu eröffnen, denn dadurch fühlen sich beide Boards etwas vor den Kopf gestoßen, wenn beide dir eine Lösung präsentieren und du nur eines (oder im Endeffekt keines) von beiden annimmst......
Danke - der Code ist wesentlich schneller, als die, die ich gefunden hatte!
Die Idee ist viel schlauer - die anderen Codes gehen den String Zeichen für Zeichen durch und ersetzten es brav oder auch nicht.
Du gehst die Zeichenliste durch und ersetzt alle Vorkommen im String - das ist vielleicht bei ganz kleinen Strings etwas langsamer, aber bei großen ganz wesentlich flotter.
Gute Sache...

...nochmals danke, das hat mir sehr geholfen!
Verfasst: 24.10.2007 17:25
von jpd
Hi WernerZ,
so wie ich sehe hast du schon eine lösung für dein problem,
ich habe trotzdem das mit api umgesetzt.
hier ein beispiel von VB portiert!
Ciao
jpd
Code: Alles auswählen
Declare.s EncodeUrl(sUrl.s)
Declare.s DecodeUrl(sUrl.s)
Enumeration
#EncodeUrl
#UrlUnescape
EndEnumeration
;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
;idea ------->>>http://vbnet.mvps.org/index.html?code/network/netconnectionenum.htm
;------------->By Randy Birch
;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
;Purebasic 4.02/4.10 b4
;
;converted by jpd
;
;Unicode ON
#MAX_PATH = 260
#ERROR_SUCCESS = 0
;'Treat entire URL param as one URL segment
#URL_ESCAPE_SEGMENT_ONLY = 8192
#URL_ESCAPE_PERCENT = 4096
#URL_UNESCAPE_INPLACE= 1048576
;'escape #'s in paths
#URL_INTERNAL_PATH = 8388608
#URL_DONT_ESCAPE_EXTRA_INFO = 33554432
#URL_ESCAPE_SPACES_ONLY = 67108864
#URL_DONT_SIMPLIFY = 134217728
;Fake_addr.s= "http://vbnet.mvps.org/vbnet code lib/net code/ip address.htm"
Fake_addr.s="a-z A-Z 0-9 dürfen%nicht ersetzt werden!!!"
buff.s = EncodeUrl(Fake_addr)
Debug buff
Debug DecodeUrl(buff )
Procedure.s EncodeUrl(sUrl.s)
;'Converts unsafe characters,
;'such as spaces, into their
;'corresponding escape sequences.
;UrlEscapeW"
Protected dwSize.l,dwFlags.l
If Len(sUrl) > 0
*buff=AllocateMemory(#MAX_PATH)
dwSize = #MAX_PATH
dwFlags = #URL_DONT_SIMPLIFY
If OpenLibrary(#EncodeUrl,"shlwapi.dll")
If CallFunction(#EncodeUrl,"UrlEscapeW",sUrl,*buff,@dwSize,dwflags) = #ERROR_SUCCESS
ret.s = PeekS(*buff)
EndIf
EndIf
EndIf
CloseLibrary(#EncodeUrl)
FreeMemory(*buff)
ProcedureReturn ret
EndProcedure
Procedure.s DecodeUrl(sUrl.s)
;'Converts escape sequences back into
;'ordinary characters.
;UrlUnescapeW
Protected dwSize.l,dwFlags.l
If Len(sUrl) > 0
*buff=AllocateMemory(#MAX_PATH)
dwSize = #MAX_PATH
dwFlags = #URL_DONT_SIMPLIFY
If OpenLibrary(#UrlUnescape,"shlwapi.dll")
If CallFunction(#UrlUnescape,"UrlUnescapeW",sUrl,*buff,@dwSize,dwFlags) = #ERROR_SUCCESS
ret.s = PeekS(*buff)
EndIf
EndIf
EndIf
CloseLibrary(#UrlUnescape)
FreeMemory(*buff)
ProcedureReturn ret
EndProcedure