Webbrowser i wywolanie okna do upload'u pliku.

0

Witam serdecznie.

Mam na komponencie WebBrowser wczytana strone w ktorej znajduje sie opcja do Upload'u pliku.
Potrzebuje ze strony kodu wywolac okno dialogowe do wyboru pliku do zaladowania na serwer.
Albo mozliwosc bezposredniego wypelnienia pola typu File, ze sciezka pliku. Z tego co sie doczytalem obiekt typu File nie pozwala na bezposrednia modyfikacje wartosci (value), dlatego tez idea z otwarcie okna dialogowego i dalsza operacja na uchwycie okna.

To jest fragment kodu HTML z komponentu WebBrowser, wktorym jest wczytana stronka:

<TABLE id=t52 class=SFileChooser eid="t52">
<TBODY><TR><TD> 
<INPUT size=16 type=file Name=t52> 
</TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></TD></TR>
<TR><TD style="PADDING-BOTTOM: 3px; PADDING-LEFT: 3px; PADDING-RIGHT: 3px; PADDING-TOP: 3px" vAlign=top align=left oversize="6">

Z gory dziekuje za wszelka pomoc.

0
arturfir napisał(a):

Z gory dziekuje za wszelka pomoc.

Pomoc w czym? Nie ma żadnego pytania.

poza tym pewnie łatwiej jest napisać ręczny system uploadu bazujący na synapse/indy.

0

To jest pytanie:

  1. Jak wywolac okno dialogowe do wyboru pliku do zaladowania na serwer pliku od strony kodu w Delphi?
  2. Jak wypelnic bezposrednio pole typu File, ze sciezka pliku, od strony kodu.

A co do Synapse/indy nie mam zielonego pojecia z ta materia. Moze jakas wskazowka? W miedzy czasie poszukam na Google.

I jeszcze cos: mi nie chodzi o to, zeby od razu wyslac plik na serwer, tylko wypelnic pole File sciezka do pliku...

0

Ech @arturfir: no niemal załamałem się. Jesteś od tak dawna na tym forum, a pytasz tutaj - zanim poszukasz w google? Wstyd ;P Co do Synapse i HTTP to mój skromny artykuł na ten temat jest tutaj: Obsługa protokołu HTTP przy użyciu pakietu Synapse - więcej znajdziesz w dokumentacji na stronie projektu i przykładach dołaczonych do archiwum z pakietem. Co do Indy to sobie pogoogluj albo mając konkretniejsze problemy po samodzielnym kombinowaniu oczekuj na odpowiedź Użytkownika @kAzek, który chyba jako jedyny ogarnia jeszcze niuanse związane z niedziałaniem czegoś w Indy.

0

W Indy szukaj na temat TIdMultiPartFormDataStream miedzy innymi tu ktoś dał odpowiedź http://www.delphigroups.info/2/80/189035.html co do okna dialogowego to zwykły OpenDialog a AddFile masz 1 parametr to name to nazwa pola w twoim przypadku to t52 , drugi to ścieżka i nazwa pliku, trzeci to typ MIME jest zależny od tego jaki plik chcesz uploadować ale jeżeli chodzi tylko wrzucenie pliku na serwer application/octet-stream jako domyślny powinien być odpowiedni.

EDIT// HTTP w przykładzie to oczywiście IdHTTP

0

Dzieki za odpowiedz...
Tak jestem juz dlugo na tym serwise, ale dawno nie odwiedzalem.... a poza tym nie wstydze sie pytac, bo przeciez kto pyta nie bladzi :) No i chyba do tego sluzy forum..

Jeszcze raz wyjasnie moj problem: pisze aplikacje ktora wspomaga dzialanie innej aplikacji opartej na HTML z JavaScript (stworzona przy pomocy WINGS Framework- bazujaca na AJAX). Moj program wyswietla za pomoca komponentu WebBrowser albo EmbeddedWB ta aplikacje i za pomoca dodatkowych procedur wypelnia odpowiednie pola zawartosci WebBrowsera..

