Program examples compiled using Visual C++ 6.0 compiler on Windows XP Pro machine with Service Pack 2 and some Figure screen snapshots have been taken on Windows 2000 server. The Internet Information Services version is IIS 4.x/5.x/6.x on Windows 2000 Server SP 4 and Windows XP Pro SP 2. The Internet Explorer is 6.x. Topics and sub topics for this tutorial are listed below. A complete information about IIS installation, configuration and testing a Web site is dumped HERE and how to setup FTP server also included HERE. Both Web and FTP servers were done on Windows 2000 Server SP4. Don’t forget to read Tenouk’s small disclaimer.
|
Debugging an ActiveX Document Server
If you want to debug your program in ActiveX document server mode, click on the Debug tab in the Project Settings dialog. Set Program Arguments to /Embedding, and then start the program. Now start the container program and use it to "start" the server, which has in fact already started in the debugger and is waiting for the container.
Figure 22: Changing the Visual C++ project setting for debugging process.
MYEX35A: Phase 2 - Adding More Functionality
Let continue our task by adding more functionalities to MYEX35A. Add two bitmaps, with ID IDB_GREEN and IDB_RED for the start and stop button. Select and right click the root folder in ResourceView and choose Insert context menu. Select Bitmap and click New. |
Figure 23: Inserting new bitmap.
Create two bitmaps as shown below.
Figure 24: IDB_GREEN bitmap for Start button.
Figure 25: IDB_RED bitmap for Stop button.
Add new dialog, IDD_DIALOGBAR for dialog bar. De-select the Title bar; choose Child for Styles and None for Border in Styles page as shown below.
Figure 26: IDD_DIALOGBAR property page.
Add Static text, Edit control and two buttons with the following properties. It is better for you to adjust the button size to fit the bitmap size later.
Figure 27: IDC_URL Edit control property page.
Figure 28: IDC_START button property page.
Figure 29: IDC_START button, Styles property page.
Figure 30: IDC_STOP button property page.
Figure 31: IDC_STOP button, Styles property page.
Add context menu, IDR_MENUCONTEXT as shown below.
Figure 32: IDR_MENUCONTEXT, new context menu.
Then add the menu item, Clear All with ID ID_EDIT_CLEAR_ALL.
Figure 33: Adding menu item Clear All to the context menu.
The Coding Part
Add new header and source files named Urlthread.h and Urlthread.cpp respectively.
Figure 34: Adding new files to project.
Figure 35: Selecting and entering the new file name.
Copy the codes as shown in the following Listing.
URLTHREAD.H
// urlthread.h
extern CString g_strURL; extern volatile BOOL g_bThreadStarted; extern CEvent g_eKill;
extern UINT UrlThreadProc(LPVOID pParam); extern void LogInternetException(LPVOID pParam, CInternetException* pe);
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
URLTHREAD.CPP
// urlthread.cpp
#include <stdafx.h> #include "urlthread.h" #define MAXBUF 100
CString g_strURL = "https://"; volatile BOOL g_bThreadStarted = FALSE; CEvent g_eKill;
UINT UrlThreadProc(LPVOID pParam) { g_bThreadStarted = TRUE; CString strLine; CInternetSession session; CStdioFile* pFile1 = NULL;
Try { pFile1 = session.OpenURL(g_strURL, 0, INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_KEEP_CONNECTION); // needed for Windows NT c/r authentication // Keep displaying text from the URL until the Kill event is received while(::WaitForSingleObject(g_eKill.m_hObject, 0) != WAIT_OBJECT_0) { // one line at a time if(pFile1->ReadString(strLine) == FALSE) break; strLine += '\n'; ::SendMessage((HWND) pParam, EM_SETSEL, (WPARAM) 999999, 1000000); ::SendMessage((HWND) pParam, EM_REPLACESEL, (WPARAM) 0, (LPARAM) (const char*) strLine); Sleep(250); // Deliberately slow down the transfer } } catch(CInternetException* e) { LogInternetException(pParam, e); e->Delete(); } if(pFile1 != NULL) delete pFile1; // closes the file -- prints a warning g_bThreadStarted = FALSE; // Post any message to update the toolbar buttons ::PostMessage((HWND) pParam, EM_SETSEL, (WPARAM) 999999, 1000000); TRACE("Post thread exiting normally\n"); return 0; }
void LogInternetException(LPVOID pParam, CInternetException* pe) { CString strGmt = CTime::GetCurrentTime().FormatGmt("%m/%d/%y %H:%M:% GMT"); char text1[300], text2[100]; wsprintf(text1, "\r\nERROR: WinInet error #%d -- %s\r\n ", pe->m_dwError, (const char*) strGmt); pe->GetErrorMessage(text2, 99); strcat(text1, text2); if(pe->m_dwError == 12152) { strcat(text1, " URL not found?\r\n"); } ::SendMessage((HWND) pParam, EM_SETSEL, (WPARAM) 999999, 1000000); ::SendMessage((HWND) pParam, EM_REPLACESEL, (WPARAM) 0, (LPARAM) text1); }
|
Listing 1.
Add the following #include in StdAfx.h.
#include <afxinet.h>
#include <afxmt.h>
Listing 2.
CMainFrame Class
Add the following public member variables.
CBitmap m_bitmapGreen;
CBitmap m_bitmapRed;
Then, change the:
CToolBar m_wndToolBar;
variable to
CDialogBar m_wndDialogBar;
And change the class access type as shown below. We need to access the public variable later.
Listing 3
Add the following #include directive to MainFrm.cpp.
#include "urlthread.h"
Listing 4.
Change the OnCreate() as shown below.
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
if (!m_wndStatusBar.Create(this) || !m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))
{
TRACE0("Failed to create status bar\n");
return -1; // fail to create
}
if (!m_wndDialogBar.Create(this, IDD_DIALOGBAR, CBRS_TOP, 0xE810))
{
TRACE0("Failed to create dialog bar\n");
return -1; // fail to create
}
m_wndDialogBar.SetDlgItemText(IDC_URL, g_strURL);
// attach the color bitmaps to the dialog bar buttons
m_bitmapGreen.LoadBitmap(IDB_GREEN);
HBITMAP hBitmap = (HBITMAP) m_bitmapGreen.GetSafeHandle();
((CButton*) m_wndDialogBar.GetDlgItem(IDC_START))->SetBitmap(hBitmap);
m_bitmapRed.LoadBitmap(IDB_RED);
hBitmap = (HBITMAP) m_bitmapRed.GetSafeHandle();
((CButton*) m_wndDialogBar.GetDlgItem(IDC_STOP))->SetBitmap(hBitmap);
return 0;
}
And PreCreateWindow() as shown below.
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CFrameWnd::PreCreateWindow(cs);
}
CMyex35aApp Class
Using ClassWizard, add ExitInstance() virtual function to CMyex35aApp class.
Figure 36: Adding ExitInstance() virtual function.
Click the Edit Code button and modify the code as shown below.
int CMyex35aApp::ExitInstance()
{
// TODO: Add your specialized code here and/or call the base class
g_eKill.SetEvent();
Sleep(500);
return CWinApp::ExitInstance();
}
Listing 5.
Add the following #include directive to myex35a.cpp.
#include "urlthread.h"
|
Add the following code in InitInstance().
Listing 6 |
Delete the following lines of code in InitInstance().
// The one and only window has been initialized, so show and update it.
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
Remove the following code of the OnDraw() in SrvrItem.cpp.
// Remove this if you use rSize
UNREFERENCED_PARAMETER(rSize);
Add variables, delete and change the class access type as shown below in lpFrame.h.
Listing 7.
Add the #include "urlthread.h" directive and modify the OnCreateControlBars() in lpFrame.cpp as shown below.
BOOL CInPlaceFrame::OnCreateControlBars(CFrameWnd* pWndFrame, CFrameWnd* pWndDoc)
{
m_wndDialogBar.SetOwner(this); // for commands
if (!m_wndDialogBar.Create(pWndFrame, IDD_DIALOGBAR, CBRS_TOP, 0xE810))
{
TRACE0("Failed to create dialog bar\n");
return -1; // fail to create
}
m_wndDialogBar.SetDlgItemText(IDC_URL, g_strURL);
// attach the color bitmaps to the dialog bar buttons
m_bitmapGreen.LoadBitmap(IDB_GREEN);
HBITMAP hBitmap = (HBITMAP) m_bitmapGreen.GetSafeHandle();
((CButton*) m_wndDialogBar.GetDlgItem(IDC_START))->SetBitmap(hBitmap);
m_bitmapRed.LoadBitmap(IDB_RED);
hBitmap = (HBITMAP) m_bitmapRed.GetSafeHandle();
((CButton*) m_wndDialogBar.GetDlgItem(IDC_STOP))->SetBitmap(hBitmap);
return TRUE;
}
Listing 8.
CMyex35aDoc Class
Change the GetDocObjectServer() virtual function to public in myex35aDoc.h.
Listing 9.
CMyex35aView Class
Using ClassWizard delete OnDestroy(). Go to ResourceView, select the IDD_DIALOGBAR, right click and select the ClassWizard context menu.
Figure 37: Invoking ClassWizard from dialog editor.
For the Adding a Class dialog prompt, choose Select an existing class.
Figure 38: Adding dialog to an existing class.
Select the CMyex35aView class.
Figure 39: Selecting an existing class.
Just click Yes for the following dialog prompt.
Figure 40: Dialog prompt for the class to dialog linking.
Add the following message map command and update command handler functions.
ID |
Command |
ID_EDIT_CLEAR_ALL |
Command |
IDC_START |
Command and update command |
IDC_STOP |
Command and update command |
Table 2. |
You may add those commands and update commands manually if needed.
Listing 10.
Add the following #include directives to myex35aView.cpp.
#include "Urlthread.h"
#include "MainFrm.h"
#include "IpFrame.h"
Listing 11.
If you add some of the previous handlers manually make sure message map in myex35aView.cpp as shown below.
Listing 12.
Don’t forget to delete the OnDestroy() implementation and complete the message handler implementations as shown below.
void CMyex35aView::OnEditClearAll()
{
// Not so useable here, coz of the save as...
SetWindowText("");
}
void CMyex35aView::OnStart()
{
CWnd* pFrm = GetParent(); // SDI only
CWnd* pBar;
if(pFrm->IsKindOf(RUNTIME_CLASS(CMainFrame))) {
pBar = &((CMainFrame*) pFrm)->m_wndDialogBar;
}
else {
pBar = &((CInPlaceFrame*) pFrm)->m_wndDialogBar;
}
// g_strURL: thread sync?
pBar->GetDlgItemText(IDC_URL, g_strURL);
TRACE("CMyex35aView::OnRequest -- URL = %s\n", g_strURL);
AfxBeginThread(UrlThreadProc, GetSafeHwnd(), THREAD_PRIORITY_NORMAL);
}
void CMyex35aView::OnStop()
{
g_eKill.SetEvent();
}
void CMyex35aView::OnUpdateStop(CCmdUI* pCmdUI)
{
pCmdUI->Enable(g_bThreadStarted);
}
void CMyex35aView::OnUpdateStart(CCmdUI* pCmdUI)
{
pCmdUI->Enable(!g_bThreadStarted);
}
Build and run. Type the localhost address or any other address if you are online and click the green button. You can stop the progress anytime by pressing the red button that only visible when the program is in progress.
Figure 41: MYEX35A phase 2 program output in action, testing the localhost.
Figure 42: MYEX35A phase 2 program output in action, testing the google.com.
Use the File Open menu to open the previous test.35a file.
Figure 43: MYEX35A phase 2 program output in action, opening test.35a file.
Create a text file, let name it test.txt. Write some content and put it under the wwwroot directory and type the address of the text file as shown below. Press the green button.
Figure 44: MYEX35A phase 2 program output in action, opening text file.
It seems very useful and fun isn’t it? Let have some story for what we have done.
Further reading and digging:
Win32 process, thread and synchronization story can be found starting from Module R.
MSDN MFC 9.0 class library online documentation - latest version.
DCOM at MSDN.
COM+ at MSDN.
COM at MSDN.
Unicode and Multi-byte character set: Story and program examples.