Delphi 2010 i Synapse - program nie działa prawidłowo

0

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+".

0

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 :(.

0

Ok, dziękuję za informację, a i jak rozumiem - zamiana w źródłach
wszystkich typów String na UnicodeString nie rozwiąże problemu?

0

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.

0

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.

0

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/

0

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 efa to samo w Delphi 2010 wygląda już tak:
ab 00 de 00 cd 00 da 00 ef 00i 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 ?

1

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.

1

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/

0

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.

1

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.

0

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 ?

0

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.

0 użytkowników online, w tym zalogowanych: 0, gości: 0