windows-nt/Source/XPSP1/NT/printscan/fax/admin/faxadmin/idevices.cpp
2020-09-26 16:20:57 +08:00

757 lines
23 KiB
C++

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
idevices.cpp
Abstract:
Internal implementation for the devices subfolder.
Environment:
WIN32 User Mode
Author:
Darwin Ouyang (t-darouy) 30-Sept-1997
--*/
#include "StdAfx.h"
#include "inode.h" // base class
#include "iroot.h" // iroot
#include "idevices.h" // devices folder
#include "idevice.h" // a device
#include "faxsnapin.h" // snapin
#include "faxdataobj.h" // dataobject
#include "faxstrt.h" // string table
#pragma hdrstop
extern CStringTable * GlobalStringTable;
// Generated with uuidgen. Each node must have a GUID associated with it.
// This one is for the devices subfolder.
const GUID GUID_DevicesNode = /* 03a815d8-3e9e-11d1-9075-00a0c90ab504 */
{
0x03a815d8,
0x3e9e,
0x11d1,
{0x90, 0x75, 0x00, 0xa0, 0xc9, 0x0a, 0xb5, 0x04}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
// Constructor and destructor
//
//
CInternalDevices::CInternalDevices(
CInternalNode * pParent,
CFaxComponentData * pCompData )
: CInternalNode( pParent, pCompData ),
pDevicesInfo( NULL )
/*++
Routine Description:
Constructor
Arguments:
pParent - pointer to parent node, in this case unused
pCompData - pointer to IComponentData implementation for snapin global data
Return Value:
None.
--*/
{
DebugPrint(( TEXT("CInternalDeviceS Created") ));
faxHandle = m_pCompData->m_FaxHandle;
assert( faxHandle != NULL );
}
CInternalDevices::~CInternalDevices( )
/*++
Routine Description:
Destructor
Arguments:
None.
Return Value:
None.
--*/
{
DebugPrint(( TEXT("CInternalDeviceS Destroyed") ));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
// Mandatory CInternalNode implementations.
//
//
const GUID *
CInternalDevices::GetNodeGUID()
/*++
Routine Description:
Returns the node's associated GUID.
Arguments:
None.
Return Value:
A const pointer to a binary GUID.
--*/
{
// DebugPrint(( TEXT("Trace: CInternalDevices::GetNodeGUID") ));
return &GUID_DevicesNode;
}
const LPTSTR
CInternalDevices::GetNodeDisplayName()
/*++
Routine Description:
Returns a const TSTR pointer to the node's display name.
Arguments:
None.
Return Value:
A const pointer to a TSTR.
--*/
{
// DebugPrint(( TEXT("Trace: CInternalDevices::GetNodeDisplayName") ));
return ::GlobalStringTable->GetString( IDS_DEVICESNODENAME );
}
const LPTSTR
CInternalDevices::GetNodeDescription()
/*++
Routine Description:
Returns a const TSTR pointer to the node's display description.
Arguments:
None.
Return Value:
A const pointer to a TSTR.
--*/
{
// DebugPrint(( TEXT("Trace: CInternalDevices::GetNodeDisplayName") ));
return ::GlobalStringTable->GetString( IDS_DEVICES_FOLDER_DESC_ROOT );
}
const LONG_PTR
CInternalDevices::GetCookie()
/*++
Routine Description:
Returns the cookie for this node.
Arguments:
None.
Return Value:
A const long containing the cookie for the pointer,
in this case, (long)this.
--*/
{
// DebugPrint(( TEXT("Trace: CInternalDevices::GetCookie") ));
DebugPrint(( TEXT("Devices Node Cookie: 0x%p"), this ));
return (LONG_PTR)this; // status node's cookie is the node id.
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
// Internal Event Handlers
//
//
HRESULT
CInternalDevices::ResultOnShow(
IN CFaxComponent* pComp,
IN CFaxDataObject * lpDataObject,
IN LPARAM arg,
IN LPARAM param)
/*++
Routine Description:
Event handler for the MMCN_SHOW message for the devices node.
Arguments:
pComp - a pointer to the instance of IComponentData which this root node is associated with.
lpDataObject - a pointer to the data object containing context information for this node.
arg, param - the arguements of the message
Return Value:
HRESULT which indicates SUCCEEDED() or FAILED()
--*/
{
DebugPrint(( TEXT("Trace: CInternalDevices::ResultOnShow") ));
HRESULT hr = S_OK;
unsigned int count;
int iResult;
LPHEADERCTRL pIHeaderCtrl;
if( m_pCompData->QueryRpcError() ) {
return E_UNEXPECTED;
}
if( arg == TRUE ) { // need to display result pane
do {
// get resultdata pointer
pIResultData = pComp->m_pResultData;
assert( pIResultData );
if( pIResultData == NULL ) {
hr = E_UNEXPECTED;
break;
}
// insert the icons into the image list
hr = pComp->InsertIconsIntoImageList();
assert( SUCCEEDED( hr ) );
if( FAILED( hr ) ) {
break;
}
// set headers
pIHeaderCtrl = pComp->m_pHeaderCtrl;
hr = pIHeaderCtrl->InsertColumn( 0,
::GlobalStringTable->GetString( IDS_DEVICE_NAME ),
LVCFMT_LEFT,
MMCLV_AUTO );
if( FAILED( hr ) ) {
break;
}
hr = pIHeaderCtrl->InsertColumn( 1,
::GlobalStringTable->GetString( IDS_DEVICE_SEND_EN ),
LVCFMT_LEFT,
MMCLV_AUTO );
if( FAILED( hr ) ) {
break;
}
hr = pIHeaderCtrl->InsertColumn( 2,
::GlobalStringTable->GetString( IDS_DEVICE_RECV_EN ),
LVCFMT_LEFT,
MMCLV_AUTO );
if( FAILED( hr ) ) {
break;
}
hr = pIHeaderCtrl->InsertColumn( 3,
::GlobalStringTable->GetString( IDS_DEVICE_TSID ),
LVCFMT_LEFT,
MMCLV_AUTO );
if( FAILED( hr ) ) {
break;
}
hr = pIHeaderCtrl->InsertColumn( 4,
::GlobalStringTable->GetString( IDS_DEVICE_CSID ),
LVCFMT_LEFT,
MMCLV_AUTO );
if( FAILED( hr ) ) {
break;
}
hr = pIHeaderCtrl->InsertColumn( 5,
::GlobalStringTable->GetString( IDS_DEVICE_STATUS ),
LVCFMT_LEFT,
MMCLV_AUTO );
if( FAILED( hr ) ) {
break;
}
hr = pIHeaderCtrl->InsertColumn( 6,
::GlobalStringTable->GetString( IDS_DEVICE_PRI ),
LVCFMT_LEFT,
MMCLV_AUTO );
if( FAILED( hr ) ) {
break;
}
// this is the first time initializing the devices node
if( pComp->pDeviceArray == NULL ) {
// get fax info
try {
if( !FaxEnumPorts( faxHandle, &pDevicesInfo, &pComp->numDevices ) ) {
if (GetLastError() == ERROR_ACCESS_DENIED) {
::GlobalStringTable->SystemErrorMsg(ERROR_ACCESS_DENIED);
} else {
m_pCompData->NotifyRpcError( TRUE );
hr = m_pCompData->m_pConsole->MessageBox(::GlobalStringTable->GetString( IDS_FAX_RETR_DEV_FAIL ),
::GlobalStringTable->GetString( IDS_ERR_TITLE ),
MB_OK,
&iResult);
}
hr = E_UNEXPECTED;
break;
}
} catch( ... ) {
m_pCompData->NotifyRpcError( TRUE );
hr = m_pCompData->m_pConsole->MessageBox(::GlobalStringTable->GetString( IDS_FAX_RETR_DEV_FAIL ),
::GlobalStringTable->GetString( IDS_ERR_TITLE ),
MB_OK,
&iResult);
hr = E_UNEXPECTED;
break;
}
assert( pComp->pDeviceArray == NULL );
pComp->pDeviceArray = new pCInternalDevice[pComp->numDevices];
if (!pComp->pDeviceArray) {
hr = E_OUTOFMEMORY;
break;
}
ZeroMemory( (void *)pComp->pDeviceArray, pComp->numDevices * sizeof( pCInternalDevice ) );
for( count = 0; count < pComp->numDevices; count ++ ) {
pComp->pDeviceArray[count] = new CInternalDevice( this, m_pCompData, faxHandle, pDevicesInfo[count].DeviceId );
if (!pComp->pDeviceArray[count]) {
hr = E_OUTOFMEMORY;
break;
}
}
}
// on each display, insert each device into the devices pane
for( count = 0; count < pComp->numDevices; count++ ) {
hr = InsertItem( &pComp->pDeviceArray[count], &(pDevicesInfo[count]) );
if( FAILED( hr ) ) {
break;
}
}
} while( 0 );
if( pDevicesInfo != NULL ) {
FaxFreeBuffer( (PVOID) pDevicesInfo );
pDevicesInfo = NULL;
}
if (FAILED(hr)) {
if (pComp->pDeviceArray) {
for (count = 0; count < pComp->numDevices; count++ ) {
if (pComp->pDeviceArray[count]) {
delete(pComp->pDeviceArray[count]);
}
}
delete(pComp->pDeviceArray);
pComp->pDeviceArray = NULL;
}
}
}
return hr;
}
HRESULT
CInternalDevices::ResultOnDelete(
IN CFaxComponent* pComp,
IN CFaxDataObject * lpDataObject,
IN LPARAM arg,
IN LPARAM param)
/*++
Routine Description:
Event handler for the MMCN_DELETE message for the devices node.
Arguments:
pComp - a pointer to the instance of IComponentData which this root node is associated with.
lpDataObject - a pointer to the data object containing context information for this node.
pdo - a pointer to the data object associated with this node
arg, param - the arguements of the message
Return Value:
HRESULT which indicates SUCCEEDED() or FAILED()
--*/
{
// unneeded because the per result view data will be deleted by destroying the
// CInternalComponent holding the information
#if 0
DebugPrint(( TEXT("Trace: CInternalDevices::ResultOnDelete") ));
unsigned int count;
for( count = 0; count < pComp->numDevices; count++ ) {
if( pComp->pDeviceArray[count] != NULL ) {
delete pComp->pDeviceArray[count];
pComp->pDeviceArray[count] = NULL;
}
}
delete pComp->pDeviceArray;
pComp->pDeviceArray = NULL;
#endif
return S_OK;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
// Internal Functions
//
//
HRESULT
CInternalDevices::CorrectServiceState()
/*++
Routine Description:
Scans the devices to see if any are enabled for receive, and if so,
resets the service's startup state to automatic from manual. If no
devices are enabled for receive, then the service is set from
automatic to manual.
Arguments:
None.
Return Value:
HRESULT which indicates SUCCEEDED() or FAILED()
--*/
{
DWORD i;
PFAX_PORT_INFO pPortInfos = NULL;
DWORD portCount;
int iResult;
BOOL setAuto = FALSE;
HRESULT hr = S_OK;
DebugPrint(( TEXT("Trace: CInternalDevices::CorrectServiceState") ));
do {
// get fax info
try {
if( m_pCompData->QueryRpcError() ) {
hr = E_UNEXPECTED;
break;
}
if( !FaxEnumPorts( faxHandle, &pPortInfos, &portCount ) ) {
if (GetLastError() == ERROR_ACCESS_DENIED) {
::GlobalStringTable->SystemErrorMsg(ERROR_ACCESS_DENIED);
} else {
m_pCompData->NotifyRpcError( TRUE );
hr = m_pCompData->m_pConsole->MessageBox(::GlobalStringTable->GetString( IDS_FAX_RETR_DEV_FAIL ),
::GlobalStringTable->GetString( IDS_ERR_TITLE ),
MB_OK,
&iResult);
}
hr = E_UNEXPECTED;
break;
}
} catch( ... ) {
m_pCompData->NotifyRpcError( TRUE );
hr = m_pCompData->m_pConsole->MessageBox(::GlobalStringTable->GetString( IDS_FAX_RETR_DEV_FAIL ),
::GlobalStringTable->GetString( IDS_ERR_TITLE ),
MB_OK,
&iResult);
hr = E_UNEXPECTED;
break;
}
for( i = 0; i < portCount; i++) {
if( pPortInfos[i].Flags & FPF_RECEIVE ) {
setAuto = TRUE;
break;
}
}
SetServiceState( setAuto );
} while( 0 );
if( pPortInfos != NULL ) {
FaxFreeBuffer( (PVOID) pPortInfos );
pPortInfos = NULL;
}
return hr;
}
HRESULT
CInternalDevices::SetServiceState(
IN BOOL fAutomatic )
/*++
Routine Description:
Opens the Service Manager on the snapin's target machine, and sets
the fax service state according to the fAutomatic parameter.
Arguments:
fAutomatic - if TRUE, sets the service to start automatically.
if FALSE, sets the service to start manually.
Return Value:
HRESULT which indicates SUCCEEDED() or FAILED()
--*/
{
SC_LOCK sclLock;
LPQUERY_SERVICE_LOCK_STATUS lpqslsBuf;
TCHAR buffer[256];
LPTSTR str;
int iResult;
HRESULT hr = S_OK;
SC_HANDLE schSCManager;
SC_HANDLE schService;
DebugPrint(( TEXT("Trace: CInternalDevices::SetServiceState") ));
DWORD dwBytesNeeded, dwStartType;
ZeroMemory( (PVOID)buffer, sizeof( TCHAR ) * 256 );
schSCManager = OpenSCManager( ((CInternalRoot*)m_pParentINode)->GetMachine(),
NULL,
SC_MANAGER_CONNECT | SC_MANAGER_LOCK
| SC_MANAGER_QUERY_LOCK_STATUS | SC_MANAGER_ENUMERATE_SERVICE );
if( schSCManager == NULL ) {
::GlobalStringTable->PopUpMsg( NULL, IDS_ERR_CONNECT_SCM, TRUE, 0 );
assert( FALSE );
return E_UNEXPECTED;
}
// Need to acquire database lock before reconfiguring.
sclLock = LockServiceDatabase(schSCManager);
// If the database cannot be locked, report the details.
if(sclLock == NULL) {
// Exit if the database is not locked by another process.
if(GetLastError() != ERROR_SERVICE_DATABASE_LOCKED) {
::GlobalStringTable->PopUpMsg( NULL, IDS_ERR_LOCK_SERVICE_DB, TRUE, 0 );
assert( FALSE );
return E_UNEXPECTED;
}
// Allocate a buffer to get details about the lock.
lpqslsBuf = (LPQUERY_SERVICE_LOCK_STATUS) LocalAlloc( LPTR,
sizeof(QUERY_SERVICE_LOCK_STATUS)+256);
if(lpqslsBuf == NULL) {
::GlobalStringTable->PopUpMsg( NULL, IDS_OUT_OF_MEMORY, TRUE, 0 );
assert( FALSE );
return E_OUTOFMEMORY;
}
do {
// Get and print the lock status information.
if(!QueryServiceLockStatus( schSCManager,
lpqslsBuf,
sizeof(QUERY_SERVICE_LOCK_STATUS)+256,
&dwBytesNeeded) ) {
::GlobalStringTable->PopUpMsg( NULL, IDS_ERR_QUERY_LOCK, TRUE, 0 );
assert( FALSE );
break;
}
if(lpqslsBuf->fIsLocked) {
str = ::GlobalStringTable->GetString( IDS_QUERY_LOCK );
_stprintf( buffer, str, lpqslsBuf->lpLockOwner, lpqslsBuf->dwLockDuration );
m_pCompData->m_pConsole->MessageBox( buffer,
::GlobalStringTable->GetString( IDS_ERR_TITLE ),
MB_OK,
&iResult);
} else {
::GlobalStringTable->PopUpMsg( NULL, IDS_ERR_LOCK_SERVICE_DB, TRUE, 0 );
}
} while( 0 );
LocalFree(lpqslsBuf);
return E_UNEXPECTED;
}
do {
// The database is locked, so it is safe to make changes.
// Open a handle to the service.
schService = OpenService( schSCManager, // SCManager database
TEXT("Fax"), // name of service
SERVICE_CHANGE_CONFIG ); // need CHANGE access
if(schService == NULL) {
::GlobalStringTable->PopUpMsg( NULL, IDS_ERR_OPEN_SERVICE, TRUE, 0 );
assert( FALSE );
hr = E_UNEXPECTED;
break;
}
dwStartType = (fAutomatic) ? SERVICE_AUTO_START :
SERVICE_DEMAND_START;
if(! ChangeServiceConfig( schService, // handle of service
SERVICE_NO_CHANGE, // service type: no change
dwStartType, // change service start type
SERVICE_NO_CHANGE, // error control: no change
NULL, // binary path: no change
NULL, // load order group: no change
NULL, // tag ID: no change
NULL, // dependencies: no change
NULL, // account name: no change
NULL, // password: no change
NULL) ) { // display string
::GlobalStringTable->PopUpMsg( NULL, IDS_ERR_CHANGE_SERVICE, TRUE, 0 );
assert( FALSE );
hr = E_UNEXPECTED;
}
// Close the handle to the service.
CloseServiceHandle(schService);
} while( 0 );
// Release the database lock.
UnlockServiceDatabase(sclLock);
return hr;
}
void
CInternalDevices::NotifyFailure(
CFaxComponent * pComp )
/*++
Routine Description:
If there was a failure in a RPC call anywhere in the child nodes, the result
pane should be cleared. This function clears the result pane.
Arguments:
pComp - a pointer to the instance of IComponentData which this root node is associated with.
Return Value:
None.
--*/
{
assert( pComp != NULL );
assert( pComp->pDeviceArray != NULL );
pComp->m_pResultData->DeleteAllRsltItems();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
// Utility Functions
//
//
HRESULT
CInternalDevices::InsertItem(
IN CInternalDevice ** pDevice,
IN PFAX_PORT_INFO pDeviceInfo )
/*++
Routine Description:
Wrapper that inserts an item into the result view pane given some information.
Arguments:
pDevice - the instance of CInternalDevice to insert
pDeviceInfo - the information associated with that log category.
Return Value:
HRESULT which indicates SUCCEEDED() or FAILED()
--*/
{
RESULTDATAITEM rdi;
HRESULT hr = S_OK;
ZeroMemory( &rdi, sizeof( RESULTDATAITEM ) );
rdi.mask = RDI_STR | RDI_IMAGE | RDI_PARAM;
rdi.nCol = 0;
rdi.bScopeItem = FALSE;
rdi.lParam = (*pDevice)->GetCookie();
rdi.nImage = (*pDevice)->GetNodeDisplayImage();
rdi.str = MMC_CALLBACK;
hr = pIResultData->InsertItem( &rdi );
assert( SUCCEEDED( hr ) );
(*pDevice)->SetItemID( rdi.itemID );
return hr;
}