/*++ Copyright (c) 1994-95 Microsoft Corporation Module Name: prdppgu.cpp Abstract: Product property page (users) implementation. Author: Don Ryan (donryan) 02-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 "prdppgu.h" #include "usrpsht.h" #define LVID_USER 0 #define LVID_LAST_USED 1 #define LVID_TOTAL_USED 2 #define LVCX_USER 40 #define LVCX_LAST_USED 30 #define LVCX_TOTAL_USED -1 static LV_COLUMN_INFO g_userColumnInfo = { 0, 0, 3, {{LVID_USER, IDS_USER, 0, LVCX_USER }, {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(CProductPropertyPageUsers, CPropertyPage) BEGIN_MESSAGE_MAP(CProductPropertyPageUsers, CPropertyPage) //{{AFX_MSG_MAP(CProductPropertyPageUsers) ON_BN_CLICKED(IDC_PP_PRODUCT_USERS_DELETE, OnDelete) ON_NOTIFY(NM_DBLCLK, IDC_PP_PRODUCT_USERS_USERS, OnDblClkUsers) ON_NOTIFY(NM_RETURN, IDC_PP_PRODUCT_USERS_USERS, OnReturnUsers) ON_NOTIFY(NM_SETFOCUS, IDC_PP_PRODUCT_USERS_USERS, OnSetFocusUsers) ON_NOTIFY(NM_KILLFOCUS, IDC_PP_PRODUCT_USERS_USERS, OnKillFocusUsers) ON_NOTIFY(LVN_COLUMNCLICK, IDC_PP_PRODUCT_USERS_USERS, OnColumnClickUsers) ON_NOTIFY(LVN_GETDISPINFO, IDC_PP_PRODUCT_USERS_USERS, OnGetDispInfoUsers) ON_WM_DESTROY() //}}AFX_MSG_MAP END_MESSAGE_MAP() CProductPropertyPageUsers::CProductPropertyPageUsers() : CPropertyPage(CProductPropertyPageUsers::IDD) /*++ Routine Description: Constructor for product property page (users). Arguments: None. Return Values: None. --*/ { //{{AFX_DATA_INIT(CProductPropertyPageUsers) //}}AFX_DATA_INIT m_pProduct = NULL; m_pUpdateHint = NULL; m_bUserProperties = FALSE; m_bAreCtrlsInitialized = FALSE; } CProductPropertyPageUsers::~CProductPropertyPageUsers() /*++ Routine Description: Destructor for product property page (users). Arguments: None. Return Values: None. --*/ { // // Nothing to do here. // } void CProductPropertyPageUsers::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(CProductPropertyPageUsers) DDX_Control(pDX, IDC_PP_PRODUCT_USERS_DELETE, m_delBtn); DDX_Control(pDX, IDC_PP_PRODUCT_USERS_USERS, m_userList); //}}AFX_DATA_MAP } void CProductPropertyPageUsers::InitCtrls() /*++ Routine Description: Initializes property page controls. Arguments: None. Return Values: None. --*/ { m_userList.SetFocus(); m_delBtn.EnableWindow(FALSE); m_bAreCtrlsInitialized = TRUE; ::LvInitColumns(&m_userList, &g_userColumnInfo); } void CProductPropertyPageUsers::InitPage( CProduct* pProduct, DWORD* pUpdateHint, BOOL bUserProperties ) /*++ Routine Description: Initializes property page. Arguments: pProduct - product object. pUpdateHint - update hint. bUserProperties - to recurse or not. Return Values: None. --*/ { ASSERT(pUpdateHint); VALIDATE_OBJECT(pProduct, CProduct); m_pProduct = pProduct; m_pUpdateHint = pUpdateHint; m_bUserProperties = bUserProperties; } void CProductPropertyPageUsers::AbortPageIfNecessary() /*++ Routine Description: Displays status and aborts if connection lost. Arguments: None. Return Values: None. --*/ { theApp.DisplayLastStatus(); if (IsConnectionDropped(LlsGetLastStatus())) { AbortPage(); // bail... } } void CProductPropertyPageUsers::AbortPage() /*++ Routine Description: Aborts property page. Arguments: None. Return Values: None. --*/ { *m_pUpdateHint = UPDATE_INFO_ABORT; GetParent()->PostMessage(WM_COMMAND, IDCANCEL); } BOOL CProductPropertyPageUsers::OnInitDialog() /*++ Routine Description: Message handler for WM_INITDIALOG. Arguments: None. Return Values: Returns false if focus set to control manually. --*/ { CPropertyPage::OnInitDialog(); PostMessage(WM_COMMAND, ID_INIT_CTRLS); return TRUE; } void CProductPropertyPageUsers::OnDestroy() /*++ Routine Description: Message handler for WM_DESTROY. Arguments: None. Return Values: None. --*/ { ::LvReleaseObArray(&m_userList); // release now... CPropertyPage::OnDestroy(); } BOOL CProductPropertyPageUsers::OnSetActive() /*++ Routine Description: Activates property page. Arguments: None. Return Values: Returns true if focus accepted. --*/ { BOOL bIsActivated; bIsActivated = CPropertyPage::OnSetActive(); if (FALSE != bIsActivated) { if (IsUserInfoUpdated(*m_pUpdateHint) && !RefreshCtrls()) { AbortPageIfNecessary(); // display error... } } return bIsActivated; } BOOL CProductPropertyPageUsers::RefreshCtrls() /*++ Routine Description: Refreshs property page controls. Arguments: None. Return Values: Returns true if controls refreshed successfully. --*/ { VALIDATE_OBJECT(m_pProduct, CProduct); BOOL bIsRefreshed = FALSE; VARIANT va; VariantInit(&va); BeginWaitCursor(); // hourglass... CStatistics* pStatistics = (CStatistics*)MKOBJ(m_pProduct->GetStatistics(va)); if (pStatistics) { VALIDATE_OBJECT(pStatistics, CStatistics); bIsRefreshed = ::LvRefreshObArray( &m_userList, &g_userColumnInfo, pStatistics->m_pObArray ); pStatistics->InternalRelease(); // add ref'd individually... } if (!bIsRefreshed) { ::LvReleaseObArray(&m_userList); // reset list now... } EndWaitCursor(); // hourglass... PostMessage(WM_COMMAND, ID_INIT_CTRLS); return bIsRefreshed; } void CProductPropertyPageUsers::OnDelete() /*++ Routine Description: Revokes licenses from user. Arguments: None. Return Values: None. --*/ { CStatistic* pStatistic; pStatistic = (CStatistic*)::LvGetSelObj(&m_userList); if (NULL != pStatistic) { VALIDATE_OBJECT(pStatistic, CStatistic); CString strConfirm; AfxFormatString2( strConfirm, IDP_CONFIRM_REVOKE_LICENSE, pStatistic->m_strEntry, m_pProduct->m_strName ); if (AfxMessageBox(strConfirm, MB_YESNO) == IDYES) { NTSTATUS NtStatus; BeginWaitCursor(); // hourglass... NtStatus = ::LlsUserProductDelete( LlsGetActiveHandle(), MKSTR(pStatistic->m_strEntry), MKSTR(m_pProduct->m_strName) ); 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... } } } } void CProductPropertyPageUsers::OnDblClkUsers(NMHDR* pNMHDR, LRESULT* pResult) /*++ Routine Description: Notification handler for NM_DBLCLK. Arguments: pNMHDR - notification header. pResult - return code. Return Values: None. --*/ { UNREFERENCED_PARAMETER(pNMHDR); ViewUserProperties(); ASSERT(NULL != pResult); *pResult = 0; } void CProductPropertyPageUsers::OnReturnUsers(NMHDR* pNMHDR, LRESULT* pResult) /*++ Routine Description: Notification handler for NM_RETURN. Arguments: pNMHDR - notification header. pResult - return code. Return Values: None. --*/ { UNREFERENCED_PARAMETER(pNMHDR); ViewUserProperties(); ASSERT(NULL != pResult); *pResult = 0; } void CProductPropertyPageUsers::OnSetFocusUsers(NMHDR* pNMHDR, LRESULT* pResult) /*++ Routine Description: Notification handler for NM_SETFOCUS. Arguments: pNMHDR - notification header. pResult - return code. Return Values: None. --*/ { UNREFERENCED_PARAMETER(pNMHDR); PostMessage(WM_COMMAND, ID_INIT_CTRLS); ASSERT(NULL != pResult); *pResult = 0; } void CProductPropertyPageUsers::OnKillFocusUsers(NMHDR* pNMHDR, LRESULT* pResult) /*++ Routine Description: Notification handler for NM_KILLFOCUS. Arguments: pNMHDR - notification header. pResult - return code. Return Values: None. --*/ { UNREFERENCED_PARAMETER(pNMHDR); ::LvSelObjIfNecessary(&m_userList); // ensure selection... PostMessage(WM_COMMAND, ID_INIT_CTRLS); ASSERT(NULL != pResult); *pResult = 0; } BOOL CProductPropertyPageUsers::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... } } ::SafeEnableWindow( &m_delBtn, &m_userList, CDialog::GetFocus(), m_userList.GetItemCount() ); return TRUE; // processed... } return CDialog::OnCommand(wParam, lParam); } void CProductPropertyPageUsers::OnColumnClickUsers(NMHDR* pNMHDR, LRESULT* pResult) /*++ Routine Description: Notification handler for LVN_COLUMNCLICK. Arguments: pNMHDR - notification header. pResult - return code. Return Values: None. --*/ { g_userColumnInfo.bSortOrder = GetKeyState(VK_CONTROL) < 0; ASSERT(NULL != pNMHDR); g_userColumnInfo.nSortedItem = ((NM_LISTVIEW*)pNMHDR)->iSubItem; m_userList.SortItems(CompareProductUsers, 0); // use column info ASSERT(NULL != pResult); *pResult = 0; } void CProductPropertyPageUsers::ViewUserProperties() /*++ Routine Description: Recurse into user property page. Arguments: None. Return Values: None. --*/ { CStatistic* pStatistic; if (!m_bUserProperties) { ::MessageBeep(MB_OK); return; // bail if recursion disabled... } pStatistic = (CStatistic*)::LvGetSelObj(&m_userList); if (NULL != pStatistic) { VALIDATE_OBJECT(pStatistic, CStatistic); CUser* pUser = new CUser(NULL, pStatistic->m_strEntry); if (pUser && pUser->Refresh()) { CString strTitle; AfxFormatString1(strTitle, IDS_PROPERTIES_OF, pUser->m_strName); CUserPropertySheet userProperties(strTitle); userProperties.InitPages(pUser, FALSE); userProperties.DoModal(); *m_pUpdateHint |= userProperties.m_fUpdateHint; if (IsUpdateAborted(userProperties.m_fUpdateHint)) { AbortPage(); // don't display error... } else if (IsUserInfoUpdated(userProperties.m_fUpdateHint) && !RefreshCtrls()) { AbortPageIfNecessary(); // display error... } } else { AbortPageIfNecessary(); // display error... } if (pUser) pUser->InternalRelease(); // delete object... } } void CProductPropertyPageUsers::OnGetDispInfoUsers(NMHDR* pNMHDR, LRESULT* pResult) /*++ Routine Description: Notification handler for LVN_GETDISPINFO. Arguments: pNMHDR - notification header. pResult - return code. Return Values: None. --*/ { ASSERT(NULL != pNMHDR); LV_ITEM* plvItem = &((LV_DISPINFO*)pNMHDR)->item; ASSERT(plvItem); CStatistic* pStatistic = (CStatistic*)plvItem->lParam; VALIDATE_OBJECT(pStatistic, CStatistic); switch (plvItem->iSubItem) { case LVID_USER: plvItem->iImage = pStatistic->m_bIsValid ? BMPI_USER : 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 { plvItem->pszText[0] = L'\0'; } } break; case LVID_TOTAL_USED: { CString strLabel; strLabel.Format(_T("%ld"), pStatistic->GetTotalUsed()); lstrcpyn(plvItem->pszText, strLabel, plvItem->cchTextMax); } break; } ASSERT(NULL != pResult); *pResult = 0; } int CALLBACK CompareProductUsers(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. --*/ { UNREFERENCED_PARAMETER(lParamSort); #define pStatistic1 ((CStatistic*)lParam1) #define pStatistic2 ((CStatistic*)lParam2) VALIDATE_OBJECT(pStatistic1, CStatistic); VALIDATE_OBJECT(pStatistic2, CStatistic); int iResult; switch (g_userColumnInfo.nSortedItem) { case LVID_USER: 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_userColumnInfo.bSortOrder ? -iResult : iResult; }