发新话题
打印

[组件应用/开发] TWebBrowser编程简述

TWebBrowser编程简述

  这里有平时我自己用TWebBrowser做程序的一些心得和上网收集到的部分例子和资料,整理了一下,希望能给有兴趣用TWebBrowser编程朋友带来些帮助。


1、初始化和终止化(Initialization & Finalization)
  大家在执行TWebBrowser的某个方法以进行期望的操作,如ExecWB等的时候可能都碰到过“试图激活未注册的丢失目标”或“OLE对象未注册”等错误,或者并没有出错但是得不到希望的结果,比如不能将选中的网页内容复制到剪贴板等。以前用它编程的时候,我发现ExecWB有时侯起作用但有时侯又不行,在Delphi生成的缺省工程主窗口上加入TWebBrowser,运行时并不会出现“OLE对象未注册”的错误。同样是一个偶然的机会,我才知道OLE对象需要初始化和终止化(懂得的东东实在太少了)。
  我用我的前一篇文章《Delphi程序窗口动画&正常排列平铺的解决》所说的方法编程,运行时出了上面所说的错误,我便猜想应该有OleInitialize之类的语句,于是,找到并加上了下面几句话,终于搞定!究其原因,我想大概是由于TWebBrowser是一个嵌入的OLE对象而不算是用Delphi编写的VCL吧。

  initialization
   OleInitialize(nil);
  finalization
   try
    OleUninitialize;
   except
   end;

  这几句话放在主窗口所有语句之后,“end.”之前。

--------------------------------------------------------------------------------------------------------

2、EmptyParam

  在Delphi 5中TWebBrowser的Navigate方法被多次重载:

  procedure Navigate(const URL: WideString); overload;
  procedure Navigate(const URL: WideString; var Flags: OleVariant); overload;
  procedure Navigate(const URL: WideString; var Flags: OleVariant; var TargetFrameName: OleVariant); overload;
  procedure Navigate(const URL: WideString; var Flags: OleVariant; var TargetFrameName: OleVariant; var PostData: OleVariant); overload;
  procedure Navigate(const URL: WideString; var Flags: OleVariant; var TargetFrameName: OleVariant; var PostData: OleVariant; var Headers: OleVariant); overload;

  而在实际应用中,使用后几种方法调用时,由于我们很少用到后面几个参数,但函数声明又要求是变量参数,一般的做法如下:

  var
   t:OleVariant;
  begin
   webbrowser1.Navigate(edit1.text,t,t,t,t);
  end;

  需要定义变量t(还有很多地方要用到它),很麻烦。其实我们可以用EmptyParam来代替(EmptyParam是一个公用的Variant空变量,不要对它赋值),只需一句话就可以了:

  webbrowser1.Navigate(edit1.text,EmptyParam,EmptyParam,EmptyParam,EmptyParam);

  虽然长一点,但比每次都定义变量方便得多。当然,也可以使用第一种方式。

  webbrowser1.Navigate(edit1.text)

--------------------------------------------------------------------------------------------------------

3、命令操作

  常用的命令操作用ExecWB方法即可完成,ExecWB同样多次被重载:

  procedure ExecWB(cmdID: OLECMDID; cmdexecopt: OLECMDEXECOPT); overload;
  procedure ExecWB(cmdID: OLECMDID; cmdexecopt: OLECMDEXECOPT; var pvaIn: OleVariant); overload;
  procedure ExecWB(cmdID: rOLECMDID; cmdexecopt: OLECMDEXECOPT; var pvaIn: OleVariant; var pvaOut: OleVariant); overload;

  打开: 弹出“打开Internet地址”对话框,CommandID为OLECMDID_OPEN(若浏览器版本为IE5.0,
      则此命令不可用)。
  另存为:调用“另存为”对话框。
      ExecWB(OLECMDID_SAVEAS,OLECMDEXECOPT_DODEFAULT, EmptyParam, EmptyParam);


  打印、打印预览和页面设置: 调用“打印”、“打印预览”和“页面设置”对话框(IE5.5及以上版本才支持打
                印预览,故实现应该检查此命令是否可用)。
      ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_DODEFAULT, EmptyParam, EmptyParam);
      if QueryStatusWB(OLECMDID_PRINTPREVIEW)=3 then
       ExecWB(OLECMDID_PRINTPREVIEW, OLECMDEXECOPT_DODEFAULT, EmptyParam,EmptyParam);
      ExecWB(OLECMDID_PAGESETUP, OLECMDEXECOPT_DODEFAULT, EmptyParam, EmptyParam);


  剪切、复制、粘贴、全选: 功能无须多说,需要注意的是:剪切和粘贴不仅对编辑框文字,而且对网页上的非编辑框文字同样有效,用得好的话,也许可以做出功能特殊的东东。获得其命令使能状态和执行命令的方法有两种(以复制为例,剪切、粘贴和全选分别将各自的关键字替换即可,分别为CUT,PASTE和SELECTALL):
   A、用TWebBrowser的QueryStatusWB方法。
     if(QueryStatusWB(OLECMDID_COPY)=OLECMDF_ENABLED) or
      OLECMDF_SUPPORTED) then
      ExecWB(OLECMDID_COPY, OLECMDEXECOPT_DODEFAULT, EmptyParam, EmptyParam);
   B、用IHTMLDocument2的QueryCommandEnabled方法。
     var
      Doc: IHTMLDocument2;
     begin
      Doc :=WebBrowser1.Document as IHTMLDocument2;
      if Doc.QueryCommandEnabled('Copy') then
       Doc.ExecCommand('Copy',false,EmptyParam);
     end;

  查找: 参考第九条“查找”功能。

