欢迎光临
我们一直在努力

Internet Explorer 编程简述(五)调用IE隐藏的命令(中文版)-.NET教程,评论及其它

建站超值云服务器,限时71元/月

关键字:add to favorite, import/export wizard, shell docobject view, internet explorer_server

1、概述

除了“整理收藏夹”和“添加到收藏夹”对话框外,还有其它一些对话框是我们希望直接通过webbrowser调用的,比如“导入/导出”对话框,用一般的方法很难调用。ishelluihelper尽管提供了importexportfavorites方法,但结果只是显示一个选择文件的对话框,且只能导入/导出收藏夹而不能对cookies操作。

2、契机

msdn中有一篇叫“webbrowser customization”的文章,其中介绍了通过idochostuihandler.showcontextmenu方法自定义webbrowser上下文菜单的方法。其原理是从“shdoclc.dll”的资源中创建菜单,作一些修改之后用trackpopupmenu函数(注意在标志中包含tpm_returncmd)将菜单弹出,然后把返回的command id发送给“internet explorer_server”窗口进行处理。

……

// 显示菜单

int iselection = ::trackpopupmenu(hmenu,

? tpm_leftalign | tpm_rightbutton | tpm_returncmd,

? ppt->x,

? ppt->y,

? 0,

? hwnd,

? (rect*)null);

// 发送command id到外壳窗口

lresult lr = ::sendmessage(hwnd, wm_command, iselection, null);

……

好,如果找到所有上下文菜单的command id,不就可以随时调用了?确实是这样的。

3、实现

用exescope之类应用程序资源探索器打开“shdoclc.dll”便可以在菜单资源下找到上下文菜单的设计,如下图:

我们要做的,就是将这些id发送到“internet explorer_server”窗口进行处理。问题是webbrowser其实是一个ole容器,我们使用的chtmlview又是更外层的封装,他们的m_hwnd成员变量并不是ie窗口的句柄,如何找到我们需要的句柄呢?请看下面的图:

根据图中显示的从属关系,顺藤摸瓜,最内层的窗口“internet explorer_server”的句柄就是我们需要的东西。为了简化问题,我这里使用了来自msdn magazine资深专栏撰稿人paul dilascia的cfindwnd类,非常好用。

////////////////////////////////////////////////////////////////

// msdn magazine — august 2003

// if this code works, it was written by paul dilascia.

// if not, i dont know who wrote it.

// compiles with visual studio .net on windows xp. tab size=3.

//

// —

// this class encapsulates the process of finding a window with a given class name

// as a descendant of a given window. to use it, instantiate like so:

//

// cfindwnd fw(hwndparent,classname);

//

// fw.m_hwnd will be the hwnd of the desired window, if found.

//

class cfindwnd {

private:

? //////////////////

? // this private function is used with enumchildwindows to find the child

? // with a given class name. returns false if found (to stop enumerating).

? //

? static bool callback findchildclasshwnd(hwnd hwndparent, lparam lparam) {

??? cfindwnd *pfw = (cfindwnd*)lparam;

??? hwnd hwnd = findwindowex(hwndparent, null, pfw->m_classname, null);

??? if (hwnd) {

????? pfw->m_hwnd = hwnd; // found: save it

????? return false; // stop enumerating

??? }

??? enumchildwindows(hwndparent, findchildclasshwnd, lparam); // recurse

??? return true; // keep looking

}

public:

? lpcstr m_classname; // class name to look for

? hwnd m_hwnd; // hwnd if found

? // ctor does the work–just instantiate and go

? cfindwnd(hwnd hwndparent, lpcstr classname)

??? : m_hwnd(null), m_classname(classname)

? {

??? findchildclasshwnd(hwndparent, (lparam)this);

? }

};

再写一个函数invokeieservercommand,调用就很方便了,《internet explorer 编程简述(四)“添加到收藏夹”对话框》中最后给出的方法就是从这里来的。

void cmyhtmlview::invokeieservercommand(int nid)

{

? cfindwnd findiewnd( m_wndbrowser.m_hwnd, "internet explorer_server");

? ::sendmessage( findiewnd.m_hwnd, wm_command, makewparam(loword(nid), 0x0), 0 );

}

void cmyhtmlview::onfavaddtofav()

{

? invokeieservercommand(id_ie_contextmenu_addfav);//调用“添加到收藏夹”对话框

}

4、command ids

