获取IE缓冲区中的验证图片


好吧,因为项目需要!在开发BHO的时候,需要获取网页的验证图片现在在界面上,所有。。。。


由于之前,一直找不到读取缓存的方法,但项目必须要继续做,开始的时候,只能曲线救国了。

方法一: 获取IHTMLControlRange,调用pRange->execCommand(strCopy, false, vEmpty, NULL);,把验证图片拷贝到剪切板中

代码

HRESULT SavePictureToClipboard( CComPtr<IWebBrowser2> spWebBrowser, LPCTSTR lpName )
{
	_variant_t index = 0;
	_variant_t varName = lpName;
	
	// html information
	CComPtr<IDispatch> pHtmlDocDispatch;
	HRESULT hr = spWebBrowser->get_Document(&pHtmlDocDispatch);
	if (SUCCEEDED(hr) && pHtmlDocDispatch)
	{
		CComQIPtr<IHTMLDocument2, &IID_IHTMLDocument2> pHtmlDoc(pHtmlDocDispatch);
		if (pHtmlDoc)
		{
			CComPtr<IHTMLElementCollection> pColl=NULL;
			hr = pHtmlDoc->get_images(&pColl);

			if (FAILED(hr) && pColl==NULL)
				return hr;
			CComPtr<IDispatch> pElemDispatch = NULL;
			hr = pColl->item (varName, index, &pElemDispatch);

			if(FAILED(hr)||pElemDispatch==NULL)
				return hr;
			CComPtr<IHTMLControlElement> pCtrlElem = NULL;
			HRESULT hr = pElemDispatch->QueryInterface (IID_IHTMLControlElement, (void**)&pCtrlElem);

			if(FAILED(hr)||pCtrlElem==NULL)
				return hr;

			CComPtr<IHTMLElement> pElem = NULL;
			hr = pHtmlDoc->get_body(&pElem);
			if(FAILED(hr)||pElem == NULL)
				return hr;

			CComPtr<IHTMLElement2> pElemt2 = NULL;
			hr = pElem->QueryInterface(IID_IHTMLElement2, (void**)&pElemt2);
			if(FAILED(hr)||pElemt2 == NULL)
				return hr;

			CComPtr<IDispatch> pHtmlDisp2 = NULL;
			hr = pElemt2->createControlRange(&pHtmlDisp2);
			if (FAILED(hr) || pHtmlDisp2 == NULL)
				return hr;

			CComQIPtr<IHTMLControlRange, &IID_IHTMLControlRange> pRange(pHtmlDisp2);
			hr = pRange->add(pCtrlElem);
			if(SUCCEEDED(hr)){

				EmptyClipboard();

				// 拷贝到剪贴板中
				CComBSTR strCopy("Copy");
				VARIANT vEmpty;
				VariantInit(&vEmpty);
				hr = pRange->execCommand(strCopy, false, vEmpty, NULL);

				// 保存到文件
				if(SUCCEEDED(hr)){

					if(!OnPasteAsFile())
						return S_FALSE;
					
				}

			}
		}
	}

	return hr;
}

BOOL OnPasteAsFile()
{
	// TODO: 在此添加命令处理程序代码
	HANDLE hNewDIB=NULL;
	if(OpenClipboard(NULL))
	{
		if(IsClipboardFormatAvailable(CF_DIB))
			hNewDIB=(HANDLE)CopyHandle(GetClipboardData(CF_DIB));
		CloseClipboard();
	}
	if(hNewDIB==NULL) return FALSE;

	BOOL bRet = FALSE;
	{
		//CString fullName(lpFile);  
		//CFile file;
		//file.Open(fullName,CFile::modeCreate|CFile::modeWrite);
		bRet = SaveToFile(hNewDIB);//将位图存为指定名字的文件
		//file.Close();
		GlobalFree(hNewDIB);
	}
	return bRet;
}