--------------------------------------------------------------------------------------------------------

4、字体大小

  类似“字体”菜单上的从“最大”到“最小”五项(对应整数0~4,Largest等假设为五个菜单项的名字,Tag 属性分别设为0~4)。
   A、读取当前页面字体大小。
     var
      t: OleVariant;
     Begin
      WebBrowser1.ExecWB(OLECMDID_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER,
       EmptyParam,t);
      case t of
      4: Largest.Checked :=true;
      3: Larger.Checked :=true;
      2: Middle.Checked :=true;
      1: Small.Checked :=true;
      0: Smallest.Checked :=true;
      end;
     end;
   B、设置页面字体大小。
     Largest.Checked :=false;
     Larger.Checked :=false;
     Middle.Checked :=false;
     Small.Checked :=false;
     Smallest.Checked :=false;
     TMenuItem(Sender).Checked :=true;
     t :=TMenuItem(Sender).Tag;
     WebBrowser1.ExecWB(OLECMDID_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER,
      t,t);

--------------------------------------------------------------------------------------------------------

5、添加到收藏夹和整理收藏夹

     const
     CLSID_ShellUIHelper: TGUID = '{64AB4BB7-111E-11D1-8F79-00C04FC2FBE1}';

    var
     p:procedure(Handle: THandle; Path: PChar); stdcall;

    procedure TForm1.OrganizeFavorite(Sender: Tobject);
    var
     H: HWnd;
    begin
     H := LoadLibrary(PChar('shdocvw.dll'));
     if H <> 0 then
     begin
    p := GetProcAddress(H, PChar('DoOrganizeFavDlg'));
      if Assigned(p) then p(Application.Handle, PChar(FavFolder));
     end;
     FreeLibrary(h);
    end;
    
    procedure TForm1.AddFavorite(Sender: TObject);
    var
     ShellUIHelper: ISHellUIHelper;
     url, title: Olevariant;
    begin
     Title := Webbrowser1.LocationName;
     Url := Webbrowser1.LocationUrl;
     if Url <> '' then
     begin
      ShellUIHelper := CreateComObject(CLSID_SHELLUIHELPER) as IShellUIHelper;
      ShellUIHelper.AddFavorite(url, title);
     end;
    end;

  用上面的通过ISHellUIHelper接口来打开“添加到收藏夹”对话框的方法比较简单,但是有个缺陷,就是打开的窗口不是模式窗口,而是独立于应用程序的。可以想象,如果使用与OrganizeFavorite过程同样的方法来打开对话框,由于可以指定父窗口的句柄,自然可以实现模式窗口(效果与在资源管理器和IE中打开“添加到收藏夹”对话框相同)。问题显然是这样的,上面两个过程的作者当时只知道shdocvw.dll中DoOrganizeFavDlg的原型而不知道DoAddToFavDlg的原型,所以只好用ISHellUIHelper接口来实现(或许是他不够严谨,认为是否是模式窗口无所谓?)。
  下面的过程就告诉你DoAddToFavDlg的函数原型。需要注意的是,这样打开的对话框并不执行“添加到收藏夹”的操作,它只是告诉应用程序用户是否选择了“确定”,同时在DoAddToFavDlg的第二个参数中返回用户希望放置Internet快捷方式的路径,建立.Url文件的工作由应用程序自己来完成。

    procedure TForm1.AddFavorite(IE: TEmbeddedWB);
     procedure CreateUrl(AUrlPath, AUrl: PChar);
     var
      URLfile: TIniFile;
     begin
      URLfile := TIniFile.Create(String(AUrlPath));
     RLfile.WriteString('InternetShortcut', 'URL', String(AUrl));
     RLfile.Free;
     end;
    var
     AddFav: function(Handle: THandle;
      UrlPath: PChar; UrlPathSize: Cardinal;
      Title: PChar; TitleSize: Cardinal;
      FavIDLIST: pItemIDList): Bool; stdcall;
     FDoc: IHTMLDocument2;
     UrlPath, url, title: array[0..MAX_PATH] of char;
     H: HWnd;
     pidl: pItemIDList;
     FRetOK: Bool;
    begin
     FDoc := IHTMLDocument2(IE.Document);
     if FDoc = nil then exit;
     StrPCopy(Title, FDoc.Get_title);
     StrPCopy(url, FDoc.Get_url);
     if Url <> '' then
     begin
      H := LoadLibrary(PChar('shdocvw.dll'));
      if H <> 0 then
      begin
       SHGetSpecialFolderLocation(0, CSIDL_FAVORITES, pidl);
       AddFav := GetProcAddress(H, PChar('DoAddToFavDlg'));
       if Assigned(AddFav) then
        FRetOK :=AddFav(Handle, UrlPath, Sizeof(UrlPath), Title, Sizeof(Title), pidl)
      end;
      FreeLibrary(h);
      if FRetOK then
       CreateUrl(UrlPath, Url);
     end
    end;


--------------------------------------------------------------------------------------------------------

