早些天,因项目需要做了一个自动登陆网站的ActiveX插件。主要功能就是通过这个插件启动一个IE实例或者使用插件所在的浏览器,
打一个网站(即通过Navigate导航),通过IHTMLDocument2接口找到相关元素,并填入相应的值,最后模拟点击登陆按钮,完成登陆。这种
方法简单,而且理论上属于模拟人工登陆,受限性比较小。但是它有一个缺点,就是有打开登陆页面,填入值的过程,没有直接进入登陆
后的页面看上去更自然。
再次查看MSDN,IWebBrowser2::Navigate声明:
HRESULT Navigate( BSTR url,
VARIANT *Flags,
VARIANT *TargetFrameName,
VARIANT *PostData,
VARIANT *Headers
);
第四个参数是PostData,那是否可以附带PostData数据直接登陆进去呢?向下看
PostData:
[in] Pointer to data to send with the HTTP POST transaction. For example, the POST transaction is used to send data gathered
by an HTML form. If this parameter does not specify any post data, IWebBrowser2::Navigate issues an HTTP GET transaction.
意思是说在这里指定PostData参数与通过 HTML form提交是一样的。当然是可行了。
这个参数的类型是VARIANT,MSDN:
The post data specified by PostData is passed as a SAFEARRAY Data Type structure. The VARIANT should be of type VT_ARRAY and point
to a SAFEARRAY Data Type. The SAFEARRAY Data Type should be of element type VT_UI1, dimension one, and have an element count equal
to the number of bytes of post data.
看明白了,PostData是一个一维的,元素类型是VT_UI1的数组,长度为PostData的字节长。我们首先来产生这个数组:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Code
HRESULT GetPostData(CComVariant &vPostData,LPCSTR szPostData)
{
HRESULT hr;
LPSAFEARRAY psa;
psa = SafeArrayCreateVector(VT_UI1, 0, strlen(szPostData));
if (!psa) {
return E_OUTOFMEMORY;
}
LPSTR pPostData;
hr = SafeArrayAccessData(psa, (LPVOID*)&pPostData);
memcpy(pPostData, szPostData, strlen(szPostData));
hr = SafeArrayUnaccessData(psa);
vPostData.vt = VT_ARRAY | VT_UI1;
vPostData.parray = psa;
return S_OK;
}
关于SafeArrayCreateVector,SafeArrayAccessData等函数的更多用法,请参考。
第五个参数Headers设定为"Content-Type: application/x-www-form-urlencoded"很熟悉吧,和HTTP协议头一样的。用个简单例了结束她吧:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Code
int LoginWebByIE(LPCSTR szUrl,LPCSTR szHeaders,LPCSTR szPostData)
{
HRESULT hr;
CComQIPtr<IWebBrowser2> pWebBrower;
hr = pWebBrower.CoCreateInstance(CLSID_InternetExplorer);
pWebBrower->put_Visible(VARIANT_TRUE);
CComBSTR bstrURL(szUrl);
CComVariant vHeaders;
vHeaders.vt = VT_BSTR;
vHeaders.bstrVal = SysAllocString(CComBSTR(szHeaders).Detach());
CComVariant vFlags;
vFlags.vt = VT_I4;
vFlags.lVal = navNoReadFromCache | navNoWriteToCache;
CComVariant vTargetFrameName;
//加上下面这段浏览器就会在一个新的窗口打开页面,几个参数都试过,
//效果都一样,还没清楚是什么原因。
// vTargetFrameName.vt = VT_BSTR;
//vTargetFrameName.bstrVal= SysAllocString(L"_SELF");
CComVariant vPostData;
GetPostData(vPostData,szPostData);
hr = pWebBrower->Navigate(bstrURL, &vFlags,
&vTargetFrameName, &vPostData, &vHeaders);
pWebBrower.Release();
return TRUE;
}
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(0);
CComVariant vUrl("http://www.javaeye.com/login");
char postData[36] = "name=anranran&password=hehe";
LoginWebByIE("http://www.javaeye.com/login","Content-Type: application/x-www-form-urlencoded\r\n",postData);
CoUninitialize();
return 0;
}
其中Navigate可以换成Navigate2,唯一需要改的是Navigate2第一个参数类型。