Wszystko funkcjonuje bardzo dobrze tylko mam problem z wypelnieniem pola gdzie znajduje sie sciezka pliku do wyslania w INPUT typu FILE (tylko wpisanie sciezki pliku, nie wysylanie). Dodam ze pole INPUT typu File jest blokowane od bezposredniego dostepu..

Jezeli da sie to zrobic z wykorzystaniem Synapse albo Indy to bede rozgryzal Synapse...
Moje Pytania:

  1. Koncentrowac sie na SYNAPSE czy nie ?
  2. Inna mozliwosc rozwiazania problemu?

Dzieki

0

Problem nadal nie rozwiazany. Czy ktos potrafi udzielic jakichkolwiek wskazowek?

Z gory dzieki...

0

A jakich jeszcze wskazówek potrzebujesz? Próbowałeś w ogóle z Synapse to ogarnąć? Pytasz się dziwnie czy próbować z Synapse. Ja bym na Twoim miejscu spróbował pokombinować. Bo czy czymś - nie wiem - ryzykujesz? Póki co masz tylko upload z przeglądarki. A tak możesz mieć przez swój program, jeżeli ogarniesz temat. I według mnie, jeśli jakaś strona nie korzysta z javascriptu to Synapse powinno się to dać ogarnąć. I zrobić coś na bazie gotowej funkcji HttpPostFile z modułu httpsend. Tylko tutaj się nie ma co sugerowac tym słowem "send" w nazwie. Nie służy on tylko do wysyłania, ponieważ to podstawowy moduł jaki należy dodać do sekcji uses, jeżeli chcemy korzystać z HTTP przy użyciu tego pakietu.

0

A jak się upierasz na ten WebBrowser to:

W WebBrowser nie ma możliwości wypełnienia pola typu file (podobno ze względów bezpieczeństwa)

Aby wywołać okno ładowania pliku w WebBrowser to poszukać (albo jakieś getElementByID albo pętelka i sprawdzanie to zależy od HTML czy jest ID czy może tylko name itp.) odpowiedniego elementu (tego input typu file) i wywołać metodę Click (pod warunkiem że jest widoczne inaczej chyba nie zadziała)

Wysłać plik za pomocą WebBrowser oczywiście można napisałem przykład (sprawdzony w Delphi 7) ale nie chciało mi się pisać komentarzy jak coś nie będzie jasne to pisz:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, OleCtrls, SHDocVw;

type
  TForm1 = class(TForm)
    WebBrowser1: TWebBrowser;
    btnSend: TButton;
    OpenDialog1: TOpenDialog;
    procedure btnSendClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    procedure WaitWhileBusy(WB: TWebBrowser);
    function StreamToVarArray(AStream: TStream): OleVariant;
    procedure WBPostMultipartData(WB: TWebBrowser; const URL, FieldName,
      FileName: string; const Data: TStream; const FormFields: TStrings);
    function GetActionURL(WB: TWebBrowser; FormName: string): string;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

uses MSHTML;

{$R *.dfm}

procedure TForm1.WaitWhileBusy(WB: TWebBrowser);
begin
  while WB.ReadyState <> READYSTATE_COMPLETE do
    Application.ProcessMessages;
end;

function TForm1.StreamToVarArray(AStream: TStream): OleVariant;
var
  Buffer: Pointer;
begin
  AStream.Position:= 0;
  Result:= VarArrayCreate([0, AStream.Size - 1], VarByte);
  Buffer:= VarArrayLock(Result);
  AStream.ReadBuffer(Buffer^, AStream.Size);
  VarArrayUnlock(Result);
end;

procedure TForm1.WBPostMultipartData(WB: TWebBrowser; const URL, FieldName,
  FileName: string; const Data: TStream; const FormFields: TStrings);
const
  CRLF = #13#10;
  FIELD_MASK = CRLF + '--%s' + CRLF +
              'Content-Disposition: form-data; name="%s"' + CRLF + CRLF + '%s';
var
  Flags, SendData, Headers: OleVariant;
  Bound, s, PostData: string;
  ms: TMemoryStream;
  i: Integer;
