对于MSIE,可以使用微软提供的IHTMLDocument2的接口,获取源代码,解析源代码中的url地址,显示在列表中,根据用户的选择,将地址到导给flashget来下载
基本的步骤如下:
1。获得IE的窗口,我使用了类似spy++的抓窗口方法,即将鼠标定位在某个窗口中
2。获得网业的代码
3。解析url地址,并显示
4。将地址导给flashget
详细的实现如下:
1。获得IE的窗口
跟踪鼠标,获得鼠标释放时的位置,跟踪的代码很简单,如下
case WM_LBUTTONDOWN:
{
SetCapture(hWnd);
SetCursor(ghcrCapture);
SendMessage(hWnd,STM_SETICON,(WPARAM)ghIconCaptured,0);
}
break;
case WM_LBUTTONUP:
{
ReleaseCapture();
SendMessage(hWnd,STM_SETICON,(WPARAM)ghIconCapture,0);
HWND hDlg = GetParent(hWnd);
SetCursor(LoadCursor(NULL,IDC_WAIT));
DoCapture(hDlg); //做2,3步骤的工作的函数
}
break;
获得窗口的句柄,并判断是否是webrowser
HWND GetWebBrowserWnd()
{
POINT pt;
GetCursorPos(&pt);
//获得窗口句柄
HWND hwndWeb = WindowFromPoint(pt);
if(!hwndWeb)
return NULL;
//根据窗口类名判断是否是webbrowser窗口
TCHAR szClassName[256];
GetClassName(hwndWeb,szClassName,256);
if(_tcscmp( szClassName, _T("Internet Explorer_Server") ) == 0)
return hwndWeb;
return NULL;
}
2。获得源代码
(这部分是从msdn上演化的,为了大家方便,就帖出来吧)
首先获得IXMLDocument2的接口
BOOL GetIHtmlDocPtr(HWND hwndWeb,IHTMLDocument2**ppHtmlDoc)
{
UINT nMsg = ::RegisterWindowMessage(_T("WM_HTML_GETOBJECT"));
LRESULT lRes;
::SendMessageTimeout( hwndWeb, nMsg, 0L, 0L, SMTO_ABORTIFHUNG, 1000, (DWORD*) &lRes );
HRESULT hr = ObjectFromLresult ( lRes, IID_IHTMLDocument2, 0 , (LPVOID *)ppHtmlDoc);
return SUCCEEDED(hr);
}
其次,取得body对象,通过取得他的innerHtml来获得代码
CComPtr<IHTMLElement> pElement;
pIHtmlDoc->get_body(&pElement);
CComBSTR strHtml;
pElement->get_innerHTML(&strHtml)
3。分析源代码
可以使用正规则表达市来分析,不过我没有使用。我是自己一个字符一个字符的解析的。因此不过完善。代码比较长,而且难以理解。不能献丑了
4。把地址发送给flashget
flashget有com接口可以使用,是一个IDispatch接口,在没有头文件的情况下即可调用
可以通过字符“JetCar.Netscape”找到他的CLSID:
CComPtr<IUnknown> pUnknown;
CLSID clsid;
if(FAILED(CLSIDFromProgID(L"JetCar.Netscape",&clsid)))
return;
if(FAILED(pUnknown.CoCreateInstance(clsid)))
return;
pUnknown->QueryInterface(IID_IDispatch,(void**)&m_pFlashGet);
m_pFlashGet是IDispatch*类型
这个对象编号为0x3的函数可以添加一个地址,调用如下
void CFlashGet::AddUrl(LPCTSTR lpszUrl,LPCTSTR lpszRef)
{
_bstr_t bstr;
EXCEPINFO excpInfo;
UINT argErr;
DISPPARAMS dispParams;
VARIANT varRet;
varRet.vt = VT_EMPTY;
memset(&dispParams,0,sizeof(DISPPARAMS));
dispParams.cArgs = 3;
dispParams.rgvarg = new VARIANT[3];
bstr = (lpszRef?lpszRef:lpszUrl);
dispParams.rgvarg[0].vt = VT_BSTR;
dispParams.rgvarg[0].bstrVal = SysAllocString(bstr);
dispParams.rgvarg[1].vt = VT_BSTR;
dispParams.rgvarg[1].bstrVal = SysAllocString(L"FlashGet 0.76");
bstr = lpszUrl;
dispParams.rgvarg[2].vt = VT_BSTR;
dispParams.rgvarg[2].bstrVal = SysAllocString(bstr);
m_pFlashGet->Invoke(0x3,IID_NULL,NULL,DISPATCH_METHOD,&dispParams,&varRet,&excpInfo,&argErr);
SysFreeString(dispParams.rgvarg[0].bstrVal);
SysFreeString(dispParams.rgvarg[1].bstrVal);
SysFreeString(dispParams.rgvarg[2].bstrVal);
delete []dispParams.rgvarg;
}
编号为0x4的函数可以添加一个地址列表,方法同上,就不罗嗦了
关于flashget 接口的详细用法,flashget官方网站的帮助中有代码,可以下载
需要注意的几个问题:
1。有很多网页,是有frame的,所以要遍历所有的frame,否则将得不到任何代码,这里有个例子,好象是从网上代码演化的,帖出来共享
void EnumFrame(IHTMLDocument2 * pIHTMLDocument2,HWND hMainDlg)
{
if (!pIHTMLDocument2) return;
HRESULT hr;
CComPtr< IHTMLFramesCollection2 > spFramesCollection2;
pIHTMLDocument2->get_frames( &spFramesCollection2 ); //取得框架frame的集合
long nFrameCount=0; //取得子框架个数
hr = spFramesCollection2->get_length( &nFrameCount );
if (FAILED (hr) || 0 == nFrameCount )
return;
for(long i=0; i<nFrameCount; i++)
{
CComVariant vDispWin2; //取得子框架的自动化接口
hr = spFramesCollection2->item(&CComVariant(i), &vDispWin2);
if (FAILED (hr)) continue;
CComQIPtr<IHTMLWindow2> spWin2 = vDispWin2.pdispVal;
if(!spWin2) continue; //取得子框架的 IHTMLWindow2 接口
CComPtr <IHTMLDocument2> spDoc2;
spWin2->get_document(&spDoc2); //取得字框架的 IHTMLDocument2 接口
GetFlashLink(spDoc2,hMainDlg); //递归枚举当前子框架 IHTMLDocument2 上的表单form
}
}
2。取得的代码都是unicode的,你可以直接对unicode处理,也可以转化后处理
3。地址的拼接。url有3种:1。绝对路径;2。相对与当前页的路径,3。相对于根的路径,表示方法是最前面是一个字符“/”表示根目录下的文件。
3。地址的过滤。我使用扩展名对地址过滤。不过,例如php,asp这些页面后有参数,需要把剔除参数后对扩展名比较。
还有就是隐藏在脚本里的地址了。这个我就不知道如何处理了。高手可以给点建议吗?