SUMMARY
To properly simulate a Form submission using WinInet, you need to send a header that indicates the proper Content-Type. For Forms, the proper Content-Type header is: Content-Type: application/x-www-form-urlencoded
MORE INFORMATION
In many cases, the server does not respond appropriately if a Content-Type is not specified. For example, the Active Server Pages component of IIS 3.0 actually checks this header specifically for 'application/x-www-form- urlencoded' before adding form variables to the "Request.Form" object. This MIME/Content-Type indicates that the data of the request is a list of URL- encoded form variables. URL-encoding means that space character (ASCII 32) is encoded as ' ', special character such '!' encoded in hexadecemal form as '!'.
Here is a snippet of code that uses the MFC WinInet classes to simulate a Form POST request:
CString strHeaders
=
_T(
"
Content-Type: application/x-www-form-urlencoded
"
);
//
URL-encoded form variables -
//
name = "John Doe", userid = "hithere", other = "P&Q"
CString strFormData
=
_T(
"
name=John Doe&userid=hithere&other=P&Q
"
);
CInternetSession session;
CHttpConnection
*
pConnection
=
session.GetHttpConnection(_T(
"
ServerNameHere
"
));
CHttpFile
*
pFile
=
pConnection
->
OpenRequest(CHttpConnection::HTTP_VERB_POST,_T(
"
FormActionHere
"
));
BOOL result
=
pFile
->
SendRequest(strHeaders,(LPVOID)(LPCTSTR)strFormData, strFormData.GetLength());
Without MFC, the same code translates to straight SDK calls as follows:
static
TCHAR hdrs[]
=
_T(
"
Content-Type: application/x-www-form-urlencoded
"
);
static
TCHAR frmdata[]
=
_T(
"
name=John Doe&userid=hithere&other=P&Q
"
);
statuc TCHAR accept[]
=
_T(
"
Accept: */*
"
);
//
for clarity, error-checking has been removed
HINTERNET hSession
=
InternetOpen(
"
MyAgent
"
,INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL,
0
);
HINTERNET hConnect
=
InternetConnect(hSession, _T(
"
ServerNameHere
"
),
INTERNET_DEFAULT_HTTP_PORT,
NULL,
NULL,
INTERNET_SERVICE_HTTP,
0
,
1
);
HINTERNET hRequest
=
HttpOpenRequest(hConnect,
"
POST
"
,
_T(
"
FormActionHere
"
),
NULL,
NULL,
accept,
0
,
1
);
HttpSendRequest(hRequest,
hdrs,
strlen(hdrs),
frmdata,
strlen(frmdata));
// close any valid internet-handles
我这里有一段程序,用来在一个对话框里显示出一次http request的原始信息,不过使用Inet API做的,希望能有帮助。
void
CHTTPRequestDlg::OnButtonRequest()

{
UpdateData(TRUE);
HINTERNET hInternet = InternetOpen("Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 5.0)",
INTERNET_OPEN_TYPE_DIRECT,
NULL,
NULL,
NULL);
HINTERNET hSession = InternetConnect(hInternet,
m_strHost,
m_nPort,
"username",
"password",
INTERNET_SERVICE_HTTP,
0,
0);

char* szAccept[] =
{"*/*",NULL};
CString strVerb;
m_comboVerb.GetWindowText(strVerb);
HINTERNET hRequest = HttpOpenRequest(hSession,
strVerb,
m_strObject,
NULL,
NULL,
(LPCSTR*)szAccept,
0,
0);
struct

{
char* Language;
char* Encoding;
char* ContentType;

}Headers =
{"Accept-Language:zh-cn/r/n",
"Accept-Encoding:gzip,deflate/r/n",
"Content-Type:application/x-www-form-urlencoded/r/n"};
if(m_bLanguage)

{
HttpAddRequestHeaders(hRequest,
Headers.Language,
-1,
HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE);
}
if(m_bEncoding)

{
HttpAddRequestHeaders(hRequest,
Headers.Encoding,
-1,
HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE);
}
if(m_bContentType)

{
HttpAddRequestHeaders(hRequest,
Headers.ContentType,
-1,
HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE);
}
LPCSTR lpAddHeader = NULL;
LPCSTR lpContent = NULL;

if(m_strHeaders.GetLength())

{
if(m_strHeaders.Right(2) != "/r/n")

{
m_strHeaders+="/r/n";
}
lpAddHeader = (LPCSTR)m_strHeaders;
}
if(m_strContent.GetLength() && (strVerb == "POST" || strVerb == "PUT"))

{
lpContent = (LPCSTR)m_strContent;
}
HttpSendRequest(hRequest,
lpAddHeader,
-1,
(LPVOID)lpContent,
m_strContent.GetLength());
m_editContentGot.SetSel(0,-1);
m_editContentGot.ReplaceSel("");
LPSTR lpszData; //buffer for the data
DWORD dwSize; //size of the data available
DWORD dwDownloaded; //size of the downloaded data
//Set the cursor to an hourglass.
SetCursor(LoadCursor(NULL,IDC_WAIT));
// This loop handles reading the data.
while(1)

{
// The call to InternetQueryDataAvailable determines the amount of
// data available to download.
if (!InternetQueryDataAvailable(hRequest,&dwSize,0,0))

{
SetCursor(LoadCursor(NULL,IDC_ARROW));
break;
}
else

{
// Allocates a buffer of the size returned by InternetQueryDataAvailable
lpszData = new char[dwSize+1];
// Reads the data from the HINTERNET handle.
if(!InternetReadFile(hRequest,(LPVOID)lpszData,dwSize,&dwDownloaded))

{
delete[] lpszData;
break;
}
else

{
// Adds a null terminator to the end of the data buffer
lpszData[dwDownloaded]='/0';
int nLen = m_editContentGot.GetWindowTextLength();
m_editContentGot.SetSel(nLen-1, nLen-1);
m_editContentGot.ReplaceSel(lpszData);
// Delete the two buffers
delete[] lpszData;
// Check the size of the remaining data. If it is zero, break.
if (dwDownloaded == 0)

{
break;
}
}
}
}
// Close the HINTERNET handle
InternetCloseHandle(hRequest);
InternetCloseHandle(hSession);
InternetCloseHandle(hInternet);
// Set the cursor back to an arrow
SetCursor(LoadCursor(NULL,IDC_ARROW));
}
==========================================
使用MFC示例如下:
首先设置m_strRequest请求字符串 eg."name=aaa&pass=bbb";
m_strServerName 服务器名称或者IP eg."www.yahoo.com"
m_strObjectName 请求文件位置 eg. "pub/aaa.asp"
请求的结果存放在m_strHtml中
void
func()

