Witam. Pytanie do MisiekD, ale może ktoś z Was też tak jak my lubi i preferuje Synapse,
to będzie umiał odpowiedzieć. Podesłałęm jednej osobie program stwrzony w Delphi 7 - z
użyciem Synapse konkretnie THttpSend. Program w oryginalnej postaci działa, ale jeżeli
ta osoba go przekompilowała pod Delphi 2010 to przestał działać, uruchamia się, ale jak
w momencie logowania ma wysłać dane POSTem do strony www to nic się nie dzieje, no
i pytanie do Was spotkaliście się z problemami z Synapse pod Delphi 2010? Pobrałem dla
pewności najnowszą dostępną wersję 39 i efekt ten sam. Ponoc Indy działa i tutaj pewnie
zwolennicy Indy triumfują i mówią "a do d**y te olesiowe Synapse, Indy rulez", ale ja do
tej pory nie miałem pojęcia że nowsze wersje Delphi mają problem - z kompatybilnością
wstecz, bo kod który działa ok pod Delphi 7 w nowszych wersjach Delphi i jeżeli, nic tam
z UAC nie koliduje to w nowszych Windowsach również. Jakie są wasze doświadczenia, z
pewnością Misiekd tworzyl już coś pod Delphi 2010 z Synapse, a może i ktoś iunny też?
Dodam, że w "Requirements" przy downloadzie napisano "experimental Delphi 2009+".
problem jest od D2k9 gdzie string zamienił się w UnicodeString. Co prawda nie musiałem kompilować nic pod d2k9> ale próbowałem i potwierdzam, że nie działało :(.
Ok, dziękuję za informację, a i jak rozumiem - zamiana w źródłach
wszystkich typów String na UnicodeString nie rozwiąże problemu?
zamiana string na unicodestring na pewno nie pomoże, bo w Delphi 2009+ jest właśnie
type string=unicodestring;
więc to NIC nie zmieni ;-)
za to może zmienić zamiana wszystkich string na ansistring, char na ansichar, pchar na pansichar – czyli przywrócenie starego porządku rzeczy.
Dziękuję za informację. Jak dla mnie Synapse nadal jest ok, ale pewnie autor jak nie porzuci projektu, a chyba raczej
nie zrobił tego, to pewnie wyda może wkrótce wersję działającą - tak, jak należy z wersjami Delphi 2009 i nowszymi.
Nie mam jak sprawdzić bo pracuje na leciwym Turbo, ale może Synapse pobrana bezpośrednio z SVN zahula, tymbardziej że jest jakas wzmianka o zmianach w niektórych unitach pod D2009 (a Synapse pobrana z zipa oznaczona jako 39 wygląda na starszą)
jeżeli ktoś ma ochotę posprawdzać
http://synalist.svn.sourceforge.net/viewvc/synalist/trunk/
Witam. Zdaję sobie sprawę, że ostatnia wypowiedź była 6 lat temu, a Synapse od 4 lat chyba nie jest rozwijane. Ale...
...mam ten sam problem. Postanowiłem przejść ze swoim kodem z Delphi 7 na Delphi 2010 w celu lepszej obsługi Unicode.
Wszystko poszło łatwo i pięknie dopóki nie musiałem wysłać POSTu.
Problem pojawia się tutaj, a dokładniej w Document.Write(Pointer(URLData)^, Length(URLData)) :
Address := strona_www;
Command := '/jakas_komenda';
URLData := 'jakies_dane';
Document.Write(Pointer(URLData)^, Length(URLData));
HTTPMethod('POST', Address + Command);
Document.Write odwołuje się do Classes.pas i funkcji function TMemoryStream.Write(const Buffer; Count: Longint): Longint;
W Delphi 7 i Delphi 2010, funkcja ta wygląda tak samo.
function TMemoryStream.Write(const Buffer; Count: Longint): Longint;
var
Pos: Longint;
begin
if (FPosition >= 0) and (Count >= 0) then
begin
Pos := FPosition + Count;
if Pos > 0 then
begin
if Pos > FSize then
begin
if Pos > FCapacity then
SetCapacity(Pos);
FSize := Pos;
end;
System.Move(Buffer, Pointer(Longint(FMemory) + FPosition)^, Count);
FPosition := Pos;
Result := Count;
Exit;
end;
end;
Result := 0;
end;
Następnie System.Move(Buffer, Pointer(Longint(FMemory) + FPosition)^, Count) odwołuje się do System.pas i procedury** procedure Move**(const Source; var Dest; count : Integer). A ta już inaczej wygląda w Delphi 7 i Delphi 2010.
Dla Delphi 7:
procedure Move( const Source; var Dest; count : Integer );
{$IFDEF PUREPASCAL}
var
S, D: PChar;
I: Integer;
begin
S := PChar(@Source);
D := PChar(@Dest);
if S = D then Exit;
if Cardinal(D) > Cardinal(S) then
for I := count-1 downto 0 do
D[I] := S[I]
else
for I := 0 to count-1 do
D[I] := S[I];
end;
{$ELSE}
asm
{ ->EAX Pointer to source }
{ EDX Pointer to destination }
{ ECX Count }
PUSH ESI
PUSH EDI
MOV ESI,EAX
MOV EDI,EDX
MOV EAX,ECX
CMP EDI,ESI
JA @@down
JE @@exit
SAR ECX,2 { copy count DIV 4 dwords }
JS @@exit
REP MOVSD
MOV ECX,EAX
AND ECX,03H
REP MOVSB { copy count MOD 4 bytes }
JMP @@exit
@@down:
LEA ESI,[ESI+ECX-4] { point ESI to last dword of source }
LEA EDI,[EDI+ECX-4] { point EDI to last dword of dest }
SAR ECX,2 { copy count DIV 4 dwords }
JS @@exit
STD
REP MOVSD
MOV ECX,EAX
AND ECX,03H { copy count MOD 4 bytes }
ADD ESI,4-1 { point to last byte of rest }
ADD EDI,4-1
REP MOVSB
CLD
@@exit:
POP EDI
POP ESI
end;
{$ENDIF}
Dla Delphi 2010:
procedure Move(const Source; var Dest; count : Integer);
{$IFDEF PUREPASCAL}
var
S, D: PAnsiChar;
I: Integer;
begin
S := PAnsiChar(@Source);
D := PAnsiChar(@Dest);
showmessage('move');
if S = D then Exit;
if Cardinal(D) > Cardinal(S) then
for I := count-1 downto 0 do
D[I] := S[I]
else
for I := 0 to count-1 do
D[I] := S[I];
end;
{$ELSE}
asm
cmp eax, edx
je @@Exit {Source = Dest}
cmp ecx, 32
ja @@LargeMove {Count > 32 or Count < 0}
sub ecx, 8
jg @@SmallMove
@@TinyMove: {0..8 Byte Move}
jmp dword ptr [@@JumpTable+32+ecx*4]
@@SmallMove: {9..32 Byte Move}
fild qword ptr [eax+ecx] {Load Last 8}
fild qword ptr [eax] {Load First 8}
cmp ecx, 8
jle @@Small16
fild qword ptr [eax+8] {Load Second 8}
cmp ecx, 16
jle @@Small24
fild qword ptr [eax+16] {Load Third 8}
fistp qword ptr [edx+16] {Save Third 8}
@@Small24:
fistp qword ptr [edx+8] {Save Second 8}
@@Small16:
fistp qword ptr [edx] {Save First 8}
fistp qword ptr [edx+ecx] {Save Last 8}
@@Exit:
ret
nop {4-Byte Align JumpTable}
nop
@@JumpTable: {4-Byte Aligned}
dd @@Exit, @@M01, @@M02, @@M03, @@M04, @@M05, @@M06, @@M07, @@M08
@@LargeForwardMove: {4-Byte Aligned}
push edx
fild qword ptr [eax] {First 8}
lea eax, [eax+ecx-8]
lea ecx, [ecx+edx-8]
fild qword ptr [eax] {Last 8}
push ecx
neg ecx
and edx, -8 {8-Byte Align Writes}
lea ecx, [ecx+edx+8]
pop edx
@FwdLoop:
fild qword ptr [eax+ecx]
fistp qword ptr [edx+ecx]
add ecx, 8
jl @FwdLoop
fistp qword ptr [edx] {Last 8}
pop edx
fistp qword ptr [edx] {First 8}
ret
@@LargeMove:
jng @@LargeDone {Count < 0}
cmp eax, edx
ja @@LargeForwardMove
sub edx, ecx
cmp eax, edx
lea edx, [edx+ecx]
jna @@LargeForwardMove
sub ecx, 8 {Backward Move}
push ecx
fild qword ptr [eax+ecx] {Last 8}
fild qword ptr [eax] {First 8}
add ecx, edx
and ecx, -8 {8-Byte Align Writes}
sub ecx, edx
@BwdLoop:
fild qword ptr [eax+ecx]
fistp qword ptr [edx+ecx]
sub ecx, 8
jg @BwdLoop
pop ecx
fistp qword ptr [edx] {First 8}
fistp qword ptr [edx+ecx] {Last 8}
@@LargeDone:
ret
@@M01:
movzx ecx, [eax]
mov [edx], cl
ret
@@M02:
movzx ecx, word ptr [eax]
mov [edx], cx
ret
@@M03:
mov cx, [eax]
mov al, [eax+2]
mov [edx], cx
mov [edx+2], al
ret
@@M04:
mov ecx, [eax]
mov [edx], ecx
ret
@@M05:
mov ecx, [eax]
mov al, [eax+4]
mov [edx], ecx
mov [edx+4], al
ret
@@M06:
mov ecx, [eax]
mov ax, [eax+4]
mov [edx], ecx
mov [edx+4], ax
ret
@@M07:
mov ecx, [eax]
mov eax, [eax+3]
mov [edx], ecx
mov [edx+3], eax
ret
@@M08:
fild qword ptr [eax]
fistp qword ptr [edx]
end;
{$ENDIF}
Główna róznica to deklaracja zmiennych jako PChar (Delphi 7) i PAnsiChar (Delphi 2010). I moim skromnym zdaniem tutaj jest sedno problemu - ale pamiętajcie, że jestem początkującym programistą.
Sekcja application/x-www-form-urlencoded pakietu wysłanego za pomocą POST w Delphi 7 ma w HEX postać (przykład):
ab de cd da ef
a to samo w Delphi 2010 wygląda już tak:
ab 00 de 00 cd 00 da 00 ef 00
i w tym momencie serwer już nie przyjmuje takiego zapytania.
Pokusiłem się o zamianę kodu w System.pas, na ten z Delphi 7. Za pomocą komend dokonałem rekompilacji zmienionego System.pas
dcc32.exe -M -Y -$D+ System.pas
dcc32.exe -M -Y -$D- System.pas
Podmieniłem odpowiednio pliki w katalogach /lib, /lib/debug, /lib/release. Projekt skompilowany ponownie, ale efektu zero.
To tyle moich wypocin. Czy macie jakiś sposób na ten problem ? Czy trzeba się pożegnać z Synapse ?
Nie wiem czy klasa TStringList
nie jest też w unicode. Ale ja bym zrobił lamerskie rozwiązanie, skoro deklarowanie AnsiString
nie pomaga. Zresztą robiłem tak, gdy nie wiedziałem sam jak zapisać string do TMemoryString
, a co kiedyś w jakimś starym kodzie pokazał mi MisiekD.
Zrób więc może tak na próbę. Utwórz TStringList
, ustaw jego właściwosć Text
na żądany AnsiString. Usuń ostatnie dwa znaki (czyli CR LF - znak nowej linii, bo zawsze on jest na końcu, powinno pomóc samo Delete
). Teraz zrób TwojaStringLista.SaveToSreeam(Document)
. Może zadziała ok.
Jeżeli nie, to ktoś inny może doradzi coś lepszego. Ja później już korzystałem na ogól z Synapse pod Delphi 7.
Wersja rozwojowa Synapse jest kompatybilna z Unicode (nie wiem czy w 100% ale to co ja robiłem na pewno i do tego należało wysyłanie POST)
https://sourceforge.net/p/synalist/code/HEAD/tree/trunk/
Jestem już po próbach i testach.
Na obecną chwilę sprawdził się sposób podany przez olesio. Zrobiłem to tak:
Address := strona_www;
Command := '/action/License/DownloadContext';
URLData := 'fileId=' + id_pliku + '&__RequestVerificationToken=' + token;
// sposób od olesio
Params := TStringList.Create;
Params.Text := URLData;
Params.SaveToStream(Document);
HTTPMethod('POST', Address + Command);
Próbowałem się pozbyć znaku ostatniej linii, ale nie wychodzi mi. Jak to zrobić, bez wyciągania tekstu z TStringList, modyfikacji wyciągniętego tekstu i ponownego wpisania do TStringList - bo to co przed chwilą napisałem nie ma sensu. Po wpisaniu do TStringList, znak nowej linii znowu powraca. Próbowałem Delete, Trim i inne nietrafione sposoby znalezione w sieci. Trzeba by to zapewne robić bezpośrednio na danym tekście w TStringList - jest to możliwe, czyżbym coś przeoczył ?
Dzięki kAzek za link do rozwojowego Synapse. Rzeczywiście są różnice, ale po zastosowaniu tej wersji Synapse, bez zmian, problem nadal występował.
PS. Mimo znaku nowej linii w wysyłanym pakiecie, serwer go akceptuje i odpowiada poprawnie. Ale kto wie jak będzie z innymi serwerami.
Sorry, nie do końca dobrze podpowiedziałem. Z klasą TStringList
się chyba nie da, zawsze dojdzie ten znak nowej lini, nawet przy operacjach na właściwości Text
. Ale jest też przecież jeszcze klasa TStringStream
. Pod Delphi 7 mi poniższy kod działa ok.
Utworzony plik D:\test.bin
ma rozmiar dokładnie czterech bajtów, czyli długość słowa Test
. A jak widać zapisuje TMemoryStream
, a takiego samego typu jest pod Synapse właściwość Document
. Także raczej będzie pewne, że nic nie zostanie namieszane w nagłowku niezgodnie z protokołem HTTP(S)
. I serwer raczej powinien otrzymać to czego oczekuje, ale sprawdź.
//...
var
SS : TStringStream;
MS : TMemoryStream;
begin
SS := TStringStream.Create('Test');
MS := TMemoryStream.Create;
MS.LoadFromStream(SS);
MS.SaveToFile('D:\test.bin');
SS.Free;
MS.Free;
end;
Innego sposobu nie znam. Chociaż kto wie jak nowsze Delphi czy FPC/Lazarus odniesie się do konstruktora. To też sprawdź, bo wszędzie te narzucanie nam UNICODE. Niby wymóg czasów, ale to tak jakby nagle wywalić z Windowsa wszelkie funkcje WinAPI z końcowką A
, zamiast W
, bo po co komu przecież wstępna kompatybilność i uproszczenie? ;)
EDIT: pod Delphi XE 8, więc w miarę nowym. Powyższy kod zachowuje się tak samo. Także może to skuteczny sposób.
A nie lepiej czasami poprawić kawałek kodu aby "było po ludzku" ?
I najlepiej w tym co jest już w IDE ?
http://docwiki.embarcadero.com/RADStudio/XE8/en/Using_an_HTTP_Client
Koncepcja poprawiania move w System.pas to tez proszenie sie o kłopoty , a po drugie to nie mialo prawa zadzialac lepiej , bo niby dlaczego, jak w obydwu wersjach działały te funkcje tak samo ?
Do @olesio : oczywiście Twój sposób działa, nie ma znaku końca linii w wysyłanym pakiecie. I można chyba uznać to za rozwiązanie zaistniałego problemu. Chyba że ktoś ma jeszcze zgrabniejszy pomysł.
Do @Adamek Adam : oczywiście, że można i tak, może i też za pomocą Indy, ale temat postu to Delphi 2010 i Synapse... i na tym się skupiamy.