6、使WebBrowser获得焦点

  TWebBrowser非常特殊,它从TWinControl继承来的SetFocus方法并不能使得它所包含的文档获得焦点,从而不能立即使用Internet Explorer本身具有得快捷键,解决方法如下:<

  procedure TForm1.SetFocusToDoc;
  begin
   if WebBrowser1.Document <> nil then
    with WebBrowser1.Application as IOleobject do
     DoVerb(OLEIVERB_UIACTIVATE, nil, WebBrowser1, 0, Handle, GetClientRect);
  end;

  除此之外,我还找到一种更简单的方法,这里一并列出:

  if WebBrowser1.Document <> nil then
   IHTMLWindow2(IHTMLDocument2(WebBrowser1.Document).ParentWindow).focus

  刚找到了更简单的方法,也许是最简单的:

  if WebBrowser1.Document <> nil then
   IHTMLWindow4(WebBrowser1.Document).focus

  还有,需要判断文档是否获得焦点这样来做:

  if IHTMLWindow4(WebBrowser1.Document).hasfocus then

--------------------------------------------------------------------------------------------------------

7、点击“提交”按钮

  如同程序里每个窗体上有一个“缺省”按钮一样,Web页面上的每个Form也有一个“缺省”按钮——即属性为“Submit”的按钮,当用户按下回车键时就相当于鼠标单击了“Submit”。但是TWebBrowser似乎并不响应回车键,并且,即使把包含TWebBrowser的窗体的KeyPreview设为True,在窗体的KeyPress事件里还是不能截获用户向TWebBrowser发出的按键。
  我的解决办法是用ApplicatinEvents构件或者自己编写TApplication对象的OnMessage事件,在其中判断消息类型,对键盘消息做出响应。至于点击“提交”按钮,可以通过分析网页源代码的方法来实现,不过我找到了更为简单快捷的方法,有两种,第一种是我自己想出来的,另一种是别人写的代码,这里都提供给大家,以做参考。

  A、用SendKeys函数向WebBrowser发送回车键
    在Delphi 5光盘上的Info\Extras\SendKeys目录下有一个SndKey32.pas文件,其中包含了两个函数SendKeys和AppActivate,我们可以用SendKeys函数来向WebBrowser发送回车键,我现在用的就是这个方法,使用很简单,在WebBrowser获得焦点的情况下(不要求WebBrowser所包含的文档获得焦点),用一条语句即可:

   Sendkeys('~',true);// press RETURN key

   SendKeys函数的详细参数说明等,均包含在SndKey32.pas文件中。

  B、在OnMessage事件中将接受到的键盘消息传递给WebBrowser。

   procedure TForm1.ApplicationEvents1Message(var Msg: TMsg; var Handled: Boolean);
   {fixes the malfunction of some keys within webbrowser control}
   const
    StdKeys = [VK_TAB, VK_RETURN]; { standard keys }
    ExtKeys = [VK_DELETE, VK_BACK, VK_LEFT, VK_RIGHT]; { extended keys }
    fExtended = $01000000; { extended key flag }
   begin
    Handled := False;
    with Msg do
    if ((Message >= WM_KEYFIRST) and (Message <= WM_KEYLAST)) and
     ((wParam in StdKeys) or
     {$IFDEF VER120}(GetKeyState(VK_CONTROL) < 0) or {$ENDIF}
     (wParam in ExtKeys) and
     ((lParam and fExtended) = fExtended)) then
    try
     if IsChild(Handle, hWnd) then { handles all browser related messages }
     begin
      with {$IFDEF VER120}Application_{$ELSE}Application{$ENDIF} as
        IOleInPlaceActiveObject do
       Handled := TranslateAccelerator(Msg) = S_OK;
       if not Handled then
       begin
        Handled := True;
        TranslateMessage(Msg);
        DispatchMessage(Msg);
       end;
       end;
    except
    end;
   end; // MessageHandler

  (此方法来自EmbeddedWB.pas)

--------------------------------------------------------------------------------------------------------

8、直接从TWebBrowser得到网页源码及Html

  下面先介绍一种极其简单的得到TWebBrowser正在访问的网页源码的方法。一般方法是利用TWebBrowser控件中的Document对象提供的IPersistStreamInit接口来实现,具体就是:先检查WebBrowser.Document对象是否有效,无效则退出;然后取得IPersistStreamInit接口,接着取得HTML源码的大小,分配全局堆内存块,建立流,再将HTML文本写到流中。程序虽然不算复杂,但是有更简单的方法,所以实现代码不再给出。其实基本上所有IE的功能TWebBrowser都应该有较为简单的方法来实现,获取网页源码也是一样。下面的代码将网页源码显示在Memo1中。

   Memo1.Lines.Add(IHtmlDocument2(WebBrowser1.Document).Body.OuterHtml);

  同时,在用TWebBrowser浏览HTML文件的时候要将其保存为文本文件就很简单了,不需要任何的语法解析工具,因为TWebBrowser也完成了,如下:

   Memo1.Lines.Add(IHtmlDocument2(WebBrowser1.Document).Body.OuterText);

--------------------------------------------------------------------------------------------------------

