Schnelles URLEncode mit WinAPI

Windowsspezifisches Forum , API ,..
Beiträge, die plattformübergreifend sind, gehören ins 'Allgemein'-Forum.
WernerZ
Beiträge: 21
Registriert: 28.09.2004 17:47
Wohnort: Wien
Kontaktdaten:

Schnelles URLEncode mit WinAPI

Beitrag 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!
WernerZ
Beiträge: 21
Registriert: 28.09.2004 17:47
Wohnort: Wien
Kontaktdaten:

Beitrag 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.
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag 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?
Zuletzt geändert von AND51 am 24.10.2007 15:35, insgesamt 1-mal geändert.
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Benutzeravatar
edel
Beiträge: 3667
Registriert: 28.07.2005 12:39
Computerausstattung: GameBoy
Kontaktdaten:

Beitrag 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
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag 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.
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
WernerZ
Beiträge: 21
Registriert: 28.09.2004 17:47
Wohnort: Wien
Kontaktdaten:

Beitrag 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).
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag 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......
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
WernerZ
Beiträge: 21
Registriert: 28.09.2004 17:47
Wohnort: Wien
Kontaktdaten:

Beitrag 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.
WernerZ
Beiträge: 21
Registriert: 28.09.2004 17:47
Wohnort: Wien
Kontaktdaten:

Beitrag 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!
Benutzeravatar
jpd
Beiträge: 380
Registriert: 14.02.2005 10:33

Beitrag 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 

PB 5.10 Windows 7 x64
Antworten