This article was contributed by Eric Sanchez.
Environment: [VC6, Win 95/98/Me/2000/XP]
Hello World!
In this article, we will journey through the world of internet, especially the simulation of the GET and POST request. The HTTP protocol, used to perform such actions, can be quite complex sometimes. To simplify these tasks, Microsoft created a set of libraries known as WinINet.
I will assume that you are already familiar with the basics of MFC and the IDE. I will go over creating a small app that demonstrates a few of its numerous features: GET and POST request, reading the output created by the exe or another script, and obtaining the html code of a given page or file, whether on an HTTP or FTP.
The page that I will use in this case is Florida International University’s teacher evaluation page for the spring 2001. One of the reason I chose this one is because the same page features a Submit button that employs GET and one for the POST method. Also, this page is not frequently updated, so the article shouldn’t go obsolete soon. The website where this can be reached is HERE. We will be interested in the two top text boxes:
We will later look at the code to get an overall understanding of how they work. You can try entering names or course numbers in the above fields and the output will be a series of ratings.
Objective
First of all, create a new MFC project using the wizard. I will call it MyInternet.
We will need to textboxes, one for the course number and one for the instructor’s last name. Two buttons will also be necessary to submit the data. Since it is very similar to the procedures for the GET/POST, I will also add a textbox allowing the user to enter an URL and then its raw code will be presented. We will need a place to show the results. For this, I added a wealthy (rich) edit box.
Here’s how mine looks so far:
Do not forget to change a few properties of the rich edit, such as making it multiline. Here’s how I set mine:
Coding
We will proceed by adding member variables for each text. I will name mine as following: m_Name, m_Course, and m_URL.
Let’s also add a CString member variable for the rich edit box. I named mine m_Output.
Before we forget, let’s initialize the rich edit box. If this is not done, the program will not run properly. On MyInternet.cpp, add AfxInitRichEdit(); inside the InitInstance() function. Now that we are ready to begin, add a function handler for the first button, the one for the professors name:
We get something similar to this:
void CMyInternetDlg::OnSearch1()
{
// TODO: Add your control notification handler code here
}
In order to determine the information required to submit the request, we must know a few things from the webpage.To do this, we’ll skim through the page’s code. After searching a bit, we will see:
In the above HTML code, you will find the instructions on what to type (”Enter Instructor’s….”). That serves as a clue that the items near it should have the info wanted. The forms that contain buttons and other resources begins with the tag <FORM ….> and end with </FORM>. That can be easily seen from line 3 to 7. This is the one for the asking for the instructors last name. A few lines below it, you will see another form, implying that’s the one inquiring for the course number.
To be able to use WinINet, we must include its header file. Add the following: #include <afxinet.h>.
We must now know a little about how HTML forms work. As we already know, they begin with <FORM . The ACTION=”…” contains the target to whom the data will be sent. When programming, this must be divided into the server (path or directory) and the target object name (the cgi script, php, executable, dll, etc). Above we can see that the server is pair.fiu.edu/cgi-bin/ibi_cgi/ (no need to use http://) and the object name, ibiweb.exe. It will also state the METHOD, in this case, GET. The way GET functions is by concatenating the data to the target, separated by ?. For instance, it might look something like this: URL…?AllSubmitedData. The POST is more ellusive, hiding the data from the user. It transmits it by sending a request and not through the URL.
Once the object receives the data, it must know how to decrypt it or interpret it. As a result, a header stating the encoding method is also sent. The most common header and the one used here is the string: “Content-Type: application/x-www-form-urlencoded”. Nonetheless, it is not the only one. The way this one works is by sending the resource name and its value. Differnet fields are separated by using &. More briefly, NAME1=VALUE1&NAME2=VALUE2, and so on.If you look at the HTML code above, you can see for the first one, its name is IBIF_ex, and its value saisp01. That field is hidden. For the text box, the name is LNAME and the value will be the text entered in the box. As a result, the encoding will be IBIF_ex=saisp01&LNAME=Text entered. Note that the name and the values of the submit and reset button are not added.
With that in mind, let’s commence the coding stage. This will be done in the function created earlier (OnSearch1). We will use three classes for this. Let’s add the following:
UpdateData(TRUE); //Updates the values of the variables
m_Output.Empty(); //Empties the rich edit
UpdateData(FALSE); //Displays a blank rich edit
//Header
CString strHeaders="Content-Type: application/x-www-form-urlencoded";
//Encodes Values
m_Name.MakeUpper(); //Remeber the name must be in UPPER CASE
CString strFormData="IBIF_ex=saisp01l&LNAME="+m_Name;//There is no need to use ?
//Declare the three classes
CInternetSession session("My Internet") ; //Class to establish the session "My Internet"
CHttpConnection *connection ;
CHttpFile *file; //Will be used to read the output file
We will now use the try and catch macros. Basically, when you insert code inside the try block and an exception (error) is thrown, execution will be redirected to the catch block. Inside the try block, we will attempt to create the connection, and if successful, read the output file and display it in the rich edit.
try {
//establish connection to the server
connection = session.GetHttpConnection("pair.fiu.edu/cgi-bin/ibi_cgi/");
//Open the connection using GET and the target name
//NULL = GET and "POST"= POST
file=connection->OpenRequest(NULL, "ibiweb.exe");
//Send the request (Header and DATA)
file->SendRequest(strHeaders,(LPVOID)(LPCTSTR)strFormData, strFormData.GetLength());
DWORD dwRet;
file->QueryInfoStatusCode(dwRet); //Get the status
if (dwRet == HTTP_STATUS_OK) //If successful
{ //Let's read the file then
BOOL Success;
do{
CString Temp;
Success = file->ReadString(Temp); //Reads a line
m_Output+=Temp+"\r\n"; //Adds the line to rich edit
} while (Success);
}
UpdateData(FALSE);
}
catch (CInternetException* pEx) {
pEx->ReportError(); //If error, report it in a message box
}
//Close everything
session.Close();
file->Close();
connection->Close();
It is now time to compile it and test it. Try entering any last name. For instance, Smith, will give:
From the resulting code, you can parse it and obtain any item you wish. In this instance, the result is the code for the student ratings for all Smith. If you scroll down, the output will not seem to be formatted. That’s because in the Rich Edit, all letters don’t have the same width. To solve this, add the following on OnInitDialog():
CFont curfont;
curfont.CreateStockObject(ANSI_FIXED_FONT);
GetDlgItem(IDC_RICHEDIT1)->SetFont(&curfont);
The code for the second search, the course number, is very similar to the one above. This is because although it uses POST, the encoding and the methods employed are the same. Add a function for the other button and here’s the code:
void CMyInternetDlg::OnSearch2()
{
// TODO: Add your control notification handler code here
UpdateData(TRUE);
m_Output.Empty();
UpdateData(FALSE);
CString strHeaders="Content-Type: application/x-www-form-urlencoded";
//***** Use m_Course and saisp01c & COURSE
m_Course.MakeUpper();
CString strFormData="IBIF_ex=saisp01c&COURSE="+m_Course;
CInternetSession session("My Internet") ;
CHttpConnection *connection ;
CHttpFile *file ;
try {
connection = session.GetHttpConnection("pair.fiu.edu/cgi-bin/ibi_cgi/");
//******Remember to use POST
file=connection->OpenRequest("POST", "ibiweb.exe");
file->SendRequest(strHeaders,(LPVOID)(LPCTSTR)strFormData, strFormData.GetLength());
DWORD dwRet;
file->QueryInfoStatusCode(dwRet);
if (dwRet == HTTP_STATUS_OK){
BOOL Success;
do{
CString Temp;
Success = file->ReadString(Temp);
m_Output+=Temp+"\r\n";
} while (Success);
}
UpdateData(FALSE);
}
catch (CInternetException* pEx) {
pEx->ReportError();
}
session.Close();
file->Close();
connection->Close();
}
Courses such as COP2994, PHY2048, etc, can be used totest the above code.
We still have one more thing to do, and that is to download the code of any page or file entered. Doing that is even easier using WinInet.Add a handler for the last button and add the following:
void CMyInternetDlg::OnVewcode()
{
// TODO: Add your control notification handler code here
UpdateData();
m_Output.Empty();
CInternetSession session("My Internet") ;
try {
CStdioFile *file;
file=session.OpenURL(m_URL); //Opens the URL
BOOL Success;
do{
CString Temp;
Success = file->ReadString(Temp);
m_Output+=Temp+"\r\n";
} while (Success);
UpdateData(FALSE);
}
catch (CInternetException* pEx) {
pEx->ReportError();
}
session.Close();
}
When we enter http://www.maxcode.com, we get:
The above code will also work if ftp files or directories are entered.
Conclusion
There are numerous other ways to optimize the above code. For instance, the requests should be ideally done in a different worker thread, so that the application does not remain inactive for a long time. Also, a function can be created that handles both the POST and GET since they share most of the code. That would save a few bytes off the exe. There are also many other ways of using WinInet. For instance, it can be easily adapted to use proxys and security layers, can be used in FTP’s, gophers, and so on. I still do not know many of those things.
Well that’s it for now. Good luck programming!
Downloads
Thank you very much for that dazzling article
I recently came throughout your web page and happen to become understanding along. I assumed I’d personally leave my initial comment. I really do not know what to say except that We’ve loved examining. Respectable web website. I am going to maintain visiting this weblog really frequently.
Hi. I learn a few of the other content material and wanted to understand if you would be interested in exchanging blogroll links?
Hello! Unfortunately, not at this moment.
Thank you for your comment!
Thanks for the effort. Can I use WinINet to send request to page and return response. the target page is already handles and processes the requests.
Thanks
I liked reading this, found you through Google.
Hi. I learn a few of your respective other articles and needed to understand if you would be interested in exchanging blogroll hyperlinks?
Hello, Climbing Gear! Unfortunately, not at this moment.
Hello, ElecTronic Drums! Unfortunately, not at this moment.
I like this information and it has given me some sort of inspiration to have success for some reason, so thank you. Moreover I´m definitely thinking about blogging these figures in my own blog!
Good blog, where did you come up with the knowledge in this piece of content? I’m glad I found it though, ill be checking back soon to see what other articles you have.
Thank you for another great article. Where else could anyone get that kind of information in such a perfect way of writing? I have a presentation next week, and I am on the look for such information.
Interesting article and one which should be more widely known about in my view. Your level of detail is good and the clarity of writing is excellent. I have bookmarked it for you so that others will be able to see what you have to say.
valuable post…
You got a really great blog I have been here reading for about half an hour. I am a newbie and your post is valuable for me….