TWebBrowser i wyskakujące MessageBoxy

0

Napisałem aplikację, któa cyklicznie przeklikuje pewien portal. Automatycznie loguje się na konta podane w konfiguracji, sprawdza konkretny obszar portalu i w razie wystąpienia pewnych elementów powiadamia użytkownika o tym fakcie.

Aby dotrzeć do obszaru, który program ma monitorować - musi się przeklikać przez strony pośrednie - oczywiście ten fragment jest, działa i nie ma co do niego zastrzeżeń.

Zdarza się jednak, że portal uruchamia okienka z komunikatami w postaci MessageBoxów, które zazwyczaj mają jeden przycisk do kliknięcia (czyste okno informacyjne). Wtedy program zatrzymuje się i czeka na reakcję użytkownika. Z założenia użytkownik nie ma widzieć procesu przeklikiwania, tylko informację w Tray'u, że w monitorowanym obszarze nastapiły zmiany - więc dobrze by było albo zasymulować kliknięcie tych komunikatów, albo w jakiś sposób wyłączyć pojawianie się tych okienek.

Używam TWebBrowser (w związku z tym, że aplikacja poza tym elementem jest i działa - wolałbym nie dyskutować nad użytą technologią - wiem, że ma swoje wady i istnieją lepsze). Właściwość "Silent" niestety nie działa.

Znalazłem rozwiązanie, które monitoruje, czy w systemie istnieje okienko o konkretnym tytule i wysyła do niego Message:
http://stackoverflow.com/questions/11885700/howto-simulate-click-ok-in-webbrowser-alert-messagebox-that-initiated-by-a-java
ale jakoś to rozwiązanie mnie nie przekonuje.

1

Zamiast TWebBrowser użyj też bazującego na IE a bardziej rozbudowanego TEmbededWB (do pobrania z http://www.bsalsa.com/downloads.html ) tam masz obsługę zdarzenia OnShowMessage (właśnie można zablokować okna komunikatów) przykład http://www.bsalsa.com/ewb_on_show_mess.html albo przejrzyj źródła i zobacz jak to tam zostało zrobione.

EDIT// Zrobiłem za Ciebie czarną robotę. Kod dodający do zwykłego TWebBrowser obsługę tego komunikatu:

//do uses SHDocVw, ActiveX
type
  IDocHostShowUI = interface(IUnknown)
    ['{c4d244b0-d43e-11cf-893b-00aa00bdce1a}']
    function ShowMessage(hwnd: THandle; lpstrText: POleStr; lpstrCaption: POleStr;
      dwType: longint; lpstrHelpFile: POleStr; dwHelpContext: longint;
      var plResult: LRESULT): HRESULT; stdcall;
  end;

  TShowMessageEvent = function(Sender: TObject; HWND: THandle;
    lpstrText: POleStr; lpstrCaption: POleStr; dwType: Longint; lpstrHelpFile: POleStr;
    dwHelpContext: Longint; var plResult: LRESULT): HRESULT of object;

  TMyWB = class(TWebBrowser, IDocHostShowUI)
  private
    fOnShowMessage: TShowMessageEvent;
  protected
    function ShowMessage(HWND: THandle; lpstrText: POleStr; lpstrCaption: POleStr;
      dwType: Longint; lpstrHelpFile: POleStr; dwHelpContext: Longint;
      var plResult: LRESULT): HRESULT; stdcall;
  published
    property OnShowMessage: TShowMessageEvent read fOnShowMessage write
      fOnShowMessage;
  end;

//....

function TMyWB.ShowMessage(HWND: THandle; lpstrText, lpstrCaption: POleStr;
  dwType: Integer; lpstrHelpFile: POleStr; dwHelpContext: Integer;
  var plResult: LRESULT): HRESULT;
begin
  if Assigned(fOnShowMessage) then
    Result := fOnShowMessage(Self, HWND, lpstrText, lpStrCaption, dwType,
      lpStrHelpFile, dwHelpContext, plResult)
  else
    Result:= S_FALSE;
end;

Teraz wystarczy stworzyć TMyWB dynamicznie (albo zrobić z tego komponent) obsłużyć OnShowMessage (zwracać S_OK) i okna komunikatów nie powinny się pojawiać.

0

Mega podziękowanie.

Natknąłem się na to rozwiązanie (to znaczy gdzieś znalazłem to rozwiązanie, ale po cichu liczyłem, że to może będzie coś na prawdę banalnego, co może w dokumentacji przeoczyłem). Niemniej - wielkie dzięki jeszcze raz.

EDIT: Niestety - powyższe rozwiązanie nie zadziałało, bo okienka nie były generowane przez przeglądarkę jako taką, tylko przez skrypt JavaScipt. Na bazie Twojego przykłądu stworzyłem nową klasę/komponent i dodatkowo rozszerzyłem o rozwiązanie z tego linka:
http://stackoverflow.com/questions/8566659/how-do-i-make-twebbrowser-keep-running-javascript-after-an-error

Dzięki jeszcze raz za naprowadzenie.

0
toyman napisał(a):

EDIT: Niestety - powyższe rozwiązanie nie zadziałało, bo okienka nie były generowane przez przeglądarkę jako taką, tylko przez skrypt JavaScipt. Na bazie Twojego przykłądu stworzyłem nową klasę/komponent i dodatkowo rozszerzyłem o rozwiązanie z tego linka:
http://stackoverflow.com/questions/8566659/how-do-i-make-twebbrowser-keep-running-javascript-after-an-error

Dzięki jeszcze raz za naprowadzenie.

Z okienkami komunikatów tworzonych przez JavaScript funkcją alert powyższy kod ma sobie radzić (chyba że coś źle zrobiłeś). Tobie raczej chodzi o komunikaty błędów skryptu w obsługę ich został także zapatrzony proponowany przeze mnie TEmbededWB tym razem zdarzenie OnScriptError http://www.bsalsa.com/ewb_on_script_err.html (oczywiście gdyby pogrzebać można je dodać i do tego kodu ale skoro jakoś sobie poradziłeś to nawet nie wnikam) więc jednak w dalszym ciągu proponuję przesiadkę bo za chwilę (oby nie) znowu Ci coś wypadnie i się przesiądziesz tylko co się do tej pory pomęczysz to Twoje.

0

Przesiadka na EmbendedWB zakończona sukcesem. Komponent rzeczywiście jest ... rozbudowany.

Dzięki za naprowadzenie i podpowiedź.

0

Potrzebuję jeszcze jednego naprowadzenia: Jak obsługiwać wyskakujące okienka ?

Ścieżka jaką muszę przejść na tym portalu wiedzie również przez wyskakujące okienko, gdzie prezentowane są wyniki wyszukiwania po filtrach zadanych w oknie głównym. Są owszem zdarzenia OnNewWindow, ale nie bardzo wiem odwołać się do obiektu obsługującego nowe okno.

To jeden problem. A drugi - formalnie docelowo aplikacja ma nie pokazywać w ogóle procesu "przeklikiwania" tylko właśnie wyniki z tego wyskakującego okienka - nie mam pomysłu jak to zrealizować.

EDIT: Przepraszam za zawracanie głowy. Znalazłem pasowny kod w dokumentacji:
http://www.bsalsa.com/ewb_on_new_win.html

i zrobiłem tak:

procedure TForm1.EmbeddedWB1NewWindow2(ASender: TObject;
  var ppDisp: IDispatch; var Cancel: WordBool);
begin
    ppDisp:=Form1.EmbeddedWB1.Application;
end; 

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