Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5382207
  • 博文数量: 671
  • 博客积分: 10010
  • 博客等级: 上将
  • 技术积分: 7310
  • 用 户 组: 普通用户
  • 注册时间: 2006-07-14 09:56
文章分类

全部博文(671)

文章存档

2011年(1)

2010年(2)

2009年(24)

2008年(271)

2007年(319)

2006年(54)

我的朋友

分类: C/C++

2008-02-15 10:16:02

作者:



  在 VCKBASE 混了这么久竟然没有写出一篇文章,想想很是惭愧,每当在这里看到一篇好文,这种感觉尤甚,总结我在程序员加油站中的一些技术点写了这个文章(虽然程序员加油站还要继续开发,但是由于时间关系不知道什么时候能完成),如果有时间我还会写一些文章的,我的写作水平可能很差,希望读者能够包涵。

程序原理:

一、在IE菜单中加入菜单项

  在注册表HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt项下建立一个新项,项的名称即为出现在菜单中的标题
将新建项的默认值设定为一个URL地址,当用户点击菜单项后,IE就会调用URL指向的页面中的脚本。

二、如何控制菜单项在合适的时候显示

  下面再介绍一下上面注册项中Contexts项的作用,通过该项可以制定菜单项在右键点击IE中的什么对象时出现,它可以为以下值的“或”组合
 

对象  值
缺省  0x1
图片  0x2
控件  0x4
表单域  0x8
选择文本  0x10
锚点  0x20
超链接  0x22

例如上面我们希望菜单项在用户点击图片或者超链接时出现,那么我们就将值设置为

dword:00000022

既在点击图片 或者 锚点时出现菜单。一个锚点是页面中描述一个超链接的对象。如果不设置Contexts 项,则菜单项会在点击任何对象时出现在右键菜单中。

注:
  一二部分我引用了《如何在IE右键菜单中添加菜单项以及如何添加IE任务栏按钮》这篇文章的部分内容,详细内容请看:

http://www.csdn.net/develop/read_article.asp?id=3621

三、编辑点击菜单项执行的script脚本

  这个脚本的文件名和1中的链接文件一致这个是我用的脚本:


//看到网海拾贝中这样用

四、在注册表中加入

HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall
\\程序员加油站加入ArticlePath - 文档存盘路径(string),ArticleNumber -文档序号(dword)。

