Internet Explorer 编程简述(一)WebBrowser还是WebBrowser_V1收藏
新一篇: Internet Explorer 编程简述(二)在IE中编辑OLE嵌入文档 | 旧一篇: Internet Explorer 编程简述(序)
<script>function StorePage(){d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();}</script>关键字:WebBrowser, WebBrowser_V1,NewWindow, NewWindow2, NewWindow3, INewWindowManager
你的机器上总是存在着“两”个WebBrowser,一个叫WebBrowser,另一个叫WebBrowser_V1,其CLASSID如下:
CLASS_WebBrowser: TGUID = '{8856F961-340A-11D0-A96B-00C04FD705A2}';
CLASS_WebBrowser_V1: TGUID = '{EAB22AC3-30C1-11CF-A7EB-0000C05BAE0B}';
它们分别对应的接口是IWebBrowser2和IWebBrowser。问题是我们该用哪一个呢?
按照微软的推荐,应该尽量使用前者,因为后者是为兼容Internet Explorer 3.x而保留的(尽管它能够响应来自Internet Explorer 3.x、4.x、5.x、6.x的事件),相应的IWebBrowser和IWebBrowserApp接口也应抛弃。
由于Internet Explorer 3.x年代久远,导致WebBrowser_V1提供的事件少得可怜,但值得一提的是它提供的两个事件OnNewWindow和OnFrameBeforeNavigate有着与OnBeforeNavigate几乎相同的参数:
OnBeforeNavigate(
BSTR URL,
long Flags,
BSTR TargetFrameName,
VARIANT* PostData,
BSTR Headers,
BOOL FAR* Cancel)
OnNewWindow(
BSTR URL,
long Flags,
BSTR TargetFrameName,
VARIANT* PostData,
BSTR Headers,
BOOL FAR* Processed)
OnFrameBeforeNavigate(
BSTR URL,
long Flags,
BSTR TargetFrameName,
VARIANT* PostData,
BSTR Headers,
BOOL FAR* Cancel)
所以使用WebBrowser_V1使得我们的浏览器在有新窗口打开时能够轻易捕捉到其URL及相关的数据,如果将Processed设置为TRUE,则可取消新窗口的弹出。同样,处理Frame也比在WebBrowser中来得容易。
但WebBrowser_V1的致命弱点是它不支持高级接口,如 IDocHostUIHandler,即便我们实现了IDocHostUIHandler接口,也不会被WebBrowser_V1调用。所以希望在自己的浏览器中实现XP的界面主题、扩展IE的DOM(Document Object Model)等高级控制的话,就肯定不能选择WebBrowser_V1了。
处理新窗口实在是很麻烦的一件事,不知道微软为什么在新版本的OnNewWindow2事件中去掉了URL这样的参数,而且OnNewWindow2事件不能完全捕捉到所有的新窗口打开。但如果安装了Windows XP SP2的话,好处又回来了。
Windows XP SP2对Internet Explorer 6作了升级,并且提供了一个新的事件OnNewWindow3,它在OnNewWindow2事件之前发生,也包含了让我们能够加以过滤处理的新窗口的URL等参数,再加上INewWindowManager接口,就是实现Windows XP SP2中过滤广告窗口功能的基础。
参考资料:
MSDN:185538 HOWTO: Cause Navigation to Occur in Same WebBrowser Window
引用地址:Internet Explorer 编程简述(一)WebBrowser还是WebBrowser_V1
Internet Explorer 编程简述(二)在IE中编辑OLE嵌入文档收藏
新一篇: Internet Explorer 编程简述(三)“整理收藏夹”对话框 | 旧一篇: Internet Explorer 编程简述(一)WebBrowser还是WebBrowser_V1
<script>function StorePage(){d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();}</script>关键字:OLE嵌入,In-Place Activating,IE, Office, Acrobat
除了打开Internet上的网页,Internet Explorer还能够浏览本地文件夹及文件。如果浏览的是PDF文档或Office文档,有时候你会发现当调用Navigate("xxx.doc") 的时候,Adobe Reader/Acrobat或Office等Document Servers会在IE中嵌入自己的一个实例以打开相应的文件,当然有时候也会在独立的Acrobat或Office窗口中打开文件。
在Adobe Reader/Acrobat的属性设置窗口中,我们可以找到“Display PDF in browser”的选项,如果勾上,则Navigate("xxx.pdf")将会以嵌入的方式在IE中浏览PDF文件,否则在独立的Adobe Reader/Acrobat窗口中浏览。但在Office的“选项”对话框中我们找不到这样的设置。
问题:如何在自己的浏览器中控制Office这类Ole Servers的打开方式?
答案:修改文件夹选项,或修改注册表。
方法1、如下所示,从控制面板中打开“文件夹”选项,在“文件类型”属性页上找到相应的文件后缀名,如“DOC”,点击“高级”按钮,在弹出的“编辑文件类型”对话框中有“在同一窗口中浏览”的选项,如果勾上,则以嵌入IE的方式打开文档,否则在独立窗口中打开。
方法2、直接修改注册表。
在“HKEY_LOCAL_MACHINE/SOFTWARE/Classes”键值下,保存了各种文件类型的注册信息,以Office文档为例,与文档相关键值如下。
文档类型 键值
Microsoft Excel 7.0 worksheet Excel.Sheet.5
Microsoft Excel 97 worksheet Excel.Sheet.8
Microsoft Excel 2000 worksheet Excel.Sheet.8
Microsoft Word 7.0 document Word.Document.6
Microsoft Word 97 document Word.Document.8
Microsoft Word 2000 document Word.Document.8
Microsoft Project 98 project MSProject.Project.8
Microsoft PowerPoint 2000 document PowerPoint.Show.8
如果我们要修改Word文档的打开方式,,则在“HKEY_LOCAL_MACHINE/SOFTWARE/Classes/Word.Document.8”下新建一个名为“BrowserFlags”,类型为“REG_DWORD”的子键值,如果设置其值为“8”,则在独立的窗口中打开Word文档,否则在嵌入 IE的Word窗口中打开文档。
注:Microsoft Excel 7.0 worksheet稍有不同,应设置BrowserFlags的值为“9”方可在独立的窗口中打开文档。
参考资料:
MSDN:259970:In-Place Activating Document Servers in Internet Explorer
MSDN:162059:How to configure Internet Explorer to open Office documents in the appropriate Office program instead of in Internet Explorer
引用地址:Internet Explorer 编程简述(二)在IE中编辑OLE嵌入文档
Internet Explorer 编程简述(三)“整理收藏夹”对话框收藏
新一篇: Internet Explorer 编程简述(四)“添加到收藏夹”对话框 | 旧一篇: Internet Explorer 编程简述(二)在IE中编辑OLE嵌入文档
<script>function StorePage(){d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();}</script>关于Internet Explorer的收藏夹,比较常见的两个问题就是调用“整理收藏夹”对话框和“添加到收藏夹”对话框。调用的方法有多种,但其中还是有些值得讨论的地方。
关键字:添加到收藏夹,整理收藏夹,DoAddToFavDlg, DoOrganizeFavDlg
1、整理收藏夹
调用“整理收藏夹”对话框(如下),基本上来说都用的是同一个方法,即调用“shdocvw.dll”中的“DoOrganizeFavDlg”函数,把父窗口句柄和收藏夹路径作为参数传入即可。
2、代码
代码实例如下所示,值得注意的是对“shdocvw.dll”的处理,为避免重复调用,应该先检查其是否已经在内存中。
void CMyHtmlView::OnFavOrganizefav()
{
typedef UINT (CALLBACK* LPFNORGFAV)(HWND, LPTSTR);
bool bResult = false;
HMODULE hMod = ::GetModuleHandle( _T("shdocvw.dll") );
if (hMod == NULL)//如果"shdocvw.dll"尚未载入则载入之
{
hMod = ::LoadLibrary( _T("shdocvw.dll") );
if (hMod == NULL)
{
MessageBox( _T("The dynamic link library ShDocVw.DLL cannot be found."),
_T("Error"), MB_OK | MB_ICONSTOP );
return;
}
LPFNORGFAV lpfnDoOrganizeFavDlg = (LPFNORGFAV)
::GetProcAddress( hMod, "DoOrganizeFavDlg" );
if (lpfnDoOrganizeFavDlg == NULL)
{
MessageBox( _T("The entry point DoOrganizeFavDlg cannot be found/n")
_T("in the dynamic link library ShDocVw.DLL."),
_T("Error"), MB_OK | MB_ICONSTOP );
return;
}
TCHAR szPath [ MAX_PATH ];
HRESULT hr;
hr = ::SHGetSpecialFolderPath( m_hWnd, szPath, CSIDL_FAVORITES, TRUE );
if (FAILED(hr))
{
MessageBox( _T("The path of the Favorites folder cannot be found."),
_T("Error"), MB_OK | MB_ICONSTOP );
return;
}
bResult = (*lpfnDoOrganizeFavDlg) ( m_hWnd, szPath ) ? true : false;
::FreeLibrary( hMod );
}
else//如果"shdocvw.dll"已经在调用者进程的地址空间中则直接使用。
{
LPFNORGFAV lpfnDoOrganizeFavDlg = (LPFNORGFAV)
::GetProcAddress( hMod, "DoOrganizeFavDlg" );
if (lpfnDoOrganizeFavDlg == NULL)
{
MessageBox( _T("The entry point DoOrganizeFavDlg cannot be found/n")
_T("in the dynamic link library ShDocVw.DLL."),
_T("Error"), MB_OK | MB_ICONSTOP );
return;
}
TCHAR szPath [ MAX_PATH ];
HRESULT hr;
hr = ::SHGetSpecialFolderPath( m_hWnd, szPath, CSIDL_FAVORITES, TRUE );
if (FAILED(hr))
{
MessageBox( _T("The path of the Favorites folder cannot be found."),
_T("Error"), MB_OK | MB_ICONSTOP );
return;
}
bResult = (*lpfnDoOrganizeFavDlg) ( m_hWnd, szPath ) ? true : false;
}
return;
}
3、讨论
实际上,从“DoOrganizeFavDlg” 函数的原型声明我们可以看到,由于需要一个路径,所以“整理收藏夹”对话框其实不仅可以用来整理收藏夹,还可以整理磁盘上的目录。而且所谓的整理也不过是提供了一个对话框使用户用起来比较方便而已,和直接在资源管理器中整理没有实质性的差别。因此调用“整理收藏夹”对话框的方法从IE4.0开始就没有变过,除了对话框的布局有所改变。
typedef UINT (CALLBACK* LPFNORGFAV)(HWND, LPTSTR);
IE 4.0的“整理收藏夹”对话框
IE 4.0的“整理收藏夹”对话框(原先的设计)
“添加到收藏夹”就不同了,“DoAddToFavDlg”函数不再像“DoOrganizeFavDlg”函数一样对所有IE的版本都适用。
参考资料:
MSDN: Adding Internet Explorer Favorites to Your Application
引用地址:Internet Explorer 编程简述(三)“整理收藏夹”对话框
Internet Explorer 编程简述(四)“添加到收藏夹”对话框收藏
新一篇: Internet Explorer 编程简述(五)调用IE隐藏的命令 | 旧一篇: Internet Explorer 编程简述(三)“整理收藏夹”对话框
<script>function StorePage(){d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();}</script>关键字:“添加到收藏夹”对话框, 模态窗口,IShellUIHelper,DoAddToFavDlg, DoOrganizeFavDlg
1、概述
调用“添加到收藏夹”对话框(如下)与调用“整理收藏夹”对话框有不同之处,前者所做的工作比后者要来得复杂。将链接添加到收藏夹除了将链接保存之外,还可能会有脱机访问的设置,从IE 4.0到IE 5.0,处理的方式也发生了一些变化。
2、IShellUIHelper接口
微软专门提供了一个接口IShellUIHelper来实现对Windows Shell API一些功能的访问,将链接添加到收藏夹也是其中之一,就是下面的AddFavorite函数。
HRESULT IShellUIHelper::AddFavorite(BSTR URL, VARIANT *Title);
实例代码如下:
void CMyHtmlView::OnAddToFavorites()
{
IShellUIHelper* pShellUIHelper;
HRESULT hr = CoCreateInstance(CLSID_ShellUIHelper, NULL,
CLSCTX_INPROC_SERVER, IID_IShellUIHelper,(LPVOID*)&pShellUIHelper);
if (SUCCEEDED(hr))
{
_variant_t vtTitle(GetTitle().AllocSysString());
CString strURL = m_webBrowser.GetLocationURL();
pShellUIHelper->AddFavorite(strURL.AllocSysString(), &vtTitle);
pShellUIHelper->Release();
}
}
我们注意到这里的“AddFavorite”函数并没有像 “DoOrganizeFavDlg”那样需要一个父窗口句柄。这也导致与在IE中打开不同,通过IShellUIHelper接口显示出来的“添加到收藏夹”对话框是“非模态”的,有一个独立于我们应用程序的任务栏按钮,这使我们的浏览器显得非常不专业(我是个追求完美的人,这也是我的浏览器迟迟不能发布的原因之一)。
于是我们很自然地想到“shdocvw.dll”中除了“DoOrganizeFavDlg”外,应该还有一个类似的函数,可以传入一个父窗口句柄用以显示模态窗口,也许就像这样:
typedef UINT (CALLBACK* LPFNADDFAV)(HWND, LPTSTR, LPTSTR);
事实上,这样的函数确实存在于“shdocvw.dll”中,那就是“DoAddToFavDlg”。
3、DoAddToFavDlg函数
“DoAddToFavDlg”函数也是“shdocvw.dll”暴露出来的函数之一,其原型如下:
typedef BOOL (CALLBACK* LPFNADDFAV)(HWND, TCHAR*, UINT, TCHAR*, UINT,LPITEMIDLIST);
第一个参数正是我们想要的父窗口句柄,第二和第四个参数分别是初始目录(一般来说就是收藏夹目录)和要添加的链接的名字(比如网页的Title),第三和第五个参数分别是第二和第四两个缓冲区的长度,而最后一个参数则是指向与第二个参数目录相关的item identifier list的指针(PIDL)。但最奇怪的是这里并没有像“AddFavorite”函数一样的链接URL,那链接是怎样添加的呢?答案是“手动创建”。
第二个参数在函数调用返回后会包含用户在“添加到收藏夹”对话框中选择或创建的完整链接路径名(如“X:/XXX/mylink.url”),我们就根据这个路径和网页的URL来创建链接,代码如下(为简化,此处省去检查"shdocvw.dll"是否已在内存中的代码,参见《Internet Explorer 编程简述(三)“整理收藏夹”对话框》):
void CMyHtmlView::OnFavAddtofav()
{
typedef BOOL (CALLBACK* LPFNADDFAV)(HWND, TCHAR*, UINT, TCHAR*, UINT,LPITEMIDLIST);
HMODULE hMod = (HMODULE)LoadLibrary("shdocvw.dll");
if (hMod)
{
LPFNADDFAV lpfnDoAddToFavDlg = (LPFNADDFAV)GetProcAddress( hMod, "DoAddToFavDlg");
if (lpfnDoAddToFavDlg)
{
TCHAR szPath[MAX_PATH];
LPITEMIDLIST pidlFavorites;
if (SHGetSpecialFolderPath(NULL, szPath, CSIDL_FAVORITES, TRUE) &&
(SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_FAVORITES, &pidlFavorites))))
{
TCHAR szTitle[MAX_PATH];
strcpy(szTitle, GetLocationName());
TCHAR szURL[MAX_PATH];
strcpy(szURL, GetLocationURL());
BOOL bOK = lpfnDoAddToFavDlg(m_hWnd, szPath,
sizeof(szPath)/sizeof(szPath[0]), szTitle,
sizeof(szTitle)/sizeof(szTitle[0]), pidlFavorites);
CoTaskMemFree(pidlFavorites);
if (bOK)
CreateInternetShortcut( szURL, szPath, ""); //创建Internet快捷方式
}
}
FreeLibrary(hMod);
}
return;
}
实现CreateInternetShortcut函数创建Internet快捷方式,可以用读写INI文件的方法,但更好的则是利用IUniformResourceLocator接口。
HRESULT CMyHtmlView::CreateInternetShortcut(LPCSTR pszURL, LPCSTR pszURLfilename,
LPCSTR szDescription,LPCTSTR szIconFile,int nIndex)
{
HRESULT hres;
CoInitialize(NULL);
IUniformResourceLocator *pHook;
hres = CoCreateInstance (CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER,
IID_IUniformResourceLocator, (void **)&pHook);
if (SUCCEEDED (hres))
{
IPersistFile *ppf;
IShellLink *psl;
// Query IShellLink for the IPersistFile interface for
hres = pHook->QueryInterface (IID_IPersistFile, (void **)&ppf);
hres = pHook->QueryInterface (IID_IShellLink, (void **)&psl);
if (SUCCEEDED (hres))
{
WORD wsz [MAX_PATH]; // buffer for Unicode string
// Set the path to the shortcut target.
pHook->SetURL(pszURL,0);
hres = psl->SetIconLocation(szIconFile,nIndex);
if (SUCCEEDED (hres))
{
// Set the description of the shortcut.
hres = psl->SetDescription (szDescription);
if (SUCCEEDED (hres))
{
// Ensure that the string consists of ANSI characters.
MultiByteToWideChar (CP_ACP, 0, pszURLfilename, -1, wsz, MAX_PATH);
// Save the shortcut via the IPersistFile::Save member function.
hres = ppf->Save (wsz, TRUE);
}
}
// Release the pointer to IPersistFile.
ppf->Release ();
psl->Release ();
}
// Release the pointer to IShellLink.
pHook->Release ();
}
return hres;
}
好,上面的方法虽然麻烦一点,但总算解决了“模态窗口”的问题,使得我们的程序不至于让用户鄙视。但是问题又来了,我们发现“允许脱机使用”是Disabled的,那“自定义”也就无从谈起了,尽管90%的人都没有使用过IE提供的脱机浏览。
难道我们的希望要破灭吗?我们一方面想像调用“AddFavorite”函数一样的不必手动创建链接,一方面又要模态显示窗口,就像IE那样,还能自定义脱机浏览。
4、脚本方式
许多网页上都会有一个按钮或链接“添加本页到收藏夹”,实际上通过下面的脚本显示模态的“添加到收藏夹”对话框将网页加入到收藏夹。
window.external.AddFavorite(location.href, document.title);
这里的external对象是WebBrowser内置的 COM自动化对象,以实现对文档对象模型(DOM)的扩展(我们也可以通过IDocHostUIHandler实现自己的扩展).查阅MSDN可以得知 external对象的的方法与IShellUIHelper接口提供的方法是一样的。我们有理由相信,IShellUIHelper提供了对 WebBrowser内置的external对象的访问,如果在适当的地方创建IShellUIHelper接口的实例,也许调用 “AddFavorite”函数显示出来的就是模态对话框了。问题是我们还没有找到这样的地方。
从上面的脚本,我们很自然地又想到另一个方法。如果能够让网页来执行上面的脚本,岂不是问题就解决了?说做就做,如下:
void CMyHtmlView::OnFavAddtofav()
{
CString strUrl = GetLocationURL();
CString strTitle = GetLocationName();
CString strjs = "javascript:window.external.AddFavorite('" + strUrl + "'," + "'" + strTitle + "');";
ExecScript(strjs);
}
void CMIEView::ExecScript(CString strjs)
{
CComQIPtr
pHTMLDoc = (IHTMLDocument2*)GetHtmlDocument();
if ( pHTMLDoc != NULL )
{
CComQIPtr
pHTMLWnd;
pHTMLDoc->get_parentWindow( &pHTMLWnd );
if ( pHTMLWnd != NULL )
{
CComBSTR bstrjs = strjs.AllocSysString();
CComBSTR bstrlan = SysAllocString(L"javascript");
VARIANT varRet;
pHTMLWnd->execScript(bstrjs, bstrlan, &varRet);
}
}
}
先从CHtmlView获得文档的父窗口window对象的指针,再调用其方法execScript来执行脚本(事实上可以执行任意的脚本)。试验发现,这个方法非常有效,不仅窗口是模态的,而且不需要手动创建链接,更重要的是“允许脱机使用”和“自定义”按钮也可以用了。
5、问题仍旧没有解决
执行脚本的方式看起来有效,可一旦我们的程序实现了 IDocHostUIHandler接口对WebBrowser进行高级控制,就会发现一旦执行的脚本包含有对“external”对象的调用,就会出现 “缺少对象”的脚本错误。原因是当MSHTML解析引擎(并非WebBrowser)检查到宿主实现了IDocHostUIHandler接口,就会调用其GetExternal方法以获得一个用以扩展DOM的自动化接口的引用。
HRESULT IDocHostUIHandler::GetExternal(IDispatch **ppDispatch)
但有时候我们并没有想要扩展DOM,同时我们还希望 WebBrowser使用它自己的DOM扩展。糟糕的是GetExternal方法的文档中说这种情况下必须把ppDispatch设置为NULL,换句话说,WebBrowser连它内置的external对象也不用了,那我们的window.external.AddFavorite就变得无处为家了。
我曾多方尝试将WebBrowser内置的external对象找出来,虽然都没有成功,但是解决问题的方法却被我找到了。
6、完美的方案
WebBrowser 内置的external对象我们虽然找不到,但它肯定存在,我们只要想办法让WebBrowser自己完成对其调用即可。实现非常简单,找到 WebBrowser中包含的“Internet Explorer_Server”窗口的句柄,发一个消息就完成了。下面的代码中假设m_hWndIE就是“Internet Explorer_Server”窗口的句柄。
#define ID_IE_ID_ADDFAV 2261
::SendMessage( m_hWndIE, WM_COMMAND, MAKEWPARAM(LOWORD(ID_IE_ID_ADDFAV), 0x0), 0 );
试一试成果,是不是和在Internet Explorer中选择“添加到收藏夹”的效果一模一样。
至于为什么这样做,后续文章再说。
参考资料:
MSDN: Adding Internet Explorer Favorites to Your Application
MSDN: IShellUIHelper Interface
MSDN: external Object
MSDN: IDocHostUIHandler Interface
引用地址:Internet Explorer 编程简述(四)“添加到收藏夹”对话框
发表于 @ 2004年09月12日 22:39:00|评论(17 <script type=text/javascript>AddFeedbackCountStack("102355")</script> )|编辑
评论
# lxwde 发表于2004-09-13 10:08:00 IP: 165.170.128.*-
楼主,你这一系列IE开发的文章非常好,继续。
# CathyEagle 发表于2004-09-13 10:21:00 IP: 222.18.4.*-
谢谢:)
# 埃及小白 发表于2004-09-13 01:41:00 IP: 219.233.101.*-
这个办法依次类推可以打开很多的IE对话框。老兄的这个办法实在是好。
# CathyEagle 发表于2004-09-13 01:56:00 IP: 222.18.4.*-
mail收到否?按键的问题应该可以解决了。
# 埃及小白 发表于2004-09-13 02:12:00 IP: 219.233.101.*-
你的上述方法应该说是:WebBrowser.AddToFavorites;
但是如果是那种javaScript:window.external.AddFavorite(...)就不行了。因为要指定网址和标题的。
# CathyEagle 发表于2004-09-13 02:32:00 IP: 222.18.4.*-
什么意思?我没有哪个地方提到“上述方法”。
# 埃及小白 发表于2004-09-13 02:46:00 IP: 219.233.101.*-
::SendMessage( m_hWndIE, WM_COMMAND, MAKEWPARAM(LOWORD(ID_IE_ID_ADDFAV), 0x0), 0 );
就是我说的上述方法,这个办法可以添加当前浏览器控件所浏览的页面到收藏夹。
但如果是点击网页内部的javascript脚本,然后从GetExternal获得了网址和标题,并不可以用上述方法添加到收藏夹。
# CathyEagle 发表于2004-09-13 02:58:00 IP: 222.18.4.*-
通过::SendMessage( m_hWndIE, WM_COMMAND, MAKEWPARAM(LOWORD(ID_IE_ID_ADDFAV), 0x0), 0 ); 显示的对话框已经包含了对网址和标题的处理。
# 埃及小白 发表于2004-09-14 01:09:00 IP: 219.233.101.*-
javaScript:window.external.AddFavorite(...) 的确也可以用这个办法打开。但是发现和在IE中点击该链接打开有区别,但是和IE右键菜单中的“添加到收藏夹”是一样的。(我这边会先告诉你,这个方法不安全,问你是否继续,按继续之后,脱机使用也是灰的)
CE,你可以试试看
# CathyEagle 发表于2004-09-14 02:49:00 IP: 211.138.91.*-
当然有区别.。选中链接后调用脚本的话,是将选中的链接添加到收藏夹,在网页上其它地方弹出右键菜单是将该页添加到收藏夹。
我这里没有提示安全问题(当然,如果级别设置得很高的话可能会有),脱机也可用。
# youdu 发表于2004-09-16 09:36:00 IP: 202.104.34.*-
好啊!!!但是C++有点陌生~~还不会~呵呵
# lingll 发表于2006-05-09 08:12:00 IP: 222.200.164.*-
谢谢,
请问该如何实现方法3呢?
# lingll 发表于2006-05-08 21:20:00 IP: 219.222.194.*-
最后的"完美的方法",也有不完美的地方,当然,对于希望完全模仿ie来说,这个是完美的,但如果希望能添加到自定义的收藏夹路经中,例如在应用程序所在目录下的favorite目录,而不是系统指定的目录,这个就不行了,这样说来还是DoAddToFavDlg比较好,但却没了"允许脱机使用"的功能,
不知是否还有更好的解决办法.
# CathyEagle 发表于2006-05-08 21:51:00 IP: 222.67.186.*-
所谓“完美”,当然是就模仿IE而言,要完成自定义的功能则需要另寻出路了。就你的要求而言,大致来说,有几个解法:
1、自己实现一个全新的“添加到收藏夹”对话框(如Maxhon的做法)。此法不受任何限制。
2、在调用IE的实现(即本文的“完美”解法)之前临时把收藏夹的位置修改为指定的目录,添加完之后再改回来。此法虽不雅观,但恐怕最为简单直接。
3、Hook对DoAddToFavDlg的调用并在适当的地方修改起始路径(第二个参数)。这就复杂了。
# lingll 发表于2006-05-09 21:08:00 IP: 219.222.194.*-
好的,非常感谢
# CathyEagle 发表于2006-05-09 18:12:00 IP: 222.67.186.*-
我没有做过具体实现,只是说说原理。至于如何Hook,上网搜一下,有例子,或者找做外挂的朋友问问。
# guti_milan 发表于2006-11-15 11:43:00 IP: 58.214.166.*-
真的受益菲浅啊!
perfect!!!!!!!
Internet Explorer 编程简述(五)调用IE隐藏的命令收藏
新一篇: 利用WH_CBT Hook将非模态对话框显示为模态对话框 | 旧一篇: Internet Explorer 编程简述(四)“添加到收藏夹”对话框
<script>function StorePage(){d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();}</script>关键字:Add To Favorite, Import/Export Wizard, Shell DocObject View, Internet Explorer_Server
文章请到CodeProject阅读——Invoke Hidden Commands in Your WebBrowser
也可以到CodeGuru阅读——Invoke Hidden Commands In Your WebBrowser
Delphi版本请到swissdelphicenter阅读——Invoke Hidden Commands In Your WebBrowser
中文版稍后附上。
Internet Explorer 编程简述(十一)实现完美的Inplace Drag & Drop——“超级拖放”收藏
新一篇: IE & Delphi再次复活 | 旧一篇: Internet Explorer 编程简述(十)响应来自HTML Element的事件通知——几个好用的类
<script>function StorePage(){d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();}</script>想到了吗?解决问题的关键就在于第一个参数pDropTarget。相信很多浏览器在处理的时候都忽略掉了第一个参数而只是将自己的实现通过第二个参数告知MSHTML,因而丢失了IE缺省的行为。既然如此,将缺省的IDropTarget接口的指针保存下来,在适当的时候调用,不就能够保留IE的原始拖放行为了吗?
Internet Explorer 编程简述(十二)正确地设置和转移焦点收藏
新一篇: FAQ: 如何动态创建并访问网页元素 | 旧一篇: IE & Delphi再次复活
<script>function StorePage(){d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();}</script>