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
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;
|
|
}
|
|
|