You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
763 lines
15 KiB
763 lines
15 KiB
/*++
|
|
|
|
Copyright (c) 1994-1999 Microsoft Corporation
|
|
|
|
Module Name :
|
|
|
|
fservic.cpp
|
|
|
|
Abstract:
|
|
|
|
FTP Service Property Page
|
|
|
|
Author:
|
|
|
|
Ronald Meijer (ronaldm)
|
|
|
|
Project:
|
|
|
|
Internet Services Manager
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
//
|
|
// Include Files
|
|
//
|
|
#include "stdafx.h"
|
|
#include "common.h"
|
|
#include "inetprop.h"
|
|
#include "InetMgrApp.h"
|
|
#include "shts.h"
|
|
#include "ftpsht.h"
|
|
#include "fservic.h"
|
|
#include "usersess.h"
|
|
#include "iisobj.h"
|
|
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char BASED_CODE THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
|
|
|
|
//
|
|
// Some sanity values on max connections
|
|
//
|
|
#define MAX_MAX_CONNECTIONS (2000000001L)
|
|
#define INITIAL_MAX_CONNECTIONS ( 1000L)
|
|
#define UNLIMITED_CONNECTIONS (2000000000L)
|
|
|
|
#define MAX_TIMEOUT (0x7FFFFFFF)
|
|
|
|
#define LIMITED_CONNECTIONS_MIN (10)
|
|
#define LIMITED_CONNECTIONS_MAX (40)
|
|
|
|
|
|
|
|
IMPLEMENT_DYNCREATE(CFtpServicePage, CInetPropertyPage)
|
|
|
|
|
|
|
|
CFtpServicePage::CFtpServicePage(
|
|
IN CInetPropertySheet * pSheet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Constructor for FTP service property page
|
|
|
|
Arguments:
|
|
|
|
CInetPropertySheet * pSheet : Associated property sheet
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
: CInetPropertyPage(CFtpServicePage::IDD, pSheet)
|
|
{
|
|
#ifdef _DEBUG
|
|
|
|
afxMemDF |= checkAlwaysMemDF;
|
|
|
|
#endif // _DEBUG
|
|
|
|
#if 0 // Keep Class Wizard happy
|
|
|
|
//{{AFX_DATA_INIT(CFtpServicePage)
|
|
m_strComment = _T("");
|
|
m_nTCPPort = 20;
|
|
m_nUnlimited = RADIO_LIMITED;
|
|
m_nIpAddressSel = -1;
|
|
m_fEnableLogging = FALSE;
|
|
//}}AFX_DATA_INIT
|
|
|
|
m_nMaxConnections = 50;
|
|
m_nVisibleMaxConnections = 50;
|
|
m_nConnectionTimeOut = 600;
|
|
m_iaIpAddress = (LONG)0L;
|
|
m_strDomainName = _T("");
|
|
|
|
#endif // 0
|
|
}
|
|
|
|
|
|
|
|
CFtpServicePage::~CFtpServicePage()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Destructor
|
|
|
|
Arguments:
|
|
|
|
N/A
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
{
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CFtpServicePage::DoDataExchange(
|
|
IN CDataExchange * pDX
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialise/Store control data
|
|
|
|
Arguments:
|
|
|
|
CDataExchange * pDX - DDX/DDV control structure
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
CInetPropertyPage::DoDataExchange(pDX);
|
|
|
|
if (!pDX->m_bSaveAndValidate)
|
|
{
|
|
m_fEnableLogging = LoggingEnabled(m_dwLogType);
|
|
}
|
|
|
|
//{{AFX_DATA_MAP(CFtpServicePage)
|
|
DDX_Radio(pDX, IDC_RADIO_UNLIMITED, m_nUnlimited);
|
|
DDX_Check(pDX, IDC_CHECK_ENABLE_LOGGING, m_fEnableLogging);
|
|
DDX_Text(pDX, IDC_EDIT_COMMENT, m_strComment);
|
|
DDV_MinMaxChars(pDX, m_strComment, 0, MAX_PATH);
|
|
DDX_Control(pDX, IDC_EDIT_MAX_CONNECTIONS, m_edit_MaxConnections);
|
|
DDX_Control(pDX, IDC_STATIC_LOG_PROMPT, m_static_LogPrompt);
|
|
DDX_Control(pDX, IDC_BUTTON_PROPERTIES, m_button_LogProperties);
|
|
DDX_Control(pDX, IDC_COMBO_IP_ADDRESS, m_combo_IpAddresses);
|
|
DDX_Control(pDX, IDC_COMBO_LOG_FORMATS, m_combo_LogFormats);
|
|
//}}AFX_DATA_MAP
|
|
|
|
if (!IsMasterInstance())
|
|
{
|
|
// This Needs to come before DDX_Text which will try to put text big number into small number
|
|
DDV_MinMaxBalloon(pDX, IDC_EDIT_TCP_PORT, 1, 65535);
|
|
}
|
|
DDX_TextBalloon(pDX, IDC_EDIT_TCP_PORT, m_nTCPPort);
|
|
|
|
if (pDX->m_bSaveAndValidate && !FetchIpAddressFromCombo(
|
|
m_combo_IpAddresses,
|
|
m_oblIpAddresses,
|
|
m_iaIpAddress
|
|
))
|
|
{
|
|
pDX->Fail();
|
|
}
|
|
|
|
//
|
|
// Private DDX/DDV Routines
|
|
//
|
|
int nMin = IsMasterInstance() ? 0 : 1;
|
|
|
|
|
|
if (!m_f10ConnectionLimit && !m_fUnlimitedConnections)
|
|
{
|
|
// This Needs to come before DDX_Text which will try to put text big number into small number
|
|
DDV_MinMaxBalloon(pDX, IDC_EDIT_MAX_CONNECTIONS, 0, UNLIMITED_CONNECTIONS);
|
|
}
|
|
|
|
if (!pDX->m_bSaveAndValidate || !m_fUnlimitedConnections )
|
|
{
|
|
DDX_Text(pDX, IDC_EDIT_MAX_CONNECTIONS, m_nVisibleMaxConnections);
|
|
}
|
|
|
|
if (m_f10ConnectionLimit)
|
|
{
|
|
//
|
|
// Special validation for unlimited connections. We use a bogus
|
|
// numeric check for data validation. Number adjustment happens
|
|
// later.
|
|
//
|
|
if (pDX->m_bSaveAndValidate &&
|
|
(m_nVisibleMaxConnections < 0 ||
|
|
m_nVisibleMaxConnections > UNLIMITED_CONNECTIONS))
|
|
{
|
|
TCHAR szMin[32];
|
|
TCHAR szMax[32];
|
|
wsprintf(szMin, _T("%ld"), 0);
|
|
wsprintf(szMax, _T("%ld"), 40);
|
|
CString prompt;
|
|
AfxFormatString2(prompt, AFX_IDP_PARSE_INT_RANGE, szMin, szMax);
|
|
AfxMessageBox(prompt, MB_ICONEXCLAMATION);
|
|
prompt.Empty(); // exception prep
|
|
pDX->Fail();
|
|
}
|
|
}
|
|
|
|
// This Needs to come before DDX_Text which will try to put text big number into small number
|
|
DDV_MinMaxBalloon(pDX, IDC_EDIT_CONNECTION_TIMEOUT, nMin, MAX_TIMEOUT);
|
|
DDX_Text(pDX, IDC_EDIT_CONNECTION_TIMEOUT, m_nConnectionTimeOut);
|
|
|
|
if (pDX->m_bSaveAndValidate)
|
|
{
|
|
EnableLogging(m_dwLogType, m_fEnableLogging);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Message Map
|
|
//
|
|
BEGIN_MESSAGE_MAP(CFtpServicePage, CInetPropertyPage)
|
|
//{{AFX_MSG_MAP(CFtpServicePage)
|
|
ON_BN_CLICKED(IDC_CHECK_ENABLE_LOGGING, OnCheckEnableLogging)
|
|
ON_BN_CLICKED(IDC_RADIO_LIMITED, OnRadioLimited)
|
|
ON_BN_CLICKED(IDC_RADIO_UNLIMITED, OnRadioUnlimited)
|
|
ON_BN_CLICKED(IDC_BUTTON_CURRENT_SESSIONS, OnButtonCurrentSessions)
|
|
ON_BN_CLICKED(IDC_BUTTON_PROPERTIES, OnButtonProperties)
|
|
ON_WM_DESTROY()
|
|
//}}AFX_MSG_MAP
|
|
|
|
ON_EN_CHANGE(IDC_EDIT_TCP_PORT, OnItemChanged)
|
|
ON_EN_CHANGE(IDC_EDIT_COMMENT, OnItemChanged)
|
|
ON_EN_CHANGE(IDC_EDIT_MAX_CONNECTIONS, OnItemChanged)
|
|
ON_EN_CHANGE(IDC_EDIT_CONNECTION_TIMEOUT, OnItemChanged)
|
|
ON_CBN_EDITCHANGE(IDC_COMBO_IP_ADDRESS, OnItemChanged)
|
|
ON_CBN_SELCHANGE(IDC_COMBO_IP_ADDRESS, OnItemChanged)
|
|
ON_CBN_SELCHANGE(IDC_COMBO_LOG_FORMATS, OnItemChanged)
|
|
|
|
END_MESSAGE_MAP()
|
|
|
|
|
|
|
|
void
|
|
CFtpServicePage::SetControlStates()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the states of the dialog control depending on its current
|
|
values.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
if (m_edit_MaxConnections.m_hWnd)
|
|
{
|
|
m_edit_MaxConnections.EnableWindow(!m_fUnlimitedConnections);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CFtpServicePage::PopulateKnownIpAddresses()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fill the combo box with known ip addresses
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
BeginWaitCursor();
|
|
PopulateComboWithKnownIpAddresses(
|
|
QueryServerName(),
|
|
m_combo_IpAddresses,
|
|
m_iaIpAddress,
|
|
m_oblIpAddresses,
|
|
m_nIpAddressSel
|
|
);
|
|
EndWaitCursor();
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Message Handlers
|
|
//
|
|
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
|
|
|
|
|
|
|
BOOL
|
|
CFtpServicePage::OnInitDialog()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
WM_INITDIALOG handler. Initialize the dialog.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE if no focus is to be set automatically, FALSE if the focus
|
|
is already set.
|
|
|
|
--*/
|
|
{
|
|
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
|
|
|
|
CInetPropertyPage::OnInitDialog();
|
|
|
|
//
|
|
// Take our direction from a phony button
|
|
//
|
|
CRect rc(0, 0, 0, 0);
|
|
m_ocx_LogProperties.Create(
|
|
_T("LogUI"),
|
|
WS_BORDER,
|
|
rc,
|
|
this,
|
|
IDC_LOGUICTRL
|
|
);
|
|
|
|
//
|
|
// Initialize the logging ocx; pass it the metabase path of the
|
|
// virtual server.
|
|
// TODO: Rewrite this crappy logui control to make it more predictable.
|
|
// Here metabase path should not contain leading / and trailing Root
|
|
//
|
|
CString path_inst = QueryMetaPath();
|
|
CString path;
|
|
if (IsMasterInstance())
|
|
{
|
|
CMetabasePath::GetServicePath(path_inst, path);
|
|
}
|
|
else
|
|
{
|
|
CMetabasePath::GetInstancePath(path_inst, path);
|
|
}
|
|
if (path[0] == _T('/'))
|
|
{
|
|
path = path.Right(path.GetLength() - 1);
|
|
}
|
|
m_ocx_LogProperties.SetAdminTarget(QueryServerName(), path);
|
|
m_ocx_LogProperties.SetUserData(QueryAuthInfo()->QueryUserName(), QueryAuthInfo()->QueryPassword());
|
|
m_ocx_LogProperties.SetComboBox(m_combo_LogFormats.m_hWnd);
|
|
|
|
GetDlgItem(IDC_RADIO_UNLIMITED)->EnableWindow(!m_f10ConnectionLimit);
|
|
|
|
if (IsMasterInstance() || !HasAdminAccess())
|
|
{
|
|
GetDlgItem(IDC_STATIC_IPADDRESS)->EnableWindow(FALSE);
|
|
GetDlgItem(IDC_STATIC_TCP_PORT)->EnableWindow(FALSE);
|
|
GetDlgItem(IDC_EDIT_TCP_PORT)->EnableWindow(FALSE);
|
|
m_combo_IpAddresses.EnableWindow(FALSE);
|
|
GetDlgItem(IDC_STATIC_DESCRIPTION)->EnableWindow(FALSE);
|
|
GetDlgItem(IDC_EDIT_COMMENT)->EnableWindow(FALSE);
|
|
}
|
|
|
|
PopulateKnownIpAddresses();
|
|
SetControlStates();
|
|
SetLogState();
|
|
|
|
GetDlgItem(IDC_BUTTON_CURRENT_SESSIONS)->EnableWindow(!IsMasterInstance());
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/* virtual */
|
|
HRESULT
|
|
CFtpServicePage::FetchLoadedValues()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Move configuration data from sheet to dialog controls
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
CError err;
|
|
|
|
m_f10ConnectionLimit = Has10ConnectionLimit();
|
|
|
|
BEGIN_META_INST_READ(CFtpSheet)
|
|
FETCH_INST_DATA_FROM_SHEET(m_nMaxConnections);
|
|
FETCH_INST_DATA_FROM_SHEET(m_nConnectionTimeOut);
|
|
FETCH_INST_DATA_FROM_SHEET(m_iaIpAddress);
|
|
FETCH_INST_DATA_FROM_SHEET(m_nTCPPort);
|
|
FETCH_INST_DATA_FROM_SHEET(m_strDomainName);
|
|
FETCH_INST_DATA_FROM_SHEET(m_strComment);
|
|
FETCH_INST_DATA_FROM_SHEET(m_dwLogType);
|
|
|
|
m_fUnlimitedConnections = m_nMaxConnections >= MAX_MAX_CONNECTIONS;
|
|
|
|
if (m_f10ConnectionLimit)
|
|
{
|
|
m_fUnlimitedConnections = FALSE;
|
|
if ((LONG)m_nMaxConnections > LIMITED_CONNECTIONS_MAX)
|
|
{
|
|
m_nMaxConnections = LIMITED_CONNECTIONS_MAX;
|
|
}
|
|
}
|
|
|
|
m_nVisibleMaxConnections = m_fUnlimitedConnections
|
|
? INITIAL_MAX_CONNECTIONS
|
|
: m_nMaxConnections;
|
|
|
|
//
|
|
// Set radio value
|
|
//
|
|
m_nUnlimited = m_fUnlimitedConnections ? RADIO_UNLIMITED : RADIO_LIMITED;
|
|
|
|
m_nOldTCPPort = m_nTCPPort;
|
|
END_META_INST_READ(err)
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
|
|
|
|
HRESULT
|
|
CFtpServicePage::SaveInfo()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Save the information on this property page
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Error return code
|
|
|
|
--*/
|
|
{
|
|
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
|
|
ASSERT(IsDirty());
|
|
|
|
TRACEEOLID("Saving FTP service page now...");
|
|
|
|
CError err;
|
|
|
|
m_nMaxConnections = m_fUnlimitedConnections
|
|
? MAX_MAX_CONNECTIONS : m_nVisibleMaxConnections;
|
|
|
|
//
|
|
// Check to make sure we're not violating the license
|
|
// agreement
|
|
//
|
|
if (m_f10ConnectionLimit)
|
|
{
|
|
if (m_nMaxConnections > LIMITED_CONNECTIONS_MAX)
|
|
{
|
|
DoHelpMessageBox(m_hWnd,IDS_CONNECTION_LIMIT, MB_APPLMODAL | MB_OK | MB_ICONINFORMATION, 0);
|
|
m_nMaxConnections = LIMITED_CONNECTIONS_MIN;
|
|
}
|
|
else if (m_nMaxConnections > LIMITED_CONNECTIONS_MIN
|
|
&& m_nMaxConnections <= LIMITED_CONNECTIONS_MAX)
|
|
{
|
|
DoHelpMessageBox(m_hWnd,IDS_WRN_CONNECTION_LIMIT, MB_APPLMODAL | MB_OK | MB_ICONINFORMATION, 0);
|
|
}
|
|
}
|
|
|
|
CString strBinding;
|
|
CStringListEx m_strlBindings;
|
|
|
|
CInstanceProps::BuildBinding(
|
|
strBinding,
|
|
m_iaIpAddress,
|
|
m_nTCPPort,
|
|
m_strDomainName
|
|
);
|
|
m_strlBindings.AddTail(strBinding);
|
|
m_ocx_LogProperties.ApplyLogSelection();
|
|
|
|
BeginWaitCursor();
|
|
BEGIN_META_INST_WRITE(CFtpSheet)
|
|
STORE_INST_DATA_ON_SHEET(m_nMaxConnections);
|
|
STORE_INST_DATA_ON_SHEET(m_nMaxConnections);
|
|
STORE_INST_DATA_ON_SHEET(m_nConnectionTimeOut);
|
|
STORE_INST_DATA_ON_SHEET(m_dwLogType);
|
|
STORE_INST_DATA_ON_SHEET(m_strComment);
|
|
STORE_INST_DATA_ON_SHEET(m_strlBindings);
|
|
END_META_INST_WRITE(err)
|
|
EndWaitCursor();
|
|
|
|
if (err.Succeeded())
|
|
{
|
|
CIISMBNode * pNode = (CIISMBNode *)GetSheet()->GetParameter();
|
|
ASSERT(pNode != NULL);
|
|
pNode->Refresh(FALSE);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CFtpServicePage::OnRadioLimited()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
'limited' radio button handler
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
m_fUnlimitedConnections = FALSE;
|
|
SetControlStates();
|
|
m_edit_MaxConnections.SetSel(0, -1);
|
|
m_edit_MaxConnections.SetFocus();
|
|
OnItemChanged();
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CFtpServicePage::OnRadioUnlimited()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
'unlimited' radio button handler
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
m_fUnlimitedConnections = TRUE;
|
|
OnItemChanged();
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CFtpServicePage::OnItemChanged()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Register a change in control value on this page. Mark the page as dirty.
|
|
All change messages map to this function
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
SetControlStates();
|
|
SetModified(TRUE);
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CFtpServicePage::SetLogState()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the enabled state of the logging controls depending on
|
|
whether logging is currently enabled
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
m_static_LogPrompt.EnableWindow(m_fEnableLogging);
|
|
m_combo_LogFormats.EnableWindow(m_fEnableLogging);
|
|
m_button_LogProperties.EnableWindow(m_fEnableLogging);
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CFtpServicePage::OnCheckEnableLogging()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
'Enable logging' checkbox has been toggled. Reset the state
|
|
of the dialog
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
m_fEnableLogging = !m_fEnableLogging;
|
|
SetLogState();
|
|
OnItemChanged();
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CFtpServicePage::OnButtonProperties()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Pass on "log properties" button click to the ocx.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
|
|
m_ocx_LogProperties.DoClick();
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CFtpServicePage::OnButtonCurrentSessions()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
'Current Sessions' button has been pressed. Bring up the current
|
|
sessions dialog
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
-*/
|
|
{
|
|
CComAuthInfo * pAuth = GetSheet()->QueryAuthInfo();
|
|
ASSERT(pAuth != NULL);
|
|
CUserSessionsDlg dlg(
|
|
pAuth->QueryServerName(),
|
|
QueryInstance(),
|
|
pAuth->QueryUserName(),
|
|
pAuth->QueryPassword(),
|
|
this,
|
|
GetSheet()->IsLocal()
|
|
);
|
|
dlg.DoModal();
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CFtpServicePage::OnDestroy()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
WM_DESTROY handler. Clean up internal data
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
CInetPropertyPage::OnDestroy();
|
|
|
|
if (m_ocx_LogProperties.m_hWnd)
|
|
{
|
|
m_ocx_LogProperties.Terminate();
|
|
}
|
|
}
|