9、“查找”功能

  查找对话框可以在文档获得焦点的时候通过按键Ctrl-F来调出,程序中则调用IOleCommandTarget对象的成员函数Exec执行OLECMDID_FIND操作来调用,下面给出的方法是如何在程序中用代码来做出文字选择,即你可以自己设计查找对话框。

   var
    Doc: IHtmlDocument2;
    TxtRange: IHtmlTxtRange;
   begin
    Doc :=WebBrowser1.Document as IHtmlDocument2;
    Doc.SelectAll;    //此处为简写,选择全部文档的方法请参见第三条命令操作
                //这句话尤为重要,因为IHtmlTxtRange对象的方法能够操作的前提是
                //Document已经有一个文字选择区域。由于接着执行下面的语句,所以不会
                //看到文档全选的过程。
    TxtRange :=Doc.Selection.CreateRange as IHtmlTxtRange;
    TxtRange.FindText('Text to be searched',0.0);
    TxtRange.Select;
   end;

  还有,从Txt.Get_text可以得到当前选中的文字内容,某些时候是有用的。

--------------------------------------------------------------------------------------------------------

10、提取网页中所有链接

  这个方法来自大富翁论坛hopfield朋友的对一个问题的回答,我本想自己试验,但总是没成功。

  var
   doc:IHTMLDocument2;
   all:IHTMLElementCollection;
   len,i:integer;
   item:OleVariant;
  begin
   doc:=WebBrowser1 .Document as IHTMLDocument2;
   all:=doc.Get_links;             //doc.Links亦可
   len:=all.length;
   for i:=0 to len-1 do begin
    item:=all.item(i,varempty);        //EmpryParam亦可
    memo1.lines.add(item.href);
   end;
  end;

--------------------------------------------------------------------------------------------------------

11、设置TWebBrowser的编码

  为什么我总是错过很多机会?其实早就该想到的,但是一念之差,便即天壤之别。当时我要是肯再多考虑一下,多试验一下,这就不会排到第11条了。下面给出一个函数,搞定,难以想象的简单。

  procedure SetCharSet(AWebBrowser: TWebBrowser; ACharSet: String);
  var
   RefreshLevel: OleVariant;
  Begin
   IHTMLDocument2(AWebBrowser.Document).Set_CharSet(ACharSet);
   RefreshLevel :=7;              //这个7应该从注册表来,帮助有Bug。
   AWebBrowser.Refresh2(RefreshLevel);
  End;

--------------------------------------------------------------------------------------------------------

12、在TWebBrowser中输入字符时激活菜单的解决

  许多朋友编程的时候都遇到了这样一个问题,在TWebBrowser中输入时,键入的字符如果与菜单(用ToolBar做的菜单)的加速键相同就会激活菜单。有朋友解决办法是把加速键前面的“&”符号去掉,使得字符失去“加速”功能,这种方法未尝不可,只不过显得不够“专业”。其实略加分析我们就可以想到,是ToolBar抢先处理了按键(因为ToolBar本身就设计为用来实现具有Windows新风格的菜单),所以只需要修改ToolBar的源代码中处理菜单按键的那部分代码即可,方法如下:

  1)、在$(Delphi)\source\vcl目录下找到comctrls.pas,拷贝到自己的程序所在目录,然后打开它。
  2)、找到TToolBar.CMDialogChar过程,把过程体注释掉(如果你愿意的话,可以修改它)。
  3)、重新编译自己的程序。

  怎么样,是不是很简单?但它确实有效。

--------------------------------------------------------------------------------------------------------

13、去掉TWebBrowser的滚动条

  缺省地,TWebBrowser是滚动条的,虽然我们可以在网页中设置不需要滚动条,不过,有些时候可能会有特殊的要求,比如,网页是有滚动条的,但又想去掉它该怎么办呢?很简单,下面给出两行代码,都可以达到目的,可谓殊途同归。

  1)、IHTMLBodyElementDisp(IHTMLDocument2(WebBrowser1.document).body).scroll:= 'no';
  2)、WebBrowser1.oleobject.Document.body.Scroll := 'no';

  注:第一种方法需要在uses部分加上MSHTML_TLB或者MSHTML。

--------------------------------------------------------------------------------------------------------

14、通过IUniformResourceLocator接口建立Internet快捷方式

  前面说到的显示“添加到收藏夹”模式对话框的方法中举了一个建立Internet快捷方式的例子,就其本身来说不太规范,属于取巧一类的方法。下面介绍的方法是通过接口来实现的。

  procedure CreateIntShotCut(aFileName, aURL: PChar);
   var IURL: IUniformResourceLocator;
   PersistFile: IPersistfile;
  begin
   if Succeeded(CoCreateInstance(CLSID_InternetShortcut,
                    nil,
                    CLSCTX_INPROC_SERVER,
                    IID_IUniformResourceLocator,
                    IURL)) then
   begin
    IUrl.SetURL(aURL, 0);
    Persistfile := IUrl as IPersistFile;
    PersistFile.Save(StringToOleStr(aFileName), False);
   end;
  end;

  其中IUniformResourceLocator接口的声明在IeConst.pas中,IeConst.pas可以在网站IE & Delphi找到; IPersistfile接口的声明在ActiveX.pas中。

  注:这个函数的AURL参数必须包含协议前缀,如“Http://eagleboost.myrice.com”。


windoze(瞌睡窗) 发表于2004-09-05 10:09:00  IP: 219.144.212.*
这个地方更详尽:
http://www.euromind.com/iedelphi/