BOOL WINAPI SaveToFile(HANDLE hDib)
{
	BITMAPFILEHEADER bmfHdr;
	LPBITMAPINFOHEADER lpBI;
	DWORD dwDIBSize;

	if (hDib == NULL)
		return FALSE;

	lpBI = (LPBITMAPINFOHEADER) ::GlobalLock((HGLOBAL) hDib);
	if (lpBI == NULL)
		return FALSE;

	bmfHdr.bfType = ((WORD) ('M' << 8) | 'B');  // "BM"

	dwDIBSize = *(LPDWORD)lpBI + ::GetPaletteSize((LPSTR)lpBI);

	if ((lpBI->biCompression == BI_RLE8) || (lpBI->biCompression == BI_RLE4))
	{
		dwDIBSize += lpBI->biSizeImage;
	}
	else
	{
		DWORD dwBmBitsSize;
		dwBmBitsSize = ( ( (lpBI->biWidth)*((DWORD)lpBI->biBitCount) + 31) / 32 * 4) * lpBI->biHeight;
		dwDIBSize += dwBmBitsSize;
		lpBI->biSizeImage = dwBmBitsSize;
	}

	bmfHdr.bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER);
	bmfHdr.bfReserved1 = 0;
	bmfHdr.bfReserved2 = 0;

	bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + lpBI->biSize
		+ GetPaletteSize((LPSTR)lpBI);

	FILE *pfile = NULL;
	pfile = fopen(BITMAP_FILE_PATH, "wb+");
	if(NULL != pfile){
		fwrite(&bmfHdr, sizeof(BITMAPFILEHEADER), 1, pfile);
		fwrite(lpBI, dwDIBSize, 1, pfile);

		fclose(pfile);
	}
	// file.Write((LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER));
	// file.Write(lpBI, dwDIBSize);

	::GlobalUnlock((HGLOBAL) hDib);
	return TRUE;
}

其方法的大概思想就是:

第一步:获取到该验证图片的节点

第二步:把该节点的文件信息拷贝到剪切板中

第三步:把剪切板中的图片信息保存到磁盘中

完成以上三部后,你想怎么整都没有问题了。。。。。


但是,这样也有一些缺点。

1.每次调用IE都会弹出一个警告信息,具体内容就是是否允许剪切板操作。。。。

2.磁盘上会存留我们的图片,即使你删除掉,但它也是存在过。感觉非常不好。。。。

。。。。

好吧,对应磁盘存储,我们还可以接受。但是每次启动都弹出一个警告信息,这样我非常不爽,更不用说客户。。。。

所有我下一步就是去掉它,不能让它每次都提示。

方法一:可以手工去掉“Ineternet选项”--》“安全”TAB中,点击“自定义级别(c)...”---》找到“脚本”,在“允许对剪贴板进行编程访问”选项中,选中“启用“--》确定--》应用

好吧,这样的确完成了本机,在启动的时候不会弹出提示框。。。但是又存在问题,不能每台电脑都手工做吧。。。当然,如果两台电脑,没有问题,但是如果很多,那不疯掉啊。。。所有第二种方法,孕育而生。。

方法二:修改注册表设置,因为我们直到,很多电脑的配置信息都记录在注册表中的。当然,这个设置也不例外!好吧,这个必须承认,之前使用工具找到过,具体位置,下次再说。。。



嗯。好吧,当项目基本完成的时候,我又回头看到这个代码,感觉还是不怎么好。感觉就是,不应该这样的啊!! 那能怎么做??

由此,我又对此研究起来,在IE临时文件看到这个验证码图片时,发现这是一个突破口!好吧。。。这个方向不会错!


经过一番努力,此处略过10万字(呵呵~~),终于完成从IE缓存中获取验证码图片。

无码无真相!码上:

#define URL_VALIDATE_CODE	"CharValidateCode.aspx"
// 获取最后时间的验证码URL
void GetLTValidateCodeUrl(LPSTR lpUrl, LPCSTR lpCompareUrl=URL_VALIDATE_CODE){

	BYTE byBuffer[20480];
	LPINTERNET_CACHE_ENTRY_INFO lpInfo = LPINTERNET_CACHE_ENTRY_INFO(byBuffer);
	DWORD dwSize = sizeof (byBuffer);
	lpInfo->dwStructSize = sizeof (INTERNET_CACHE_ENTRY_INFO);
	HANDLE h;
	BOOL bSuccess = TRUE;

	SYSTEMTIME sysMax = {0};
	for (h = FindFirstUrlCacheEntryEx (NULL, 0, URLCACHE_FIND_DEFAULT_FILTER, 0, lpInfo, &dwSize, 0, 0, 0);
		h && bSuccess;
		bSuccess = FindNextUrlCacheEntryEx(h, lpInfo, &dwSize, 0, 0, 0))
	{
		dwSize = sizeof(byBuffer);

		if(strstr(lpInfo->lpszSourceUrlName, lpCompareUrl) == NULL)
			continue;

		SYSTEMTIME syncTime, AccTime;
		FileTimeToSystemTime(&lpInfo->LastAccessTime, &AccTime);
		FileTimeToSystemTime(&lpInfo->LastSyncTime, &syncTime);

		int re = memcmp(&syncTime,&sysMax,sizeof(SYSTEMTIME));
		if(re>0){
			sysMax = syncTime;
			strcpy(lpUrl, lpInfo->lpszSourceUrlName);
		}

		printf ("====%s\n\t%s\n", lpInfo->lpszSourceUrlName, lpInfo->lpszLocalFileName);
	}

	FindCloseUrlCache (h);
}