对所有的command id逐一尝试后我们发现:

1)不是所有的command id都可以用上面的方法调用;

2)不是所有的command id都是由“internet explorer_server”窗口处理;

3)有一些command id是由上一级窗口“shell docobject view”处理。

所以我们还需要写一个函数。

void cmyhtmlview::invokeshelldocobjcommand(int nid)

{

? cfindwnd findiewnd( m_wndbrowser.m_hwnd, "shell docobject view");

? ::sendmessage( findiewnd.m_hwnd, wm_command, makewparam(loword(nid), 0x0), 0 );

}

调用文章开头提到的“导入/导出”对话框可以这样来做:

void cdemoview::onimportexport()

{

? invokeshelldocobjcommand(id_ie_file_importexport);//调用“导入/导出”对话框

}

由"internet explorer_server"窗口处理的command id:

#define id_ie_contextmenu_addfav 2261

#define id_ie_contextmenu_viewsource 2139

#define id_ie_contextmenu_refresh 6042

由"shell docobject view"窗口处理的command id:

#define id_ie_file_saveas 258

#define id_ie_file_pagesetup 259

#define id_ie_file_print 260

#define id_ie_file_newwindow 275

#define id_ie_file_printpreview 277

#define id_ie_file_newmail 279

#define id_ie_file_senddesktopshortcut 284

#define id_ie_help_aboutie 336

#define id_ie_help_helpindex 337

#define id_ie_help_webtutorial 338

#define id_ie_help_freestuff 341

#define id_ie_help_productupdate 342

#define id_ie_help_faq 343

#define id_ie_help_onlinesupport 344

#define id_ie_help_feedback 345

#define id_ie_help_bestpage 346

#define id_ie_help_searchweb 347

#define id_ie_help_mshome 348

#define id_ie_help_visitinternet 349

#define id_ie_help_startpage 350

#define id_ie_file_importexport 374

#define id_ie_file_addtrust 376

#define id_ie_file_addlocal 377

#define id_ie_file_newpublishinfo 387

#define id_ie_file_newcorrespondent 390

#define id_ie_file_newcall 395

#define id_ie_help_netscapeuser 351

#define id_ie_help_enhancedsecurity 375

5、refresh

熟悉tembeddedwb的读者可能注意到了id_ie_contextmenu_refresh(6042)这个id,在tembeddedwb中给出了一个当网页刷新时触发的onrefresh事件,其中的关键代码如下:

……

if assigned(fonrefresh) and ((ncmdid = 6041 {f5}) or (ncmdid = 6042 {contextmenu}) or (ncmdid = 2300)) then

begin

? fcancel := false;

? fonrefresh(self, ncmdid, fcancel);

? if fcancel then result := s_ok;

end;

……

其中的6402就是我们这里的id_ie_contextmenu_refresh,2300是内置的刷新命令,那6041呢。见下图,还是“shdoclc.dll”,6041原来是ie“查看”菜单下“刷新”菜单的命令id。实际开发中我们发现直接调用webbrowser的refresh命令有时候会导致一些错误,可以用这里的方法替换一下。

6、需要注意的问题

1)用invokeieservercommand(id_ie_contextmenu_addfav)调用“添加到收藏夹”对话框时需要注意的是,ie接收到id_ie_contextmenu_addfav命令时是对网页中当前被选中的链接来执行“添加到收藏夹”操作的,如果没有选中的链接,才是将当前网页添加到收藏夹。

2)新建ie窗口。这是浏览器编程中的难题之一,即从当前窗口新建一个internet explorer窗口,完全复制当前页的内容(包括“前进”、“后退”的状态),这可以通过invokeshelldocobjcommand(id_ie_file_newwindow)来实现。

3)显示ie的版本信息。调用invokeshelldocobjcommand(id_ie_help_aboutie),如下:

4)invokeshelldocobjcommand(id_ie_file_print)调出的“打印”对话框是非模态的(我们不太清楚microsoft的设计意图,我认为“打印”对话框应该是模态的),显示模态窗口的方法请参加我的另一篇文章《利用wh_cbt hook将非模态对话框显示为模态对话框》

赞(0)
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com 特别注意:本站所有转载文章言论不代表本站观点! 本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。未经允许不得转载:IDC资讯中心 » Internet Explorer 编程简述(五)调用IE隐藏的命令(中文版)-.NET教程,评论及其它
分享到: 更多 (0)