好吧,因为项目需要!在开发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);
}
}
到此,结束!!
谢谢观看~~~