{
CInternetSession m_InetSession("session");
CHttpConnection *pServer = NULL;
CHttpFile* pFile = NULL;
try

{
INTERNET_PORT nPort;
nPort=80;
pServer = m_InetSession.GetHttpConnection(m_strServerName, nPort);
pFile = pServer->OpenRequest(CHttpConnection::HTTP_VERB_POST,m_strObjectName);
char szHeaders[100];
strcpy(szHeaders,"Accept: text*/*/r/nContent-Type: application/x-www-form-urlencoded");
pFile->AddRequestHeaders(szHeaders);
pFile->SendRequestEx(m_strRequest.GetLength());
pFile->WriteString(m_strRequest);//重要-->m_Request 中有"name=aaa&name2=BBB&
"
pFile->EndRequest();
DWORD dwRet;
pFile->QueryInfoStatusCode(dwRet);
CString str;
m_Mutex.Lock();
m_strHtml="";
char szBuff[1024];

if (dwRet == HTTP_STATUS_OK)

{
UINT nRead;
while ((nRead = pFile->Read(szBuff,1023))>0)

{
m_strHtml += CString(szBuff,nRead);
}
}
m_Mutex.Unlock();
delete pFile;
delete pServer;
}
catch (CInternetException* e)

{
CString s;
s.Format("Internet Exception/r/nm_dwError%u,m_dwContextError%u",e->m_dwError,e->m_dwContext);
AfxMessageBox(s);
//catch errors from WinInet
}
}
============================
1、获得WebBrowser Control的DWebBrowserEvents2::DocumentComplete事件
2、在DWebBrowserEvents2::DocumentComplete事件中根据IWebBrowser2::Document获得IHTMLDocument2
3、IHTMLDocument2::forms得到IHTMLElementCollection
4、在IHTMLElementCollection中根据name、tagName、ID得到指定的IHTMLElement
5、从IHTMLElement得到IHTMLFormElement
6、执行IHTMLFormElement::submit