CathyEagle 发表于2004-09-05 11:15:00  IP: 222.18.4.*
2000年写这篇文章时学习刚刚起步,许多东西是自己摸索出来的,当时并不知道IE & Delphi的存在,否则会少走很多弯路。
IE & Delphi的组件尽管涉及了WebBrowser编程的很多方面,我也曾从中收益不浅,不过它有很多没有提到的东西,比如DoAddToFavDlg的函数原型,比如设置网页编码,不一而足。
再次贴这篇文章的目的,一是作为前一阶段的完结,所以文章中的错误都不作修改;二是希望作为一个新的起点。我准备整理一下至今所积累的浏览器编程的知识,比较完整地写出来,与网友共勉。


youdu 发表于2004-09-09 19:52:00  IP: 219.133.172.*
"CommandID为OLECMDID_OPEN(若浏览器版本为IE5.0,则此命令不可用)"

为什么会这样呢?IE6也是这样的吧?要怎么解决?

困扰了我好久了~


埃及小白 发表于2004-09-10 00:14:00  IP: 219.233.101.*
这个似乎没有什么办法。一般都是自己做一个类似的对话框来弥补的。像类似的还有导入导出向导对话框。

To CathyEagle: 添加到收藏夹对话框用DoAddToFavDlg还是不错的,除了“脱机浏览”选项为灰之外,都比用IShellHelper的办法好。

关于网页编码菜单,我看见一种新的做法,就是调网页右键菜单的编码子菜单,然后Popup在合适的位置。(我还没有具体研究)


CathyEagle 发表于2004-09-10 04:20:00  IP: 222.18.4.*
WebBrowser与InternetExplorer对象毕竟不是同一个东西,有些功能不是由WebBrowser提供,而是由IE的外壳框架提供的,如“打开”对话框。这种情况下只有自己来实现了,当然对话框的模板还是可以从相应的资源Dll中调用。


youdu 发表于2004-09-10 13:29:00  IP: 210.83.237.*
"关于网页编码菜单,我看见一种新的做法,就是调网页右键菜单的编码子菜单,然后Popup在合适的位置。(我还没有具体研究) "

"调网页右键菜单的编码子菜单"这个好像挺难的,大富翁那儿就有人想find弹出式菜单的句柄,好像一直没有成功,主菜单是可以找句柄,AppendMenu等操作的.


CathyEagle 发表于2004-09-10 22:54:00  IP: 222.18.4.*
上面提到的几个问题:

“添加到收藏夹”模态对话框(且“脱机浏览”可用)
“导入/导出向导”模态对话框
调用网页右键菜单的编码子菜单

还有“新建IE窗口”并且保持当前页状态等一系列问题

我已经一并解决,过几天将作为《Internet Explorer 编程简述》的一章或几章写出来。


youdu 发表于2004-09-10 23:10:00  IP: 210.83.237.*
有没有可能实现控制图片,声音,脚本的加载?

我知道http://www.euromind.com/iedelphi/那里有增强的TWebBrowser,但是可不可以另外实现呢?

CathyEagle好勤奋~帮大家解决了好多问题~辛苦了~
以CathyEagle的功力~用TWebBrowser写一个完整的浏览器是绰绰有余了~呵呵~


CathyEagle 发表于2004-09-10 23:33:00  IP: 222.18.4.*
控制图片,声音,脚本的加载在MSDN里面有文章介绍,当然我也会在《Internet Explorer 编程简述》中都写进去。


埃及小白 发表于2004-09-11 13:29:00  IP: 219.233.101.*
本来想给你(CE)发mail的,不过你的邮箱是暴了还是被block了。换了好几个发信服务器都发不过来。连用网页中的“联系”都无法发送。我把email放在http://????????/cathyeagle_iecoding.eml <域名你知道的;)>


CathyEagle 发表于2004-09-12 12:22:00  IP: 222.18.4.*
To:埃及小白,Mail已收到。


wlongy2k 发表于2004-09-13 22:16:00  IP: 159.226.67.*
当加载图片,声音,脚本时,能否产生事件


CathyEagle 发表于2004-09-14 00:52:00  IP: 222.18.4.*
恐怕比较困难,但我觉得没有太大意义,说说你想干什么吧,也许有变相的方法可以实现。


wlongy2k  发表于2004-09-14 10:29:00  IP: 159.226.67.*
需要知道一个页面要调用了哪些图片声音脚本等,就是脚本不好弄


CathyEagle 发表于2004-09-14 15:18:00  IP: 211.138.91.*
Flash、图片、声音等文件可以通过注册一个Asynchronous Pluggable Protocol来过滤掉,脚本的话恐怕要在你实现的协议插件中中获取源代码来分析了。


Pingback/Trackback 发表于2004-09-19 22:11:00  IP:
TrackBack来自《pconline》:

太平洋电脑网


Pingback/Trackback 发表于2004-09-30 13:42:00  IP:
TrackBack来自《网页教学网》:

网页教学网


Pingback/Trackback 发表于2004-10-02 00:22:00  IP:
TrackBack来自《太平洋电脑网》:

太平洋电脑网


Pingback/Trackback 发表于2004-10-10 02:22:00  IP:
TrackBack来自《中华宽带网》:

中华宽带网


