Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1070 lines
27 KiB

  1. // LCWizPgs.cpp : implementation file
  2. //
  3. #include "stdafx.h"
  4. #include "resource.h"
  5. #include "LCWizPgs.h"
  6. #include "LCWiz.h"
  7. #include "LCWizSht.h"
  8. #include <lmaccess.h>
  9. #include <lmapibuf.h>
  10. #include <lmerr.h>
  11. #ifdef _DEBUG
  12. #undef THIS_FILE
  13. static char BASED_CODE THIS_FILE[] = __FILE__;
  14. #endif
  15. IMPLEMENT_DYNCREATE(CLicCompWizPage1, CPropertyPage)
  16. IMPLEMENT_DYNCREATE(CLicCompWizPage3, CPropertyPage)
  17. IMPLEMENT_DYNCREATE(CLicCompWizPage4, CPropertyPage)
  18. /////////////////////////////////////////////////////////////////////////////
  19. // CLicCompWizPage1 property page
  20. CLicCompWizPage1::CLicCompWizPage1() : CPropertyPage(CLicCompWizPage1::IDD)
  21. {
  22. //{{AFX_DATA_INIT(CLicCompWizPage1)
  23. m_nRadio = 0;
  24. m_strText = _T("");
  25. //}}AFX_DATA_INIT
  26. }
  27. CLicCompWizPage1::~CLicCompWizPage1()
  28. {
  29. }
  30. void CLicCompWizPage1::DoDataExchange(CDataExchange* pDX)
  31. {
  32. CPropertyPage::DoDataExchange(pDX);
  33. //{{AFX_DATA_MAP(CLicCompWizPage1)
  34. DDX_Control(pDX, IDC_WELCOME, m_wndWelcome);
  35. DDX_Radio(pDX, IDC_RADIO_LOCAL_COMPUTER, m_nRadio);
  36. DDX_Text(pDX, IDC_TEXT, m_strText);
  37. //}}AFX_DATA_MAP
  38. }
  39. BEGIN_MESSAGE_MAP(CLicCompWizPage1, CPropertyPage)
  40. //{{AFX_MSG_MAP(CLicCompWizPage1)
  41. //}}AFX_MSG_MAP
  42. END_MESSAGE_MAP()
  43. /////////////////////////////////////////////////////////////////////////////
  44. // CLicCompWizPage1 property page
  45. BOOL CLicCompWizPage1::OnSetActive()
  46. {
  47. ((CLicCompWizSheet*)GetParent())->SetWizardButtons(PSWIZB_NEXT);
  48. return CPropertyPage::OnSetActive();
  49. }
  50. BOOL CLicCompWizPage1::OnInitDialog()
  51. {
  52. CPropertyPage::OnInitDialog();
  53. m_strText.LoadString(IDS_TEXT_PAGE1);
  54. // Get the font for the welcome static control and make the font bold.
  55. CFont* pFont = m_wndWelcome.GetFont();
  56. // Get the default GUI font if GetFont() fails.
  57. if (pFont == NULL)
  58. pFont = CFont::FromHandle((HFONT)::GetStockObject(DEFAULT_GUI_FONT));
  59. LOGFONT lf;
  60. if (pFont != NULL && pFont->GetLogFont(&lf))
  61. {
  62. // Add to the font weight to make it bold.
  63. lf.lfWeight += BOLD_WEIGHT;
  64. if (m_fontBold.CreateFontIndirect(&lf))
  65. {
  66. // Set the font for the static control.
  67. m_wndWelcome.SetFont(&m_fontBold);
  68. }
  69. }
  70. return TRUE; // return TRUE unless you set the focus to a control
  71. // EXCEPTION: OCX Property Pages should return FALSE
  72. }
  73. LRESULT CLicCompWizPage1::OnWizardNext()
  74. {
  75. UpdateData();
  76. CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp();
  77. CLicCompWizSheet* pSheet = (CLicCompWizSheet*)GetParent();
  78. pApp->IsRemote() = m_nRadio;
  79. pApp->m_strEnterprise.Empty();
  80. if (m_nRadio == 0)
  81. {
  82. if (::IsWindow(pSheet->m_Page3.m_hWnd))
  83. {
  84. pSheet->m_Page3.GetEnterpriseEdit().SetWindowText(_T(""));
  85. }
  86. return IDD_PROPPAGE4;
  87. }
  88. else
  89. return CPropertyPage::OnWizardNext();
  90. }
  91. /////////////////////////////////////////////////////////////////////////////
  92. // CLicCompWizPage3 property page
  93. CLicCompWizPage3::CLicCompWizPage3()
  94. : CPropertyPage(CLicCompWizPage3::IDD), m_bExpandedOnce(FALSE)
  95. {
  96. //{{AFX_DATA_INIT(CLicCompWizPage3)
  97. //}}AFX_DATA_INIT
  98. }
  99. CLicCompWizPage3::~CLicCompWizPage3()
  100. {
  101. }
  102. void CLicCompWizPage3::DoDataExchange(CDataExchange* pDX)
  103. {
  104. CPropertyPage::DoDataExchange(pDX);
  105. //{{AFX_DATA_MAP(CLicCompWizPage3)
  106. DDX_Control(pDX, IDC_TEXT_SELECT_DOMAIN, m_wndTextSelectDomain);
  107. DDX_Control(pDX, IDC_TEXT_DOMAIN, m_wndTextDomain);
  108. DDX_Control(pDX, IDC_EDIT_ENTERPRISE, m_wndEnterprise);
  109. DDX_Control(pDX, IDC_TREE_NETWORK, m_wndTreeNetwork);
  110. //}}AFX_DATA_MAP
  111. }
  112. BEGIN_MESSAGE_MAP(CLicCompWizPage3, CPropertyPage)
  113. //{{AFX_MSG_MAP(CLicCompWizPage3)
  114. ON_NOTIFY(TVN_SELCHANGED, IDC_TREE_NETWORK, OnSelChangedTree)
  115. ON_EN_CHANGE(IDC_EDIT_ENTERPRISE, OnChangeEditEnterprise)
  116. ON_NOTIFY(NM_OUTOFMEMORY, IDC_TREE_NETWORK, OnNetworkTreeOutOfMemory)
  117. //}}AFX_MSG_MAP
  118. END_MESSAGE_MAP()
  119. /////////////////////////////////////////////////////////////////////////////
  120. // CLicCompWizPage3 message handlers
  121. BOOL CLicCompWizPage3::OnSetActive()
  122. {
  123. BOOL bReturn = CPropertyPage::OnSetActive();
  124. CLicCompWizSheet* pSheet = (CLicCompWizSheet*)GetParent();
  125. // Do the default domain expansion only once.
  126. if (!m_bExpandedOnce)
  127. {
  128. m_bExpandedOnce = TRUE;
  129. m_wndTreeNetwork.PopulateTree();
  130. }
  131. pSheet->SetWizardButtons(PSWIZB_BACK | PSWIZB_NEXT);
  132. return bReturn;
  133. }
  134. void CLicCompWizPage3::OnSelChangedTree(NMHDR* pNMHDR, LRESULT* pResult)
  135. {
  136. NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
  137. ASSERT(pNMTreeView->itemNew.mask & TVIF_PARAM);
  138. // Copy the remote name for the selected item into the edit control.
  139. if (pNMTreeView->itemNew.mask & TVIF_PARAM)
  140. {
  141. CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp();
  142. int nImage, nSelectedImage;
  143. nImage = nSelectedImage = 0;
  144. m_wndTreeNetwork.GetItemImage(m_wndTreeNetwork.GetSelectedItem(), nImage, nSelectedImage);
  145. // Set the enterprise name in the App object.
  146. if (nImage == CNetTreeCtrl::IMG_ROOT)
  147. pApp->m_strEnterprise.Empty();
  148. else
  149. pApp->m_strEnterprise = ((LPNETRESOURCE)pNMTreeView->itemNew.lParam)->lpRemoteName;
  150. // Set the text in the edit control.
  151. m_wndEnterprise.SetWindowText(pApp->m_strEnterprise);
  152. // Select the text in the edit control.
  153. m_wndEnterprise.SetSel(0, -1);
  154. }
  155. *pResult = 0;
  156. }
  157. void CLicCompWizPage3::OnChangeEditEnterprise()
  158. {
  159. CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp();
  160. m_wndEnterprise.GetWindowText(pApp->m_strEnterprise);
  161. }
  162. void CLicCompWizPage3::OnNetworkTreeOutOfMemory(NMHDR* pNMHDR, LRESULT* pResult)
  163. {
  164. m_wndTreeNetwork.NotifyThread(TRUE);
  165. AfxMessageBox(IDS_MEM_ERROR, MB_OK | MB_ICONSTOP);
  166. *pResult = 0;
  167. }
  168. /////////////////////////////////////////////////////////////////////////////
  169. // CLicCompWizPage3 functions
  170. /////////////////////////////////////////////////////////////////////////////
  171. // Global variables
  172. extern TCHAR pszLicenseEvent[];
  173. /////////////////////////////////////////////////////////////////////////////
  174. // Static member functions
  175. UINT CLicCompWizPage4::GetLicenseInfo(LPVOID pParam)
  176. {
  177. // Create an event object to match that in the application object.
  178. CEvent event(TRUE, TRUE, pszLicenseEvent);
  179. CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp();
  180. CLicCompWizPage4* pPage = (CLicCompWizPage4*)pParam;
  181. CLicCompWizSheet* pSheet = (CLicCompWizSheet*)pPage->GetParent();
  182. CWaitCursor wc;
  183. NTSTATUS status = STATUS_ACCESS_DENIED;
  184. try
  185. {
  186. CString strText;
  187. // Unsignal the event object.
  188. event.ResetEvent();
  189. // Reset the exit flag.
  190. pApp->NotifyLicenseThread(FALSE);
  191. // Disable the Back and Next buttons while the thread is running.
  192. pSheet->SetWizardButtons(0);
  193. LPBYTE lpbBuf = NULL;
  194. LLS_HANDLE hLls = NULL;
  195. DWORD dwTotalEntries, dwResumeHandle;
  196. dwTotalEntries = dwResumeHandle = 0;
  197. // Save the machine or domain name that the user typed.
  198. CString strFocus = pApp->m_strEnterprise;
  199. // Display a message indicating what the wizard is doing.
  200. strText.LoadString(IDS_WORKING);
  201. pPage->m_wndUnlicensedProducts.SetWindowText(strText);
  202. strText.Empty(); // Avoids a memory leak.
  203. // Connect to the license server.
  204. status = ::LlsConnectEnterprise(const_cast<LPTSTR>((LPCTSTR)pApp->m_strEnterprise),
  205. &hLls, 0, &lpbBuf);
  206. if (NT_ERROR(status))
  207. goto ErrorMessage;
  208. // It's OK for the user to click the Back button now, so enable it.
  209. pSheet->SetWizardButtons(PSWIZB_BACK);
  210. if (lpbBuf != NULL)
  211. {
  212. PLLS_CONNECT_INFO_0 pllsci = (PLLS_CONNECT_INFO_0)lpbBuf;
  213. // Reset the domain and enterprise server names.
  214. pApp->m_strDomain = pllsci->Domain;
  215. pApp->m_strEnterpriseServer = pllsci->EnterpriseServer;
  216. // Free embedded pointers
  217. //::LlsFreeMemory(pllsci->Domain);
  218. //::LlsFreeMemory(pllsci->EnterpriseServer);
  219. // Free memory allocated by the LLS API.
  220. status = ::LlsFreeMemory(lpbBuf);
  221. lpbBuf = NULL;
  222. }
  223. if (NT_SUCCESS(status))
  224. {
  225. // Display a message indicating what the wizard is doing.
  226. strText.LoadString(IDS_ENUM_PRODUCTS);
  227. pPage->m_wndUnlicensedProducts.SetWindowText(strText);
  228. strText.Empty(); // Avoids a memory leak.
  229. USHORT nProductCount = 0;
  230. DWORD dwEntriesRead, dwTotalEntriesRead;
  231. dwEntriesRead = dwTotalEntriesRead = 0;
  232. // Build a list of all the products.
  233. do
  234. {
  235. // Check the exit thread flag. The user may have clicked the Back button.
  236. if (pApp->m_bExitLicenseThread)
  237. goto ExitThread;
  238. status = ::LlsProductEnum(hLls, 1, &lpbBuf, CLicCompWizPage4::LLS_PREFERRED_LENGTH,
  239. &dwEntriesRead, &dwTotalEntries, &dwResumeHandle);
  240. if (!NT_SUCCESS(status))
  241. goto ErrorMessage;
  242. dwTotalEntriesRead += dwEntriesRead;
  243. PLLS_PRODUCT_INFO_1 pllspi = (PLLS_PRODUCT_INFO_1)lpbBuf;
  244. while (dwEntriesRead--)
  245. {
  246. // Check the exit thread flag. The user may have clicked the Back button.
  247. if (pApp->m_bExitLicenseThread)
  248. goto ExitThread;
  249. if ((LONG)pllspi->InUse > (LONG)pllspi->Purchased)
  250. {
  251. pPage->FillListCtrl(pllspi->Product, (WORD)pllspi->InUse, (WORD)pllspi->Purchased);
  252. // Increment the unlicensed products counter.
  253. nProductCount++;
  254. }
  255. // Free embedded pointer.
  256. ::LlsFreeMemory(pllspi->Product);
  257. pllspi++;
  258. }
  259. // Free memory allocated by the LLS API.
  260. status = ::LlsFreeMemory(lpbBuf);
  261. lpbBuf = NULL;
  262. ASSERT(NT_SUCCESS(status));
  263. }
  264. while (dwTotalEntries);
  265. // Close the LLS handle.
  266. status = ::LlsClose(hLls);
  267. // Check the exit thread flag. The user may have clicked the Back button.
  268. if (pApp->m_bExitLicenseThread)
  269. goto ExitThread;
  270. ASSERT(NT_SUCCESS(status));
  271. // Show the user how many unlicensed products were found.
  272. if (nProductCount)
  273. {
  274. strText.Format(IDS_UNLICENSED_PRODUCTS, pApp->m_strEnterpriseServer);
  275. pPage->m_wndUnlicensedProducts.SetWindowText(strText);
  276. // Make the static text box the appropriate size.
  277. pPage->m_wndUnlicensedProducts.SetWindowPos(&CWnd::wndTop, 0, 0,
  278. pPage->m_sizeSmallText.cx,
  279. pPage->m_sizeSmallText.cy,
  280. SWP_NOMOVE | SWP_NOZORDER);
  281. // Make sure the list control is visible.
  282. pPage->m_wndProductList.ShowWindow(SW_SHOW);
  283. // Make sure the print button is visible.
  284. pPage->m_wndPrint.ShowWindow(SW_SHOW);
  285. }
  286. else
  287. {
  288. // Make the static text box the appropriate size.
  289. pPage->m_wndUnlicensedProducts.SetWindowPos(&CWnd::wndTop, 0, 0,
  290. pPage->m_sizeLargeText.cx,
  291. pPage->m_sizeLargeText.cy,
  292. SWP_NOMOVE | SWP_NOZORDER);
  293. // Display a message if no unlicensed products were found.
  294. strText.LoadString(IDS_NO_UNLICENSED_PRODUCTS);
  295. pPage->m_wndUnlicensedProducts.SetWindowText(strText);
  296. }
  297. // Enable the Back button.
  298. pSheet->SetWizardButtons(PSWIZB_BACK);
  299. CString strFinished;
  300. CButton* pCancel = (CButton*)pSheet->GetDlgItem(IDCANCEL);
  301. // Change the text on the cancel button to "Done."
  302. strFinished.LoadString(IDS_DONE);
  303. pCancel->SetWindowText(strFinished);
  304. // Signal the event object.
  305. event.SetEvent();
  306. // Reset the pointer to the license thread.
  307. pApp->m_pLicenseThread = NULL;
  308. // Restore the normal cursor.
  309. pPage->PostMessage(WM_SETCURSOR);
  310. }
  311. return 0;
  312. ErrorMessage:
  313. // Check the exit thread flag. The user may have clicked the Back button.
  314. if (pApp->m_bExitLicenseThread)
  315. goto ExitThread;
  316. // Make the static text box the appropriate size.
  317. pPage->m_wndUnlicensedProducts.SetWindowPos(&CWnd::wndTop, 0, 0,
  318. pPage->m_sizeLargeText.cx,
  319. pPage->m_sizeLargeText.cy,
  320. SWP_NOMOVE | SWP_NOZORDER);
  321. // Create an error message based on the return value from LlsConnectEnterprise().
  322. switch (status)
  323. {
  324. case STATUS_NO_SUCH_DOMAIN:
  325. if (pApp->IsRemote())
  326. strText.Format(IDS_BAD_DOMAIN_NAME, strFocus);
  327. else
  328. strText.LoadString(IDS_UNAVAILABLE);
  329. break;
  330. case STATUS_ACCESS_DENIED:
  331. if (pApp->IsRemote())
  332. strText.Format(IDS_ACCESS_DENIED, strFocus);
  333. else
  334. strText.LoadString(IDS_LOCAL_ACCESS_DENIED);
  335. break;
  336. case RPC_NT_SERVER_UNAVAILABLE:
  337. strText.Format(IDS_SERVER_UNAVAILABLE);
  338. break;
  339. default:
  340. if (pApp->IsRemote())
  341. strText.Format(IDS_NO_LICENSE_INFO_REMOTE, strFocus);
  342. else
  343. strText.LoadString(IDS_NO_LICENSE_INFO_LOCAL);
  344. }
  345. // Display an error message if LlsProductEnum() fails.
  346. pPage->m_wndUnlicensedProducts.SetWindowText(strText);
  347. // Enable the Back button.
  348. pSheet->SetWizardButtons(PSWIZB_BACK);
  349. // Signal the event object.
  350. event.SetEvent();
  351. // Reset the pointer to the license thread.
  352. pApp->m_pLicenseThread = NULL;
  353. // Restore the normal cursor.
  354. pPage->PostMessage(WM_SETCURSOR);
  355. return 1;
  356. ExitThread:
  357. // Signal the event object.
  358. event.SetEvent();
  359. // Reset the pointer to the license thread.
  360. pApp->m_pLicenseThread = NULL;
  361. return 2;
  362. }
  363. catch(...)
  364. {
  365. // Signal the event object.
  366. event.SetEvent();
  367. CString strText;
  368. // Display an error message.
  369. strText.LoadString(IDS_GENERIC_ERROR);
  370. pPage->m_wndUnlicensedProducts.SetWindowText(strText);
  371. // Reset the pointer to the license thread.
  372. pApp->m_pLicenseThread = NULL;
  373. // Restore the normal cursor.
  374. pPage->PostMessage(WM_SETCURSOR);
  375. return 3;
  376. }
  377. }
  378. /////////////////////////////////////////////////////////////////////////////
  379. // CLicCompWizPage4 property page
  380. CLicCompWizPage4::CLicCompWizPage4()
  381. : CPropertyPage(CLicCompWizPage4::IDD), m_ptPrint(0, 0), m_nHorzMargin(0),
  382. m_nVertMargin(0),m_ptOrg(0, 0), m_ptExt(0, 0), m_sizeSmallText(0, 0),
  383. m_sizeLargeText(0, 0)
  384. {
  385. //{{AFX_DATA_INIT(CLicCompWizPage4)
  386. //}}AFX_DATA_INIT
  387. m_strCancel.Empty();
  388. m_pTabs = new INT[PRINT_COLUMNS];
  389. }
  390. CLicCompWizPage4::~CLicCompWizPage4()
  391. {
  392. if (m_pTabs != NULL)
  393. delete[] m_pTabs;
  394. }
  395. void CLicCompWizPage4::DoDataExchange(CDataExchange* pDX)
  396. {
  397. CPropertyPage::DoDataExchange(pDX);
  398. //{{AFX_DATA_MAP(CLicCompWizPage4)
  399. DDX_Control(pDX, IDC_FLAG_BMP, m_wndPicture);
  400. DDX_Control(pDX, IDC_BUT_PRINT, m_wndPrint);
  401. DDX_Control(pDX, IDC_TEXT_UNCOMP_PRODUCTS, m_wndUnlicensedProducts);
  402. DDX_Control(pDX, IDC_LIST_PRODUCTS, m_wndProductList);
  403. //}}AFX_DATA_MAP
  404. }
  405. BEGIN_MESSAGE_MAP(CLicCompWizPage4, CPropertyPage)
  406. //{{AFX_MSG_MAP(CLicCompWizPage4)
  407. ON_BN_CLICKED(IDC_BUT_PRINT, OnPrintButton)
  408. ON_NOTIFY(NM_OUTOFMEMORY, IDC_LIST_PRODUCTS, OnListProductsOutOfMemory)
  409. ON_WM_DESTROY()
  410. ON_WM_SETCURSOR()
  411. //}}AFX_MSG_MAP
  412. END_MESSAGE_MAP()
  413. void CLicCompWizPage4::PumpMessages()
  414. {
  415. // Must call Create() before using the dialog
  416. ASSERT(m_hWnd!=NULL);
  417. MSG msg;
  418. try
  419. {
  420. // Handle dialog messages
  421. while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  422. {
  423. if(!IsDialogMessage(&msg))
  424. {
  425. TranslateMessage(&msg);
  426. DispatchMessage(&msg);
  427. }
  428. }
  429. }
  430. catch(...)
  431. {
  432. TRACE(_T("Exception in CLicCompWizPage4::PumpMessages()\n"));
  433. }
  434. }
  435. BOOL CLicCompWizPage4::FillListCtrl(LPTSTR pszProduct, WORD wInUse, WORD wPurchased)
  436. {
  437. TCHAR pszLicenses[BUFFER_SIZE];
  438. ::wsprintf(pszLicenses, _T("%u"), wInUse - wPurchased);
  439. USHORT nIndex;
  440. LV_ITEM lvi;
  441. lvi.mask = LVIF_TEXT | LVIF_PARAM;
  442. lvi.iItem = 0;
  443. lvi.iSubItem = 0;
  444. lvi.lParam = MAKELONG(wInUse, wPurchased);
  445. lvi.pszText = pszProduct;
  446. if ((nIndex = (USHORT)m_wndProductList.InsertItem(&lvi)) != (USHORT)-1)
  447. {
  448. m_wndProductList.SetItemText(nIndex, 1, pszLicenses);
  449. }
  450. return TRUE;
  451. }
  452. BOOL CLicCompWizPage4::OnInitDialog()
  453. {
  454. CPropertyPage::OnInitDialog();
  455. // Set the header text for the list control.
  456. CRect rcList;
  457. m_wndProductList.GetWindowRect(&rcList);
  458. CString strColumnTitle;
  459. LV_COLUMN lvc;
  460. lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
  461. lvc.fmt = LVCFMT_LEFT;
  462. USHORT nColumns = COLUMNS;
  463. UINT uStringID[COLUMNS] = {IDS_PRODUCTS_LIST, IDS_LICENSES_LIST};
  464. for (USHORT i = 0; i < nColumns; i++)
  465. {
  466. strColumnTitle.LoadString(uStringID[i]);
  467. lvc.pszText = strColumnTitle.GetBuffer(strColumnTitle.GetLength());
  468. lvc.cx = rcList.Width() / COLUMNS;
  469. m_wndProductList.InsertColumn(i, &lvc);
  470. strColumnTitle.ReleaseBuffer();
  471. }
  472. CLicCompWizSheet* pSheet = (CLicCompWizSheet*)GetParent();
  473. // Store the text on the cancel button.
  474. CButton* pCancel = (CButton*)pSheet->GetDlgItem(IDCANCEL);
  475. pCancel->GetWindowText(m_strCancel);
  476. CRect rcText;
  477. // Create the large and small extents for the static text control.
  478. m_wndUnlicensedProducts.GetWindowRect(&rcText);
  479. m_sizeSmallText.cx = rcText.right - rcText.left;
  480. m_sizeSmallText.cy = rcText.bottom - rcText.top;
  481. // Make the large extents match those for the list control.
  482. m_sizeLargeText.cx = rcList.right - rcList.left;
  483. m_sizeLargeText.cy = rcList.bottom - rcList.top;
  484. return TRUE; // return TRUE unless you set the focus to a control
  485. // EXCEPTION: OCX Property Pages should return FALSE
  486. }
  487. void CLicCompWizPage4::OnListProductsOutOfMemory(NMHDR* pNMHDR, LRESULT* pResult)
  488. {
  489. AfxMessageBox(IDS_MEM_ERROR, MB_OK | MB_ICONSTOP);
  490. CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp();
  491. // Let the license thread know it's supposed to quit.
  492. pApp->NotifyLicenseThread(TRUE);
  493. *pResult = 0;
  494. }
  495. void CLicCompWizPage4::OnPrintButton()
  496. {
  497. CDC dc;
  498. CPrintDialog dlg(FALSE,
  499. PD_ALLPAGES | PD_USEDEVMODECOPIESANDCOLLATE |
  500. PD_NOPAGENUMS | PD_HIDEPRINTTOFILE |
  501. PD_NOSELECTION,
  502. this);
  503. if (dlg.DoModal() == IDOK)
  504. {
  505. CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp();
  506. m_wndPrint.RedrawWindow();
  507. DOCINFO di;
  508. CString strDocName;
  509. strDocName.Format(IDS_DOC_NAME, pApp->m_strEnterpriseServer);
  510. di.cbSize = sizeof(DOCINFO);
  511. di.lpszDocName = strDocName.GetBuffer(BUFFER_SIZE);
  512. di.lpszOutput = NULL;
  513. if (dc.Attach(dlg.GetPrinterDC()))
  514. {
  515. PrepareForPrinting(dc);
  516. dc.StartDoc(&di);
  517. PrintReport(dc);
  518. dc.EndDoc();
  519. dc.DeleteDC();
  520. ::GlobalFree(dlg.m_pd.hDevNames);
  521. ::GlobalFree(dlg.m_pd.hDevMode);
  522. }
  523. }
  524. }
  525. BOOL CLicCompWizPage4::PrepareForPrinting(CDC& dc)
  526. {
  527. // Create various fonts...
  528. CString strFont;
  529. // Create a heading font.
  530. strFont.LoadString(IDS_FONT_BOLD);
  531. m_fontHeading.CreatePointFont(FONT_SIZE_HEADING, strFont, &dc);
  532. // Create a bold, underlined header font.
  533. strFont.LoadString(IDS_FONT_BOLD);
  534. m_fontHeader.CreatePointFont(FONT_SIZE, strFont, &dc);
  535. LOGFONT lf;
  536. m_fontHeader.GetLogFont(&lf);
  537. m_fontHeader.DeleteObject();
  538. lf.lfUnderline = TRUE;
  539. m_fontHeader.CreateFontIndirect(&lf);
  540. // Create a footer font.
  541. strFont.LoadString(IDS_FONT_BOLD);
  542. m_fontFooter.CreatePointFont(FONT_SIZE_FOOTER, strFont, &dc);
  543. // Create a default font.
  544. strFont.LoadString(IDS_FONT);
  545. m_fontNormal.CreatePointFont(FONT_SIZE, strFont, &dc);
  546. // Get the text metrics for each font.
  547. CFont* pOldFont = dc.SelectObject(&m_fontHeading);
  548. dc.GetTextMetrics(&m_tmHeading);
  549. dc.SelectObject(&m_fontHeader);
  550. dc.GetTextMetrics(&m_tmHeader);
  551. dc.SelectObject(&m_fontFooter);
  552. dc.GetTextMetrics(&m_tmFooter);
  553. dc.SelectObject(&m_fontNormal);
  554. dc.GetTextMetrics(&m_tmNormal);
  555. // Select the original font back in to the device context.
  556. dc.SelectObject(pOldFont);
  557. // Set the horizontal and vertical margins.
  558. m_nHorzMargin = (LONG)(dc.GetDeviceCaps(LOGPIXELSX) * HORZ_MARGIN);
  559. m_nVertMargin = (LONG)(dc.GetDeviceCaps(LOGPIXELSY) * VERT_MARGIN);
  560. // Get the printable page offsets for the origin.
  561. m_ptOrg.x = dc.GetDeviceCaps(PHYSICALOFFSETX);
  562. m_ptOrg.y = dc.GetDeviceCaps(PHYSICALOFFSETY);
  563. dc.SetWindowOrg(m_ptOrg);
  564. m_ptOrg.x += m_nHorzMargin;
  565. m_ptOrg.y += m_nVertMargin;
  566. // Get the printable page offsets for the page extents.
  567. m_ptExt.x = dc.GetDeviceCaps(PHYSICALWIDTH) - m_ptOrg.x;
  568. m_ptExt.y = dc.GetDeviceCaps(PHYSICALHEIGHT) - m_ptOrg.y;
  569. dc.SetViewportOrg(m_ptOrg);
  570. CalculateTabs(dc);
  571. return TRUE;
  572. }
  573. BOOL CLicCompWizPage4::PrintReport(CDC& dc)
  574. {
  575. // Set the starting point for printing.
  576. m_ptPrint.x = m_ptPrint.y = 0;
  577. // Prepare to print a heading.
  578. CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp();
  579. CString strHeading;
  580. CFont* pOldFont = dc.SelectObject(&m_fontHeading);
  581. strHeading.Format(IDS_DOC_NAME, pApp->m_strEnterpriseServer);
  582. dc.StartPage();
  583. CRect rc(m_ptPrint.x, m_ptPrint.y, m_ptExt.x - m_ptOrg.x, m_tmHeading.tmHeight);
  584. // Calculate the size of the rectangle needed to draw the text.
  585. m_ptPrint.y += dc.DrawText(strHeading, &rc, DT_EXTERNALLEADING | DT_CENTER | DT_WORDBREAK | DT_NOCLIP);
  586. // Normalize the rectangle.
  587. rc.NormalizeRect();
  588. // Add a blank line below the heading.
  589. m_ptPrint.y += m_tmHeading.tmHeight;
  590. // Move the right side of the rectangle out to the right margin so text is properly centered.
  591. rc.right = m_ptExt.x - m_ptOrg.x;
  592. // Draw the text in the rectangle.
  593. dc.DrawText(strHeading, &rc, DT_EXTERNALLEADING | DT_CENTER | DT_WORDBREAK | DT_NOCLIP);
  594. dc.SelectObject(pOldFont);
  595. PrintPages(dc, 100);
  596. // Delete the fonts.
  597. m_fontNormal.DeleteObject();
  598. m_fontHeader.DeleteObject();
  599. m_fontFooter.DeleteObject();
  600. m_fontHeading.DeleteObject();
  601. return TRUE;
  602. }
  603. BOOL CLicCompWizPage4::PrintPageHeader(CDC& dc)
  604. {
  605. CFont* pOldFont = dc.SelectObject(&m_fontHeader);
  606. dc.StartPage();
  607. CString strHeader, strProducts, strLicenses, strPurchased, strUsed;
  608. strProducts.LoadString(IDS_PRODUCTS);
  609. strLicenses.LoadString(IDS_LICENSES);
  610. strPurchased.LoadString(IDS_PURCHASED);
  611. strUsed.LoadString(IDS_USED);
  612. strHeader.Format(_T("%s\t%s\t%s\t%s"), strProducts, strLicenses,
  613. strPurchased, strUsed);
  614. dc.TabbedTextOut(m_ptPrint.x, m_ptPrint.y, strHeader, PRINT_COLUMNS, m_pTabs, 0);
  615. m_ptPrint.y += ((m_tmHeader.tmHeight + m_tmHeader.tmExternalLeading) * 2);
  616. dc.SelectObject(pOldFont);
  617. return TRUE;
  618. }
  619. BOOL CLicCompWizPage4::PrintPageFooter(CDC& dc, USHORT nPage)
  620. {
  621. CFont* pOldFont = dc.SelectObject(&m_fontFooter);
  622. CString strFooter;
  623. CTime time(CTime::GetCurrentTime());
  624. strFooter.Format(IDS_PAGE_DATE, nPage, time.Format(IDS_FMT_DATE));
  625. CRect rc(m_ptPrint.x, m_ptExt.y - m_nVertMargin, m_ptOrg.x, m_tmFooter.tmHeight);
  626. // Calculate the size of the rectangle needed to draw the text.
  627. m_ptPrint.y += dc.DrawText(strFooter, &rc, DT_CALCRECT | DT_EXTERNALLEADING | DT_CENTER | DT_WORDBREAK | DT_NOCLIP);
  628. // Move the right side of the rectangle out to the right margin so text is properly centered.
  629. rc.right = m_ptExt.x - m_ptOrg.x;
  630. // Draw the text in the rectangle.
  631. dc.DrawText(strFooter, &rc, DT_EXTERNALLEADING | DT_CENTER | DT_WORDBREAK | DT_NOCLIP);
  632. dc.EndPage();
  633. dc.SelectObject(pOldFont);
  634. return TRUE;
  635. }
  636. BOOL CLicCompWizPage4::PrintPages(CDC& dc, UINT nStart)
  637. {
  638. CFont* pOldFont = dc.SelectObject(&m_fontNormal);
  639. UINT nPage = 1;
  640. UINT nItems = m_wndProductList.GetItemCount();
  641. // Print the initial header.
  642. PrintPageHeader(dc);
  643. DWORD dwParam = 0;
  644. CString strTextOut;
  645. for (UINT i = 0; i < nItems; i++)
  646. {
  647. dwParam = (DWORD)m_wndProductList.GetItemData(i);
  648. CString strProduct = m_wndProductList.GetItemText(i, 0);
  649. CSize sizeProduct = dc.GetTextExtent(strProduct);
  650. if (sizeProduct.cx > m_pTabs[0] - (m_tmNormal.tmAveCharWidth * TAB_WIDTH))
  651. TruncateText(dc, strProduct);
  652. // Format the output text.
  653. strTextOut.Format(_T("%s\t%s\t%u\t%u"), strProduct,
  654. m_wndProductList.GetItemText(i, 1),
  655. HIWORD(dwParam), LOWORD(dwParam));
  656. dc.TabbedTextOut(m_ptPrint.x, m_ptPrint.y, strTextOut, PRINT_COLUMNS, m_pTabs, 0);
  657. // Calculate the vertical position for the next line of text.
  658. m_ptPrint.y += m_tmNormal.tmHeight + m_tmNormal.tmExternalLeading;
  659. if ((m_ptPrint.y + m_ptOrg.y) >= m_ptExt.y)
  660. {
  661. PrintPageFooter(dc, nPage++);
  662. // Reset the printing position.
  663. m_ptPrint.y = 0;
  664. PrintPageHeader(dc);
  665. }
  666. }
  667. // Print the final footer.
  668. PrintPageFooter(dc, (USHORT)nPage);
  669. dc.SelectObject(pOldFont);
  670. return TRUE;
  671. }
  672. void CLicCompWizPage4::TruncateText(CDC& dc, CString& strInput)
  673. {
  674. CString strText, strEllipsis;
  675. USHORT nLen, nChars = 0;
  676. UINT nMaxWidth = m_pTabs[0] - (m_tmNormal.tmAveCharWidth * TAB_WIDTH);
  677. nLen = (USHORT)strInput.GetLength();
  678. strEllipsis.LoadString(IDS_ELLIPSIS);
  679. CSize sizeText = dc.GetTextExtent(strInput);
  680. // Keep lopping off characters until the string is short enough.
  681. while ((UINT)sizeText.cx > nMaxWidth)
  682. {
  683. strText = strInput.Left(nLen - nChars++);
  684. sizeText = dc.GetTextExtent(strText);
  685. }
  686. // Remove the last characters and replace them with an ellipsis.
  687. ASSERT(strText.GetLength() > strEllipsis.GetLength());
  688. strInput = strText.Left(strText.GetLength() - strEllipsis.GetLength()) + strEllipsis;
  689. }
  690. BOOL CLicCompWizPage4::CalculateTabs(CDC& dc)
  691. {
  692. INT nTotalExt = 0;
  693. INT nTabSize = TAB_WIDTH * m_tmHeader.tmAveCharWidth;
  694. UINT uStrIds[] = {IDS_LICENSES, IDS_PURCHASED, IDS_USED};
  695. m_pTabs[0] = 0;
  696. for (USHORT i = 1; i < PRINT_COLUMNS; i++)
  697. {
  698. CString strText;
  699. strText.LoadString(uStrIds[i - 1]);
  700. // Get the text extent for each string.
  701. m_pTabs[i] = dc.GetTextExtent(strText).cx;
  702. // Keep a running total of the extents.
  703. nTotalExt += m_pTabs[i];
  704. }
  705. // Add tab space between columns.
  706. nTotalExt += nTabSize * (PRINT_COLUMNS - 2);
  707. // The second column will begin at the difference between the right
  708. // margin and the total extent.
  709. m_pTabs[0] = m_ptExt.x - m_ptOrg.x - nTotalExt;
  710. // Now set the actual tab positions in the array.
  711. for (i = 1; i < PRINT_COLUMNS; i++)
  712. {
  713. m_pTabs[i] += m_pTabs[i - 1] + nTabSize;
  714. }
  715. return TRUE;
  716. }
  717. LRESULT CLicCompWizPage4::OnWizardBack()
  718. {
  719. CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp();
  720. // Let the license thread know it's time to quit.
  721. pApp->NotifyLicenseThread(TRUE);
  722. CLicCompWizSheet* pSheet = (CLicCompWizSheet*)GetParent();
  723. // Set the cancel button text back to "Cancel."
  724. CButton* pCancel = (CButton*)pSheet->GetDlgItem(IDCANCEL);
  725. pCancel->SetWindowText(m_strCancel);
  726. if (pSheet->m_Page1.m_nRadio == 0)
  727. return IDD_PROPPAGE1;
  728. else
  729. return CPropertyPage::OnWizardBack();
  730. }
  731. void CLicCompWizPage4::OnDestroy()
  732. {
  733. CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp();
  734. pApp->NotifyLicenseThread(TRUE);
  735. PumpMessages();
  736. CPropertyPage::OnDestroy();
  737. }
  738. BOOL CLicCompWizPage4::OnSetActive()
  739. {
  740. CLicCompWizSheet* pSheet = (CLicCompWizSheet*)GetParent();
  741. pSheet->SetWizardButtons(PSWIZB_BACK);
  742. // Hide the list control and clear it.
  743. m_wndProductList.ShowWindow(SW_HIDE);
  744. m_wndProductList.DeleteAllItems();
  745. // Hide the print button.
  746. m_wndPrint.ShowWindow(SW_HIDE);
  747. CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp();
  748. // Make sure the last thread has terminated before starting a new one.
  749. if (pApp->m_pLicenseThread != NULL)
  750. {
  751. pApp->NotifyLicenseThread(TRUE);
  752. CEvent event(TRUE, TRUE, pszLicenseEvent);
  753. CSingleLock lock(&event);
  754. lock.Lock();
  755. }
  756. // Keep a pointer to the thread so we can find out if it's still running.
  757. pApp->m_pLicenseThread = AfxBeginThread((AFX_THREADPROC)GetLicenseInfo, (LPVOID)this);
  758. return CPropertyPage::OnSetActive();
  759. }
  760. LRESULT CLicCompWizPage3::OnWizardNext()
  761. {
  762. CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp();
  763. m_wndEnterprise.GetWindowText(pApp->m_strEnterprise);
  764. // Trim off any white space in the enterprise name.
  765. pApp->m_strEnterprise.TrimLeft();
  766. pApp->m_strEnterprise.TrimRight();
  767. if (pApp->m_strEnterprise.IsEmpty() ||
  768. pApp->m_strEnterprise.Find(_T("\\\\")) != -1)
  769. {
  770. AfxMessageBox(IDS_SPECIFY_DOMAIN, MB_OK | MB_ICONEXCLAMATION);
  771. return IDD;
  772. }
  773. return CPropertyPage::OnWizardNext();
  774. }
  775. BOOL CLicCompWizPage4::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
  776. {
  777. CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp();
  778. if (pApp->m_pLicenseThread == NULL)
  779. {
  780. return CPropertyPage::OnSetCursor(pWnd, nHitTest, message);
  781. }
  782. else
  783. {
  784. // Restore the wait cursor if the thread is running.
  785. RestoreWaitCursor();
  786. return TRUE;
  787. }
  788. }