/*++ Module Name: CusTop.cpp Abstract: This module contains the Implementation of CCustomTopology. This class displays the Customize Topology Dialog. */ #include "stdafx.h" #include "CusTop.h" #include "utils.h" #include "dfshelp.h" #include "ldaputils.h" int g_FRS_CUSTOP_Last_SortColumn = 1; #define NUM_OF_FRS_CUSTOP_COLUMNS 5 RSTOPOLOGYPREF_STRING g_TopologyPref[] = { {FRS_RSTOPOLOGYPREF_RING, IDS_FRSPROP_RING}, {FRS_RSTOPOLOGYPREF_HUBSPOKE, IDS_FRSPROP_HUBSPOKE}, {FRS_RSTOPOLOGYPREF_FULLMESH, IDS_FRSPROP_FULLMESH}, {FRS_RSTOPOLOGYPREF_CUSTOM, IDS_FRSPROP_CUSTOM} }; ///////////////////////////////////////////////////////////////////////////// // // CCustomTopology // CCustomTopology::CCustomTopology() { } CCustomTopology::~CCustomTopology() { } HRESULT CCustomTopology::_GetMemberList() { FreeCusTopMembers(&m_MemberList); RETURN_INVALIDARG_IF_NULL((IReplicaSet *)m_piReplicaSet); VARIANT var; VariantInit(&var); HRESULT hr = m_piReplicaSet->GetMemberListEx(&var); RETURN_IF_FAILED(hr); if (V_VT(&var) != (VT_ARRAY | VT_VARIANT)) return E_INVALIDARG; SAFEARRAY *psa_1 = V_ARRAY(&var); if (!psa_1) // no member at all return hr; long lLowerBound_1 = 0; long lUpperBound_1 = 0; long lCount_1 = 0; SafeArrayGetLBound(psa_1, 1, &lLowerBound_1); SafeArrayGetUBound(psa_1, 1, &lUpperBound_1); lCount_1 = lUpperBound_1 - lLowerBound_1 + 1; VARIANT HUGEP *pArray_1; SafeArrayAccessData(psa_1, (void HUGEP **) &pArray_1); for (long i = 0; i < lCount_1; i++) { if (V_VT(&(pArray_1[i])) != (VT_ARRAY | VT_VARIANT)) { hr = E_INVALIDARG; break; } SAFEARRAY *psa_0 = V_ARRAY(&(pArray_1[i])); if (!psa_0) { hr = E_INVALIDARG; break; } long lLowerBound_0 = 0; long lUpperBound_0 = 0; long lCount_0 = 0; SafeArrayGetLBound(psa_0, 1, &lLowerBound_0); SafeArrayGetUBound(psa_0, 1, &lUpperBound_0); lCount_0 = lUpperBound_0 - lLowerBound_0 + 1; if (NUM_OF_FRSMEMBER_ATTRS != lCount_0) { hr = E_INVALIDARG; break; } VARIANT HUGEP *pArray_0; SafeArrayAccessData(psa_0, (void HUGEP **) &pArray_0); do { CCusTopMember* pNew = new CCusTopMember; BREAK_OUTOFMEMORY_IF_NULL(pNew, &hr); hr = pNew->Init( pArray_0[2].bstrVal, //bstrMemberDN, pArray_0[4].bstrVal, //bstrServer, pArray_0[6].bstrVal //bstrSite ); if (SUCCEEDED(hr)) m_MemberList.push_back(pNew); else delete pNew; } while (0); SafeArrayUnaccessData(psa_0); } SafeArrayUnaccessData(psa_1); if (SUCCEEDED(hr)) hr = _SortMemberList(); if (FAILED(hr)) FreeCusTopMembers(&m_MemberList); SafeArrayDestroy(psa_1); // it should free psa_0 as well return hr; } HRESULT CCustomTopology::_GetConnectionList() { FreeCusTopConnections(&m_ConnectionList); RETURN_INVALIDARG_IF_NULL((IReplicaSet *)m_piReplicaSet); VARIANT var; VariantInit(&var); HRESULT hr = m_piReplicaSet->GetConnectionListEx(&var); RETURN_IF_FAILED(hr); if (V_VT(&var) != (VT_ARRAY | VT_VARIANT)) return E_INVALIDARG; SAFEARRAY *psa_1 = V_ARRAY(&var); if (!psa_1) // no connection at all return hr; long lLowerBound_1 = 0; long lUpperBound_1 = 0; long lCount_1 = 0; SafeArrayGetLBound(psa_1, 1, &lLowerBound_1); SafeArrayGetUBound(psa_1, 1, &lUpperBound_1); lCount_1 = lUpperBound_1 - lLowerBound_1 + 1; VARIANT HUGEP *pArray_1; SafeArrayAccessData(psa_1, (void HUGEP **) &pArray_1); for (long i = 0; i < lCount_1; i++) { if (V_VT(&(pArray_1[i])) != (VT_ARRAY | VT_VARIANT)) { hr = E_INVALIDARG; break; } SAFEARRAY *psa_0 = V_ARRAY(&(pArray_1[i])); if (!psa_0) { hr = E_INVALIDARG; break; } long lLowerBound_0 = 0; long lUpperBound_0 = 0; long lCount_0 = 0; SafeArrayGetLBound(psa_0, 1, &lLowerBound_0); SafeArrayGetUBound(psa_0, 1, &lUpperBound_0); lCount_0 = lUpperBound_0 - lLowerBound_0 + 1; if (NUM_OF_FRSCONNECTION_ATTRS != lCount_0) { hr = E_INVALIDARG; break; } VARIANT HUGEP *pArray_0; SafeArrayAccessData(psa_0, (void HUGEP **) &pArray_0); do { CComBSTR bstrFromServer; CComBSTR bstrFromSite; hr = _GetMemberDNInfo(pArray_0[1].bstrVal, &bstrFromServer, &bstrFromSite); BREAK_IF_FAILED(hr); CComBSTR bstrToServer; CComBSTR bstrToSite; hr = _GetMemberDNInfo(pArray_0[2].bstrVal, &bstrToServer, &bstrToSite); BREAK_IF_FAILED(hr); CCusTopConnection* pNew = new CCusTopConnection; BREAK_OUTOFMEMORY_IF_NULL(pNew, &hr); hr = pNew->Init( pArray_0[1].bstrVal, //bstrFromDN, bstrFromServer, bstrFromSite, pArray_0[2].bstrVal, //bstrToDN, bstrToServer, bstrToSite, (BOOL)(pArray_0[3].lVal) //bEnable ); // CONNECTION_OPTYPE_OTHERS if (SUCCEEDED(hr)) m_ConnectionList.push_back(pNew); else delete pNew; } while (0); SafeArrayUnaccessData(psa_0); } SafeArrayUnaccessData(psa_1); if (FAILED(hr)) FreeCusTopConnections(&m_ConnectionList); SafeArrayDestroy(psa_1); return hr; } void CCustomTopology::_Reset() { m_bstrTopologyPref.Empty(); m_bstrHubMemberDN.Empty(); FreeCusTopMembers(&m_MemberList); FreeCusTopConnections(&m_ConnectionList); m_piReplicaSet = NULL; } HRESULT CCustomTopology::put_ReplicaSet ( IReplicaSet* i_piReplicaSet ) { RETURN_INVALIDARG_IF_NULL(i_piReplicaSet); _Reset(); m_piReplicaSet = i_piReplicaSet; HRESULT hr = S_OK; do { hr = m_piReplicaSet->get_TopologyPref(&m_bstrTopologyPref); BREAK_IF_FAILED(hr); hr = m_piReplicaSet->get_HubMemberDN(&m_bstrHubMemberDN); BREAK_IF_FAILED(hr); hr = _GetMemberList(); BREAK_IF_FAILED(hr); hr = _GetConnectionList(); BREAK_IF_FAILED(hr); } while (0); if (FAILED(hr)) _Reset(); return hr; } int __cdecl CompareCusTopMembers(const void *arg1, const void *arg2 ) { return lstrcmpi( (*(CCusTopMember**)arg1)->m_bstrServer, (*(CCusTopMember**)arg2)->m_bstrServer ); } HRESULT CCustomTopology::_SortMemberList() { HRESULT hr = S_OK; int cMembers = m_MemberList.size(); if (2 > cMembers) return hr; CCusTopMember** ppMember = (CCusTopMember **)calloc(cMembers, sizeof(CCusTopMember *)); RETURN_OUTOFMEMORY_IF_NULL(ppMember); int i = 0; for (CCusTopMemberList::iterator it = m_MemberList.begin(); it != m_MemberList.end(); it++, i++) { ppMember[i] = (*it); } qsort((void *)ppMember, cMembers, sizeof(CCusTopMember *), CompareCusTopMembers); m_MemberList.clear(); // without deleting the object for (i = 0; i < cMembers; i++) { m_MemberList.push_back(ppMember[i]); } free((void *)ppMember); return hr; } HRESULT CCustomTopology::_GetMemberDNInfo( IN BSTR i_bstrMemberDN, OUT BSTR* o_pbstrServer, OUT BSTR* o_pbstrSite ) { RETURN_INVALIDARG_IF_NULL(i_bstrMemberDN); RETURN_INVALIDARG_IF_NULL(o_pbstrServer); RETURN_INVALIDARG_IF_NULL(o_pbstrSite); for (CCusTopMemberList::iterator i = m_MemberList.begin(); i != m_MemberList.end(); i++) { if (!lstrcmpi(i_bstrMemberDN, (*i)->m_bstrMemberDN)) break; } if (i == m_MemberList.end()) return S_FALSE; *o_pbstrServer = (*i)->m_bstrServer.Copy(); RETURN_OUTOFMEMORY_IF_NULL(*o_pbstrServer); *o_pbstrSite = (*i)->m_bstrSite.Copy(); if (!*o_pbstrSite) { SysFreeString(*o_pbstrServer); return E_OUTOFMEMORY; } return S_OK; } HRESULT CCustomTopology::_GetHubMember( OUT CCusTopMember** o_ppHubMember ) { RETURN_INVALIDARG_IF_NULL(o_ppHubMember); int index = SendDlgItemMessage(IDC_FRS_CUSTOP_HUBSERVER, CB_GETCURSEL, 0, 0); int len = SendDlgItemMessage(IDC_FRS_CUSTOP_HUBSERVER, CB_GETLBTEXTLEN, index, 0); PTSTR pszServer = (PTSTR)calloc(len + 1, sizeof(TCHAR)); RETURN_OUTOFMEMORY_IF_NULL(pszServer); SendDlgItemMessage(IDC_FRS_CUSTOP_HUBSERVER, CB_GETLBTEXT, index, (LPARAM)pszServer); CCusTopMemberList::iterator i; for (i = m_MemberList.begin(); i != m_MemberList.end(); i++) { if (!lstrcmpi(pszServer, (*i)->m_bstrServer)) break; } free(pszServer); if (i == m_MemberList.end()) return E_INVALIDARG; *o_ppHubMember = (*i); return S_OK; } LRESULT CCustomTopology::OnInitDialog ( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) { int i = 0; int nControlID = 0; // // set IDC_FRS_CUSTOP_TOPOLOGYPREF // nControlID = IDC_FRS_CUSTOP_TOPOLOGYPREF; for (i = 0; i < 4; i++) { CComBSTR bstrTopologyPref; LoadStringFromResource(g_TopologyPref[i].nStringID, &bstrTopologyPref); SendDlgItemMessage(nControlID, CB_INSERTSTRING, i, (LPARAM)(BSTR)bstrTopologyPref); if (!lstrcmpi(m_bstrTopologyPref, g_TopologyPref[i].pszTopologyPref)) { SendDlgItemMessage(nControlID, CB_SETCURSEL, i, 0); ::EnableWindow(GetDlgItem(IDC_FRS_CUSTOP_REBUILD), (0 != lstrcmpi(m_bstrTopologyPref, FRS_RSTOPOLOGYPREF_CUSTOM))); } } // // set IDC_FRS_CUSTOP_HUBSERVER // nControlID = IDC_FRS_CUSTOP_HUBSERVER; int index = 0; CCusTopMemberList::iterator itMem; for (i = 0, itMem = m_MemberList.begin(); itMem != m_MemberList.end(); i++, itMem++) { SendDlgItemMessage(nControlID, CB_INSERTSTRING, i, (LPARAM)(BSTR)(*itMem)->m_bstrServer); if (!lstrcmpi(m_bstrHubMemberDN, (*itMem)->m_bstrMemberDN)) index = i; } SendDlgItemMessage(nControlID, CB_SETCURSEL, index, 0); if (lstrcmpi(m_bstrTopologyPref, FRS_RSTOPOLOGYPREF_HUBSPOKE)) { MyShowWindow(GetDlgItem(IDC_FRS_CUSTOP_HUBSERVER_LABEL), FALSE); MyShowWindow(GetDlgItem(IDC_FRS_CUSTOP_HUBSERVER), FALSE); } // // set IDC_FRS_CUSTOP_CONNECTIONS // nControlID = IDC_FRS_CUSTOP_CONNECTIONS; HWND hwndControl = GetDlgItem(nControlID); AddLVColumns(hwndControl, IDS_FRS_CUSTOP_COL_ENABLE, NUM_OF_FRS_CUSTOP_COLUMNS); ListView_SetExtendedListViewStyle(hwndControl, LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES); CCusTopConnectionList::iterator itConn; for (itConn = m_ConnectionList.begin(); itConn != m_ConnectionList.end(); itConn++) _InsertConnection(*itConn); ListView_SortItems( hwndControl, ConnectionsListCompareProc, (LPARAM)g_FRS_CUSTOP_Last_SortColumn); _EnableButtonsForConnectionList(); return TRUE; // Let the system set the focus } void CCustomTopology::_EnableButtonsForConnectionList() { // // enable New/Delete/Schedule buttons accordingly // int nCount = ListView_GetSelectedCount(GetDlgItem(IDC_FRS_CUSTOP_CONNECTIONS)); ::EnableWindow(GetDlgItem(IDC_FRS_CUSTOP_SCHEDULE), (nCount >= 1)); int index = SendDlgItemMessage(IDC_FRS_CUSTOP_TOPOLOGYPREF, CB_GETCURSEL, 0, 0); if (3 == index) // bCustomTopology { ::EnableWindow(GetDlgItem(IDC_FRS_CUSTOP_CONNECTIONS_NEW), TRUE); ::EnableWindow(GetDlgItem(IDC_FRS_CUSTOP_CONNECTIONS_DELETE), (nCount >= 1)); } else { ::EnableWindow(GetDlgItem(IDC_FRS_CUSTOP_CONNECTIONS_NEW), FALSE); ::EnableWindow(GetDlgItem(IDC_FRS_CUSTOP_CONNECTIONS_DELETE), FALSE); } } /*++ This function is called when a user clicks the ? in the top right of a property sheet and then clciks a control, or when they hit F1 in a control. --*/ LRESULT CCustomTopology::OnCtxHelp( IN UINT i_uMsg, IN WPARAM i_wParam, IN LPARAM i_lParam, IN OUT BOOL& io_bHandled ) { LPHELPINFO lphi = (LPHELPINFO) i_lParam; if (!lphi || lphi->iContextType != HELPINFO_WINDOW || lphi->iCtrlId < 0) return FALSE; ::WinHelp((HWND)(lphi->hItemHandle), DFS_CTX_HELP_FILE, HELP_WM_HELP, (DWORD_PTR)(PVOID)g_aHelpIDs_IDD_FRS_CUSTOP); return TRUE; } /*++ This function handles "What's This" help when a user right clicks the control --*/ LRESULT CCustomTopology::OnCtxMenuHelp( IN UINT i_uMsg, IN WPARAM i_wParam, IN LPARAM i_lParam, IN OUT BOOL& io_bHandled ) { ::WinHelp((HWND)i_wParam, DFS_CTX_HELP_FILE, HELP_CONTEXTMENU, (DWORD_PTR)(PVOID)g_aHelpIDs_IDD_FRS_CUSTOP); return TRUE; } BOOL CCustomTopology::_EnableRebuild() { BOOL bSameTopologyPref = FALSE; int index = SendDlgItemMessage(IDC_FRS_CUSTOP_TOPOLOGYPREF, CB_GETCURSEL, 0, 0); if (lstrcmpi(FRS_RSTOPOLOGYPREF_CUSTOM, g_TopologyPref[index].pszTopologyPref) && !lstrcmpi(m_bstrTopologyPref, g_TopologyPref[index].pszTopologyPref)) { bSameTopologyPref = TRUE; } if (!bSameTopologyPref || 0 != lstrcmpi(m_bstrTopologyPref, FRS_RSTOPOLOGYPREF_HUBSPOKE)) return bSameTopologyPref; BOOL bSameHub = FALSE; CCusTopMember* pHubMember = NULL; HRESULT hr = _GetHubMember(&pHubMember); if (SUCCEEDED(hr)) bSameHub = (!lstrcmpi(m_bstrHubMemberDN, pHubMember->m_bstrMemberDN)); return bSameHub; } LRESULT CCustomTopology::OnTopologyPref ( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled ) { HRESULT hr = S_OK; if (CBN_SELCHANGE == wNotifyCode) { int index = SendDlgItemMessage(wID, CB_GETCURSEL, 0, 0); BOOL bCmdShow = (1 == index); MyShowWindow(GetDlgItem(IDC_FRS_CUSTOP_HUBSERVER_LABEL), bCmdShow); MyShowWindow(GetDlgItem(IDC_FRS_CUSTOP_HUBSERVER), bCmdShow); if (1 == index) { CCusTopMember* pHubMember = NULL; hr = _GetHubMember(&pHubMember); if (SUCCEEDED(hr)) hr = _RebuildConnections(FRS_RSTOPOLOGYPREF_HUBSPOKE, pHubMember); } else hr = _RebuildConnections(g_TopologyPref[index].pszTopologyPref, NULL); _EnableButtonsForConnectionList(); BOOL bSameTopology = _EnableRebuild(); ::EnableWindow(GetDlgItem(IDC_FRS_CUSTOP_REBUILD), bSameTopology); } return (SUCCEEDED(hr)); } LRESULT CCustomTopology::OnHubServer ( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled ) { HRESULT hr = S_OK; if (CBN_SELCHANGE == wNotifyCode) { CCusTopMember* pHubMember = NULL; hr = _GetHubMember(&pHubMember); if (SUCCEEDED(hr)) hr = _RebuildConnections(FRS_RSTOPOLOGYPREF_HUBSPOKE, pHubMember); BOOL bSameTopology = _EnableRebuild(); ::EnableWindow(GetDlgItem(IDC_FRS_CUSTOP_REBUILD), bSameTopology); } return (SUCCEEDED(hr)); } LRESULT CCustomTopology::OnRebuild ( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled ) { HRESULT hr = S_OK; if (!lstrcmpi(m_bstrTopologyPref, FRS_RSTOPOLOGYPREF_HUBSPOKE)) { CCusTopMember* pHubMember = NULL; hr = _GetHubMember(&pHubMember); if (SUCCEEDED(hr)) hr = _RebuildConnections(m_bstrTopologyPref, pHubMember); } else hr = _RebuildConnections(m_bstrTopologyPref, NULL); return (SUCCEEDED(hr)); } HRESULT CCustomTopology::_RebuildConnections( IN BSTR i_bstrTopologyPref, IN CCusTopMember* i_pHubMember) { HRESULT hr = S_OK; // // delete all existing connections from list and view // CCusTopConnectionList::iterator it = m_ConnectionList.begin(); while (it != m_ConnectionList.end()) { CCusTopConnectionList::iterator itConn = it++; if (CONNECTION_OPTYPE_ADD == (*itConn)->m_opType) { delete (*itConn); m_ConnectionList.erase(itConn); } else { (*itConn)->m_opType = CONNECTION_OPTYPE_DEL; } } ListView_DeleteAllItems(GetDlgItem(IDC_FRS_CUSTOP_CONNECTIONS)); // // re-create the connections as specified // if (m_MemberList.size() == 1) return hr; CCusTopMemberList::iterator n1; CCusTopMemberList::iterator n2; CCusTopConnection Conn; if (!lstrcmpi(i_bstrTopologyPref, FRS_RSTOPOLOGYPREF_RING)) { CCusTopMemberList::iterator head; head = n1 = m_MemberList.begin(); while (n1 != m_MemberList.end()) { n2 = n1++; if (n1 == m_MemberList.end()) { if (m_MemberList.size() == 2) break; n1 = head; } hr = Conn.Init((*n1)->m_bstrMemberDN, (*n1)->m_bstrServer, (*n1)->m_bstrSite, (*n2)->m_bstrMemberDN, (*n2)->m_bstrServer, (*n2)->m_bstrSite, TRUE, CONNECTION_OPTYPE_ADD); BREAK_IF_FAILED(hr); hr = _AddToConnectionListAndView(&Conn); BREAK_IF_FAILED(hr); hr = Conn.Init((*n2)->m_bstrMemberDN, (*n2)->m_bstrServer, (*n2)->m_bstrSite, (*n1)->m_bstrMemberDN, (*n1)->m_bstrServer, (*n1)->m_bstrSite, TRUE, CONNECTION_OPTYPE_ADD); BREAK_IF_FAILED(hr); hr = _AddToConnectionListAndView(&Conn); BREAK_IF_FAILED(hr); if (n1 == head) break; } } else if (!lstrcmpi(i_bstrTopologyPref, FRS_RSTOPOLOGYPREF_HUBSPOKE)) { for (n1 = m_MemberList.begin(); n1 != m_MemberList.end(); n1++) { if (!lstrcmpi((*n1)->m_bstrMemberDN, i_pHubMember->m_bstrMemberDN)) continue; hr = Conn.Init((*n1)->m_bstrMemberDN, (*n1)->m_bstrServer, (*n1)->m_bstrSite, i_pHubMember->m_bstrMemberDN, i_pHubMember->m_bstrServer, i_pHubMember->m_bstrSite, TRUE, CONNECTION_OPTYPE_ADD); BREAK_IF_FAILED(hr); hr = _AddToConnectionListAndView(&Conn); BREAK_IF_FAILED(hr); hr = Conn.Init(i_pHubMember->m_bstrMemberDN, i_pHubMember->m_bstrServer, i_pHubMember->m_bstrSite, (*n1)->m_bstrMemberDN, (*n1)->m_bstrServer, (*n1)->m_bstrSite, TRUE, CONNECTION_OPTYPE_ADD); BREAK_IF_FAILED(hr); hr = _AddToConnectionListAndView(&Conn); BREAK_IF_FAILED(hr); } } else if (!lstrcmpi(i_bstrTopologyPref, FRS_RSTOPOLOGYPREF_FULLMESH)) { for (n1 = m_MemberList.begin(); n1 != m_MemberList.end(); n1++) { for (n2 = m_MemberList.begin(); n2 != m_MemberList.end(); n2++) { if (!lstrcmpi((*n1)->m_bstrMemberDN, (*n2)->m_bstrMemberDN)) continue; hr = Conn.Init((*n1)->m_bstrMemberDN, (*n1)->m_bstrServer, (*n1)->m_bstrSite, (*n2)->m_bstrMemberDN, (*n2)->m_bstrServer, (*n2)->m_bstrSite, TRUE, CONNECTION_OPTYPE_ADD); BREAK_IF_FAILED(hr); hr = _AddToConnectionListAndView(&Conn); BREAK_IF_FAILED(hr); } BREAK_IF_FAILED(hr); } } return hr; } HRESULT CCustomTopology::_SetConnectionState(CCusTopConnection *pConn) { HWND hwnd = GetDlgItem(IDC_FRS_CUSTOP_CONNECTIONS); int nIndex = ListView_GetNextItem(hwnd, -1, LVNI_ALL); while (-1 != nIndex) { if (pConn == (CCusTopConnection *)GetListViewItemData(hwnd, nIndex)) break; nIndex = ListView_GetNextItem(hwnd, nIndex, LVNI_ALL); } if (-1 != nIndex) { ListView_SetCheckState(hwnd, nIndex, pConn->m_bStateNew); ListView_Update(hwnd, nIndex); } return S_OK; } HRESULT CCustomTopology::_InsertConnection(CCusTopConnection *pConn) { RETURN_INVALIDARG_IF_NULL(pConn); HWND hwndControl = GetDlgItem(IDC_FRS_CUSTOP_CONNECTIONS); LVITEM lvItem; lvItem.mask = LVIF_TEXT | LVIF_PARAM; lvItem.lParam = (LPARAM)pConn; lvItem.pszText = _T(""); lvItem.iSubItem = 0; int iItemIndex = ListView_InsertItem(hwndControl, &lvItem); lvItem.mask = LVIF_TEXT; lvItem.iItem = iItemIndex; lvItem.pszText = pConn->m_bstrFromServer; lvItem.iSubItem = 1; ListView_SetItem(hwndControl, &lvItem); lvItem.mask = LVIF_TEXT; lvItem.iItem = iItemIndex; lvItem.pszText = pConn->m_bstrToServer; lvItem.iSubItem = 2; ListView_SetItem(hwndControl, &lvItem); lvItem.mask = LVIF_TEXT; lvItem.iItem = iItemIndex; lvItem.pszText = pConn->m_bstrFromSite; lvItem.iSubItem = 3; ListView_SetItem(hwndControl, &lvItem); lvItem.mask = LVIF_TEXT; lvItem.iItem = iItemIndex; lvItem.pszText = pConn->m_bstrToSite; lvItem.iSubItem = 4; ListView_SetItem(hwndControl, &lvItem); ListView_SetCheckState(hwndControl, iItemIndex, pConn->m_bStateNew); ListView_Update(hwndControl, iItemIndex); return S_OK; } LRESULT CCustomTopology::OnConnectionsNew ( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled ) { HRESULT hr = S_OK; CNewConnections NewConnDlg; hr = NewConnDlg.Initialize(&m_MemberList); if (SUCCEEDED(hr)) { hr = NewConnDlg.DoModal(); if (S_OK == hr) { CCusTopConnectionList* pNewConnectionList = NULL; hr = NewConnDlg.get_NewConnections(&pNewConnectionList); if (SUCCEEDED(hr)) { HWND hwnd = GetDlgItem(IDC_FRS_CUSTOP_CONNECTIONS); int nCount = ListView_GetItemCount(hwnd); CCusTopConnectionList::iterator it; for (it = pNewConnectionList->begin(); it != pNewConnectionList->end(); it++) { hr = _AddToConnectionListAndView(*it); BREAK_IF_FAILED(hr); } if (ListView_GetItemCount(hwnd) > nCount) ListView_SortItems(hwnd, ConnectionsListCompareProc, (LPARAM)g_FRS_CUSTOP_Last_SortColumn); } } } // if FAILED, display msg? return (SUCCEEDED(hr)); } LRESULT CCustomTopology::OnConnectionsDelete ( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled ) { CCusTopConnection* pConn; HWND hwnd = GetDlgItem(IDC_FRS_CUSTOP_CONNECTIONS); int nIndex = ListView_GetNextItem(hwnd, -1, LVNI_ALL | LVNI_SELECTED); while (-1 != nIndex && (pConn = (CCusTopConnection *)GetListViewItemData(hwnd, nIndex))) { _RemoveFromConnectionList(pConn); ListView_DeleteItem(hwnd, nIndex); nIndex = ListView_GetNextItem(hwnd, -1, LVNI_ALL | LVNI_SELECTED); } return TRUE; } HRESULT CCustomTopology::_InitScheduleOnSelectedConnections() { HRESULT hr = S_OK; int nIndex = -1; CCusTopConnection* pConn = NULL; HWND hwnd = GetDlgItem(IDC_FRS_CUSTOP_CONNECTIONS); while ( -1 != (nIndex = ListView_GetNextItem(hwnd, nIndex, LVNI_ALL | LVNI_SELECTED)) && NULL != (pConn = (CCusTopConnection *)GetListViewItemData(hwnd, nIndex))) { if (!pConn->m_pScheduleNew) { if (pConn->m_pScheduleOld) { hr = CopySchedule(pConn->m_pScheduleOld, &pConn->m_pScheduleNew); RETURN_IF_FAILED(hr); } else { if (CONNECTION_OPTYPE_OTHERS == pConn->m_opType) { // // read schedule on an existing connection for the very first time // VARIANT var; VariantInit(&var); hr = m_piReplicaSet->GetConnectionScheduleEx(pConn->m_bstrFromMemberDN, pConn->m_bstrToMemberDN, &var); RETURN_IF_FAILED(hr); hr = VariantToSchedule(&var, &pConn->m_pScheduleOld); VariantClear(&var); if (SUCCEEDED(hr)) hr = CopySchedule(pConn->m_pScheduleOld, &pConn->m_pScheduleNew); RETURN_IF_FAILED(hr); } else { // must be ADD operation hr = GetDefaultSchedule(&pConn->m_pScheduleNew); RETURN_IF_FAILED(hr); } } } } return hr; } HRESULT CCustomTopology::_UpdateScheduleOnSelectedConnections(IN SCHEDULE* i_pSchedule) { HRESULT hr = S_OK; int nIndex = -1; CCusTopConnection* pConn = NULL; HWND hwnd = GetDlgItem(IDC_FRS_CUSTOP_CONNECTIONS); while ( -1 != (nIndex = ListView_GetNextItem(hwnd, nIndex, LVNI_ALL | LVNI_SELECTED)) && NULL != (pConn = (CCusTopConnection *)GetListViewItemData(hwnd, nIndex))) { if (pConn->m_pScheduleNew) { free(pConn->m_pScheduleNew); pConn->m_pScheduleNew = NULL; } hr = CopySchedule(i_pSchedule, &pConn->m_pScheduleNew); BREAK_IF_FAILED(hr); } return hr; } LRESULT CCustomTopology::OnSchedule ( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled ) { HRESULT hr = S_OK; HWND hwnd = GetDlgItem(IDC_FRS_CUSTOP_CONNECTIONS); int nCount = ListView_GetSelectedCount(hwnd); if (nCount < 1) { DisplayMessageBoxWithOK(IDS_FRS_CUSTOP_NOSELECTION); return FALSE; } do { // // get schedule info on each selected connections // hr = _InitScheduleOnSelectedConnections(); BREAK_IF_FAILED(hr); // // get schedule of the first selected item // int nIndex = ListView_GetNextItem(hwnd, -1, LVNI_ALL | LVNI_SELECTED); if (-1 == nIndex) { hr = E_INVALIDARG; break; } CCusTopConnection* pConn = (CCusTopConnection *)GetListViewItemData(hwnd, nIndex); if (!pConn) { hr = E_INVALIDARG; break; } SCHEDULE* pSchedule = NULL; hr = CopySchedule(pConn->m_pScheduleNew, &pSchedule); BREAK_IF_FAILED(hr); hr = InvokeScheduleDlg(m_hWnd, pSchedule); if (S_OK == hr) hr = _UpdateScheduleOnSelectedConnections(pSchedule); free(pSchedule); } while (0); if (FAILED(hr)) DisplayMessageBoxForHR(hr); return (SUCCEEDED(hr)); } LRESULT CCustomTopology::OnOK ( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled ) { CWaitCursor wait; BOOL bValidInput = FALSE; int idString = 0; HRESULT hr = S_OK; do { // // if changed, update TopologyPref // int index = SendDlgItemMessage(IDC_FRS_CUSTOP_TOPOLOGYPREF, CB_GETCURSEL, 0, 0); if (0 != lstrcmpi(m_bstrTopologyPref, g_TopologyPref[index].pszTopologyPref)) { hr = m_piReplicaSet->put_TopologyPref(g_TopologyPref[index].pszTopologyPref); BREAK_IF_FAILED(hr); } // // if changed, update HubServer // if (!lstrcmpi(m_bstrTopologyPref, FRS_RSTOPOLOGYPREF_HUBSPOKE) && 0 != lstrcmpi(g_TopologyPref[index].pszTopologyPref, FRS_RSTOPOLOGYPREF_HUBSPOKE)) { hr = m_piReplicaSet->put_HubMemberDN(NULL); BREAK_IF_FAILED(hr); } else if (!lstrcmpi(g_TopologyPref[index].pszTopologyPref, FRS_RSTOPOLOGYPREF_HUBSPOKE)) { CCusTopMember* pHubMember = NULL; hr = _GetHubMember(&pHubMember); BREAK_IF_FAILED(hr); if (0 != lstrcmpi(m_bstrHubMemberDN, pHubMember->m_bstrMemberDN)) hr = m_piReplicaSet->put_HubMemberDN(pHubMember->m_bstrMemberDN); BREAK_IF_FAILED(hr); } // // if changed, update connections // CCusTopConnection* pConn = NULL; HWND hwnd = GetDlgItem(IDC_FRS_CUSTOP_CONNECTIONS); index = -1; while (-1 != (index = ListView_GetNextItem(hwnd, index, LVNI_ALL))) { pConn = (CCusTopConnection *)GetListViewItemData(hwnd, index); if (pConn) pConn->m_bStateNew = ListView_GetCheckState(hwnd, index); } hr = _MakeConnections(); BREAK_IF_FAILED(hr); bValidInput = TRUE; } while (0); if (FAILED(hr)) { DisplayMessageBoxForHR(hr); return FALSE; } else if (bValidInput) { EndDialog(S_OK); return TRUE; } else { if (idString) DisplayMessageBoxWithOK(idString); return FALSE; } } LRESULT CCustomTopology::OnCancel ( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled ) { /*++ Routine Description: Called OnCancel. Ends the dialog with S_FALSE; */ EndDialog(S_FALSE); return(true); } int CALLBACK ConnectionsListCompareProc( IN LPARAM lParam1, IN LPARAM lParam2, IN LPARAM lParamColumn) { CCusTopConnection* pItem1 = (CCusTopConnection *)lParam1; CCusTopConnection* pItem2 = (CCusTopConnection *)lParam2; int iResult = 0; if (pItem1 && pItem2) { g_FRS_CUSTOP_Last_SortColumn = lParamColumn; switch (lParamColumn) { case 0: // Sort by bStateNew. iResult = pItem1->m_bStateNew - pItem2->m_bStateNew; break; case 1: // Sort by From Server. iResult = lstrcmpi(pItem1->m_bstrFromServer, pItem2->m_bstrFromServer); break; case 2: // Sort by To Server. iResult = lstrcmpi(pItem1->m_bstrToServer, pItem2->m_bstrToServer); break; case 3: // Sort by From Site. iResult = lstrcmpi(pItem1->m_bstrFromSite, pItem2->m_bstrFromSite); break; case 4: // Sort by To Site. iResult = lstrcmpi(pItem1->m_bstrToSite, pItem2->m_bstrToSite); break; default: iResult = 0; break; } } return(iResult); } LRESULT CCustomTopology::OnNotify( IN UINT i_uMsg, IN WPARAM i_wParam, IN LPARAM i_lParam, IN OUT BOOL& io_bHandled ) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)i_lParam; io_bHandled = FALSE; // So that the base class gets this notify too if (IDC_FRS_CUSTOP_CONNECTIONS == pNMListView->hdr.idFrom) { HWND hwndList = GetDlgItem(IDC_FRS_CUSTOP_CONNECTIONS); if (LVN_COLUMNCLICK == pNMListView->hdr.code) { // sort items ListView_SortItems( hwndList, ConnectionsListCompareProc, (LPARAM)(pNMListView->iSubItem)); io_bHandled = TRUE; } else if (LVN_ITEMCHANGED == pNMListView->hdr.code) { _EnableButtonsForConnectionList(); } } return io_bHandled; } // // Update the connection objects in the DS // HRESULT CCustomTopology::_MakeConnections() { HRESULT hr = S_OK; CCusTopConnectionList::iterator it; for (it = m_ConnectionList.begin(); it != m_ConnectionList.end(); it++) { switch ((*it)->m_opType) { case CONNECTION_OPTYPE_ADD: hr = m_piReplicaSet->AddConnection( (*it)->m_bstrFromMemberDN, (*it)->m_bstrToMemberDN, (*it)->m_bStateNew, NULL ); BREAK_IF_FAILED(hr); if ((*it)->m_pScheduleNew) { VARIANT var; VariantInit(&var); hr = ScheduleToVariant((*it)->m_pScheduleNew, &var); BREAK_IF_FAILED(hr); hr = m_piReplicaSet->SetConnectionScheduleEx( (*it)->m_bstrFromMemberDN, (*it)->m_bstrToMemberDN, &var); VariantClear(&var); } break; case CONNECTION_OPTYPE_DEL: hr = m_piReplicaSet->RemoveConnectionEx( (*it)->m_bstrFromMemberDN, (*it)->m_bstrToMemberDN ); break; default: if ((*it)->m_bStateNew != (*it)->m_bStateOld) { hr = m_piReplicaSet->EnableConnectionEx( (*it)->m_bstrFromMemberDN, (*it)->m_bstrToMemberDN, (*it)->m_bStateNew ); BREAK_IF_FAILED(hr); } if (S_OK == CompareSchedules((*it)->m_pScheduleNew, (*it)->m_pScheduleOld)) break; // no change on shcedule if ((*it)->m_pScheduleNew) { VARIANT var; VariantInit(&var); hr = ScheduleToVariant((*it)->m_pScheduleNew, &var); BREAK_IF_FAILED(hr); hr = m_piReplicaSet->SetConnectionScheduleEx( (*it)->m_bstrFromMemberDN, (*it)->m_bstrToMemberDN, &var); VariantClear(&var); } break; } BREAK_IF_FAILED(hr); } return hr; } ////////////////////////////////////////////////////////// // // void FreeCusTopMembers(CCusTopMemberList* pList) { if (pList && !pList->empty()) { for (CCusTopMemberList::iterator i = pList->begin(); i != pList->end(); i++) delete (*i); pList->clear(); } } void FreeCusTopConnections(CCusTopConnectionList* pList) { if (pList && !pList->empty()) { for (CCusTopConnectionList::iterator i = pList->begin(); i != pList->end(); i++) delete (*i); pList->clear(); } } ////////////////////////////////////////////////////////// // // CCusTopMember // CCusTopMember::~CCusTopMember() { _Reset(); } HRESULT CCusTopMember::Init(BSTR bstrMemberDN, BSTR bstrServer, BSTR bstrSite) { RETURN_INVALIDARG_IF_NULL(bstrMemberDN); RETURN_INVALIDARG_IF_NULL(bstrServer); RETURN_INVALIDARG_IF_NULL(bstrSite); _Reset(); HRESULT hr = S_OK; do { m_bstrMemberDN = bstrMemberDN; BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrMemberDN, &hr); m_bstrServer = bstrServer; BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrServer, &hr); m_bstrSite = bstrSite; BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrSite, &hr); } while (0); if (FAILED(hr)) _Reset(); return hr; } void CCusTopMember::_Reset() { m_bstrMemberDN.Empty(); m_bstrServer.Empty(); m_bstrSite.Empty(); } ////////////////////////////////////////////////////////// // // CCusTopConnection // CCusTopConnection::CCusTopConnection() { m_bStateOld = m_bStateNew = TRUE; m_pScheduleOld = m_pScheduleNew = NULL; m_opType = CONNECTION_OPTYPE_OTHERS; } CCusTopConnection::~CCusTopConnection() { _Reset(); } HRESULT CCusTopConnection::Init( BSTR bstrFromMemberDN, BSTR bstrFromServer, BSTR bstrFromSite, BSTR bstrToMemberDN, BSTR bstrToServer, BSTR bstrToSite, BOOL bState, // = TRUE CONNECTION_OPTYPE opType // = CONNECTION_OPTYPE_OTHERS ) { RETURN_INVALIDARG_IF_NULL(bstrFromMemberDN); RETURN_INVALIDARG_IF_NULL(bstrFromServer); RETURN_INVALIDARG_IF_NULL(bstrFromSite); RETURN_INVALIDARG_IF_NULL(bstrToMemberDN); RETURN_INVALIDARG_IF_NULL(bstrToServer); RETURN_INVALIDARG_IF_NULL(bstrToSite); _Reset(); HRESULT hr = S_OK; do { m_bstrFromMemberDN = bstrFromMemberDN; BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrFromMemberDN, &hr); m_bstrFromServer = bstrFromServer; BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrFromServer, &hr); m_bstrFromSite = bstrFromSite; BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrFromSite, &hr); m_bstrToMemberDN = bstrToMemberDN; BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrToMemberDN, &hr); m_bstrToServer = bstrToServer; BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrToServer, &hr); m_bstrToSite = bstrToSite; BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrToSite, &hr); m_bStateNew = m_bStateOld = bState; m_opType = opType; m_pScheduleOld = m_pScheduleNew = NULL; } while (0); if (FAILED(hr)) _Reset(); return hr; } void CCusTopConnection::_Reset() { m_bstrFromMemberDN.Empty(); m_bstrFromServer.Empty(); m_bstrFromSite.Empty(); m_bstrToMemberDN.Empty(); m_bstrToServer.Empty(); m_bstrToSite.Empty(); m_bStateOld = TRUE; m_bStateNew = TRUE; m_opType = CONNECTION_OPTYPE_OTHERS; if (m_pScheduleOld) { free(m_pScheduleOld); m_pScheduleOld = NULL; } if (m_pScheduleNew) { free(m_pScheduleNew); m_pScheduleNew = NULL; } } HRESULT CCusTopConnection::Copy(CCusTopConnection* pConn) { if (!pConn || !(pConn->m_bstrFromMemberDN) || !*(pConn->m_bstrFromMemberDN)) return E_INVALIDARG; _Reset(); HRESULT hr = S_OK; do { m_bstrFromMemberDN = pConn->m_bstrFromMemberDN; BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrFromMemberDN, &hr); m_bstrFromServer = pConn->m_bstrFromServer; BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrFromServer, &hr); m_bstrFromSite = pConn->m_bstrFromSite; BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrFromSite, &hr); m_bstrToMemberDN = pConn->m_bstrToMemberDN; BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrToMemberDN, &hr); m_bstrToServer = pConn->m_bstrToServer; BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrToServer, &hr); m_bstrToSite = pConn->m_bstrToSite; BREAK_OUTOFMEMORY_IF_NULL((BSTR)m_bstrToSite, &hr); m_bStateOld = pConn->m_bStateOld; m_bStateNew = pConn->m_bStateNew; m_opType = pConn->m_opType; if (pConn->m_pScheduleOld) { hr = CopySchedule(pConn->m_pScheduleOld, &m_pScheduleOld); BREAK_IF_FAILED(hr); } if (pConn->m_pScheduleNew) { hr = CopySchedule(pConn->m_pScheduleNew, &m_pScheduleNew); BREAK_IF_FAILED(hr); } } while (0); if (FAILED(hr)) _Reset(); return hr; } HRESULT CCustomTopology::_AddToConnectionListAndView(CCusTopConnection* pConn) { RETURN_INVALIDARG_IF_NULL(pConn); BOOL bFound = FALSE; CCusTopConnectionList::iterator it; for (it = m_ConnectionList.begin(); it != m_ConnectionList.end(); it++) { if (!lstrcmpi((*it)->m_bstrFromMemberDN, pConn->m_bstrFromMemberDN) && !lstrcmpi((*it)->m_bstrToMemberDN, pConn->m_bstrToMemberDN)) { bFound = TRUE; break; } } HRESULT hr = S_OK; if (!bFound) { CCusTopConnection* pNew = new CCusTopConnection; RETURN_OUTOFMEMORY_IF_NULL(pNew); hr = pNew->Copy(pConn); if (FAILED(hr)) delete pNew; else { m_ConnectionList.push_back(pNew); hr = _InsertConnection(pNew); } } else { (*it)->m_bStateNew = TRUE; if ((*it)->m_opType == CONNECTION_OPTYPE_DEL) { (*it)->m_opType = CONNECTION_OPTYPE_OTHERS; hr = _InsertConnection(*it); } else { (*it)->m_opType = CONNECTION_OPTYPE_OTHERS; hr = _SetConnectionState(*it); } } return hr; } HRESULT CCustomTopology::_RemoveFromConnectionList(CCusTopConnection* pConn) { RETURN_INVALIDARG_IF_NULL(pConn); BOOL bFound = FALSE; CCusTopConnectionList::iterator it; for (it = m_ConnectionList.begin(); it != m_ConnectionList.end(); it++) { if (!lstrcmpi((*it)->m_bstrFromMemberDN, pConn->m_bstrFromMemberDN) && !lstrcmpi((*it)->m_bstrToMemberDN, pConn->m_bstrToMemberDN)) { bFound = TRUE; break; } } if (it != m_ConnectionList.end()) { if (CONNECTION_OPTYPE_ADD == (*it)->m_opType) { delete (*it); m_ConnectionList.erase(it); } else { (*it)->m_opType = CONNECTION_OPTYPE_DEL; } } return S_OK; } ///////////////////////////////////////////////////////////////////////////// // // CNewConnections // CNewConnections::CNewConnections() : m_pMemberList(NULL) { } CNewConnections::~CNewConnections() { FreeCusTopConnections(&m_NewConnectionList); } HRESULT CNewConnections::Initialize ( CCusTopMemberList* i_pMemberList ) { RETURN_INVALIDARG_IF_NULL(i_pMemberList); m_pMemberList = i_pMemberList; return S_OK; } #define NUM_OF_FRS_NEWCONN_COLUMNS 2 LRESULT CNewConnections::OnInitDialog ( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) { int nControlID[] = {IDC_FRS_NEWCONN_FROM, IDC_FRS_NEWCONN_TO}; int nColStringID[] = {IDS_FRS_NEWCONN_COL_FROMSERVER, IDS_FRS_NEWCONN_COL_TOSERVER}; HWND hwndControl = NULL; CCusTopMemberList::iterator it; for (int i = 0; i < 2; i++) { hwndControl = GetDlgItem(nControlID[i]); AddLVColumns(hwndControl, nColStringID[i], NUM_OF_FRS_NEWCONN_COLUMNS); ListView_SetExtendedListViewStyle(hwndControl, LVS_EX_FULLROWSELECT); for (it = m_pMemberList->begin(); it != m_pMemberList->end(); it++) { LVITEM lvItem; lvItem.mask = LVIF_TEXT | LVIF_PARAM; lvItem.lParam = (LPARAM)(*it); lvItem.pszText = (*it)->m_bstrServer; lvItem.iSubItem = 0; int iItemIndex = ListView_InsertItem(hwndControl, &lvItem); lvItem.mask = LVIF_TEXT; lvItem.iItem = iItemIndex; lvItem.pszText = (*it)->m_bstrSite; lvItem.iSubItem = 1; ListView_SetItem(hwndControl, &lvItem); } } return TRUE; // Let the system set the focus } /*++ This function is called when a user clicks the ? in the top right of a property sheet and then clciks a control, or when they hit F1 in a control. --*/ LRESULT CNewConnections::OnCtxHelp( IN UINT i_uMsg, IN WPARAM i_wParam, IN LPARAM i_lParam, IN OUT BOOL& io_bHandled ) { LPHELPINFO lphi = (LPHELPINFO) i_lParam; if (!lphi || lphi->iContextType != HELPINFO_WINDOW || lphi->iCtrlId < 0) return FALSE; ::WinHelp((HWND)(lphi->hItemHandle), DFS_CTX_HELP_FILE, HELP_WM_HELP, (DWORD_PTR)(PVOID)g_aHelpIDs_IDD_FRS_NEWCONN); return TRUE; } /*++ This function handles "What's This" help when a user right clicks the control --*/ LRESULT CNewConnections::OnCtxMenuHelp( IN UINT i_uMsg, IN WPARAM i_wParam, IN LPARAM i_lParam, IN OUT BOOL& io_bHandled ) { ::WinHelp((HWND)i_wParam, DFS_CTX_HELP_FILE, HELP_CONTEXTMENU, (DWORD_PTR)(PVOID)g_aHelpIDs_IDD_FRS_NEWCONN); return TRUE; } HRESULT CNewConnections::get_NewConnections(CCusTopConnectionList** ppConnectionList) { RETURN_INVALIDARG_IF_NULL(ppConnectionList); *ppConnectionList = &m_NewConnectionList; return S_OK; } LRESULT CNewConnections::OnOK ( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled ) { BOOL bValidInput = FALSE; int idString = 0; HRESULT hr = S_OK; do { idString = IDS_FRS_NEWCONN_NOSELECTION; // // get all selected From servers // CCusTopMember* pMember; CCusTopMemberList fromMemberList; HWND hwndFrom = GetDlgItem(IDC_FRS_NEWCONN_FROM); int nIndexFrom = ListView_GetNextItem(hwndFrom, -1, LVNI_ALL | LVNI_SELECTED); while (-1 != nIndexFrom && (pMember = (CCusTopMember *)GetListViewItemData(hwndFrom, nIndexFrom))) { fromMemberList.push_back(pMember); nIndexFrom = ListView_GetNextItem(hwndFrom, nIndexFrom, LVNI_ALL | LVNI_SELECTED); } if (fromMemberList.empty()) break; // // get all selected To servers // CCusTopMemberList toMemberList; HWND hwndTo = GetDlgItem(IDC_FRS_NEWCONN_TO); int nIndexTo = ListView_GetNextItem(hwndTo, -1, LVNI_ALL | LVNI_SELECTED); while (-1 != nIndexTo && (pMember = (CCusTopMember *)GetListViewItemData(hwndTo, nIndexTo))) { toMemberList.push_back(pMember); nIndexTo = ListView_GetNextItem(hwndTo, nIndexTo, LVNI_ALL | LVNI_SELECTED); } if (toMemberList.empty()) break; // // init the list // FreeCusTopConnections(&m_NewConnectionList); // // build the connection list // CCusTopMemberList::iterator from, to; for (from = fromMemberList.begin(); from != fromMemberList.end(); from++) { for (to = toMemberList.begin(); to != toMemberList.end(); to++) { if (!lstrcmpi((*from)->m_bstrServer, (*to)->m_bstrServer)) continue; CCusTopConnection* pNew = new CCusTopConnection; BREAK_OUTOFMEMORY_IF_NULL(pNew, &hr); hr = pNew->Init( (*from)->m_bstrMemberDN, (*from)->m_bstrServer, (*from)->m_bstrSite, (*to)->m_bstrMemberDN, (*to)->m_bstrServer, (*to)->m_bstrSite, TRUE, CONNECTION_OPTYPE_ADD); BREAK_IF_FAILED(hr); m_NewConnectionList.push_back(pNew); } BREAK_IF_FAILED(hr); } if (SUCCEEDED(hr)) bValidInput = TRUE; } while (0); if (FAILED(hr)) { DisplayMessageBoxForHR(hr); return FALSE; } else if (bValidInput) { EndDialog(S_OK); return TRUE; } else { if (idString) DisplayMessageBoxWithOK(idString); return FALSE; } } LRESULT CNewConnections::OnCancel ( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled ) { /*++ Routine Description: Called OnCancel. Ends the dialog with S_FALSE; */ EndDialog(S_FALSE); return(true); } int CALLBACK MembersListCompareProc( IN LPARAM lParam1, IN LPARAM lParam2, IN LPARAM lParamColumn) { CCusTopMember* pItem1 = (CCusTopMember *)lParam1; CCusTopMember* pItem2 = (CCusTopMember *)lParam2; int iResult = 0; if (pItem1 && pItem2) { switch( lParamColumn) { case 0: // Sort by Server. iResult = lstrcmpi(pItem1->m_bstrServer, pItem2->m_bstrServer); break; case 1: // Sort by Site. iResult = lstrcmpi(pItem1->m_bstrSite, pItem2->m_bstrSite); break; default: iResult = 0; break; } } return(iResult); } LRESULT CNewConnections::OnNotify( IN UINT i_uMsg, IN WPARAM i_wParam, IN LPARAM i_lParam, IN OUT BOOL& io_bHandled ) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)i_lParam; io_bHandled = FALSE; // So that the base class gets this notify too if (IDC_FRS_NEWCONN_FROM == pNMListView->hdr.idFrom || IDC_FRS_NEWCONN_TO == pNMListView->hdr.idFrom) { HWND hwndList = GetDlgItem(pNMListView->hdr.idFrom); if (LVN_COLUMNCLICK == pNMListView->hdr.code) { // sort items ListView_SortItems( hwndList, MembersListCompareProc, (LPARAM)(pNMListView->iSubItem)); io_bHandled = TRUE; } } return io_bHandled; }