begin
  Bound:= '===============' + IntToHex(Random(MaxInt), 8) + '==';

  s:= '--' + Bound + CRLF;
  s:= s + 'content-disposition: form-data; name="' + FieldName + '";';
  s:= s + ' filename="' + FileName +'"' + CRLF;
  s:= s + 'Content-Type: Application/octet-string' + CRLF + CRLF;
  ms:= TMemoryStream.Create;
  try
  ms.Write(Pointer(s)^, Length(s));
  ms.CopyFrom(Data, Data.Size);
  for i:= 0 to FormFields.Count - 1 do
  begin
    s:= Format(FIELD_MASK,[Bound, FormFields.Names[I],
        FormFields.Values[FormFields.Names[I]]]);
    ms.Write(Pointer(s)^, Length(s));
  end;
  s:= CRLF + '--' + Bound + '--' + CRLF;
  ms.Write(Pointer(s)^, Length(s));
  //stare kopiowanie
  {SetString(PostData, PChar(ms.Memory), ms.Size div SizeOf(Char));
  SendData:= VarArrayCreate([0, length(PostData)-1], varByte);
  for i := 1 to length(PostData) do
    SendData[i-1] := ord(PostData[i]);}
  SendData:= StreamToVarArray(ms); 
  finally
  ms.Free;
  end;

  Headers:= 'Content-Type: multipart/form-data; boundary=' +  Bound + CRLF;
  Flags:= NavNoHistory or NavNoReadFromCache or NavNoWriteToCache
    or NavAllowAutosearch;

  WB.Navigate(URL, Flags, EmptyParam, SendData, Headers);

  WaitWhileBusy(WB);

  VarClear(SendData);
end;

function TForm1.GetActionURL(WB: TWebBrowser; FormName: string): string;
var
  i: Integer;
  doc: IHTMLDocument2;
  form: IHTMLFormElement;
begin
  result:='';
  doc:= WB.Document as IHTMLDocument2;
  if Assigned(doc) then
  begin
    for i:= 0 to doc.forms.length - 1 do
    begin
      form:= doc.forms.item(i, EmptyParam) as IHTMLFormElement;
      if form.name = FormName then
      begin
        result:= form.action;
        break;
      end;
    end;
  end;
end;

procedure TForm1.btnSendClick(Sender: TObject);
var
  FileName: string;
  URL: string;
  DataStream: TFileStream;
  FormFields: TStringList;
begin
  WebBrowser1.Navigate('http://encodable.com/uploaddemo/');
  WaitWhileBusy(WebBrowser1);
  if OpenDialog1.Execute then
  begin
    DataStream:= TFileStream.Create(OpenDialog1.FileName, fmOpenRead);
    try
    FormFields:= TStringList.Create;
    try
    FormFields.Delimiter:= '&';
    FormFields.DelimitedText:= 'numitems=1&numfileelements=2&subdir1=/&newsubdir1=';
    FileName:= ExtractFileName(OpenDialog1.FileName);
    URL:= 'http://encodable.com' + GetActionURL(WebBrowser1, 'theuploadform');
    WBPostMultipartData(WebBrowser1, URL, 'uploadname1', FileName, DataStream,
      FormFields);
    WaitWhileBusy(WebBrowser1);
    finally
    FormFields.Free;
    end;
    finally
    DataStream.Free;
    end;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Randomize;
end;

end.

No ale jednak tak jak @olesio twierdzę że porywania się z tym WebBrowser (o ile to nie jest konieczne) do uploadu pliku to jak polowania na muchy z armatą. Od kiedy zadałeś pytanie na pewno znalazłbyś czas aby poczytać trochę i poznać podstawy Synapse czy Indy bo naprawdę wysłać plik za pomocą tych pakietów to nic skomplikowanego.

0

Dzieki wszystkim za udzielone odpowiedzi.
Dzieki kAek za kod, na dniach zobacze jak daleko dojde i dam znac, ale z tego co widze to po otwarciu OpenDialog i wybraniu pliku od razu wysyla do serwera, a ja wlasnie tego nie chce.
A o co Chodzi z ta metoda Click? i jak ja wywolac?

