1803 lines
48 KiB
C++
1803 lines
48 KiB
C++
/*++
|
|
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;
|
|
}
|