我是小学生 发表于2004-10-14 18:00:00  IP: 220.192.97.*
请问怎么样编程控制一个联动的下拉列表呢?例如省、县联动的select,从外边用程序控制自动输入某些值,
期待您的帮助,alexyang2002@sohu.com


alan 发表于2004-11-05 17:36:00  IP: 210.21.120.*
有没有用VB实现的啊。Email:xyl006@126.com


CathyEagle 发表于2004-11-07 16:02:00  IP: 211.83.120.*
我VB用得很少,不过多数实现的代码在网上能够搜到。
在MSDN中也有用VB编写WebBrowser的例子可以参考。


阿涛 发表于2005-02-16 01:32:00  IP: 221.194.49.*
有个问题,
不知道如何才能像flashget那样利用引用页面下载文件?
希望能给予解答!


CathyEagle 发表于2005-02-21 17:02:00  IP: 61.236.183.*
引用页面很简单,通过脚本就能访问了,下面就是flashget的方法,

<script language="VBScript">
'Great thanks to Vladimir Romanov(Author of ReGet Pro)

On Error Resume Next
set JetCarCatch=CreateObject("JetCar.Netscape")
if err<>0 then
MsgBox("FlashGet not properly installed!"+ vbCrLf+"Please Install FlashGet again")
else
set links = external.menuArguments.document.links
ReDim params(links.length*2)
params(0)=external.menuArguments.document.Url
for i = 0 to links.length-1
params(i*2+1)=links(i).href
params(i*2+2)=links(i).innerText
next
JetCarCatch.AddUrlList params
end if
</script>



jbas 发表于2005-06-26 19:47:00  IP: 61.186.252.*
老大,关于你的

A、用SendKeys函数向WebBrowser发送回车键
    在Delphi 5光盘上的Info\Extras\SendKeys目录下有一个SndKey32.pas文件,其中包含了两个函数SendKeys和AppActivate,我们可以用SendKeys函数来向WebBrowser发送回车键,我现在用的就是这个方法,使用很简单,在WebBrowser获得焦点的情况下(不要求WebBrowser所包含的文档获得焦点),用一条语句即可:

   Sendkeys('~',true);// press RETURN key

   SendKeys函数的详细参数说明等,均包含在SndKey32.pas文件中。


我用的是delphi2005,我该uses 什么单元呢?

谢谢了!


CathyEagle 发表于2005-07-03 22:00:00  IP: 61.186.252.*
我不知道D2005有没有SndKey32.pas这个单元。
你可以上网搜一下Sendkeys函数,应该会有所获。


qsl1982 发表于2005-07-19 16:56:00  IP: 61.186.252.*
请教如何实现在TWebBrowser中自动点击某个href


CathyEagle 发表于2005-07-30 16:48:00  IP: 61.186.252.*
“自动点击”的意思,我理解为从WebBrowser出发,找到document,进而找到href的集合,再从集合中找到自己要的那个IHTMLLinkElement类型的接口指针,然后,由于它也是一个IHTMLElement,所以转换位IHTMLElement之后再调用后者的click方法。


knocker 发表于2005-08-29 15:06:00  IP: 211.100.4.*
CathyEagle前辈 你好:
我这几天正在学习WebBrowser这个控件,遇到一个问题,想请你费点时间指点一下,谢谢你了。问题在:
http://bbs.bc-cn.net/bbs/dispbbs ... ID=26190&page=1

因为,我要找的“编辑框”就是上面的这个论坛,所以,直接贴上了问题的链接,请勿怪罪,再次谢谢了。


CathyEagle 发表于2005-09-01 12:51:00  IP: 61.186.252.*
呵呵,你的问题是这样产生的。
Body确实是用来post数据的,不过对它的赋值是由脚本完成的。
注意<form id="Dvform" action="savepost.asp?action=sre&method=fastreply&BoardID=10" method=POST name="Dvform" onSubmit="Dvbbs_CopyData('Body');">
这里的Dvbbs_CopyData('Body')把真实的数据(即用户在Editor里面输入的数据)复制到Hidden的Body。即在post之前把Body的数据修改了。
Dvbbs_CopyData在这个http://bbs.bc-cn.net/bbs/images/post/reply.js里面。
function Dvbbs_CopyData(hiddenid)
{
Dvbbs_formatimg()
d = IframeID.document;
document.Dvform.Submit.disabled=true;
cont = d.body.innerHTML;
cont = Dvbbs_correctUrl(cont);
cont = Dvbbs_cleanHtml(cont);
cont = Dvbbs_FilterScript(cont);
document.getElementById(hiddenid).value = cont;
}

可见真实的数据来自于IframeID,而IframeID又在哪里呢?其实就是那个Editor。
var Dvbbs_bIsIE5=document.all
if (Dvbbs_bIsIE5)
{var IframeID=frames["Dvbbs_Composition"];}
else
{
var IframeID=document.getElementById("Dvbbs_Composition").contentWindow;
}

<iframe class="Dvbbs_Reply" ID="Dvbbs_Composition" MARGINHEIGHT="5" MARGINWIDTH="5" width="100%" height="100%" onBlur="CheckCount('Body','total');"></iframe>

所以你需要把数据直接填写到Editor里面去,或者是拦截Form Element的OnSubmit,去掉复制数据的操作,手动复制。


