/*++ Copyright (c) 1994-95 Microsoft Corporation Module Name: usrppgp.cpp Abstract: User property page (products) implementation. Author: Don Ryan (donryan) 05-Feb-1995 Environment: User Mode - Win32 Revision History: Jeff Parham (jeffparh) 30-Jan-1996 o Added new element to LV_COLUMN_ENTRY to differentiate the string used for the column header from the string used in the menus (so that the menu option can contain hot keys). --*/ #include "stdafx.h" #include "llsmgr.h" #include "usrppgp.h" #include "prdpsht.h" #define LVID_PRODUCT 0 #define LVID_LAST_USED 1 #define LVID_TOTAL_USED 2 #define LVCX_PRODUCT 40 #define LVCX_LAST_USED 30 #define LVCX_TOTAL_USED -1 static LV_COLUMN_INFO g_productColumnInfo = { 0, 0, 3, {{LVID_PRODUCT, IDS_PRODUCT, 0, LVCX_PRODUCT }, {LVID_LAST_USED, IDS_LAST_DATE_USED, 0, LVCX_LAST_USED }, {LVID_TOTAL_USED, IDS_USAGE_COUNT, 0, LVCX_TOTAL_USED}}, }; #ifdef _DEBUG #undef THIS_FILE static char BASED_CODE THIS_FILE[] = __FILE__; #endif IMPLEMENT_DYNCREATE(CUserPropertyPageProducts, CPropertyPage) BEGIN_MESSAGE_MAP(CUserPropertyPageProducts, CPropertyPage) //{{AFX_MSG_MAP(CUserPropertyPageProducts) ON_BN_CLICKED(IDC_PP_USER_PRODUCTS_DELETE, OnDelete) ON_BN_CLICKED(IDC_PP_USER_PRODUCTS_BACKOFFICE, OnBackOfficeUpgrade) ON_NOTIFY(NM_DBLCLK, IDC_PP_USER_PRODUCTS_PRODUCTS, OnDblClkProducts) ON_NOTIFY(NM_RETURN, IDC_PP_USER_PRODUCTS_PRODUCTS, OnReturnProducts) ON_NOTIFY(NM_SETFOCUS, IDC_PP_USER_PRODUCTS_PRODUCTS, OnSetFocusProducts) ON_NOTIFY(NM_KILLFOCUS, IDC_PP_USER_PRODUCTS_PRODUCTS, OnKillFocusProducts) ON_NOTIFY(LVN_COLUMNCLICK, IDC_PP_USER_PRODUCTS_PRODUCTS, OnColumnClickProducts) ON_NOTIFY(LVN_GETDISPINFO, IDC_PP_USER_PRODUCTS_PRODUCTS, OnGetDispInfoProducts) ON_WM_DESTROY() //}}AFX_MSG_MAP END_MESSAGE_MAP() CUserPropertyPageProducts::CUserPropertyPageProducts() : CPropertyPage(CUserPropertyPageProducts::IDD) /*++ Routine Description: Constructor for user property page (products). Arguments: None. Return Values: None. --*/ { //{{AFX_DATA_INIT(CUserPropertyPageProducts) m_bUseBackOffice = FALSE; //}}AFX_DATA_INIT m_pUser = NULL; m_pUpdateHint = NULL; m_bProductProperties = TRUE; m_bAreCtrlsInitialized = FALSE; } CUserPropertyPageProducts::~CUserPropertyPageProducts() /*++ Routine Description: Destructor for user property page (products). Arguments: None. Return Values: None. --*/ { // // Nothing to do here... // } void CUserPropertyPageProducts::DoDataExchange(CDataExchange* pDX) /*++ Routine Description: Called by framework to exchange dialog data. Arguments: pDX - data exchange object. Return Values: None. --*/ { CPropertyPage::DoDataExchange(pDX); //{{AFX_DATA_MAP(CUserPropertyPageProducts) DDX_Control(pDX, IDC_PP_USER_PRODUCTS_BACKOFFICE, m_upgBtn); DDX_Control(pDX, IDC_PP_USER_PRODUCTS_DELETE, m_delBtn); DDX_Control(pDX, IDC_PP_USER_PRODUCTS_PRODUCTS, m_productList); DDX_Check(pDX, IDC_PP_USER_PRODUCTS_BACKOFFICE, m_bUseBackOffice); //}}AFX_DATA_MAP } void CUserPropertyPageProducts::InitCtrls() /*++ Routine Description: Initializes property page controls. Arguments: None. Return Values: None. --*/ { m_upgBtn.SetCheck(0); m_delBtn.EnableWindow(FALSE); m_productList.SetFocus(); m_bAreCtrlsInitialized = TRUE; ::LvInitColumns(&m_productList, &g_productColumnInfo); } void CUserPropertyPageProducts::InitPage(CUser* pUser, DWORD* pUpdateHint, BOOL bProductProperties) /*++ Routine Description: Initializes property page. Arguments: pUser - user object. pUpdateHint - update hint. bProductProperties - to recurse or not Return Values: None. --*/ { ASSERT(pUpdateHint); VALIDATE_OBJECT(pUser, CUser); m_pUser = pUser; m_pUpdateHint = pUpdateHint; m_bProductProperties = bProductProperties; } void CUserPropertyPageProducts::AbortPageIfNecessary() /*++ Routine Description: Displays status and aborts if connection lost. Arguments: None. Return Values: None. --*/ { theApp.DisplayLastStatus(); if (IsConnectionDropped(LlsGetLastStatus())) { AbortPage(); // bail... } } void CUserPropertyPageProducts::AbortPage() /*++ Routine Description: Aborts property page. Arguments: None. Return Values: None. --*/ { *m_pUpdateHint = UPDATE_INFO_ABORT; GetParent()->PostMessage(WM_COMMAND, IDCANCEL); } BOOL CUserPropertyPageProducts::OnInitDialog() /*++ Routine Description: Message handler for WM_INITDIALOG. Arguments: None. Return Values: Return false if focus set manually. --*/ { CPropertyPage::OnInitDialog(); PostMessage(WM_COMMAND, ID_INIT_CTRLS); return TRUE; } void CUserPropertyPageProducts::OnDestroy() /*++ Routine Description: Message handler for WM_DESTROY. Arguments: None. Return Values: None. --*/ { ::LvReleaseObArray(&m_productList); // release now... CPropertyPage::OnDestroy(); } BOOL CUserPropertyPageProducts::OnSetActive() /*++ Routine Description: Activates property page. Arguments: None. Return Values: Returns true if focus accepted. --*/ { BOOL bIsActivated; if (bIsActivated = CPropertyPage::OnSetActive()) { if (IsProductInfoUpdated(*m_pUpdateHint) && !RefreshCtrls()) { AbortPageIfNecessary(); // display error... } } return bIsActivated; } BOOL CUserPropertyPageProducts::RefreshCtrls() /*++ Routine Description: Refreshs property page controls. Arguments: None. Return Values: Returns true if controls refreshed. --*/ { VALIDATE_OBJECT(m_pUser, CUser); BOOL bIsRefreshed = FALSE; VARIANT va; VariantInit(&va); BeginWaitCursor(); // hourglass... CStatistics* pStatistics = (CStatistics*)MKOBJ(m_pUser->GetStatistics(va)); if (pStatistics) { VALIDATE_OBJECT(pStatistics, CStatistics); bIsRefreshed = ::LvRefreshObArray( &m_productList, &g_productColumnInfo, pStatistics->m_pObArray ); pStatistics->InternalRelease(); // add ref'd individually... } if (!bIsRefreshed) { ::LvReleaseObArray(&m_productList); // reset list now... } EndWaitCursor(); // hourglass... PostMessage(WM_COMMAND, ID_INIT_CTRLS); return bIsRefreshed; } void CUserPropertyPageProducts::OnDelete() /*++ Routine Description: Revokes license from user. Arguments: None. Return Values: None. --*/ { CStatistic* pStatistic; if (pStatistic = (CStatistic*)::LvGetSelObj(&m_productList)) { VALIDATE_OBJECT(pStatistic, CStatistic); CString strConfirm; AfxFormatString2( strConfirm, IDP_CONFIRM_REVOKE_LICENSE, m_pUser->m_strName, pStatistic->m_strEntry ); if (AfxMessageBox(strConfirm, MB_YESNO) == IDYES) { NTSTATUS NtStatus; BeginWaitCursor(); // hourglass... NtStatus = ::LlsUserProductDelete( LlsGetActiveHandle(), MKSTR(m_pUser->m_strName), MKSTR(pStatistic->m_strEntry) ); EndWaitCursor(); // hourglass... if (NtStatus == STATUS_OBJECT_NAME_NOT_FOUND) NtStatus = STATUS_SUCCESS; LlsSetLastStatus(NtStatus); // called api... if (NT_SUCCESS(NtStatus)) { *m_pUpdateHint |= UPDATE_LICENSE_REVOKED; if (!RefreshCtrls()) { AbortPageIfNecessary(); // display error... } } else { AbortPageIfNecessary(); // display error... } } } } BOOL CUserPropertyPageProducts::OnKillActive() /*++ Routine Description: Processes backoffice upgrade. Arguments: None. Return Values: Returns true if upgrade processed successfully. --*/ { if (m_pUser->m_bIsBackOffice != m_upgBtn.GetCheck()) { NTSTATUS NtStatus; LLS_USER_INFO_1 UserInfo1; UserInfo1.Name = MKSTR(m_pUser->m_strName); UserInfo1.Group = MKSTR(m_pUser->m_strMapping); UserInfo1.Licensed = m_pUser->m_lInUse; UserInfo1.UnLicensed = m_pUser->m_lUnlicensed; UserInfo1.Flags = m_upgBtn.GetCheck() ? LLS_FLAG_SUITE_USE : 0; BeginWaitCursor(); // hourglass... NtStatus = ::LlsUserInfoSet( LlsGetActiveHandle(), MKSTR(m_pUser->m_strName), 1, (LPBYTE)&UserInfo1 ); EndWaitCursor(); // hourglass... LlsSetLastStatus(NtStatus); // called api... if (NT_SUCCESS(NtStatus)) { m_pUser->m_bIsBackOffice = m_upgBtn.GetCheck() ? TRUE : FALSE; *m_pUpdateHint |= UPDATE_LICENSE_UPGRADED; SetModified(FALSE); if (!RefreshCtrls()) { AbortPageIfNecessary(); // display error... return FALSE; } } else { AbortPageIfNecessary(); // display error... return FALSE; } } return TRUE; } void CUserPropertyPageProducts::OnBackOfficeUpgrade() /*++ Routine Description: Enables Apply Now button. Arguments: None. Return Values: None. --*/ { SetModified(m_pUser->m_bIsBackOffice != m_upgBtn.GetCheck()); } void CUserPropertyPageProducts::OnDblClkProducts(NMHDR* pNMHDR, LRESULT* pResult) /*++ Routine Description: Notification handler for NM_DBLCLK. Arguments: pNMHDR - notification header. pResult - return code. Return Values: None. --*/ { ViewProductProperties(); *pResult = 0; } void CUserPropertyPageProducts::OnReturnProducts(NMHDR* pNMHDR, LRESULT* pResult) /*++ Routine Description: Notification handler for NM_RETURN. Arguments: pNMHDR - notification header. pResult - return code. Return Values: None. --*/ { ViewProductProperties(); *pResult = 0; } void CUserPropertyPageProducts::OnSetFocusProducts(NMHDR* pNMHDR, LRESULT* pResult) /*++ Routine Description: Notification handler for NM_SETFOCUS. Arguments: pNMHDR - notification header. pResult - return code. Return Values: None. --*/ { PostMessage(WM_COMMAND, ID_INIT_CTRLS); *pResult = 0; } void CUserPropertyPageProducts::OnKillFocusProducts(NMHDR* pNMHDR, LRESULT* pResult) /*++ Routine Description: Notification handler for NM_KILLFOCUS. Arguments: pNMHDR - notification header. pResult - return code. Return Values: None. --*/ { ::LvSelObjIfNecessary(&m_productList); // ensure selection... PostMessage(WM_COMMAND, ID_INIT_CTRLS); *pResult = 0; } BOOL CUserPropertyPageProducts::OnCommand(WPARAM wParam, LPARAM lParam) /*++ Routine Description: Message handler for WM_COMMAND. Arguments: wParam - message specific. lParam - message specific. Return Values: Returns true if message processed. --*/ { if (wParam == ID_INIT_CTRLS) { if (!m_bAreCtrlsInitialized) { InitCtrls(); if (!RefreshCtrls()) { AbortPageIfNecessary(); // display error... } } m_upgBtn.SetCheck(m_pUser->m_bIsBackOffice); ::SafeEnableWindow( &m_delBtn, &m_productList, CDialog::GetFocus(), m_productList.GetItemCount() ); return TRUE; // processed... } return CDialog::OnCommand(wParam, lParam); } void CUserPropertyPageProducts::OnColumnClickProducts(NMHDR* pNMHDR, LRESULT* pResult) /*++ Routine Description: Notification handler for LVN_COLUMNCLICK. Arguments: pNMHDR - notification header. pResult - return code. Return Values: None. --*/ { g_productColumnInfo.bSortOrder = GetKeyState(VK_CONTROL) < 0; g_productColumnInfo.nSortedItem = ((NM_LISTVIEW*)pNMHDR)->iSubItem; m_productList.SortItems(CompareUserProducts, 0); // use column info *pResult = 0; } void CUserPropertyPageProducts::ViewProductProperties() /*++ Routine Description: Recurse into product property page. Arguments: None. Return Values: None. --*/ { CStatistic* pStatistic; if (!m_bProductProperties) { ::MessageBeep(MB_OK); return; // bail... } if (pStatistic = (CStatistic*)::LvGetSelObj(&m_productList)) { VALIDATE_OBJECT(pStatistic, CStatistic); CProduct* pProduct = new CProduct(NULL, pStatistic->m_strEntry); if (pProduct) { CString strTitle; AfxFormatString1(strTitle, IDS_PROPERTIES_OF, pProduct->m_strName); CProductPropertySheet productProperties(strTitle); productProperties.InitPages(pProduct, FALSE); productProperties.DoModal(); *m_pUpdateHint |= productProperties.m_fUpdateHint; if (IsUpdateAborted(productProperties.m_fUpdateHint)) { AbortPage(); // don't display error... } else if (IsProductInfoUpdated(productProperties.m_fUpdateHint) && !RefreshCtrls()) { AbortPageIfNecessary(); // display error... } } else { AbortPageIfNecessary(); // display error... } if (pProduct) pProduct->InternalRelease(); // delete object... } } void CUserPropertyPageProducts::OnGetDispInfoProducts(NMHDR* pNMHDR, LRESULT* pResult) /*++ Routine Description: Notification handler for LVN_GETDISPINFO. Arguments: pNMHDR - notification header. pResult - return code. Return Values: None. --*/ { LV_ITEM* plvItem = &((LV_DISPINFO*)pNMHDR)->item; ASSERT(plvItem); CStatistic* pStatistic = (CStatistic*)plvItem->lParam; VALIDATE_OBJECT(pStatistic, CStatistic); switch (plvItem->iSubItem) { case LVID_PRODUCT: plvItem->iImage = pStatistic->m_bIsValid ? BMPI_PRODUCT_PER_SEAT : BMPI_VIOLATION; lstrcpyn(plvItem->pszText, pStatistic->m_strEntry, plvItem->cchTextMax); break; case LVID_LAST_USED: { BSTR bstrDateLastUsed = pStatistic->GetLastUsedString(); if( bstrDateLastUsed != NULL ) { lstrcpyn(plvItem->pszText, bstrDateLastUsed, plvItem->cchTextMax); SysFreeString(bstrDateLastUsed); } else { lstrcpy(plvItem->pszText, L""); } } break; case LVID_TOTAL_USED: { CString strLabel; strLabel.Format(_T("%ld"), pStatistic->GetTotalUsed()); lstrcpyn(plvItem->pszText, strLabel, plvItem->cchTextMax); } break; } *pResult = 0; } int CALLBACK CompareUserProducts(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) /*++ Routine Description: Notification handler for LVM_SORTITEMS. Arguments: lParam1 - object to sort. lParam2 - object to sort. lParamSort - sort criteria. Return Values: Same as lstrcmp. --*/ { #define pStatistic1 ((CStatistic*)lParam1) #define pStatistic2 ((CStatistic*)lParam2) VALIDATE_OBJECT(pStatistic1, CStatistic); VALIDATE_OBJECT(pStatistic2, CStatistic); int iResult; switch (g_productColumnInfo.nSortedItem) { case LVID_PRODUCT: iResult = pStatistic1->m_strEntry.CompareNoCase(pStatistic2->m_strEntry); break; case LVID_LAST_USED: iResult = pStatistic1->m_lLastUsed - pStatistic2->m_lLastUsed; break; case LVID_TOTAL_USED: iResult = pStatistic1->GetTotalUsed() - pStatistic2->GetTotalUsed(); break; default: iResult = 0; break; } return g_productColumnInfo.bSortOrder ? -iResult : iResult; }