五、写一个ATL的DLL,就是上面脚本中调用的那个对象,提供一个接口GetHtmlText(),看到有些其他程序使用external.menuArguments.document做为参数,可是我没试验成功,无法直接获得其中的document所以只能用笨方法了,取得当前窗口,然后取得IE子窗口的句柄,然后取得document指针,取得选取的内容,然后保存网页,并下载图片。
  下面就介绍一下ATL组件的制作,主要技术包括ATL编程,IE编程,注册表操作。
  • 1,用ATL COM模板创建一个工程
  • 2,加入一个接口testa
  • 3,加入Urlmon.Lib 和 #include
  • 4,加入接口函数GetHtmlText()
  • 实现如下:

    STDMETHODIMP Ctesta::GetHtmlText()
    {
    	//保存网页内容的目录
    	char chFilePath[MAX_PATH];
    	DWORD Number = 0;
    	
    	CRegistry reg;
    	reg.Open(HKEY_LOCAL_MACHINE,
    		"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\程序员加油站\\");
    	BOOL ret = reg.ReadDWORD("ArticleNumber",&Number); 
    	if(!ret)
    		return S_FALSE;
    	
    	//读取保存网页文件的目录
    	ret = reg.ReadString("ArticlePath",chFilePath);
    	if(!ret)
    		return S_FALSE;
    	
    	//取得当前活动窗口的窗口句柄
    	HWND hWnd = GetActiveWindow();
    	
    	
    	CoInitialize( NULL );
    	
    	//显式装载 MSAA 判断是否被安装
    	HINSTANCE hInst = ::LoadLibrary( _T("OLEACC.DLL") );
    	if ( hInst != NULL )
    	{
    		if ( hWnd != NULL )
    		{
    			HWND hWndChild=NULL;
    			// 取得当前窗口的IE子窗口指针
    			::EnumChildWindows( hWnd, EnumChildProc, (LPARAM)&hWndChild );
    			if ( hWndChild )
    			{
    				//定义IE文档
    				CComPtr pHTMLDoc;
    				LRESULT lRes;
    				
    				//由于WM_HTML_GETOBJECT非Windows标准消息,所以需要RegisterWindowMessage
    				UINT nMsg = ::RegisterWindowMessage( _T("WM_HTML_GETOBJECT") );
    				::SendMessageTimeout( hWndChild, nMsg, 0L, 0L, SMTO_ABORTIFHUNG, 1000, (DWORD*)&lRes );
    				
    				LPFNOBJECTFROMLRESULT pfObjectFromLresult = (LPFNOBJECTFROMLRESULT)::GetProcAddress( hInst, _T("ObjectFromLresult") );
    				if ( pfObjectFromLresult != NULL )
    				{
    					HRESULT hr;
    					//获取网页的IHTMLDocument2接口
    					hr = (*pfObjectFromLresult)( lRes, IID_IHTMLDocument, 0, (void**)&pHTMLDoc );
    					if ( SUCCEEDED(hr) )
    					{
    						CComPtr pSelObj;
    						CComPtr pTxtRange;
    						
    						//根据IHTMLDocument2指针取得IHTMLSelectionObject接口指针
    						pHTMLDoc->get_selection(&pSelObj);
    						//再获得IHTMLTxtRange指针
    						hr = pSelObj->createRange((IDispatch**)&pTxtRange);
    						if(!CheckResult(hr,"pTxtRange"))
    							return hr;
    						//选择所有被选择的内容
    						pTxtRange->select();
    						
    						BSTR bstrTxt,bstrTxt1;
    						char strPath[MAX_PATH];
    						char *strTxt = NULL;
    						char*strTxt1 = NULL;
    						
    						//取得主站域名
    						CComPtr pLocation;
    						pHTMLDoc->get_location(&pLocation);
    						pLocation->get_hostname(&bstrTxt1);
    						strTxt1 = _com_util::ConvertBSTRToString(bstrTxt1);
    						
    						sprintf(strPath,"http://%s",strTxt1);
    						SaveCharToFile(strTxt1,debugpath);
    						
    						//取得选中的内容
    						pTxtRange->get_htmlText(&bstrTxt);
    						strTxt = _com_util::ConvertBSTRToString(bstrTxt);
    						
    						//下载内容中的图片资源,并修改相应链接
    						std::string webpage;
    						char chSavePath[MAX_PATH];
    						sprintf(chSavePath,"%s\\T%ld.htm",chFilePath,Number);
    						CreateAllDirectory(chSavePath);
    						
    						//取得所有图片资源并保存网页
    						if(CheckData(strTxt,strPath,chFilePath,Number,webpage) == FALSE)
    							SaveCharToFile(strTxt,chSavePath,TRUE);
    						else
    							SaveCharToFile(webpage.c_str(),chSavePath,TRUE);
    						BOOL ret = reg.WriteDWORD("ArticleNumber",++Number);
    						//释放内存
    						if(strTxt1)
    							delete[] strTxt1;
    						if(strTxt)
    							delete[] strTxt;
    						SysFreeString(bstrTxt1); // 用完释放
    						SysFreeString(bstrTxt); // 用完释放
    					}
    				}
    			}
    		} // else Internet Explorer is not running
    		::FreeLibrary( hInst );
    	} // else Active Accessibility is not installed
    	CoUninitialize();
    	
    	return S_OK;
    }
    
    
      在取得选取网页内容之后,需要对HTML内容进行重新编辑以获得正确的显示,CheckData函数便是做这个工作的这个函数对HTML内容中图像信息的地址进行编辑,如果图像保存在本地则使用本地图像,如果图像没有下载保持原样。
    BOOL CheckData(const LPCTSTR data,
    			   const LPCTSTR host,
    			   const LPCTSTR path,
    			   DWORD Number,
    			   std::string &outstring)
    {
    	char chImgPath[1024];//图像路径 !:由于有些图像路径可能会很长所以申请内存多一点
    	char chImgSrc[MAX_PATH];//图像地址
    	char chDownLoadPath[MAX_PATH];//下载图像文件路径
    	char chWriteImgSrc[MAX_PATH];//图像文件路径
    
    	memset(chImgPath,0,1024);
    	memset(chImgSrc,0,MAX_PATH);
    	memset(chDownLoadPath,0,MAX_PATH);
    	memset(chWriteImgSrc,0,MAX_PATH);
    
    	char dirname[20];//根目录名
    	ltoa(Number,dirname,10);
    
    	try{
    		//查找是否有");
    		if(p1 == NULL||p2 == NULL||p3 == NULL||p4 == NULL)
    			return FALSE;
    
    		//找到一个图像文件标记
    
    		//拷贝图像链接之前的文字
    		int n = p4-p1+1;
    
    		strncpy(chImgPath,p1,n);
    		outstring.append(data,p2-data+5);
    
    		//提取图像链接
    
    		n = p3-p2-5;
    		strncpy(chImgSrc,p2+5,n);
    		if(FindString(chImgSrc,"http://") == NULL){
    			if(FindString(chImgSrc,".."))
    				strcpy(chImgSrc,&chImgSrc[2]);
    			sprintf(chDownLoadPath,"%s%s",host,chImgSrc);
    			sprintf(chWriteImgSrc,"%s//%s%s",path,dirname,chImgSrc);
    		}else{
    			strcpy(chDownLoadPath,chImgSrc);
    			const char *p5 = FindString(chImgSrc+7,"/");
    			sprintf(chWriteImgSrc,"%s\\%s%s",path,dirname,&chImgSrc[p5-chImgSrc]);
    		}
    		char Output[MAX_PATH];
    		sprintf(Output,"图像地址:%s\r\n存盘地址:%s\r\n主机地址:%s\r\n",chImgSrc,chWriteImgSrc,host);
    		SaveCharToFile(Output,debugpath);
    		n = strlen(chWriteImgSrc);
    		for(int i=0;i
    

    其他几个辅助函数这里简单介绍,详细内容请参看源代码

    函数:void SaveCharToFile
    功能:将字符串保存为给定文件名
    const LPCTSTR data,//[IN] 给定待保存的数据
    const LPCTSTR saveFileName,//[IN]给定文件名
    BOOL flag = FALSE//[IN]追加写入还是覆盖标志
    
    函数:const char *FindString
    功能:在给定字符串中查找给定字符串
    const LPCTSTR source,//[IN] 给定源字符串的数据
    const LPCTSTR key)//[IN]待查字符串
    
    函数:void CreateAllDirectory
    功能:创建给定路径的所有未建目录
    const char* AllPath)//[IN] 需要创建的详细目录
    例如 输入为:"d:\a\b\c\d"则在D盘下创建相应a,b,c,d相应目录

      好了,到此为止,我们已经做成一个取得网页选取内容的并保存在本地的程序,你可以举一反三,将它应用到更有趣更有用的领域。
    这个程序是我研究了一周才写完的,其中取得domument的方法我觉得很笨,可我现在没有找到好办法,希望能够抛砖引玉,有更好的方法别忘了告诉我,我的Email:lgtest@sina.com欢迎来信讨论。

    阅读(740) | 评论(0) | 转发(0) |
    给主人留下些什么吧!~~