Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1332 lines
38 KiB

/////////////////////////////////////////////////////////////////////////////
// FILE : C_Snapin.cpp (Snapin.cpp) //
// //
// DESCRIPTION : Implementation file for //
// CSnapin class //
// CSnapinComponent class //
// //
// AUTHOR : ATL Snapin wizard //
// //
// HISTORY : //
// May 25 1998 adik Init. //
// Aug 24 1998 adik WEB IVR instead IVR. //
// Sep 14 1998 yossg seperate common source to an included file //
// Oct 18 1998 adik Merged with new wizard version. //
// Jan 12 1999 adik Add ParentArrayInterfaceFromDataObject. //
// Mar 28 1999 adik Remove persistence support. //
// Mar 30 1999 adik Support of ICometSnapinNode in IDataObject. //
// Apr 27 1999 adik Help support. //
// Jun 10 1999 adik Change bitmap mask to white. //
// Jun 14 1999 roytal used UNREFERENCED_PARAMETER to fix build wrn //
// Jun 21 1999 adik Handle MMCN_COLUMN_CLICK to avoid ASSERT. //
// Jun 22 1999 zvib change handling of property change //
// //
// Oct 13 1999 yossg Welcome to Fax Server //
// Jan 19 2000 yossg Add CFaxPropertyChangeNotification to //
// CSnapinComponent::Notify MMCN_PROPERTY_CHANGE //
// Apr 14 2000 yossg Add support for primary snapin mode //
// Jun 25 2000 yossg Add stream and command line primary snapin //
// machine targeting. //
// //
// Copyright (C) 1998 - 2000 Microsoft Corporation All Rights Reserved //
/////////////////////////////////////////////////////////////////////////////
#include "StdAfx.h"
#include "C_Snapin.h"
#include "ResUtil.h"
#include "FaxServerNode.h"
#include "FaxMMCPropertyChange.h"
#include "FxsValid.h"
#include "Icons.h"
#include <ObjBase.h>
#include <windns.h> //DNS_MAX_NAME_BUFFER_LENGTH
HRESULT
AddBitmaps(IImageList *pImageList)
{
HBITMAP hBitmap16 = NULL;
HBITMAP hBitmap32 = NULL;
HINSTANCE hInst;
HRESULT hr;
// Load bitmaps associated with the scope pane
// and add them to the image list
// Loads the default bitmaps generated by the wizard
// Change as required
hInst = _Module.GetResourceInstance();
//
// Load 16 bits
//
hBitmap16 = LoadBitmap(hInst, MAKEINTRESOURCE(IDR_TOOLBAR_16));
if (hBitmap16 == NULL)
{
hr = E_FAIL;
ATLTRACE(_T("LoadBitmap failed\n"));
goto Cleanup;
}
//
// Load 32 bits
//
hBitmap32 = LoadBitmap(hInst, MAKEINTRESOURCE(IDR_TOOLBAR_32));
if (hBitmap32 == NULL)
{
hr = E_FAIL;
ATLTRACE(_T("LoadBitmap failed\n"));
goto Cleanup;
}
//
// Add to image list
//
hr = pImageList->ImageListSetStrip(
(LONG_PTR*)hBitmap16,
(LONG_PTR*)hBitmap32,
0,
RGB(0, 0, 0));
if ( FAILED(hr) )
{
ATLTRACE(_T("IImageList::ImageListSetStrip failed\n"));
goto Cleanup;
}
Cleanup:
if (NULL != hBitmap32)
{
DeleteObject(hBitmap32);
}
if (NULL != hBitmap16)
{
DeleteObject(hBitmap16);
}
return hr;
}
class CFaxServerNode;
CSnapin::CSnapin()
{
m_bstrServerName = L""; //LocalMachine as default
m_fAllowOverrideServerName = TRUE;
m_pPrimaryFaxServerNode = new CFaxServerNode(
NULL,
this,
L""); //m_bstrServerName.m_str
ATLASSERT(m_pPrimaryFaxServerNode != NULL);
m_pPrimaryFaxServerNode->SetIcons(IMAGE_FAX, IMAGE_FAX);
m_pNode = (CSnapInItem *) m_pPrimaryFaxServerNode;
m_pComponentData = this;
m_CSnapinExtData.m_pComponentData = this;
}
CSnapin::~CSnapin()
{
if (NULL != m_pPrimaryFaxServerNode)
{
delete m_pPrimaryFaxServerNode;
m_pPrimaryFaxServerNode = NULL;
}
m_pNode = NULL;
}
HRESULT
CSnapin::Initialize(LPUNKNOWN pUnknown)
{
HRESULT hr = IComponentDataImpl<CSnapin, CSnapinComponent >::Initialize(pUnknown);
if (FAILED(hr))
return hr;
CComPtr<IImageList> spImageList;
if (m_spConsole->QueryScopeImageList(&spImageList) != S_OK)
{
ATLTRACE(_T("IConsole::QueryScopeImageList failed\n"));
return E_UNEXPECTED;
}
hr = ::AddBitmaps(spImageList);
return hr;
}
HRESULT
CSnapinExtData::CreatePropertyPages(LPPROPERTYSHEETCALLBACK lpProvider,
LONG_PTR handle,
IUnknown* pUnk,
DATA_OBJECT_TYPES type)
{
UNREFERENCED_PARAMETER (lpProvider);
UNREFERENCED_PARAMETER (handle);
UNREFERENCED_PARAMETER (pUnk);
// override this method.
if (type == CCT_SCOPE || type == CCT_RESULT)
{
return S_OK;
}
return E_UNEXPECTED;
}
//////////////////////////////////////////////////////////////////////////////
CSnapinComponent::CSnapinComponent():m_pSelectedNode(NULL)
{
}
//////////////////////////////////////////////////////////////////////////////
CSnapinComponent::~CSnapinComponent()
{
}
//////////////////////////////////////////////////////////////////////////////
/*++
CSnapinComponent::Notify
--*/
//////////////////////////////////////////////////////////////////////////////
HRESULT
CSnapinComponent::Notify(LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param)
{
DEBUG_FUNCTION_NAME( _T("CSnapinComponent::Notify"));
HRESULT hr = S_OK;
if(lpDataObject != NULL && MMCN_SHOW != event)
{
return IComponentImpl<CSnapinComponent>::Notify(lpDataObject, event, arg, param);
}
//
// In this routine we handle only
// lpDataObject ==NULL, or we have a MMCN_SHOW event.
//
if(MMCN_SHOW == event)
{
//
// On Show event, we want to keep, or reset
// the node currenlty selected
//
ATLASSERT(lpDataObject != NULL);
//
// Retreive the pItem data type
//
CSnapInItem* pItem;
DATA_OBJECT_TYPES type;
hr = m_pComponentData->GetDataClass(lpDataObject, &pItem, &type);
if(FAILED(hr))
return(hr);
if( arg )
{
// We are being selected.
m_pSelectedNode = pItem;
}
else
{
// We are being deselected.
// Check to make sure that our result view doesn't think
// this node is the currently selected one.
if( m_pSelectedNode == pItem)
{
// We don't want to be the selected node anymore.
m_pSelectedNode = NULL;
}
}
//
// Call SnapinItem notification routine
//
return IComponentImpl<CSnapinComponent>::Notify(lpDataObject, event, arg, param);
}
//
// lpDataObject == NULL
//
// Currently handling only View Change (UpdateAllViews)
// And PropertyChange
switch (event)
{
case MMCN_VIEW_CHANGE:
if( ( arg == NULL || (CSnapInItem *) arg == m_pSelectedNode ) && m_pSelectedNode != NULL )
{
if ( FXS_HINT_DELETE_ALL_RSLT_ITEMS == param)
{
ATLASSERT(m_spConsole);
CComQIPtr<IResultData, &IID_IResultData> pResultData(m_spConsole);
ATLASSERT(pResultData);
hr = pResultData->DeleteAllRsltItems();
if( FAILED(hr) )
{
DebugPrintEx(
DEBUG_ERR,
TEXT("Fail to DeleteAllRsltItems().(hRc: %08X)"),
hr);
return( hr );
}
break;
}
// We basically tell MMC to simulate reselecting the
// currently selected node, which causes it to redraw.
// This will cause MMC to send the MMCN_SHOW notification
// to the selected node.
// This function requires an HSCOPEITEM. This is the ID member
// of the HSCOPEDATAITEM associated with this node.
SCOPEDATAITEM *pScopeDataItem;
m_pSelectedNode->GetScopeData(&pScopeDataItem);
hr = m_spConsole->SelectScopeItem(pScopeDataItem->ID);
}
break;
case MMCN_PROPERTY_CHANGE:
CFaxPropertyChangeNotification * pNotification;
CSnapInItem * pItem;
pNotification = ( CFaxPropertyChangeNotification * ) param;
ATLASSERT(pNotification);
pItem = pNotification->pItem;
ATLASSERT(pItem);
hr = pItem->Notify(event, arg, param, NULL, (IComponent*) this, CCT_RESULT);
break;
// CSnapInItem * pNode;
// pNode = (CSnapInItem *) param;
// hr = pNode->Notify(event, arg, param, NULL, (IComponent*) this, CCT_RESULT);
// break;
// case MMCN_PROPERTY_CHANGE:
// {
//
// CComQIPtr<IResultData, &IID_IResultData> spResultData(m_spConsole);
// hr = spResultData->UpdateItem((HRESULTITEM)(param));
// }
// break;
case MMCN_SNAPINHELP:
ATLASSERT(0); // Shouldn't been called since we support ISnapinHelp
//
// Call imported method from NeMmcUtl.dll
//
OnSnapinHelp(arg, param);
break;
case MMCN_COLUMN_CLICK:
//
// MMC 1.2 handles this
//
break;
default:
//
// Catch un handeled events
//
ATLASSERT(0);
} // endswitch (event)
return hr;
}
/////////////////////////////////////////////////////////////////////////////
/*++
CSnapinComponent::CompareObjects
Needed so that IPropertySheetProvider::FindPropertySheet will work.
FindPropertySheet is used to bring a pre-existing property sheet to the foreground
so that we don't open multiple copies of Properties on the same node.
It requires CompareObjects to be implemented on both IComponent and IComponentData.
--*/
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
CSnapinComponent::CompareObjects(LPDATAOBJECT lpDataObjectA,
LPDATAOBJECT lpDataObjectB)
{
ATLTRACE(_T("# CSnapinComponent::CompareObjects\n"));
HRESULT hr;
CSnapInItem *pDataA, *pDataB;
DATA_OBJECT_TYPES typeA, typeB;
hr = GetDataClass(lpDataObjectA, &pDataA, &typeA);
if ( FAILED( hr ) )
{
return hr;
}
hr = GetDataClass(lpDataObjectB, &pDataB, &typeB);
if ( FAILED( hr ) )
{
return hr;
}
if( pDataA == pDataB )
{
// They are the same object.
return S_OK;
}
else
{
// They are different.
return S_FALSE;
}
}
/////////////////////////////////////////////////////////////////////////////
/*++
CSnapinComponent::OnColumnClick
HRESULT OnColumnClick(
LPARAM arg
, LPARAM param
)
In our implementation, this method gets called when the MMCN_COLUMN_CLICK
Notify message is sent for our IComponent object.
MMC sends this message when the user clicks on a result-list view column header.
Parameters
arg
Column number.
param
Sort option flags. By default, the sort is in ascending order. To specify descending order, use the RSI_DESCENDING (0x0001) flag.
Return Values
Not used.
--*/
//////////////////////////////////////////////////////////////////////////////
HRESULT
CSnapinComponent::OnColumnClick(LPARAM arg, LPARAM param)
{
ATLTRACE(_T("# CSnapinComponent::OnColumnClick -- Not implemented\n"));
UNREFERENCED_PARAMETER (arg);
UNREFERENCED_PARAMETER (param);
// Check for preconditions:
// None.
return E_NOTIMPL;
}
/////////////////////////////////////////////////////////////////////////////
/*++
CSnapinComponent::OnCutOrMove
HRESULT OnCutOrMove(
LPARAM arg
, LPARAM param
)
In our implementation, this method gets called when the MMCN_COLUMN_CLICK
Notify message is sent for our IComponent object.
MMC sends this message when the user clicks on a result-list view column header.
Parameters
arg
Column number.
param
Sort option flags. By default, the sort is in ascending order. To specify descending order, use the RSI_DESCENDING (0x0001) flag.
Return Values
Not used.
--*/
//////////////////////////////////////////////////////////////////////////////
HRESULT
CSnapinComponent::OnCutOrMove(LPARAM arg, LPARAM param)
{
ATLTRACE(_T("# CSnapinComponent::OnCutOrMove\n"));
// ISSUE: This may need to be changed once the MMC team finalizes their
// cut and paste protocol -- they seem to be in flux for 1.1 as of 02/16/98.
// Currently, we will assume that the arg value passed to us is the source item
// in the cut-and-paste or drag-n-drop operation. That is, it is the object
// to be deleted.
// We supplied this pointer in our response to the MMCN_PASTE notification,
// when we set param to point to the source IDataObject.
HRESULT hr;
if( arg != NULL )
{
CSnapInItem* pData;
DATA_OBJECT_TYPES type;
hr = CSnapInItem::GetDataClass( (IDataObject *) arg, &pData, &type);
ATLASSERT(SUCCEEDED(hr));
if (SUCCEEDED(hr))
{
// We need a richer Notify method which has information about the IComponent and IComponentData objects
//hr = pData->Notify(event, arg, param, TRUE, m_spConsole, NULL, NULL);
hr = pData->Notify( MMCN_CUTORMOVE, arg, param, NULL, this, type );
}
}
// return E_NOTIMPL;
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
/*++
CSnapinComponent::OnSnapinHelp
HRESULT OnSnapinHelp(
LPARAM arg
, LPARAM param
)
In our implementation, this method gets called when the MMCN_SNAPINHELP
Notify message is sent for our IComponent object.
MMC sends this message when the user requests help about the snap-in.
Parameters
arg
0
param
0
Return Values
Not used.
--*/
//////////////////////////////////////////////////////////////////////////////
HRESULT
CSnapinComponent::OnSnapinHelp(LPARAM arg, LPARAM param)
{
ATLTRACE(_T("# CSnapinComponent::OnSnapinHelp\n"));
UNREFERENCED_PARAMETER (arg);
UNREFERENCED_PARAMETER (param);
// Check for preconditions:
_ASSERTE( m_spConsole != NULL );
::OnSnapinHelp(m_spConsole);
#if 0
HRESULT hr;
//TCHAR szFileName[MAX_PATH];
HWND hWnd;
// Get HWND from MMC.
hr = m_spConsole->GetMainWindow( &hWnd );
_ASSERTE( SUCCEEDED( hr ) && NULL != hWnd );
#ifdef UNICODE_HHCTRL
// ISSUE: We seemed to have a problem with passing WCHAR's to the hhctrl.ocx
// installed on this machine -- it appears to be non-unicode.
//lstrcpy( szFileName, HTMLHELP_NAME );
//HtmlHelp( hWnd, szFileName, HH_DISPLAY_TOPIC, (DWORD) _T("iasmmc_main_help.htm") );
#else
//strcpy( (CHAR *) szFileName, HTMLHELP_NAME );
//HtmlHelp( hWnd, (TCHAR *) szFileName, HH_DISPLAY_TOPIC, (DWORD) "iasmmc_main_help.htm" );
#endif
#endif // 0
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
/*++
CSnapinComponent::OnViewChange
HRESULT OnViewChange(
LPARAM arg
, LPARAM param
)
This is where we respond to an MMCN_VIEW_CHANGE notification.
In our implementation, this is a signal to check the currently selected node in
the result pane for this component, and refresh the view if the node happens to
be the same as the pointer to a CSnapInItem passed in through arg.
We do this because you only want to refresh the view of the currently selected
node, and you only want to do that if its children have changed.
If the arg passed in is NULL, we just reselect the currently selected node.
--*/
//////////////////////////////////////////////////////////////////////////////
HRESULT
CSnapinComponent::OnViewChange(LPARAM arg, LPARAM param)
{
ATLTRACE(_T("# CNodeWithResultChildrenList::OnViewChange\n"));
// Check for preconditions:
UNREFERENCED_PARAMETER (param);
_ASSERTE( m_spConsole != NULL );
HRESULT hr = S_FALSE;
// What localsec snapin checks for:
if( ( arg == NULL || (CSnapInItem *) arg == m_pSelectedNode ) && m_pSelectedNode != NULL )
{
// We basically tell MMC to simulate reselecting the
// currently selected node, which causes it to redraw.
// This will cause MMC to send the MMCN_SHOW notification
// to the selected node.
// This function requires an HSCOPEITEM. This is the ID member
// of the HSCOPEDATAITEM associated with this node.
SCOPEDATAITEM *pScopeDataItem;
m_pSelectedNode->GetScopeData( &pScopeDataItem );
hr = m_spConsole->SelectScopeItem( pScopeDataItem->ID );
}
return hr;
}
//////////////////////////////////////////////////////////////////////////////
/*++
CSnapinComponent::OnPropertyChange
HRESULT OnPropertyChange(
LPARAM arg
, LPARAM param
)
This is where we respond to an MMCN_PROPERTY_CHANGE notification.
This notification is sent when we call MMCPropertyChangeNotify.
We call this in our property pages when changes are made to the data
they contain and we may need to update of view of the data.
--*/
//////////////////////////////////////////////////////////////////////////////
HRESULT
CSnapinComponent::OnPropertyChange(LPARAM arg, LPARAM param)
{
ATLTRACE(_T("# CSnapinComponent::OnPropertyChange\n"));
// Check for preconditions:
_ASSERTE( m_spConsole != NULL );
UNREFERENCED_PARAMETER (arg);
HRESULT hr = S_FALSE;
if( param == NULL )
{
// We want to make sure all views get updated.
hr = m_spConsole->UpdateAllViews( NULL, (LPARAM) m_pSelectedNode, NULL);
}
else
{
// We passed a pointer to a CSnapInItem in the param argument.
// We call notify on that node, passing it our own custom event type
// so that it knows that it must refresh its data.
CSnapInItem * pSnapInItem = (CSnapInItem *) param;
// Call notify on this node with the MMCN_PROPERTY_CHANGE notification.
// We had to use this trick because of the fact that we are using template
// classes and so we have no common object among all our nodes
// other than CSnapInItem. But we can't change CSnapInItem
// so instead we use the notify method it already has with a new
// notification.
// Note: We are trying to deal gracefully here with the fact that the
// MMCN_PROPERTY_CHANGE notification doesn't pass us an lpDataObject
// so we have to have our own protocol for picking out which node
// needs to update itself.
hr = pSnapInItem->Notify( MMCN_PROPERTY_CHANGE
, NULL
, NULL
, NULL
, NULL
, (DATA_OBJECT_TYPES) 0
);
// We want to make sure all views with this node select also get updated.
hr = m_spConsole->UpdateAllViews( NULL, (LPARAM) pSnapInItem, NULL);
}
return hr;
}
//////////////////////////////////////////////////////////////////////////////
/*++
CSnapinComponent::GetTitle
IExtendTaskPad interface member.
This is the title that show up under the banner.
ISSUE: Why does this not appear to be working?
--*/
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
CSnapinComponent::GetTitle(LPOLESTR pszGroup, LPOLESTR *pszTitle)
{
ATLTRACE(_T("# CSnapinComponent::GetTitle\n"));
UNREFERENCED_PARAMETER (pszGroup);
// Check for preconditions:
_ASSERTE( pszTitle != NULL );
OLECHAR szTitle[256];
int nLoadStringResult = LoadString(_Module.GetResourceInstance(), IDS_TASKPAD_TITLE, szTitle, 256);
_ASSERT( nLoadStringResult > 0 );
*pszTitle= (LPOLESTR)CoTaskMemAlloc(sizeof(OLECHAR)*(lstrlen(szTitle)+1) );
if( ! *pszTitle )
{
return E_OUTOFMEMORY;
}
lstrcpy( *pszTitle, szTitle );
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
/*++
CSnapinComponent::GetBanner
IExtendTaskPad interface member.
We provide the color bar banner that appears at the top of the taskpad.
It is a resource in our snapin DLL.
--*/
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
CSnapinComponent::GetBanner (LPOLESTR pszGroup, LPOLESTR *pszBitmapResource)
{
ATLTRACE(_T("# CSnapinComponent::GetBanner\n"));
UNREFERENCED_PARAMETER (pszGroup);
// We are constructing a string pointing to the bitmap resource
// of the form: "res://D:\MyPath\MySnapin.dll/img\ntbanner.gif"
OLECHAR szBuffer[MAX_PATH*2]; // A little extra.
// Get "res://"-type string for bitmap.
lstrcpy (szBuffer, L"res://");
OLECHAR * temp = szBuffer + lstrlen(szBuffer);
// Get our executable's filename.
HINSTANCE hInstance = _Module.GetResourceInstance();
::GetModuleFileName (hInstance, temp, MAX_PATH);
// Add the name of the image within our resources.
lstrcat (szBuffer, L"/img\\IASTaskpadBanner.gif");
// Alloc and copy bitmap resource string.
*pszBitmapResource = (LPOLESTR) CoTaskMemAlloc(sizeof(OLECHAR)*(lstrlen(szBuffer)+1) );
if (!*pszBitmapResource)
{
return E_OUTOFMEMORY;
}
lstrcpy( *pszBitmapResource, szBuffer);
return S_OK;
}
/*
- CSnapin::GetHelpTopic
-
* Purpose:
* See MMC help on ISnapinHelp::GetHelpTopic
*
* Arguments:
* [out] lpCompiledHelpFile - Pointer to the address of the NULL-terminated
* UNICODE string that contains the full path of
* the compiled help file (.chm) for the snap-in.
*
* Return:
* OLE error code
*/
HRESULT STDMETHODCALLTYPE
CSnapin::GetHelpTopic(LPOLESTR* lpCompiledHelpFile)
{
WCHAR *pszFilePath;
WCHAR *pszTopic;
HRESULT hRc = S_OK;
ULONG ulLen;
DEBUG_FUNCTION_NAME( _T("CSnapin::GetHelpTopic"));
ATLASSERT(lpCompiledHelpFile != NULL);
//
// Get the CHM file name and the current topic
//
pszFilePath = GetHelpFile();
pszTopic = NULL; //pszTopic = GetHelpTopic(); current implementation.
if (pszFilePath == NULL)
{
hRc = E_OUTOFMEMORY;
DebugPrintEx(DEBUG_ERR,_T("Failed to GetHelpFile(). (hRc: %08X)"), hRc);
goto Cleanup;
}
//
// Allocate mem for it
ulLen = lstrlen(pszFilePath) + 1;
if (pszTopic && *pszTopic)
{
ulLen += 2 /* for "::" */ + lstrlen(pszTopic);
}
ulLen *= sizeof(WCHAR);
*lpCompiledHelpFile = reinterpret_cast<LPOLESTR>(::CoTaskMemAlloc(ulLen));
if (*lpCompiledHelpFile == NULL)
{
hRc = E_OUTOFMEMORY;
DebugPrintEx(DEBUG_ERR,_T("Failed to do CoTaskMemAlloc. (hRc: %08X)"), hRc);
goto Cleanup;
}
wcscpy(*lpCompiledHelpFile, pszFilePath);
//
// Copy the help file::topic
//
if (pszTopic && *pszTopic)
{
wcscat(*lpCompiledHelpFile, L"::");
wcscat(*lpCompiledHelpFile, pszTopic);
}
Cleanup:
return hRc;
}
WCHAR*
CSnapin::GetHelpFile()
{
DEBUG_FUNCTION_NAME( _T("CSnapin::GetHelpFile"));
return ::GetHelpFile();
}
///////////////////////////////////////////////////////////////
//
// IPesistStream
//
/////////////////////////////////////////////////////////////////////
//const WCHAR szOverrideCommandLineEquals[] = _T("/Computer="); // Not subject to localization
//const WCHAR szOverrideCommandLineColon[] = _T("/Computer:"); // Not subject to localization
const WCHAR g_szFaxOverrideCommandLineEquals[] = _T("/FAX="); // Not subject to localization
const WCHAR g_szLocalMachine[] = _T("LocalMachine"); // Not subject to localization
//we keep the version of persistence information of CSnapin
//when the persistence format is changed we need to increase this integer number
//we will read persistnce information only if the persistence version in the stream
//matches that of the PERISISTENCE_VERSION.
#define PERISISTENCE_VERSION 100002
//
// The persist stream format is:
//
// Version (UINT)
// AllowOverride (BOOL)
// Server Name length (UINT)
// Server Name string ( <= WCHAR * DNS_MAX_NAME_BUFFER_LENGTH )
//
/*
- CSnapin::Load
-
* Purpose:
* Initializes an object from the stream where it was previously saved.
*
* Arguments:
* [in] pStm - Pointer to the stream from which the object
* should be loaded.
* Return:
* S_OK - The object was successfully loaded.
* E_OUTOFMEMORY - The object was not loaded due to a lack of memory.
* E_FAIL - The object was not loaded due to some reason other
* than a lack of memory.
*
*/
STDMETHODIMP CSnapin::Load(IStream *pStm)
{
DEBUG_FUNCTION_NAME( _T("CSnapin::Load"));
HRESULT hRc = S_OK;
BOOL fServerNameFoundInCommandLine = FALSE;
CComBSTR bstrCommandLineServerName = L"";
WCHAR wszPersistStreamServerName[DNS_MAX_NAME_BUFFER_LENGTH+1] = {0};
UINT uiVersion = 0;
ULONG nBytesRead = 0;
//
// Pre-conditions
//
ATLASSERT( NULL != pStm );
//
// A. Read the Stream
// ==================
//
//
// Read the Version
//
hRc = pStm->Read(&uiVersion, sizeof(uiVersion), NULL);
if( FAILED( hRc ) )
{
DebugPrintEx( DEBUG_ERR,
_T("pStm->Read(version). (hRc: %08X)"), hRc);
return E_FAIL;
}
if (uiVersion == PERISISTENCE_VERSION)
{
//
// Read Allow-to-override stream machine-name flag
// from command line source
//
hRc = pStm->Read( &m_fAllowOverrideServerName, sizeof(m_fAllowOverrideServerName), NULL );
if( FAILED( hRc ) )
{
DebugPrintEx( DEBUG_ERR,
_T("pStm->Read(fAllowOverrideServerName). (hRc: %08X)"), hRc);
return E_FAIL;
}
//
// Read the Server Name from stream
//
hRc = pStm->Read (&nBytesRead , sizeof(ULONG), NULL);
if( FAILED( hRc ) )
{
DebugPrintEx( DEBUG_ERR,
_T("Fail to Read server name length from stream. (hRc: %08X)"), hRc);
return E_FAIL;
}
ATLASSERT (nBytesRead <= DNS_MAX_NAME_BUFFER_LENGTH * sizeof (WCHAR));
if (nBytesRead <= DNS_MAX_NAME_BUFFER_LENGTH * sizeof (WCHAR))
{
hRc = pStm->Read ((PVOID) wszPersistStreamServerName, nBytesRead, NULL);
if( FAILED( hRc ) )
{
DebugPrintEx( DEBUG_ERR,
_T("Fail to Read server name from stream. (hRc: %08X)"), hRc);
return E_FAIL;
}
}
}
else // version!=PERISISTENCE_VERSION
{
//
// Persistance data will not be read due to inconsitency.
//
DebugPrintEx( DEBUG_ERR,
_T("The current *.msc file version (%ld) is differnt from the\n pesistance version the dll expecting (%ld)."), uiVersion, PERISISTENCE_VERSION);
//
// Next we'll try to Read ServerName from Command line
//
}
//
// B. Try to read from command line
// ================================
//
// fServerNameFoundInCommandLine initial state == FALSE
if (m_fAllowOverrideServerName)
{
int argCount = 0;
PWSTR* argV = NULL;
const int cchFaxOverrideCommandLine = ( sizeof(g_szFaxOverrideCommandLineEquals) / sizeof(g_szFaxOverrideCommandLineEquals[0]) ) - 1;
argV = CommandLineToArgvW(GetCommandLine() , &argCount);
if (argV == NULL)
{
DWORD ec;
ec = GetLastError();
DebugPrintEx(
DEBUG_ERR,
_T("Fail to parse Command Line To Argv. (ec: %ld)"),
ec);
return E_FAIL;
}
//argV[0] is not an argument
for (int i = 1; i < argCount; i++)
{
WCHAR * psz = argV[i];
if ( 0 == wcsnicmp( psz , g_szFaxOverrideCommandLineEquals , cchFaxOverrideCommandLine ) )
{
fServerNameFoundInCommandLine = TRUE;
psz = _tcsninc(psz, cchFaxOverrideCommandLine); //psz = psz + cchFaxOverrideCommandLine;
if ( 0 != wcscmp( psz , g_szLocalMachine ) )
{
//
// Server Name initial '\\' trancation (if they are there)
//
if ( ( _tcslen(psz) > 2 ) && ( 0 == wcsncmp( psz , _T("\\\\") , 2 )) )
{
psz = _tcsninc(psz, 2);
}
if ( _tcslen(psz) > 0)
{
//
// Server Name validity checks
//
CComBSTR bstrServerNameValidation = psz;
UINT uTmp = 0;
if (!IsValidServerNameString(bstrServerNameValidation, &uTmp, TRUE /*DNS Name Length*/))
{
// Err msg by called func.
// As in comupter management we do not pop-up here
// but we fix the found flag to be FALSE
fServerNameFoundInCommandLine = FALSE;
break;
}
bstrCommandLineServerName = psz;
//
// we will also check if the explictly inserted Server Name
// is the local Server Name. This check will be done in one place
// the selected readed server name (Command line or Stream)
//
}
else // the case of argV[2] == "/FAX=" only => LocalMachine
{
bstrCommandLineServerName = L""; //just to be sure - the default
}
}
else // "/FAX=LocalMachine"
{
bstrCommandLineServerName = L""; //just to be sure - the default
}
break;
}
} //if /FAX= was not found bstrCommandLineServerName stays L""
//
// free resources
//
GlobalFree(argV);
}
//
// C. Derived Server name from the results
// =======================================
//
//
// When there is no command line explicitly request for server name
//
// or
//
// when we are not allowed to take the command data and to use it
// to override the straem server name
//
// just then the server is taken from the stream
//
ATLASSERT (0 == m_bstrServerName.Length());
if (
(!fServerNameFoundInCommandLine)
||
(!m_fAllowOverrideServerName)
)
{
//
// We should take the stream server name
//
if (NULL != wszPersistStreamServerName)
{
if ( 0 != wcscmp( wszPersistStreamServerName , g_szLocalMachine ) )
{
m_bstrServerName = wszPersistStreamServerName;
}
else //LocalMachine
{
m_bstrServerName = L""; //Just to be sure
}
}
else
{
// not a regular case:
// for example can occur while version inconsitancy
// and no command line /FAX= server name instruction
m_bstrServerName = L""; //Just to be sure this is actually the default
}
}
else
{
//
// We should take the command line server name
//
m_bstrServerName = bstrCommandLineServerName;
}
//
// Checks if the explictly inserted Server Name
// is the local Server Name
//
if (m_bstrServerName.Length() > 0 )
{
if ( IsLocalServerName(m_bstrServerName.m_str) )
{
DebugPrintEx( DEBUG_MSG,
_T("The computer name %ws is the same as the name of the current managed server."),m_bstrServerName.m_str);
m_bstrServerName = L"";
}
}
//
// We do not check here if the server is on the net
// and if fax is installed and running there
//
//
// D. Update FaxServer and FaxServerNode DisplayName with the name
// retrieved during the load process
// =======================================
//
ATLASSERT( m_pNode);
CFaxServerNode * pFaxServerNode = (CFaxServerNode *)m_pNode;
ATLASSERT( pFaxServerNode);
hRc = pFaxServerNode->UpdateServerName(m_bstrServerName);
if (S_OK != hRc)
{
DebugPrintEx(DEBUG_MSG,_T("Out of memory - fail to UpdateServerName."));
return hRc; //E_OUTOFMEMORY;
}
hRc = pFaxServerNode->InitDetailedDisplayName();
if (S_OK != hRc)
{
DebugPrintEx(DEBUG_MSG,_T("Out of memory - fail to InitDetailedDisplayName."));
return hRc; //E_OUTOFMEMORY;
}
pFaxServerNode->SetIsLaunchedFromSavedMscFile();
ATLASSERT (S_OK == hRc);
return hRc;
}
/////////////////////////////////////////////////////////////////////
STDMETHODIMP CSnapin::Save(IStream *pStm, BOOL /*fClearDirty*/)
{
DEBUG_FUNCTION_NAME( _T("CSnapin::Save"));
HRESULT hRc = S_OK;
UINT uiVersion = PERISISTENCE_VERSION;
ATLASSERT( NULL != pStm );
//
// Write the version
//
hRc = pStm->Write((void *)&uiVersion, sizeof(uiVersion), 0);
if( FAILED( hRc ) )
{
DebugPrintEx( DEBUG_ERR,
_T("pStm->Write(&uiVersion). (hRc: %08X)"), hRc);
return STG_E_CANTSAVE;
}
//
// Write Allow-to-override machine-name flag to the stream
//
hRc = pStm->Write((void *)&m_fAllowOverrideServerName, sizeof(m_fAllowOverrideServerName), 0);
if( FAILED( hRc ) )
{
DebugPrintEx( DEBUG_ERR,
_T("pStm->Write(&uiVersion. (hRc: %08X)"), hRc);
return STG_E_CANTSAVE;
}
//
// Write the Server Name length
//
LPCWSTR wcszMachineName;
if ( 0 == m_bstrServerName.Length() ) // m_bstrServerName == L"" -> LocalMachine
{
wcszMachineName = g_szLocalMachine; // m_bstrServerName = L"LocalMachine"
}
else
{
wcszMachineName = m_bstrServerName;
}
DWORD dwLen = (::wcslen (wcszMachineName) + 1) * sizeof (WCHAR);
hRc = pStm->Write ((void *)&dwLen, sizeof(DWORD), NULL);
if ( FAILED(hRc) )
{
DebugPrintEx( DEBUG_ERR,
_T("Fail to Write server name length to stream. (hRc: %08X)"), hRc);
return STG_E_CANTSAVE;
}
//
// Write the Server Name
//
hRc = pStm->Write ((void *)wcszMachineName, dwLen, NULL);
if ( FAILED (hRc) )
{
DebugPrintEx( DEBUG_ERR,
_T("Fail to Write server name to stream. (hRc: %08X)"), hRc);
return STG_E_CANTSAVE;
}
ATLASSERT( S_OK == hRc);
return hRc;
}
STDMETHODIMP CSnapin::GetSizeMax(ULARGE_INTEGER *pcbSize)
{
ATLASSERT(pcbSize);
ULISet32(*pcbSize, (DNS_MAX_NAME_BUFFER_LENGTH * sizeof(WCHAR)) + (2 * sizeof(UINT)) + 1);
return S_OK;
}
/*
- CSnapin::GetSizeMax
-
* Purpose:
* Checks the object for changes since it was last saved.
*
* Arguments:
*
* Return:
* OLE error code
*/
STDMETHODIMP CSnapin::IsDirty()
{
// Always save / Always dirty.
return S_OK;
}