499 lines
13 KiB
C++
499 lines
13 KiB
C++
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1997.
|
||
|
//
|
||
|
// File: N C P R S H T . C P P
|
||
|
//
|
||
|
// Contents: NetCfg custom PropertySheet
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
// Author: billbe 8 Apr 1997
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#include "pch.h"
|
||
|
#pragma hdrstop
|
||
|
#include "ncprsht.h"
|
||
|
#include <prsht.h>
|
||
|
#include "nceh.h"
|
||
|
|
||
|
// Necessary evil globals
|
||
|
CAPAGES g_capPagesToAdd; // Counted array of pages to add after Property
|
||
|
// Sheet is initialized
|
||
|
CAINCP g_cai; // Counted array of INetCfgProperty pointers
|
||
|
HRESULT g_hr; // Global error code
|
||
|
BOOL g_fChanged; // Global flag representing whether a PSM_CHANGED
|
||
|
// message was sent by a page
|
||
|
|
||
|
DLGPROC lpfnOldWndProc; // Previous dialog procedure
|
||
|
|
||
|
// NetCfg Property Sheet dialog procedure
|
||
|
LONG FAR PASCAL NetCfgPsDlgProc(HWND hDlg, UINT msg, WPARAM wParam,
|
||
|
LPARAM lParam);
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: SetLastHresult
|
||
|
//
|
||
|
// Purpose: This sets a global hresult variable. The function
|
||
|
// is analogous to SetLastError
|
||
|
//
|
||
|
// Arguments:
|
||
|
// HRESULT [in] Result to set
|
||
|
//
|
||
|
// Returns: nothing
|
||
|
//
|
||
|
// Author: billbe 8 Apr 1997
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//
|
||
|
inline void
|
||
|
SetLastHresult(HRESULT hr)
|
||
|
{
|
||
|
g_hr = hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrGetLastHresult
|
||
|
//
|
||
|
// Purpose: This returns the value of the global hresult variable.
|
||
|
// The function is analogous to GetLastError
|
||
|
//
|
||
|
// Arguments:
|
||
|
// none
|
||
|
//
|
||
|
// Returns: HRESULT. Value of the global g_hr.
|
||
|
//
|
||
|
// Author: billbe 8 Apr 1997
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//
|
||
|
inline HRESULT
|
||
|
HrGetLastHresult()
|
||
|
{
|
||
|
return (g_hr);
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: ResetChanged
|
||
|
//
|
||
|
// Purpose: This resets the global changed flag. The reset state
|
||
|
// indicates that a PSM_VHANGED message was not sent
|
||
|
//
|
||
|
// Arguments:
|
||
|
// none
|
||
|
//
|
||
|
// Returns:
|
||
|
// (nothing)
|
||
|
//
|
||
|
// Author: billbe 3 May 1997
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//
|
||
|
inline void
|
||
|
ResetChanged()
|
||
|
{
|
||
|
g_fChanged = FALSE;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: SetChanged
|
||
|
//
|
||
|
// Purpose: This sets the global changed flag. The set state indicates
|
||
|
// that a PSM_CHANGED message was sent
|
||
|
//
|
||
|
// Arguments:
|
||
|
// none
|
||
|
//
|
||
|
// Returns:
|
||
|
// (nothing)
|
||
|
//
|
||
|
// Author: billbe 3 May 1997
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//
|
||
|
inline void
|
||
|
SetChanged()
|
||
|
{
|
||
|
g_fChanged = TRUE;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: FGetChanged
|
||
|
//
|
||
|
// Purpose: This returns the state of the global changed flag. The set
|
||
|
// state indicates whether a PSM_CHANGED message was sent
|
||
|
// or not.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// none
|
||
|
//
|
||
|
// Returns:
|
||
|
// BOOL. Value of the global g_fChanged flag.
|
||
|
//
|
||
|
// Author: billbe 3 May 1997
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//
|
||
|
inline BOOL
|
||
|
FGetChanged()
|
||
|
{
|
||
|
return (g_fChanged);
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: NetCfgPropSheetCallback
|
||
|
//
|
||
|
// Purpose: This callback is called after the aheet dialog is
|
||
|
// initialized. We subclass the dialog and add any OEM
|
||
|
// pages here (if common pages exist). See Win32 for
|
||
|
// discussion of PropSheetProc
|
||
|
//
|
||
|
// Arguments:
|
||
|
// HWND [in] hwndDlg handle to the property sheet dialog box
|
||
|
// UINT uMsg [in] message identifier
|
||
|
// LPARAM lParam [in] message parameter
|
||
|
//
|
||
|
// Returns: int, The function returns zero.
|
||
|
//
|
||
|
// Author: billbe 11 Nov 1996
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//
|
||
|
int
|
||
|
CALLBACK NetCfgPropSheetCallback(HWND hwndDlg, UINT uMsg, LPARAM lParam)
|
||
|
{
|
||
|
// If the sheet has just been initialized
|
||
|
if (uMsg == PSCB_INITIALIZED)
|
||
|
{
|
||
|
// Replace the original procedure with ours
|
||
|
lpfnOldWndProc = (DLGPROC)SetWindowLongPtr(hwndDlg, DWLP_DLGPROC, (LONG_PTR) NetCfgPsDlgProc);
|
||
|
Assert(lpfnOldWndProc);
|
||
|
|
||
|
// Add the OEM pages that were scheduled for late add
|
||
|
// This will cause them to be clipped if they are larger than
|
||
|
// the common (default) pages. Note that this is the desired
|
||
|
// result.
|
||
|
//
|
||
|
for (int i = 0; i < g_capPagesToAdd.nCount; i++)
|
||
|
{
|
||
|
PropSheet_AddPage(hwndDlg, g_capPagesToAdd.ahpsp[i]);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrCallValidateProperties
|
||
|
//
|
||
|
// Purpose: This function calls the notify objects'
|
||
|
// INetCfgProperties::ValidateProperties method.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// none
|
||
|
//
|
||
|
// Returns: HRESULT, S_OK if all of the INetCfgProperties return S_OK
|
||
|
// of the result of the first interface that does not
|
||
|
// return S_OK.
|
||
|
//
|
||
|
// Author: billbe 8 Apr 1997
|
||
|
//
|
||
|
// Notes: If one of the interfaces returns something other than S_OK, the
|
||
|
// others will not be called and the function will return the hresult
|
||
|
// of that interface.
|
||
|
//
|
||
|
HRESULT
|
||
|
HrCallValidateProperties(HWND hwndSheet)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
// enumerate through the counted array of interfaces
|
||
|
// and call ValidateProperties
|
||
|
//
|
||
|
for (int i = 0; i < g_cai.nCount; i++)
|
||
|
{
|
||
|
// At the first sign of non-S_OK get out
|
||
|
if (S_OK != (hr = g_cai.apncp[i]->ValidateProperties(hwndSheet)))
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
TraceError("HrCallValidateProperties", hr);
|
||
|
return (hr);
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: NetCfgPsDlgProc
|
||
|
//
|
||
|
// Purpose: This function is the dialog procedure for the property sheet
|
||
|
// See Win32 documentation on DialogProc for more information
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hwndDlg [in] handle to dialog box
|
||
|
// uMsg [in] message
|
||
|
// wParam [in] first message parameter
|
||
|
// lParam [in] second message parameter
|
||
|
//
|
||
|
// Returns: LONG, Except in response to the WM_INITDIALOG message, the
|
||
|
// dialog box procedure should return nonzero if it processes
|
||
|
// the message, and zero if it does not.
|
||
|
//
|
||
|
// Author: billbe 8 Apr 1997
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
LONG
|
||
|
FAR PASCAL NetCfgPsDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
switch (msg)
|
||
|
{
|
||
|
case WM_DESTROY:
|
||
|
// restore the dialog procedure before we exit
|
||
|
SetWindowLongPtr(hDlg, DWLP_DLGPROC, (LONG_PTR) lpfnOldWndProc);
|
||
|
break;
|
||
|
case WM_SYSCOMMAND:
|
||
|
// The user is closing through the system menu. This is like
|
||
|
// canceling
|
||
|
if (SC_CLOSE == wParam)
|
||
|
{
|
||
|
SetLastHresult(HRESULT_FROM_WIN32(ERROR_CANCELLED));
|
||
|
}
|
||
|
break;
|
||
|
case PSM_CHANGED:
|
||
|
SetChanged();
|
||
|
break;
|
||
|
case WM_COMMAND:
|
||
|
// If the user pressed OK
|
||
|
if ((IDOK == LOWORD(wParam)) && (BN_CLICKED == HIWORD(wParam)))
|
||
|
{
|
||
|
|
||
|
// Send a KillActive message to the currect page. This echoes
|
||
|
// what the Win32 propertysheet would do. This results in a
|
||
|
// second KillActive message being sent to the active page
|
||
|
// when the OK message is processed. It is necessary
|
||
|
// to send it here because we need its result before we
|
||
|
// call HrCallValidateProperties which is done before the OK
|
||
|
// is processed.
|
||
|
//
|
||
|
|
||
|
NMHDR nmhdr;
|
||
|
ZeroMemory(&nmhdr, sizeof(NMHDR));
|
||
|
nmhdr.hwndFrom = hDlg;
|
||
|
nmhdr.code = PSN_KILLACTIVE;
|
||
|
|
||
|
if (SendMessage(PropSheet_GetCurrentPageHwnd(hDlg), WM_NOTIFY,
|
||
|
0, (LPARAM) &nmhdr))
|
||
|
{
|
||
|
// The page does not want the PropertySheet to go away so exit
|
||
|
// without allowing the original procedure to get the message
|
||
|
return (TRUE);
|
||
|
}
|
||
|
|
||
|
// The current page validated okay so now we must call all the
|
||
|
// ValidateProperties necessary.
|
||
|
if (S_OK != HrCallValidateProperties(hDlg))
|
||
|
{
|
||
|
// One of the interfaces returned something other than S_OK
|
||
|
// from Validateproperties so we exit without letting
|
||
|
// the original dialog procedure process the message.
|
||
|
// This will keep the PropertySheet active.
|
||
|
return (TRUE);
|
||
|
}
|
||
|
}
|
||
|
else if (IDCANCEL == LOWORD(wParam) && BN_CLICKED == HIWORD(wParam))
|
||
|
{
|
||
|
// If Cancel was pressed set the last hresult
|
||
|
SetLastHresult(HRESULT_FROM_WIN32(ERROR_CANCELLED));
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
// call the original dialog procedure
|
||
|
return (CallWindowProc((WNDPROC)lpfnOldWndProc, hDlg, msg, wParam, lParam));
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: VerifyCAPAGES
|
||
|
//
|
||
|
// Synopsis: function to check the validity of a given CAPAGES structure
|
||
|
//
|
||
|
// Arguments: [cap] --
|
||
|
//
|
||
|
// Returns: BOOL
|
||
|
//
|
||
|
// Notes: 14-Jan-1998 SumitC Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
BOOL
|
||
|
FVerifyCAPAGES(const struct CAPAGES& cap)
|
||
|
{
|
||
|
BOOL fGood = FALSE;
|
||
|
|
||
|
if (cap.nCount == 0)
|
||
|
{
|
||
|
fGood = (cap.ahpsp == NULL);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fGood = !IsBadReadPtr(cap.ahpsp, sizeof(HPROPSHEETPAGE) * cap.nCount);
|
||
|
}
|
||
|
|
||
|
return fGood;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrNetCfgPropertySheet
|
||
|
//
|
||
|
// Purpose: This function is sets up our custom property sheet which is
|
||
|
// a subclassed Win32 property sheet.
|
||
|
// See Win32 documentation on PropertySheet for more information
|
||
|
//
|
||
|
// Arguments:
|
||
|
// lppsh [in] a PROPSHEETHEADER
|
||
|
// capOem [in] A counted array of Oem pages
|
||
|
// pStartPage [in] Name of the initial page that appears when the property
|
||
|
// sheet dialog box is created. This member can specify
|
||
|
// either the identifier of a string resource or the
|
||
|
// pointer to a string that specifies the name.
|
||
|
// caiProperties [in] A counted array of INetCfgProperties interfaces
|
||
|
//
|
||
|
// Returns: HRESULT, S_OK if OK was pressed and changes were made,
|
||
|
// S_FALSE if OK was pressed and no changes were
|
||
|
// made. An error code otherwise.
|
||
|
//
|
||
|
// Author: billbe 8 Apr 1997
|
||
|
//
|
||
|
// Notes:
|
||
|
// HRESULT_FROM_WIN32(ERROR_CANCELLED) is returned if the
|
||
|
// cancel button was pressed
|
||
|
//
|
||
|
HRESULT
|
||
|
HrNetCfgPropertySheet(
|
||
|
IN OUT LPPROPSHEETHEADER lppsh,
|
||
|
IN const CAPAGES& capOem,
|
||
|
IN PCWSTR pStartPage,
|
||
|
const CAINCP& caiProperties)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
Assert(lppsh);
|
||
|
|
||
|
// The following should not be set since we are setting them
|
||
|
Assert(0 == lppsh->nPages);
|
||
|
Assert(NULL == lppsh->phpage);
|
||
|
Assert(!(PSH_USECALLBACK & lppsh->dwFlags));
|
||
|
Assert(!(PSH_PROPSHEETPAGE & lppsh->dwFlags));
|
||
|
|
||
|
// If a start page was specified than there had better be Oem Pages
|
||
|
Assert(FImplies(pStartPage, capOem.nCount));
|
||
|
|
||
|
// We have to have at least one INetCfgProperties since we are here
|
||
|
Assert(caiProperties.nCount);
|
||
|
Assert(caiProperties.apncp);
|
||
|
|
||
|
// Set our global CAINCP structure
|
||
|
g_cai.nCount = caiProperties.nCount;
|
||
|
g_cai.apncp = caiProperties.apncp;
|
||
|
|
||
|
// Reset our global CAPAGES
|
||
|
g_capPagesToAdd.nCount = 0;
|
||
|
g_capPagesToAdd.ahpsp = NULL;
|
||
|
|
||
|
// We need to set up a callback to subclass the dialog
|
||
|
lppsh->dwFlags |= PSH_USECALLBACK;
|
||
|
lppsh->pfnCallback = NetCfgPropSheetCallback;
|
||
|
|
||
|
// There are no common pages to show so we will use the OEM pages
|
||
|
// instead
|
||
|
Assert(capOem.nCount);
|
||
|
if (FVerifyCAPAGES(capOem))
|
||
|
{
|
||
|
lppsh->nPages = capOem.nCount;
|
||
|
lppsh->phpage = capOem.ahpsp;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//$ REVIEW sumitc: or just return E_INVALIDARG?
|
||
|
lppsh->nPages = 0;
|
||
|
lppsh->phpage = NULL;
|
||
|
}
|
||
|
Assert(FImplies(lppsh->nPages, lppsh->phpage));
|
||
|
|
||
|
// If a start page was specified, set the propsheet flag and
|
||
|
// start page member.
|
||
|
// Note: (billbe) This will not work if common pages exist since
|
||
|
// that means Oem pages are added after the sheet is initialized
|
||
|
if (pStartPage)
|
||
|
{
|
||
|
lppsh->dwFlags |= PSH_USEPSTARTPAGE;
|
||
|
lppsh->pStartPage = pStartPage;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Clear last hresult and changed flag
|
||
|
SetLastHresult(S_OK);
|
||
|
ResetChanged();
|
||
|
|
||
|
// Call the Win32 property sheet
|
||
|
NC_TRY
|
||
|
{
|
||
|
int iRetVal = PropertySheet(lppsh);
|
||
|
if (-1 == iRetVal)
|
||
|
{
|
||
|
// The Win32 Sheet failed so we return E_FAIL
|
||
|
SetLastHresult(E_FAIL);
|
||
|
}
|
||
|
}
|
||
|
NC_CATCH_ALL
|
||
|
{
|
||
|
hr = E_UNEXPECTED;
|
||
|
}
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
// if the catch hasn't set hr to some error
|
||
|
hr = HrGetLastHresult();
|
||
|
}
|
||
|
|
||
|
// if everthing went well, return the correct value based on whether
|
||
|
// any of the pages changed
|
||
|
//
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// S_OK - changes were made, S_FALSE - no changes were made
|
||
|
hr = FGetChanged() ? S_OK : S_FALSE;
|
||
|
}
|
||
|
|
||
|
TraceError("HrNetCfgPropertySheet",
|
||
|
((HRESULT_FROM_WIN32(ERROR_CANCELLED) == hr) || (S_FALSE == hr)) ? S_OK : hr);
|
||
|
|
||
|
return hr;
|
||
|
}
|