// LCWizPgs.cpp : implementation file // #include "stdafx.h" #include "resource.h" #include "LCWizPgs.h" #include "LCWiz.h" #include "LCWizSht.h" #include #include #include #ifdef _DEBUG #undef THIS_FILE static char BASED_CODE THIS_FILE[] = __FILE__; #endif IMPLEMENT_DYNCREATE(CLicCompWizPage1, CPropertyPage) IMPLEMENT_DYNCREATE(CLicCompWizPage3, CPropertyPage) IMPLEMENT_DYNCREATE(CLicCompWizPage4, CPropertyPage) ///////////////////////////////////////////////////////////////////////////// // CLicCompWizPage1 property page CLicCompWizPage1::CLicCompWizPage1() : CPropertyPage(CLicCompWizPage1::IDD) { //{{AFX_DATA_INIT(CLicCompWizPage1) m_nRadio = 0; m_strText = _T(""); //}}AFX_DATA_INIT } CLicCompWizPage1::~CLicCompWizPage1() { } void CLicCompWizPage1::DoDataExchange(CDataExchange* pDX) { CPropertyPage::DoDataExchange(pDX); //{{AFX_DATA_MAP(CLicCompWizPage1) DDX_Control(pDX, IDC_WELCOME, m_wndWelcome); DDX_Radio(pDX, IDC_RADIO_LOCAL_COMPUTER, m_nRadio); DDX_Text(pDX, IDC_TEXT, m_strText); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CLicCompWizPage1, CPropertyPage) //{{AFX_MSG_MAP(CLicCompWizPage1) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CLicCompWizPage1 property page BOOL CLicCompWizPage1::OnSetActive() { ((CLicCompWizSheet*)GetParent())->SetWizardButtons(PSWIZB_NEXT); return CPropertyPage::OnSetActive(); } BOOL CLicCompWizPage1::OnInitDialog() { CPropertyPage::OnInitDialog(); m_strText.LoadString(IDS_TEXT_PAGE1); // Get the font for the welcome static control and make the font bold. CFont* pFont = m_wndWelcome.GetFont(); // Get the default GUI font if GetFont() fails. if (pFont == NULL) pFont = CFont::FromHandle((HFONT)::GetStockObject(DEFAULT_GUI_FONT)); LOGFONT lf; if (pFont != NULL && pFont->GetLogFont(&lf)) { // Add to the font weight to make it bold. lf.lfWeight += BOLD_WEIGHT; if (m_fontBold.CreateFontIndirect(&lf)) { // Set the font for the static control. m_wndWelcome.SetFont(&m_fontBold); } } return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } LRESULT CLicCompWizPage1::OnWizardNext() { UpdateData(); CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp(); CLicCompWizSheet* pSheet = (CLicCompWizSheet*)GetParent(); pApp->IsRemote() = m_nRadio; pApp->m_strEnterprise.Empty(); if (m_nRadio == 0) { if (::IsWindow(pSheet->m_Page3.m_hWnd)) { pSheet->m_Page3.GetEnterpriseEdit().SetWindowText(_T("")); } return IDD_PROPPAGE4; } else return CPropertyPage::OnWizardNext(); } ///////////////////////////////////////////////////////////////////////////// // CLicCompWizPage3 property page CLicCompWizPage3::CLicCompWizPage3() : CPropertyPage(CLicCompWizPage3::IDD), m_bExpandedOnce(FALSE) { //{{AFX_DATA_INIT(CLicCompWizPage3) //}}AFX_DATA_INIT } CLicCompWizPage3::~CLicCompWizPage3() { } void CLicCompWizPage3::DoDataExchange(CDataExchange* pDX) { CPropertyPage::DoDataExchange(pDX); //{{AFX_DATA_MAP(CLicCompWizPage3) DDX_Control(pDX, IDC_TEXT_SELECT_DOMAIN, m_wndTextSelectDomain); DDX_Control(pDX, IDC_TEXT_DOMAIN, m_wndTextDomain); DDX_Control(pDX, IDC_EDIT_ENTERPRISE, m_wndEnterprise); DDX_Control(pDX, IDC_TREE_NETWORK, m_wndTreeNetwork); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CLicCompWizPage3, CPropertyPage) //{{AFX_MSG_MAP(CLicCompWizPage3) ON_NOTIFY(TVN_SELCHANGED, IDC_TREE_NETWORK, OnSelChangedTree) ON_EN_CHANGE(IDC_EDIT_ENTERPRISE, OnChangeEditEnterprise) ON_NOTIFY(NM_OUTOFMEMORY, IDC_TREE_NETWORK, OnNetworkTreeOutOfMemory) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CLicCompWizPage3 message handlers BOOL CLicCompWizPage3::OnSetActive() { BOOL bReturn = CPropertyPage::OnSetActive(); CLicCompWizSheet* pSheet = (CLicCompWizSheet*)GetParent(); // Do the default domain expansion only once. if (!m_bExpandedOnce) { m_bExpandedOnce = TRUE; m_wndTreeNetwork.PopulateTree(); } pSheet->SetWizardButtons(PSWIZB_BACK | PSWIZB_NEXT); return bReturn; } void CLicCompWizPage3::OnSelChangedTree(NMHDR* pNMHDR, LRESULT* pResult) { NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; ASSERT(pNMTreeView->itemNew.mask & TVIF_PARAM); // Copy the remote name for the selected item into the edit control. if (pNMTreeView->itemNew.mask & TVIF_PARAM) { CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp(); int nImage, nSelectedImage; nImage = nSelectedImage = 0; m_wndTreeNetwork.GetItemImage(m_wndTreeNetwork.GetSelectedItem(), nImage, nSelectedImage); // Set the enterprise name in the App object. if (nImage == CNetTreeCtrl::IMG_ROOT) pApp->m_strEnterprise.Empty(); else pApp->m_strEnterprise = ((LPNETRESOURCE)pNMTreeView->itemNew.lParam)->lpRemoteName; // Set the text in the edit control. m_wndEnterprise.SetWindowText(pApp->m_strEnterprise); // Select the text in the edit control. m_wndEnterprise.SetSel(0, -1); } *pResult = 0; } void CLicCompWizPage3::OnChangeEditEnterprise() { CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp(); m_wndEnterprise.GetWindowText(pApp->m_strEnterprise); } void CLicCompWizPage3::OnNetworkTreeOutOfMemory(NMHDR* pNMHDR, LRESULT* pResult) { m_wndTreeNetwork.NotifyThread(TRUE); AfxMessageBox(IDS_MEM_ERROR, MB_OK | MB_ICONSTOP); *pResult = 0; } ///////////////////////////////////////////////////////////////////////////// // CLicCompWizPage3 functions ///////////////////////////////////////////////////////////////////////////// // Global variables extern TCHAR pszLicenseEvent[]; ///////////////////////////////////////////////////////////////////////////// // Static member functions UINT CLicCompWizPage4::GetLicenseInfo(LPVOID pParam) { // Create an event object to match that in the application object. CEvent event(TRUE, TRUE, pszLicenseEvent); CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp(); CLicCompWizPage4* pPage = (CLicCompWizPage4*)pParam; CLicCompWizSheet* pSheet = (CLicCompWizSheet*)pPage->GetParent(); CWaitCursor wc; NTSTATUS status = STATUS_ACCESS_DENIED; try { CString strText; // Unsignal the event object. event.ResetEvent(); // Reset the exit flag. pApp->NotifyLicenseThread(FALSE); // Disable the Back and Next buttons while the thread is running. pSheet->SetWizardButtons(0); LPBYTE lpbBuf = NULL; LLS_HANDLE hLls = NULL; DWORD dwTotalEntries, dwResumeHandle; dwTotalEntries = dwResumeHandle = 0; // Save the machine or domain name that the user typed. CString strFocus = pApp->m_strEnterprise; // Display a message indicating what the wizard is doing. strText.LoadString(IDS_WORKING); pPage->m_wndUnlicensedProducts.SetWindowText(strText); strText.Empty(); // Avoids a memory leak. // Connect to the license server. status = ::LlsConnectEnterprise(const_cast((LPCTSTR)pApp->m_strEnterprise), &hLls, 0, &lpbBuf); if (NT_ERROR(status)) goto ErrorMessage; // It's OK for the user to click the Back button now, so enable it. pSheet->SetWizardButtons(PSWIZB_BACK); if (lpbBuf != NULL) { PLLS_CONNECT_INFO_0 pllsci = (PLLS_CONNECT_INFO_0)lpbBuf; // Reset the domain and enterprise server names. pApp->m_strDomain = pllsci->Domain; pApp->m_strEnterpriseServer = pllsci->EnterpriseServer; // Free embedded pointers //::LlsFreeMemory(pllsci->Domain); //::LlsFreeMemory(pllsci->EnterpriseServer); // Free memory allocated by the LLS API. status = ::LlsFreeMemory(lpbBuf); lpbBuf = NULL; } if (NT_SUCCESS(status)) { // Display a message indicating what the wizard is doing. strText.LoadString(IDS_ENUM_PRODUCTS); pPage->m_wndUnlicensedProducts.SetWindowText(strText); strText.Empty(); // Avoids a memory leak. USHORT nProductCount = 0; DWORD dwEntriesRead, dwTotalEntriesRead; dwEntriesRead = dwTotalEntriesRead = 0; // Build a list of all the products. do { // Check the exit thread flag. The user may have clicked the Back button. if (pApp->m_bExitLicenseThread) goto ExitThread; status = ::LlsProductEnum(hLls, 1, &lpbBuf, CLicCompWizPage4::LLS_PREFERRED_LENGTH, &dwEntriesRead, &dwTotalEntries, &dwResumeHandle); if (!NT_SUCCESS(status)) goto ErrorMessage; dwTotalEntriesRead += dwEntriesRead; PLLS_PRODUCT_INFO_1 pllspi = (PLLS_PRODUCT_INFO_1)lpbBuf; while (dwEntriesRead--) { // Check the exit thread flag. The user may have clicked the Back button. if (pApp->m_bExitLicenseThread) goto ExitThread; if ((LONG)pllspi->InUse > (LONG)pllspi->Purchased) { pPage->FillListCtrl(pllspi->Product, (WORD)pllspi->InUse, (WORD)pllspi->Purchased); // Increment the unlicensed products counter. nProductCount++; } // Free embedded pointer. ::LlsFreeMemory(pllspi->Product); pllspi++; } // Free memory allocated by the LLS API. status = ::LlsFreeMemory(lpbBuf); lpbBuf = NULL; ASSERT(NT_SUCCESS(status)); } while (dwTotalEntries); // Close the LLS handle. status = ::LlsClose(hLls); // Check the exit thread flag. The user may have clicked the Back button. if (pApp->m_bExitLicenseThread) goto ExitThread; ASSERT(NT_SUCCESS(status)); // Show the user how many unlicensed products were found. if (nProductCount) { strText.Format(IDS_UNLICENSED_PRODUCTS, pApp->m_strEnterpriseServer); pPage->m_wndUnlicensedProducts.SetWindowText(strText); // Make the static text box the appropriate size. pPage->m_wndUnlicensedProducts.SetWindowPos(&CWnd::wndTop, 0, 0, pPage->m_sizeSmallText.cx, pPage->m_sizeSmallText.cy, SWP_NOMOVE | SWP_NOZORDER); // Make sure the list control is visible. pPage->m_wndProductList.ShowWindow(SW_SHOW); // Make sure the print button is visible. pPage->m_wndPrint.ShowWindow(SW_SHOW); } else { // Make the static text box the appropriate size. pPage->m_wndUnlicensedProducts.SetWindowPos(&CWnd::wndTop, 0, 0, pPage->m_sizeLargeText.cx, pPage->m_sizeLargeText.cy, SWP_NOMOVE | SWP_NOZORDER); // Display a message if no unlicensed products were found. strText.LoadString(IDS_NO_UNLICENSED_PRODUCTS); pPage->m_wndUnlicensedProducts.SetWindowText(strText); } // Enable the Back button. pSheet->SetWizardButtons(PSWIZB_BACK); CString strFinished; CButton* pCancel = (CButton*)pSheet->GetDlgItem(IDCANCEL); // Change the text on the cancel button to "Done." strFinished.LoadString(IDS_DONE); pCancel->SetWindowText(strFinished); // Signal the event object. event.SetEvent(); // Reset the pointer to the license thread. pApp->m_pLicenseThread = NULL; // Restore the normal cursor. pPage->PostMessage(WM_SETCURSOR); } return 0; ErrorMessage: // Check the exit thread flag. The user may have clicked the Back button. if (pApp->m_bExitLicenseThread) goto ExitThread; // Make the static text box the appropriate size. pPage->m_wndUnlicensedProducts.SetWindowPos(&CWnd::wndTop, 0, 0, pPage->m_sizeLargeText.cx, pPage->m_sizeLargeText.cy, SWP_NOMOVE | SWP_NOZORDER); // Create an error message based on the return value from LlsConnectEnterprise(). switch (status) { case STATUS_NO_SUCH_DOMAIN: if (pApp->IsRemote()) strText.Format(IDS_BAD_DOMAIN_NAME, strFocus); else strText.LoadString(IDS_UNAVAILABLE); break; case STATUS_ACCESS_DENIED: if (pApp->IsRemote()) strText.Format(IDS_ACCESS_DENIED, strFocus); else strText.LoadString(IDS_LOCAL_ACCESS_DENIED); break; case RPC_NT_SERVER_UNAVAILABLE: strText.Format(IDS_SERVER_UNAVAILABLE); break; default: if (pApp->IsRemote()) strText.Format(IDS_NO_LICENSE_INFO_REMOTE, strFocus); else strText.LoadString(IDS_NO_LICENSE_INFO_LOCAL); } // Display an error message if LlsProductEnum() fails. pPage->m_wndUnlicensedProducts.SetWindowText(strText); // Enable the Back button. pSheet->SetWizardButtons(PSWIZB_BACK); // Signal the event object. event.SetEvent(); // Reset the pointer to the license thread. pApp->m_pLicenseThread = NULL; // Restore the normal cursor. pPage->PostMessage(WM_SETCURSOR); return 1; ExitThread: // Signal the event object. event.SetEvent(); // Reset the pointer to the license thread. pApp->m_pLicenseThread = NULL; return 2; } catch(...) { // Signal the event object. event.SetEvent(); CString strText; // Display an error message. strText.LoadString(IDS_GENERIC_ERROR); pPage->m_wndUnlicensedProducts.SetWindowText(strText); // Reset the pointer to the license thread. pApp->m_pLicenseThread = NULL; // Restore the normal cursor. pPage->PostMessage(WM_SETCURSOR); return 3; } } ///////////////////////////////////////////////////////////////////////////// // CLicCompWizPage4 property page CLicCompWizPage4::CLicCompWizPage4() : CPropertyPage(CLicCompWizPage4::IDD), m_ptPrint(0, 0), m_nHorzMargin(0), m_nVertMargin(0),m_ptOrg(0, 0), m_ptExt(0, 0), m_sizeSmallText(0, 0), m_sizeLargeText(0, 0) { //{{AFX_DATA_INIT(CLicCompWizPage4) //}}AFX_DATA_INIT m_strCancel.Empty(); m_pTabs = new INT[PRINT_COLUMNS]; } CLicCompWizPage4::~CLicCompWizPage4() { if (m_pTabs != NULL) delete[] m_pTabs; } void CLicCompWizPage4::DoDataExchange(CDataExchange* pDX) { CPropertyPage::DoDataExchange(pDX); //{{AFX_DATA_MAP(CLicCompWizPage4) DDX_Control(pDX, IDC_FLAG_BMP, m_wndPicture); DDX_Control(pDX, IDC_BUT_PRINT, m_wndPrint); DDX_Control(pDX, IDC_TEXT_UNCOMP_PRODUCTS, m_wndUnlicensedProducts); DDX_Control(pDX, IDC_LIST_PRODUCTS, m_wndProductList); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CLicCompWizPage4, CPropertyPage) //{{AFX_MSG_MAP(CLicCompWizPage4) ON_BN_CLICKED(IDC_BUT_PRINT, OnPrintButton) ON_NOTIFY(NM_OUTOFMEMORY, IDC_LIST_PRODUCTS, OnListProductsOutOfMemory) ON_WM_DESTROY() ON_WM_SETCURSOR() //}}AFX_MSG_MAP END_MESSAGE_MAP() void CLicCompWizPage4::PumpMessages() { // Must call Create() before using the dialog ASSERT(m_hWnd!=NULL); MSG msg; try { // Handle dialog messages while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if(!IsDialogMessage(&msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } } catch(...) { TRACE(_T("Exception in CLicCompWizPage4::PumpMessages()\n")); } } BOOL CLicCompWizPage4::FillListCtrl(LPTSTR pszProduct, WORD wInUse, WORD wPurchased) { TCHAR pszLicenses[BUFFER_SIZE]; ::wsprintf(pszLicenses, _T("%u"), wInUse - wPurchased); USHORT nIndex; LV_ITEM lvi; lvi.mask = LVIF_TEXT | LVIF_PARAM; lvi.iItem = 0; lvi.iSubItem = 0; lvi.lParam = MAKELONG(wInUse, wPurchased); lvi.pszText = pszProduct; if ((nIndex = (USHORT)m_wndProductList.InsertItem(&lvi)) != (USHORT)-1) { m_wndProductList.SetItemText(nIndex, 1, pszLicenses); } return TRUE; } BOOL CLicCompWizPage4::OnInitDialog() { CPropertyPage::OnInitDialog(); // Set the header text for the list control. CRect rcList; m_wndProductList.GetWindowRect(&rcList); CString strColumnTitle; LV_COLUMN lvc; lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; lvc.fmt = LVCFMT_LEFT; USHORT nColumns = COLUMNS; UINT uStringID[COLUMNS] = {IDS_PRODUCTS_LIST, IDS_LICENSES_LIST}; for (USHORT i = 0; i < nColumns; i++) { strColumnTitle.LoadString(uStringID[i]); lvc.pszText = strColumnTitle.GetBuffer(strColumnTitle.GetLength()); lvc.cx = rcList.Width() / COLUMNS; m_wndProductList.InsertColumn(i, &lvc); strColumnTitle.ReleaseBuffer(); } CLicCompWizSheet* pSheet = (CLicCompWizSheet*)GetParent(); // Store the text on the cancel button. CButton* pCancel = (CButton*)pSheet->GetDlgItem(IDCANCEL); pCancel->GetWindowText(m_strCancel); CRect rcText; // Create the large and small extents for the static text control. m_wndUnlicensedProducts.GetWindowRect(&rcText); m_sizeSmallText.cx = rcText.right - rcText.left; m_sizeSmallText.cy = rcText.bottom - rcText.top; // Make the large extents match those for the list control. m_sizeLargeText.cx = rcList.right - rcList.left; m_sizeLargeText.cy = rcList.bottom - rcList.top; return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } void CLicCompWizPage4::OnListProductsOutOfMemory(NMHDR* pNMHDR, LRESULT* pResult) { AfxMessageBox(IDS_MEM_ERROR, MB_OK | MB_ICONSTOP); CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp(); // Let the license thread know it's supposed to quit. pApp->NotifyLicenseThread(TRUE); *pResult = 0; } void CLicCompWizPage4::OnPrintButton() { CDC dc; CPrintDialog dlg(FALSE, PD_ALLPAGES | PD_USEDEVMODECOPIESANDCOLLATE | PD_NOPAGENUMS | PD_HIDEPRINTTOFILE | PD_NOSELECTION, this); if (dlg.DoModal() == IDOK) { CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp(); m_wndPrint.RedrawWindow(); DOCINFO di; CString strDocName; strDocName.Format(IDS_DOC_NAME, pApp->m_strEnterpriseServer); di.cbSize = sizeof(DOCINFO); di.lpszDocName = strDocName.GetBuffer(BUFFER_SIZE); di.lpszOutput = NULL; if (dc.Attach(dlg.GetPrinterDC())) { PrepareForPrinting(dc); dc.StartDoc(&di); PrintReport(dc); dc.EndDoc(); dc.DeleteDC(); ::GlobalFree(dlg.m_pd.hDevNames); ::GlobalFree(dlg.m_pd.hDevMode); } } } BOOL CLicCompWizPage4::PrepareForPrinting(CDC& dc) { // Create various fonts... CString strFont; // Create a heading font. strFont.LoadString(IDS_FONT_BOLD); m_fontHeading.CreatePointFont(FONT_SIZE_HEADING, strFont, &dc); // Create a bold, underlined header font. strFont.LoadString(IDS_FONT_BOLD); m_fontHeader.CreatePointFont(FONT_SIZE, strFont, &dc); LOGFONT lf; m_fontHeader.GetLogFont(&lf); m_fontHeader.DeleteObject(); lf.lfUnderline = TRUE; m_fontHeader.CreateFontIndirect(&lf); // Create a footer font. strFont.LoadString(IDS_FONT_BOLD); m_fontFooter.CreatePointFont(FONT_SIZE_FOOTER, strFont, &dc); // Create a default font. strFont.LoadString(IDS_FONT); m_fontNormal.CreatePointFont(FONT_SIZE, strFont, &dc); // Get the text metrics for each font. CFont* pOldFont = dc.SelectObject(&m_fontHeading); dc.GetTextMetrics(&m_tmHeading); dc.SelectObject(&m_fontHeader); dc.GetTextMetrics(&m_tmHeader); dc.SelectObject(&m_fontFooter); dc.GetTextMetrics(&m_tmFooter); dc.SelectObject(&m_fontNormal); dc.GetTextMetrics(&m_tmNormal); // Select the original font back in to the device context. dc.SelectObject(pOldFont); // Set the horizontal and vertical margins. m_nHorzMargin = (LONG)(dc.GetDeviceCaps(LOGPIXELSX) * HORZ_MARGIN); m_nVertMargin = (LONG)(dc.GetDeviceCaps(LOGPIXELSY) * VERT_MARGIN); // Get the printable page offsets for the origin. m_ptOrg.x = dc.GetDeviceCaps(PHYSICALOFFSETX); m_ptOrg.y = dc.GetDeviceCaps(PHYSICALOFFSETY); dc.SetWindowOrg(m_ptOrg); m_ptOrg.x += m_nHorzMargin; m_ptOrg.y += m_nVertMargin; // Get the printable page offsets for the page extents. m_ptExt.x = dc.GetDeviceCaps(PHYSICALWIDTH) - m_ptOrg.x; m_ptExt.y = dc.GetDeviceCaps(PHYSICALHEIGHT) - m_ptOrg.y; dc.SetViewportOrg(m_ptOrg); CalculateTabs(dc); return TRUE; } BOOL CLicCompWizPage4::PrintReport(CDC& dc) { // Set the starting point for printing. m_ptPrint.x = m_ptPrint.y = 0; // Prepare to print a heading. CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp(); CString strHeading; CFont* pOldFont = dc.SelectObject(&m_fontHeading); strHeading.Format(IDS_DOC_NAME, pApp->m_strEnterpriseServer); dc.StartPage(); CRect rc(m_ptPrint.x, m_ptPrint.y, m_ptExt.x - m_ptOrg.x, m_tmHeading.tmHeight); // Calculate the size of the rectangle needed to draw the text. m_ptPrint.y += dc.DrawText(strHeading, &rc, DT_EXTERNALLEADING | DT_CENTER | DT_WORDBREAK | DT_NOCLIP); // Normalize the rectangle. rc.NormalizeRect(); // Add a blank line below the heading. m_ptPrint.y += m_tmHeading.tmHeight; // Move the right side of the rectangle out to the right margin so text is properly centered. rc.right = m_ptExt.x - m_ptOrg.x; // Draw the text in the rectangle. dc.DrawText(strHeading, &rc, DT_EXTERNALLEADING | DT_CENTER | DT_WORDBREAK | DT_NOCLIP); dc.SelectObject(pOldFont); PrintPages(dc, 100); // Delete the fonts. m_fontNormal.DeleteObject(); m_fontHeader.DeleteObject(); m_fontFooter.DeleteObject(); m_fontHeading.DeleteObject(); return TRUE; } BOOL CLicCompWizPage4::PrintPageHeader(CDC& dc) { CFont* pOldFont = dc.SelectObject(&m_fontHeader); dc.StartPage(); CString strHeader, strProducts, strLicenses, strPurchased, strUsed; strProducts.LoadString(IDS_PRODUCTS); strLicenses.LoadString(IDS_LICENSES); strPurchased.LoadString(IDS_PURCHASED); strUsed.LoadString(IDS_USED); strHeader.Format(_T("%s\t%s\t%s\t%s"), strProducts, strLicenses, strPurchased, strUsed); dc.TabbedTextOut(m_ptPrint.x, m_ptPrint.y, strHeader, PRINT_COLUMNS, m_pTabs, 0); m_ptPrint.y += ((m_tmHeader.tmHeight + m_tmHeader.tmExternalLeading) * 2); dc.SelectObject(pOldFont); return TRUE; } BOOL CLicCompWizPage4::PrintPageFooter(CDC& dc, USHORT nPage) { CFont* pOldFont = dc.SelectObject(&m_fontFooter); CString strFooter; CTime time(CTime::GetCurrentTime()); strFooter.Format(IDS_PAGE_DATE, nPage, time.Format(IDS_FMT_DATE)); CRect rc(m_ptPrint.x, m_ptExt.y - m_nVertMargin, m_ptOrg.x, m_tmFooter.tmHeight); // Calculate the size of the rectangle needed to draw the text. m_ptPrint.y += dc.DrawText(strFooter, &rc, DT_CALCRECT | DT_EXTERNALLEADING | DT_CENTER | DT_WORDBREAK | DT_NOCLIP); // Move the right side of the rectangle out to the right margin so text is properly centered. rc.right = m_ptExt.x - m_ptOrg.x; // Draw the text in the rectangle. dc.DrawText(strFooter, &rc, DT_EXTERNALLEADING | DT_CENTER | DT_WORDBREAK | DT_NOCLIP); dc.EndPage(); dc.SelectObject(pOldFont); return TRUE; } BOOL CLicCompWizPage4::PrintPages(CDC& dc, UINT nStart) { CFont* pOldFont = dc.SelectObject(&m_fontNormal); UINT nPage = 1; UINT nItems = m_wndProductList.GetItemCount(); // Print the initial header. PrintPageHeader(dc); DWORD dwParam = 0; CString strTextOut; for (UINT i = 0; i < nItems; i++) { dwParam = (DWORD)m_wndProductList.GetItemData(i); CString strProduct = m_wndProductList.GetItemText(i, 0); CSize sizeProduct = dc.GetTextExtent(strProduct); if (sizeProduct.cx > m_pTabs[0] - (m_tmNormal.tmAveCharWidth * TAB_WIDTH)) TruncateText(dc, strProduct); // Format the output text. strTextOut.Format(_T("%s\t%s\t%u\t%u"), strProduct, m_wndProductList.GetItemText(i, 1), HIWORD(dwParam), LOWORD(dwParam)); dc.TabbedTextOut(m_ptPrint.x, m_ptPrint.y, strTextOut, PRINT_COLUMNS, m_pTabs, 0); // Calculate the vertical position for the next line of text. m_ptPrint.y += m_tmNormal.tmHeight + m_tmNormal.tmExternalLeading; if ((m_ptPrint.y + m_ptOrg.y) >= m_ptExt.y) { PrintPageFooter(dc, nPage++); // Reset the printing position. m_ptPrint.y = 0; PrintPageHeader(dc); } } // Print the final footer. PrintPageFooter(dc, (USHORT)nPage); dc.SelectObject(pOldFont); return TRUE; } void CLicCompWizPage4::TruncateText(CDC& dc, CString& strInput) { CString strText, strEllipsis; USHORT nLen, nChars = 0; UINT nMaxWidth = m_pTabs[0] - (m_tmNormal.tmAveCharWidth * TAB_WIDTH); nLen = (USHORT)strInput.GetLength(); strEllipsis.LoadString(IDS_ELLIPSIS); CSize sizeText = dc.GetTextExtent(strInput); // Keep lopping off characters until the string is short enough. while ((UINT)sizeText.cx > nMaxWidth) { strText = strInput.Left(nLen - nChars++); sizeText = dc.GetTextExtent(strText); } // Remove the last characters and replace them with an ellipsis. ASSERT(strText.GetLength() > strEllipsis.GetLength()); strInput = strText.Left(strText.GetLength() - strEllipsis.GetLength()) + strEllipsis; } BOOL CLicCompWizPage4::CalculateTabs(CDC& dc) { INT nTotalExt = 0; INT nTabSize = TAB_WIDTH * m_tmHeader.tmAveCharWidth; UINT uStrIds[] = {IDS_LICENSES, IDS_PURCHASED, IDS_USED}; m_pTabs[0] = 0; for (USHORT i = 1; i < PRINT_COLUMNS; i++) { CString strText; strText.LoadString(uStrIds[i - 1]); // Get the text extent for each string. m_pTabs[i] = dc.GetTextExtent(strText).cx; // Keep a running total of the extents. nTotalExt += m_pTabs[i]; } // Add tab space between columns. nTotalExt += nTabSize * (PRINT_COLUMNS - 2); // The second column will begin at the difference between the right // margin and the total extent. m_pTabs[0] = m_ptExt.x - m_ptOrg.x - nTotalExt; // Now set the actual tab positions in the array. for (i = 1; i < PRINT_COLUMNS; i++) { m_pTabs[i] += m_pTabs[i - 1] + nTabSize; } return TRUE; } LRESULT CLicCompWizPage4::OnWizardBack() { CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp(); // Let the license thread know it's time to quit. pApp->NotifyLicenseThread(TRUE); CLicCompWizSheet* pSheet = (CLicCompWizSheet*)GetParent(); // Set the cancel button text back to "Cancel." CButton* pCancel = (CButton*)pSheet->GetDlgItem(IDCANCEL); pCancel->SetWindowText(m_strCancel); if (pSheet->m_Page1.m_nRadio == 0) return IDD_PROPPAGE1; else return CPropertyPage::OnWizardBack(); } void CLicCompWizPage4::OnDestroy() { CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp(); pApp->NotifyLicenseThread(TRUE); PumpMessages(); CPropertyPage::OnDestroy(); } BOOL CLicCompWizPage4::OnSetActive() { CLicCompWizSheet* pSheet = (CLicCompWizSheet*)GetParent(); pSheet->SetWizardButtons(PSWIZB_BACK); // Hide the list control and clear it. m_wndProductList.ShowWindow(SW_HIDE); m_wndProductList.DeleteAllItems(); // Hide the print button. m_wndPrint.ShowWindow(SW_HIDE); CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp(); // Make sure the last thread has terminated before starting a new one. if (pApp->m_pLicenseThread != NULL) { pApp->NotifyLicenseThread(TRUE); CEvent event(TRUE, TRUE, pszLicenseEvent); CSingleLock lock(&event); lock.Lock(); } // Keep a pointer to the thread so we can find out if it's still running. pApp->m_pLicenseThread = AfxBeginThread((AFX_THREADPROC)GetLicenseInfo, (LPVOID)this); return CPropertyPage::OnSetActive(); } LRESULT CLicCompWizPage3::OnWizardNext() { CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp(); m_wndEnterprise.GetWindowText(pApp->m_strEnterprise); // Trim off any white space in the enterprise name. pApp->m_strEnterprise.TrimLeft(); pApp->m_strEnterprise.TrimRight(); if (pApp->m_strEnterprise.IsEmpty() || pApp->m_strEnterprise.Find(_T("\\\\")) != -1) { AfxMessageBox(IDS_SPECIFY_DOMAIN, MB_OK | MB_ICONEXCLAMATION); return IDD; } return CPropertyPage::OnWizardNext(); } BOOL CLicCompWizPage4::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) { CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp(); if (pApp->m_pLicenseThread == NULL) { return CPropertyPage::OnSetCursor(pWnd, nHitTest, message); } else { // Restore the wait cursor if the thread is running. RestoreWaitCursor(); return TRUE; } }