A TWebbrowser a Microsoft Internet Explorerének ActiveX komponense, melynek használatával alkalmazásunkban megjeleníthetünk weblapokat, megtekinthetünk különböző fájlokat, könyvtárak tartalmát. Röviden egy komplett böngészőt integrálhatunk programunkba.
A Microsoft Webbrowser komponens részletes ismertetése megtalálható a Microsoft Developer Network oldalán (http://msdn.microsoft.com/en-us/library/aa752040(VS.85).aspx).
A Delphi 5.0 változattól már az alapcsomag részét képezi, azonban a „gyári” komponenst célszerű eltávolítani, mert az még egy régebbi Internet Explorer változatát tartalmazza. A Delphiben a Component - Install package... menü választása után a megjelenő ablakban a Design packages közül keressük meg az Internet Explorer Components sort, majd kattintsunk a Remove gombra.
Az új TWebbrowser komponens telepítéséhez a következő lépéseket kell végrehajtani: Component - Import ActiveX control... menü kiválasztása, majd a megjelenő ablakban a Microsoft Internet Controls sort kiválasztva kattintsunk az Install… gombra. Ennek hatására az ActiveX fülön létrejön 2 új komponens - a TWebbrowser és a TWebbrowser_V1, valamint elkészült a SHDocVw_TLB.pas fájl is. Ebből a két komponensből bennünket csak a TWebbrowser fog érdekelni. A TWebbrowser_V1 az IE 3.0-ás változatáig, míg az IE 4.0-ás változattól már a TWebbrowser komponens használandó. Jelenleg a legtöbb gépen már az Internet Explorer 8.0-s verziója található. A TWebbrowser komponensünk is a gépünkön lévő Internet Explorer verziójával lesz kompatibilis.
A TWebbrowser komponens telepítésén túl szükségünk lehet még a MSHTML_TLB.pas fájlra is, melyet a következő módon készíthetünk el. Component - Import ActivX control… - Microsoft HTML Object Library kiválasztása után kattintsunk a Create Unit gombra.
Most már képesek vagyunk megírni életünk első böngésző programját. Hozzunk létre egy új alkalmazást, a formra helyezzünk ki egy TWebbrowser komponenst WB néven, igazítsuk a megfelelő méretre, helyezzünk el egy TButtont Button néven, majd írjuk meg a ButtonOnClick eseményt.
procedure ButtonClick(Sender: TObject); begin WB.Navigate('http://inf.elte.hu'); end;
vagy használhatjuk a Navigate2 eljárást a következő módon.
procedure TForm1.ButtonClick(Sender: TObject); var URL : OleVariant begin URL := 'http://inf.elte.hu'; WB.Navigate2(URL); end;
Az alkalmazást futtatva és a Buttonra kattintva megjelenik a 'http://inf.elte.hu' oldal. Az oldalon kattinthatunk a linkekre, használhatjuk a jobb oldali egérgomb megnyomásakor megjelenő menüket, használhatjuk a fontosabb navigáló billentyűket (Alt + Balra, Alt + Jobbra, F5 stb.). Tehát pár sor megírásával elkészítettünk egy majdnem komplett böngésző programot. Természetesen nem csak weboldalak megtekintésére alkalmas a TWebbrowser komponens, hanem mappák ('file://c:\'), fájlok ('file://c:\a.txt') megjelenítésére is. Segítségével akár FTP-zhetünk is ('ftp://……').
Használhatjuk a Drog&Drop funkciót is. Egyszerűen az egérrel húzzunk rá egy fájlt vagy egy parancsikont és az rögtön megjelenik.
Egy TWebbrowser komponens használatának egyik legfontosabb eljárása a Navigate és a Navigate2. Ezek paraméterezésének részletes leírása megtalálható a http://msdn.microsoft.com/en-us/library/aa752093(VS.85).aspx oldalon.
A Navigate vagy Navigate2 eljárással elkezdődik a megadott oldal betöltése. Betöltés alatt számos esemény lekezelésére van lehetőségünk.
BeforeNavigate2 = procedure(Sender: TObject; const pDisp: IDispatch; var URL: OleVariant; var Flags: OleVariant; var TargetFrameName: OleVariant; var PostData: OleVariant; var Headers: OleVariant; var Cancel: WordBool) of object;
Meghívásra kerül minden olyan esetben, amikor valamilyen „dokumentum” kerül letöltésre. Mivel egy weblap tartalmazhat számos FRAME ill. IFRAME „dokumentum”-ot, így az OnBeforeNavigate2 esemény minden ilyen „dokumentum” letöltése előtt meghívásra kerül. Az URL tartalmazza az adott „dokumentum” címét, a pDisp pedig ennek az iDispatch interface-ét. Lehetőség van a Cancel := True; beállításával a navigálást megszakítani (csak az adott „dokumentum”), amit vagy az URL, vagy pedig a pDisp alapján választhatunk ki. Itt módosíthatjuk pl. a PostData-t. Felmerül a kérdés, hogy hogyan lehet megállapítani,hogy az ún. főoldal navigálását kezdjük meg és nem pedig ennek a „dokumentum”-nak a különböző FRAME-jeit, IFRAME-jeit? Erre szolgál a pDisp. Ha (pDisp as IWebBrowser) = ((aSender as TWebbrowser).DefaultInterface) igaz, akkor az URL a „fődokumentum”, minden más esetben az adott oldal FRAME-jeinek a navigálása kezdődik meg. Pl. ha szeretnénk letiltani az oldal összes FRAME-jenek letöltését, akkor a Cancel := not ((pDisp as IWebBrowser) = ((aSender as TWebbrowser).DefaultInterface)) használjuk.
CommandStateChange = procedure(Sender: TObject; Command: Integer; Enable: WordBool) of object;
Meghívásra kerül, amennyiben változtatni kell a programon belül bizonyos műveletek elérhetőségét. A Command három értéket vehet fel (CSC_NAVIGATEBACK, CSC_NAVIGATEFORWARD, CSC_UPDATECOMMANDS) és az adott Command engedélyezését az Enable tartalmazza. Pl. a CSC_NAVIGATEBACK határozza meg, hogy engedélyezzük-e programon belül a BackButtont.
case Command of CSC_NAVIGATEBACK : BackButton.Enabled := Enable; CSC_NAVIGATEFORWARD : ForwardButton.Enabled := Enable; end;
DocumentComplete = procedure(Sender: TObject; const pDisp: IDispatch; var URL: OleVariant) of object;
Hasonlóan az OnBeforeNavigate2-höz információt kapunk, hogy mely „dokumentum”-ok letöltése fejeződött be. A „fődokumentum”-ot szintén a (pDisp as IWebBrowser) = ((aSender as TWebbrowser).DefaultInterface) kifejezéssel ellenőrizhetjük le.
NewWindow2 = procedure(Sender: TObject; var ppDisp: IDispatch; var Cancel: WordBool) of object;
Itt kezelhetjük le, hogy mi történjen akkor, amikor egy link új lapon kerül megnyitásra. Ezt kiválthatja egy felhasználói kattintás vagy akár egy JAVASCRIPT utasítás is. A ppDisppel adjuk meg az új TWebbrowser komponens IDispatch-ét (ha nem adunk meg semmit, akkor az operációs rendszer alapértelmezett böngészője kerül megnyitásra), a Cancel := True; beállításával tudjuk visszautasítani az új ablak nyitás kérelmét.
Hogyan lehet azt megadni, hogy az új lap pl. a programon belül a WB2-es komponensben kerüljenek megnyitásra? A megoldás: ppDisp := WB2.DefaultInterface as IDispatch;
ProgressChange = procedure(Sender: TObject; Progress: Integer; ProgressMax: Integer) of object;
Az aktuális oldal betöltés állapotáról kapunk tájékoztatást. Pl. egy TProgressBar használatával tájékoztathatjuk a felhasználót, hogy hány %-on áll a folyamat.
StatusTextChange = procedure(Sender: TObject; const Text: WideString) of object;
A komponens állapotváltozásait tudjuk megjeleníteni pl. a formon elhelyezett TStausBar komponensen. Ezt kiválthatja egy oldal letöltése vagy akár egy felhasználói egérmozgás is, amikor pl. egy linkre kerül az egérmutató.
TitleChange = procedure(Sender: TObject; const Text: WideString) of object;
A betöltött oldal nevének (TITLE) változásáról kapunk tájékoztatást. Pl. Form.Caption := Text;
procedure GoBack; procedure GoForward; procedure GoHome; procedure GoSearch; procedure Refresh; procedure Stop;
Nem szorul magyarázatra. Pl. a BackButton OnClick eseménye legyen a WB.GoBack;
procedure ExecWB(cmdID: OLECMDID; cmdexecopt: OLECMDEXECOPT; var pvaIn: OleVariant; var pvaOut: OleVariant);
Különböző utasításokat adhatunk ki a TWebbrowser komponens részére. A pvaIn az adott utasítás bemenő értéke, míg a pvaOut a kiadott utasítás esetleges visszatérési értéke. A cmdID és cmdexecopt értékei a következők lehetnek.
type OLECMDID = TOleEnum; const OLECMDID_OPEN = $00000001; OLECMDID_NEW = $00000002; OLECMDID_SAVE = $00000003; OLECMDID_SAVEAS = $00000004; OLECMDID_SAVECOPYAS = $00000005; OLECMDID_PRINT = $00000006; OLECMDID_PRINTPREVIEW = $00000007; OLECMDID_PAGESETUP = $00000008; OLECMDID_SPELL = $00000009; OLECMDID_PROPERTIES = $0000000A; OLECMDID_CUT = $0000000B; OLECMDID_COPY = $0000000C; OLECMDID_PASTE = $0000000D; OLECMDID_PASTESPECIAL = $0000000E; OLECMDID_UNDO = $0000000F; OLECMDID_REDO = $00000010; OLECMDID_SELECTALL = $00000011; OLECMDID_CLEARSELECTION = $00000012; OLECMDID_ZOOM = $00000013; OLECMDID_GETZOOMRANGE = $00000014; OLECMDID_UPDATECOMMANDS = $00000015; OLECMDID_REFRESH = $00000016; OLECMDID_STOP = $00000017; OLECMDID_HIDETOOLBARS = $00000018; OLECMDID_SETPROGRESSMAX = $00000019; OLECMDID_SETPROGRESSPOS = $0000001A; OLECMDID_SETPROGRESSTEXT = $0000001B; OLECMDID_SETTITLE = $0000001C; OLECMDID_SETDOWNLOADSTATE = $0000001D; OLECMDID_STOPDOWNLOAD = $0000001E; OLECMDID_ONTOOLBARACTIVATED = $0000001F; OLECMDID_FIND = $00000020; OLECMDID_DELETE = $00000021; OLECMDID_HTTPEQUIV = $00000022; OLECMDID_HTTPEQUIV_DONE = $00000023; OLECMDID_ENABLE_INTERACTION = $00000024; OLECMDID_ONUNLOAD = $00000025; OLECMDID_PROPERTYBAG2 = $00000026; OLECMDID_PREREFRESH = $00000027; OLECMDID_SHOWSCRIPTERROR = $00000028; OLECMDID_SHOWMESSAGE = $00000029; OLECMDID_SHOWFIND = $0000002A; OLECMDID_SHOWPAGESETUP = $0000002B; OLECMDID_SHOWPRINT = $0000002C; OLECMDID_CLOSE = $0000002D; OLECMDID_ALLOWUILESSSAVEAS = $0000002E; OLECMDID_DONTDOWNLOADCSS = $0000002F; OLECMDID_UPDATEPAGESTATUS = $00000030; OLECMDID_PRINT2 = $00000031; OLECMDID_PRINTPREVIEW2 = $00000032; OLECMDID_SETPRINTTEMPLATE = $00000033; OLECMDID_GETPRINTTEMPLATE = $00000034; OLECMDID_PAGEACTIONBLOCKED = $00000037; OLECMDID_PAGEACTIONUIQUERY = $00000038; OLECMDID_FOCUSVIEWCONTROLS = $00000039; OLECMDID_FOCUSVIEWCONTROLSQUERY = $0000003A; OLECMDID_SHOWPAGEACTIONMENU = $0000003B; OLECMDID_ADDTRAVELENTRY = $0000003C; OLECMDID_UPDATETRAVELENTRY = $0000003D; OLECMDID_UPDATEBACKFORWARDSTATE = $0000003E; OLECMDID_OPTICAL_ZOOM = $0000003F; OLECMDID_OPTICAL_GETZOOMRANGE = $00000040; OLECMDID_WINDOWSTATECHANGED = $00000041; OLECMDID_ACTIVEXINSTALLSCOPE = $00000042; OLECMDID_UPDATETRAVELENTRY_DATARECOVERY = $00000043; type OLECMDEXECOPT = TOleEnum; const OLECMDEXECOPT_DODEFAULT = $00000000; OLECMDEXECOPT_PROMPTUSER = $00000001; OLECMDEXECOPT_DONTPROMPTUSER = $00000002; OLECMDEXECOPT_SHOWHELP = $00000003;
Pl. szeretnénk az adott oldal nagyítását beállítani a megadott értékre. Előszőr lekérdezzük a lehetséges nagyítási tartományt az OLECMDID_OPTICAL_GETZOOMRANGE-dzsel. A lehetséges értékek alsó és felső határát a vaOut változóban kapjuk meg. A value-ban lévő értéket ellenőrizzük, majd beállítjuk a vaIn értékét és ismét meghívjuk az ExecWB-t az OLECMDID_OPTICAL_ZOOM-mal.
procedure SetOpticalZoom(Value : integer); var vaIn, vaOut : OleVariant; begin vaIn := null; vaOut := null; wb.ExecWB(OLECMDID_OPTICAL_GETZOOMRANGE,OLECMDEXECOPT_DONTPROMPTUSER,vaIn,vaOut); if Value < LoWord(DWORD(vaOut)) then vaIn := LoWord(DWORD(vaOut)) else if Value > HiWord(DWORD(vaOut)) then vaIn := HiWord(DWORD(vaOut)) else vaIn := Value; wb.ExecWB(OLECMDID_OPTICAL_ZOOM,OLECMDEXECOPT_DONTPROMPTUSER,vaIn,vaOut); end;
function QueryStatusWB(cmdID: OLECMDID): OLECMDF;
A cmdID állapotát kérdezhetjük le, vagyis az adott művelet végrehajthatóságára kapunk visszajelzést. Visszatérési értékei a következők lehetnek:
type OLECMDF = TOleEnum; const OLECMDF_SUPPORTED = $00000001; OLECMDF_ENABLED = $00000002; OLECMDF_LATCHED = $00000004; OLECMDF_NINCHED = $00000008; OLECMDF_INVISIBLE = $00000010; OLECMDF_DEFHIDEONCTXTMENU = $00000020;
Pl. szeretnénk a programunkban a Másolás menüpont engedélyezését beállítani.
mnuCopy.Enabled := ((wb.QueryStatusWB(OLECMDID_COPY) and OLECMDF_ENABLED) = OLECMDF_ENABLED);
Szinte minden információ adott, hogy elkészítsünk egy ún. többablakos böngésző alkalmazást. Ekkor azonban futásidőben kell létrehoznunk a TWebbrowser komponenseinket. Helyezzünk el a formon egy TPageControl komponenst, majd ezen hozunk létre TTabSheeteket és a TWebbrowser komponenseket. Tehát első lépésben meg kell oldani futásidőben új TWebbrowser komponens létrehozását. Ez általában két esetben fordulhat elő. Vagy a felhasználó kattint pl. az „Új lap” menüre vagy TButtonra, vagy valamelyik megjelenített weboldal akar új lapot létrehozni. Írjuk meg a NewTab eljárást, mely paraméterként a létrehozandó TTabSheet helyét határozza meg (pl. az aktuális lap után vagy utolsó lapként).
function NewTAB(where : integer) : TTabSheet; var WB : TWebbrowser; TabSheet : TTabSheet; i : integer; begin result := nil; try PageControl.OnChange := nil; TabSheet := TTabSheet.Create(PageControl); TabSheet.PageControl := PageControl; TabSheet.ImageIndex := -1; TabSheet.BorderWidth := 0; WB := TWebbrowser.Create(Application); TWinControl(WB).Parent := TabSheet; WB.Align := alClient; WB.OnBeforeNavigate2 := WBBeforeNavigate2; //beállítjuk az összes lekezelendő eseményt …. try TabSheet.PageIndex := where+1; except end; try //beállítjuk a TabSheet-ek Caption-ját if PageControl.PageCount > 0 then begin for i := 0 to PageControl.PageCount-1 do begin if (not assigned((PageControl.Pages[i].Controls[0] as TWebbrowser).Document)) or ((PageControl.Pages[i].Controls[0] as TWebbrowser).LocationURL = 'about:blank' then begin if (PageControl.Pages[i].Controls[0] as TWebbrowser).Visible then PageControl.Pages[i].Caption := IntToStr(i+1)+'.'; end; end; end; except end; PageControl.ActivePage := TabSheet; PageControlChange(PageControl); PageControl.Refresh; PageControl.OnChange := PageControlChange; result := TabSheet; except end; end;
A fenti kódban látható, hogy a létrehozott TWebbrowser komponenst a következő módon érhetjük el:
var aBrowser : TWebbrowser; begin aBrowser := (PageControl.Pages[i].Controls[0] as TWebbrowser); //az i-edik TabSheet-en lévő aBrowser := (PageControl.ActivePage.Controls[0] as TWebbrowser); //az aktuális TabShet-en lévő .... //itt használhatom az aBrowsert pl. aBrowser.Navigate(...); end;
Nézzük meg, hogy az OnNewWindow2 eseménynél hogyan kell használnunk az újonnan létrehozott TWebbrowser komponenst.
procedure NewWindow2(ASender: TObject; var ppDisp: IDispatch; var Cancel: WordBool); var aBrowser : TWebbrowser; begin cancel := true; try aBrowser := NewTab((TWinControl(ASender).Parent as TTabSheet).PageIndex).Controls[0] as TWebbrowser; except end; if assigned(aBrowser) then begin ppDisp := aBrowser.DefaultInterface as IDispatch; cancel := false; end end;
Azonban egy ilyen programban nem csak létrehozni, hanem megszüntetni is tudni kell a létrehozott TWebbrowser komponenseket. A megszüntetés 2 lépésből áll. Először a bezárásra ítélt TWebbrowser komponenst el kell navigálni az „about:blank”-ra (amennyiben ezt nem tesszük meg, a megnyitott weboldalon lévő ActiveX vezérlők a bezárást követően is aktívak maradhatnak), majd ennek befejeződése után szüntethetjük meg a komponensünket. Ne felejtsük el, hagy amennyiben pl. egy TTabSheeten hoztuk létre, úgy azt is el kell távolítanunk.
procedure mnuCloseClick(Sender : TObject); var i : integer; begin CloseButton.Enabled := false; try try index := PageControl.ActivePageIndex; (PageControl.pages[index].Controls[0] as TWebbrowser).Silent := True; PageControl.pages[index].TabVisible := false; if assigned((PageControl.pages[index].Controls[0] as TWebbrowser).Document) then begin (PageControl.pages[index].Controls[0] as TWebbrowser).Navigate('about:blank'); while (PageControl.pages[index].Controls[0] as TWebbrowser).WB.LocationURL <> 'about:blank' do Application.ProcessMessages; end; finally DeleteTab(PageControl.pages[index]); end; except end; end; procedure DeleteTab(TabSheet : TTabSheet); var i, index : integer; begin PageControl.OnChange := nil; if TabSheet = nil then TabSheet := PageControl.ActivePage; index := TabSheet.PageIndex; TabSheet.TabVisible := false; (TabSheet.Controls[0] as TWebbrowser).Silent := true; (TabSheet.Controls[0] as TWebbrowser).Free; TabSheet.free; if PageControl.PageCount > 0 then begin for i := 0 to PageControl.PageCount-1 do begin if (not assigned((PageControl.Pages[i].Controls[0] as TWebbrowser).Document)) or ((PageControl.Pages[i].Controls[0] as TWebbrowser).LocationURL = 'about:blank') then begin if (PageControl.Pages[i].Controls[0] as TWebbrowser).Visible then PageControl.Pages[i].Caption := IntToStr(i+1)+'.'; end; end; end else begin NewTab(-1); end; PageControlChange(PageControl); PageControl.Refresh; PageControl.OnChange := PageControlChange; end;
Futási időben sajnos nem csak a felhasználó szüntetheti meg a meglévő TWebbrowser komponensünket, hanem a megnyitott weboldalon lévő JavaScript vagy bármely ActiveX vezérlő is. Ennek az eseménynek az „elkapása” és „felügyelete” már nem tartozik a TWebbrowser komponens bemutatásához. Ezt a WM_CLOSE esemény lekezelésével lehet megoldani. Ehhez létre kell hoznunk egy GetMsgProc eljárást, ezt beregisztrálni (SetWindowsHookEx) az alkalmazás indításakor, majd megszüntetni (UnhookWindowsHookEx) a programból való kilépéskor.
Térjünk vissza a programunkhoz. Hozzunk létre egy TElteWebbrowser komponenst, melyet a TWebbrowserből illetve az IDocHostUIHandler és IDispatch interfészekből származtatunk.
IDocHostUIHandler = interface(IUnknown) ['{bd3f23c0-d43e-11cf-893b-00aa00bdce1a}'] function ShowContextMenu(const dwID: DWORD; const ppt: PPOINT; const CommandTarget: IUnknown; const Context: IDispatch): HRESULT; stdcall; function GetHostInfo(var pInfo: TDOCHOSTUIINFO): HRESULT; stdcall; function ShowUI(const dwID: DWORD; const pActiveObject: IOleInPlaceActiveObject; const pCommandTarget: IOleCommandTarget; const pFrame: IOleInPlaceFrame; const pDoc: IOleInPlaceUIWindow): HRESULT; stdcall; function HideUI: HRESULT; stdcall; function UpdateUI: HRESULT; stdcall; function EnableModeless(const fEnable: BOOL): HRESULT; stdcall; function OnDocWindowActivate(const fActivate: BOOL): HRESULT; stdcall; function OnFrameWindowActivate(const fActivate: BOOL): HRESULT; stdcall; function ResizeBorder(const prcBorder: PRECT; const pUIWindow: IOleInPlaceUIWindow; const fRameWindow: BOOL): HRESULT; stdcall; function TranslateAccelerator(const lpMsg: PMSG; const pguidCmdGroup: PGUID; const nCmdID: DWORD): HRESULT; stdcall; function GetOptionKeyPath(out pchKey: POLESTR; const dw: DWORD): HRESULT; stdcall; function GetDropTarget(const pDropTarget: IDropTarget; out ppDropTarget: IDropTarget): HRESULT; stdcall; function GetExternal(out ppDispatch: IDispatch): HRESULT; stdcall; function TranslateUrl(const dwTranslate: DWORD; const pchURLIn: POLESTR; out ppchURLOut: POLESTR): HRESULT; stdcall; function FilterDataObject(const pDO: IDataObject; out ppDORet: IDataObject): HRESULT; stdcall; end;
IDispatch = interface(IUnknown) ['{00020400-0000-0000-C000-000000000046}'] function GetTypeInfoCount(out Count: Integer): HResult; stdcall; function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall; function GetIDsOfNames(const IID: TGUID; Names: Pointer; NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall; function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall; end;
TElteWebbrowser = class(TWebBrowser, IDocHostUIHandler,IDispatch) private FDownloadOptionValue : longint; protected function GetTypeInfoCount(out Count: Integer): HResult; stdcall; function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall; function GetIDsOfNames(const IID: TGUID; Names: Pointer; NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall; function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall; public property DownloadOptionValue : longint read FDownloadOptionValue write FDownloadOptionValue; function ShowContextMenu(const dwID: DWORD; const ppt: PPOINT; const CommandTarget: IUnknown; const Context: IDispatch): HRESULT; stdcall; function GetHostInfo(var pInfo: TDOCHOSTUIINFO): HRESULT; stdcall; function ShowUI(const dwID: DWORD; const pActiveObject: IOleInPlaceActiveObject; const pCommandTarget: IOleCommandTarget; const pFrame: IOleInPlaceFrame; const pDoc: IOleInPlaceUIWindow): HRESULT; stdcall; function HideUI: HRESULT; stdcall; function UpdateUI: HRESULT; stdcall; function EnableModeless(const fEnable: BOOL): HRESULT; stdcall; function OnDocWindowActivate(const fActivate: BOOL): HRESULT; stdcall; function OnFrameWindowActivate(const fActivate: BOOL): HRESULT; stdcall; function ResizeBorder(const prcBorder: PRECT; const pUIWindow: IOleInPlaceUIWindow; const fRameWindow: BOOL): HRESULT; stdcall; function TranslateAccelerator(const lpMsg: PMSG; const pguidCmdGroup: PGUID; const nCmdID: DWORD): HRESULT; stdcall; function GetOptionKeyPath(out pchKey: POLESTR; const dw: DWORD): HRESULT; stdcall; function GetDropTarget(const pDropTarget: IDropTarget; out ppDropTarget: IDropTarget): HRESULT; stdcall; function GetExternal(out ppDispatch: IDispatch): HRESULT; stdcall; function TranslateUrl(const dwTranslate: DWORD; const pchURLIn: POLESTR; out ppchURLOut: POLESTR): HRESULT; stdcall; function FilterDataObject(const pDO: IDataObject; out ppDORet: IDataObject): HRESULT; stdcall; published {Published} end;
Miért vezettük be azt a két új interfészt? Az IDocHostUIHandlert azért, mert alapesetben a TWebbrowser komponens által megnyitott weboldalak a régi 4.0 verzió megjelenéséhez hasonlítanak (nyomógombok, comboboxok, szövegbeviteli mezők, kerete van a komponensnek stb.). Szeretnénk, hogy minden oldal az ún. „XP stílusban” jelenjen meg. Ezt a GetHostInfo funkció használatával tehetjük meg. A különbség, remélem, látható!
type TDOCHOSTUIINFO = record cbSize: ULONG; dwFlags: DWORD; dwDoubleClick: DWORD; chHostCss: POLESTR; chHostNS: POLESTR; end; function TElteWebbrowser.GetHostInfo(var pInfo: TDOCHOSTUIINFO): HRESULT; const DOCHOSTUIDBLCLK_DEFAULT = 0; DOCHOSTUIFLAG_NO3DBORDER = $00000004; DOCHOSTUIFLAG_THEME = $00040000; begin FillChar(pInfo, SizeOf(TDOCHOSTUIINFO), #0); pInfo.cbSize := SizeOf(pInfo); pInfo.dwFlags := DOCHOSTUIFLAG_THEME or DOCHOSTUIFLAG_NO3DBORDER; pInfo.dwDoubleClick := DOCHOSTUIDBLCLK_DEFAULT; Result := S_OK; end;
Az IDispatch interfész használatát pedig azért vezettük be, mert szeretnénk szabályozni a megjelenített (letöltött) elemeket. Pl. ne jelenjenek meg a képek, az adott oldalon ne fussanak a beépített JavaScipt eljárások (reklámok megjelenésének tiltása), ne lépjenek működésbe a különböző ActiveX vezérlők (pl. flash animációk, reklámok).
Mikor lehet erre szükség? Pl. mobil internettel netezve (korlátos, lassú) lehetőségem van szabályozni a letöltendő elemeket, ezáltal gyorsítva a böngészést és csökkenteni az adatforgalmat. Egy index.hu nyitólap akár 1-3 MB adatot is tartalmazhat, azonban pl. a JavaSriptek és az ActiveX vezérlőt tiltásával ez 200-300 KB lesz. Így ha szükséges időt és adatforgalmat takaríthatunk meg. Ezt az Invoke funkció használatával tehetjük meg.
const DISPID_AMBIENT_DLCONTROL = (-5512); function TElteWebbrowser.Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; begin Result := S_OK; if (Flags and DISPATCH_PROPERTYGET <> 0) and (VarResult <> nil) and (DispId = DISPID_AMBIENT_DLCONTROL) then begin PVariant(VarResult)^ := fDownloadOptionValue; end else begin Result := inherited Invoke(DispID, IID, LocaleID, Flags, Params, VarResult, ExcepInfo, ArgErr); end; end;
Látható, hogy a bal oldali kép felső részén egy flash reklám található, míg a jobb oladali képen ezt nem jelenítettük meg.
Szerző: Nagy Róbert