knocker 发表于2005-09-04 15:53:00  IP: 211.100.21.*
非常感谢CathyEagle前辈。请前辈再费心指一下如何实现:
1。数据直接填写到Editor里面去
2。拦截Form Element的OnSubmit,去掉复制数据的操作,手动复制

昨天晚上就看到前辈的回复了,但是昨晚和今早我回复这个贴子怎么回不上,IE竟然要死机,不知道是不是内容太长了(不知道现在能不能回上_^_).

烦请前辈简单地写两个C++的示例?我用的是BCB,DELPHI不太看得懂。我想知道两种方法的实现。



shuszj 发表于2005-09-24 09:58:00  IP: 211.100.21.*
在Delphi中用TWebBrowser用制作游览器时,虽然比较简单,但当网页出现脚本错误,它就会跳出一个错误框,提示是否继续执行。我想当你游览某网站跳出错误框时,一定是很反感。
所以我想知道,如果不想让这个错误提示框弹出来,像IE一样提示在左下角状态栏?
不知哪位高手能帮忙?谢谢!


hi9_cn 发表于2005-12-04 09:05:00  IP: 59.57.223.*
to shuszj:

你可以找个有错的网页试试,
procedure TForm1.WebBrowser1NavigateError(ASender: TObject;
const pDisp: IDispatch; var URL, Frame, StatusCode: OleVariant;
var Cancel: WordBool);
begin
cancel:=true;
end;


具体的请到我的主页中联系我我的主页中有我的联系方式.
我的主页www.hi9.cn


CathyEagle 发表于2005-12-04 22:00:00  IP: 222.65.40.*
to shuszj:
MSDN上有篇文章《How to handle script errors as a WebBrowser control host》讲了如何压制脚本错误对话框,地址如下
http://support.microsoft.com/default.aspx?scid=kb;en-us;261003


ORCHER 发表于2005-12-12 12:32:00  IP: 219.133.233.*
请教一下我用Twebbrowser浏览网页,有些网页会很烦探出alert和confirm,有不有办法 自动帮我点掉?但是不影响其他javascript的效果,最好还能获得alert的内容


CathyEagle 发表于2005-12-12 19:10:00  IP: 222.65.57.*
用Hook+subclassing可以很好地处理这种窗口。要得到alert的内容可以通过实现IDocHostShowUI接口的ShowMessage方法来实现。

下面的例子来自MSDN

IDocHostShowUI::ShowMessage Method

--------------------------------------------------------------------------------

Called by MSHTML when it needs to display a message box.

Syntax

HRESULT ShowMessage( HWND hwnd,
LPOLESTR lpstrText,
LPOLESTR lpstrCaption,
DWORD dwType,
LPOLESTR lpstrHelpFile,
DWORD dwHelpContext,
LRESULT *plResult
);
Parameters

hwnd
[in] HWND of the owner window.
lpstrText
[in] LPOLESTR pointer to a string containing the text for the message box.
lpstrCaption
[in] LPOLESTR pointer to a string containing the caption for the message box.
dwType
[in] DWORD containing the flag type (taken from the MessageBox MB_xxxx constants).
lpstrHelpFile
[in] LPOLESTR pointer to a string containing the Help file name.
dwHelpContext
[in] DWORD containing the Help context identifier.
plResult
[out] Pointer to an LRESULT which indicates what button the user clicked (taken from the MessageBox IDxxx constants).
Return Value

Returns one of the following values:

S_OK Host displayed its user interface (UI). MSHTML does not display its message box.
S_FALSE Host did not display its UI. MSHTML displays its message box.


Example