Aby wywołać okno ładowania pliku w WebBrowser to poszukać (albo jakieś getElementByID albo pętelka i sprawdzanie to zależy od HTML czy jest ID czy może tylko name itp.) odpowiedniego elementu (tego input typu file) i wywołać metodę Click (pod warunkiem że jest widoczne inaczej chyba nie zadziała)

Jak to dokladnie funkcjonuje? Bo wlasnie dokladnie tego mi trzeba.

A co do Synapse to faktycznie bardzo przydatne narzedzie, ale nie w tym przypadku. Ja potrzebuje wypelnic pola w WebBrowser'ze a nie wysylac (uploadowac pliku). Sam proces wysylania do serwera jest w reku uzytkownika...on potwierdza wysylanie pliku.
Takze z wykorzystaniem Synapse nie zrealizuje tego zadania, chyba ze napisze dodatkowo przegladarke... ale po co? jak juz jest :)
Jezeli sie myle to prosze o sprostowanie.

Pozdrowiam

1

Jak już napisałem pola typu file automatycznie nie wypełnisz (ze względów bezpieczeństwa to jest niemożliwe - wyobraź sobie powiedzmy JavaScript na stronie który wypełnia to pole (wystarczyło by znać lokalizację pliku) i wysyła formularz "podkradając" plik z komputera użyszkodnika)

co do metody Click to chodzi o pokazanie okna wyboru pliku do wysłania (tego z przeglądarki) poprzez kliknięcie na pole file a kod ma mniej więcej wyglądać tak:

//do uses MSHTML;
var
  doc: IHTMLDocument2;
  form: IHTMLFormElement;
  elem: IHTMLElement;
  i, j: Integer;
begin
  WebBrowser1.Navigate('http://encodable.com/uploaddemo/');
  while WebBrowser1.ReadyState <> READYSTATE_COMPLETE do //poczekaj na zaladowanie strony
    Application.ProcessMessages;
  doc:= WebBrowser1.Document as IHTMLDocument2;  //pobranie dokumentu
  if Assigned(doc) then //dokument istnieje czyli strona zaladowana
  begin
    for i:= 0 to doc.forms.length - 1 do //szukamy formularza ktory ma byc wyslany
    begin
      form:= doc.forms.item(i, EmptyParam) as IHTMLFormElement; //mamy formularz
      if form.name = 'theuploadform' then  //np. sprawdzamy name czy o ten formularz chodzi
      begin
        for j:= 0 to form.length - 1 do  //teraz poszukamy pola file
        begin
          elem:= form.item(j, EmptyParam) as IHTMLElement;
          if (elem.tagName = 'INPUT') and //czy to pole input
           ((elem as IHTMLInputElement).name = 'uploadname1') then //i o nie chodzi?
          begin
            elem.click; //klikamy na to pole aby pokazac okno wyboru pliku
            exit; //nie mamy wiecej nic do zrobienia wiec wyskok z obu petli na koniec
          end;
        end;
      end;
    end;
  end;
end;

Ja kod oczywiście daje do tamtej przykładowej strony aby pokazać jak to mniej więcej się robi, Ty musisz sobie go dostosować do swoich potrzeb.

0

Dzieki kAzek.... wlasnie o to mi chodzilo.. takie proste.... jak sie wie :)
Troche przerobilem kod, bo pole input nie jest zdefiniowane prze ID tylko przez atrybut NAME..

Tags := Body.getElementsByTagName('*');   
for I := 0 to Pred(Tags.length) do
  begin
    Tag := Tags.item(I, EmptyParam) as IHTMLElement;
    name_str:= Format('%s',[Tag.getAttribute('name',0)]);
    if AnsiSameText(name_str, 'nazwa_inputa') then
    begin
      tag.click;     
      Break;
    end;
  end;

a potem to tylko obsluga uchwytu okna... jak przestestuja to dolacze kod :)

No i wlasnie o to chodzilo !!!

Pozdrawiam wszystkich i dzieki za rady....
w szczegolnosci dla kAzek

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