<span style="white-space:pre">	</span>char szUrl[MAX_PATH] = {0};
	GetLTValidateCodeUrl(szUrl);
	LPCTSTR lpUrl = szUrl;
	

	if(TRUE) {
		DWORD dwTest = 0; //dwSize;
		
		RetrieveUrlCacheEntryStream(lpUrl, NULL, &dwTest, TRUE, 0);

		if(GetLastError() == ERROR_INSUFFICIENT_BUFFER){
			lpInfo = (LPINTERNET_CACHE_ENTRY_INFO) new char[dwTest];
		} else {
			return ;
		}

		HANDLE handle = RetrieveUrlCacheEntryStream(lpUrl, lpInfo, &dwTest, TRUE, 0);
		if(handle){

			DWORD dwLen = lpInfo->dwSizeLow;
			char* pbuffer = (char*)malloc(dwLen);

			if(ReadUrlCacheEntryStream(handle, 0, pbuffer, &dwLen, 0)){

				FILE *pf = fopen("d:\\abc.jpg", "wb");
				if(pf){
					fwrite(pbuffer, dwLen, 1, pf);
					fclose(pf);
				}

			}
<span style="white-space:pre">			</span>free(pbuffer); pbuffer = NULL;
			UnlockUrlCacheEntryStream(handle, 0);
		}

	}

好吧。简单介绍下:

第一步:从所有缓存文件中,找到最新的验证图片

第二步:获取缓存的图片内容

当然:第三步就是,把图片保存到磁盘中。


啊啊!!为什么还要保存到磁盘,为什么不可以直接显示到界面上!好吧,亲,满足你。

void CLoginDlg::ReadValidateCode()
{
	IStream *pStream;
	IPicture *pPictrue;
	HGLOBAL hMem;

	DWORD dwSize = 0;
	char szUrl[MAX_PATH] = {0};
	LPINTERNET_CACHE_ENTRY_INFO lpInfo=NULL;

	GetLTValidateCodeUrl(szUrl);
	if(strlen(szUrl)==0) return;

	RetrieveUrlCacheEntryStream(szUrl, NULL, &dwSize, TRUE, 0);
	if(dwSize && GetLastError() == ERROR_INSUFFICIENT_BUFFER){
		lpInfo = (LPINTERNET_CACHE_ENTRY_INFO) new char[dwSize];
	} else {
		return ;
	}	

	HANDLE handle = RetrieveUrlCacheEntryStream(szUrl, lpInfo, &dwSize, TRUE, 0);
	if(handle){

		DWORD dwLen = lpInfo->dwSizeLow;
		hMem=GlobalAlloc(GMEM_MOVEABLE,dwLen);
		LPVOID pData=NULL;
		pData=GlobalLock(hMem);

		if(ReadUrlCacheEntryStream(handle, 0, pData, &dwLen, 0)){
			GlobalUnlock(hMem);

			CreateStreamOnHGlobal(hMem,TRUE,&pStream);
			if(SUCCEEDED(OleLoadPicture(pStream, dwSize,TRUE,IID_IPicture,(LPVOID*)&pPictrue)))
			{
				OLE_HANDLE picHandle;
				pPictrue->get_Handle(&picHandle);
				m_cPicture.SetBitmap((HBITMAP)picHandle);
			}
		}
		else {
			GlobalUnlock(hMem);
		}

		GlobalFree(hMem);
		UnlockUrlCacheEntryStream(handle, 0);
	}
}

到此,结束!!

谢谢观看~~~ 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值