When hosting the browser control, you can replace the Microsoft Internet Explorer message box caption (used for Microsoft JScript alerts (among other things) with a custom caption for your own application. The Internet Explorer message box caption is stored as a string resource in Shdoclc.dll. It is identified by the symbol IDS_MESSAGE_BOX_TITLE, which has a value of 2213. You can load this resource yourself and compare it with the lpstrCaption value to determine when to replace the message box caption with your own custom string. The following example shows one way you can implement IDocHostShowUI::ShowMessage to do this.

Security Alert Using LoadLibrary incorrectly can compromise the security of your application by loading the wrong dynamic-link library (DLL). Refer to the LoadLibrary documentation for information on how to correctly load DLLs with different versions of Microsoft Windows.

Hide Example

HRESULT CBrowserHost::ShowMessage(HWND hwnd,
LPOLESTR lpstrText,
LPOLESTR lpstrCaption,
DWORD dwType,
LPOLESTR lpstrHelpFile,
DWORD dwHelpContext,
LRESULT *plResult)
{
USES_CONVERSION;
TCHAR pBuffer[50];

// resource identifier for window caption "Microsoft Internet Explorer"
#define IDS_MESSAGE_BOX_TITLE 2213

// Load Shdoclc.dll and the IE message box title string
HINSTANCE hinstSHDOCLC = LoadLibrary(TEXT("SHDOCLC.DLL"));

if (hinstSHDOCLC == NULL)
{
//Error loading module -- fail as securely as possible
return;
}

LoadString(hinstSHDOCLC, IDS_MESSAGE_BOX_TITLE, pBuffer, 50);

// Compare the IE message box title string with lpstrCaption
// If they're the same, substitute your own Caption
if (_tcscmp(OLE2T(lpstrCaption), pBuffer) == 0)
lpstrCaption = L"New Caption";

// Create your own message box and display it
*plResult = MessageBox(OLE2T(lpstrText), OLE2T(lpstrCaption), dwType);

// Unload Shdoclc.dll and return
FreeLibrary(hinstSHDOCLC);
return S_OK;
}




jbas 发表于2005-12-25 14:31:00  IP: 222.46.36.*
老大,请问怎么得到frames中的各个网页的title属性值?
我的下面的代码为什么得不到title值?
请指教一下我吧,谢谢了!

procedure TFmMain.WebBrowser1DocumentComplete(ASender: TObject;
const pDisp: IDispatch; var URL: OleVariant);
var
d:Variant;
htMsg:string;
index:Integer;
document: IHTMLDocument2;
ole_index: OleVariant;
doc_all: IHTMLElementCollection;
frame_dispatch: IDispatch;
frame_win: IHTMLWindow2;
frame_doc: IHTMLDocument2;
frameCount: Integer;
begin
try
document := WebBrowser1.Document as IHTMLDocument2;
if Assigned(document) then
begin
if(document.frames.length=0) then
begin
d:=WebBrowser1.OleObject.Document;
htMsg:=d.title;
end
else
begin
for index:=1 to document.Frames.Length do
begin
ole_index := index-1;
frame_dispatch := document.Frames.Item(ole_index);
if Assigned(frame_dispatch) then
begin
frame_win := frame_dispatch as IHTMLWindow2;
htMsg:=frame_win.document.title;
showmessage('pp'+htMsg);
end;
end;
end;
end;
Except

end;


//d:=WebBrowser1.Document;
// htMsg := WebBrowser1.OleObject.Document.title;
FmMain.Caption:=htMsg;
showmessage('hixh'+htMsg);
if((htMsg='没有可以显示的页面') or (htMsg='HTTP 404 未找到')) then
begin
d.Write('<b>出错了!</b>');
d.Close;
end;
end;



jbas 发表于2005-12-25 14:49:00  IP: 222.46.36.*
我用上面的方法得到的title有乱码,不管用中文的title,还是英文的title,都是乱码.


CathyEagle 发表于2005-12-25 22:06:00  IP: 222.65.53.*
我测试过你的代码,不管是中文的title还是英文的title都能正确得到,没有问题。


jbas 发表于2005-12-26 09:08:00  IP: 218.74.226.*
谢谢你的回复,原来是我自己的错误,我的一个页面是这样的情况,所以搞致出不来title了

<head>
<title>titlestr</title>
<link rel="stylesheet" type="text/css" href="../../include/css/styles.css">
<script src="../../include/js/public.js"></script>
</head>
<%@ include file="../../include/jsp/head/logonheader.jsp" %>


冬灿 发表于2006-07-17 16:33:00  IP: 222.43.166.*
请问TWebBrowser载入的网页中的flash游戏,为何不能再接受键盘操作了?该如何实现键盘操作呢?难道是TWebBrowser没有得到焦点?我按您的方法设置过焦点后仍不行,请问该如何解决?谢谢


CathyEagle 发表于2006-08-17 21:15:00  IP: 58.38.126.*
很久没对TWebBrowser编程了。至于使浏览器获得焦点的问题,你是否试过鼠标点击浏览器页面后Flash游戏能否接收键盘操作?如果可以,则是设置焦点的方法不对,可参考我最近的一篇文章《Internet Explorer 编程简述(十二)正确地设置和转移焦点》http://blog.csdn.net/CathyEagle/archive/2006/05/29/762468.aspx


cmilk 发表于2006-09-18 14:42:00  IP: 59.53.133.*
TWebBrowser中如何做到和ie那样发送电子邮件页面的功能?


CathyEagle 发表于2006-09-27 23:24:00  IP: 222.71.164.*
这个功能我没有写过。不过Messaging Application Program Interface (MAPI)中有个函数MAPISendDocuments可以完成类似的功能,详细资料可参考MSDN。


顶一下哈 发表于2006-10-27 09:36:00  IP: 221.232.137.*
刚学delphi,谢谢仍然在更新。


Liaohz 发表于2006-11-16 17:20:00  IP: 219.134.74.*
请教一个问题,使用TWebBrowser如何判断网页的当前页的所有内容已经下载完了(其中包括所有的frames、图片等等)。


CathyEagle 发表于2006-11-17 00:38:00  IP: 58.38.120.*
参考下面的代码:
LPDISPATCH glpDisp = NULL; // global LPDISPATCH, can also
// be of class scope

// NavigateComplete2 event
void CWebbrDlg::OnNavigateComplete2Explorer1(LPDISPATCH pDisp,
VARIANT FAR* URL)
{
// Check if glpDisp is NULL. If NULL, that means it is
// the top level NavigateComplete2. Save the LPDISPATCH
if (!glpDisp)
glpDisp = pDisp;
}

void CWebbrDlg::OnDocumentCompleteExplorer1(LPDISPATCH pDisp,
VARIANT FAR* URL)
{
if (glpDisp && glpDisp == pDisp)
{
// if the LPDISPATCH are same, that means
// it is the final DocumentComplete. Reset glpDisp
TRACE("Document is done downloading");
glpDisp = NULL;
}
}
妖城欢迎您!

TOP

发新话题