windows-nt/Source/XPSP1/NT/base/fs/hsm/rms/server/rmschngr.cpp

2034 lines
47 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
<EFBFBD> 1998 Seagate Software, Inc. All rights reserved
Module Name:
RmsChngr.cpp
Abstract:
Implementation of CRmsMediumChanger
Author:
Brian Dodd [brian] 15-Nov-1996
Revision History:
--*/
#include "stdafx.h"
#include "RmsChngr.h"
#include "RmsServr.h"
////////////////////////////////////////////////////////////////////////////////
//
HRESULT
CRmsMediumChanger::FinalConstruct(
void
)
/*++
Implements:
CComObjectRoot::FinalConstruct
--*/
{
HRESULT hr = S_OK;
try {
WsbAssertHr(CWsbObject::FinalConstruct());
// Initialize fields
m_isAutomatic = FALSE;
m_canRotate = FALSE;
m_operation = RMS_UNDEFINED_STRING;
m_percentComplete = 0;
m_handle = INVALID_HANDLE_VALUE;
} WsbCatch(hr);
return(hr);
}
HRESULT
CRmsMediumChanger::FinalRelease(
void
)
/*++
Implements:
CComObjectRoot::FinalRelease
--*/
{
HRESULT hr = S_OK;
try {
WsbAssertHr( ReleaseDevice() );
} WsbCatch(hr);
return(hr);
}
STDMETHODIMP
CRmsMediumChanger::CompareTo(
IN IUnknown *pCollectable,
OUT SHORT *pResult
)
/*++
Implements:
IWsbCollectable::CompareTo
--*/
{
HRESULT hr = E_FAIL;
SHORT result = 1;
WsbTraceIn( OLESTR("CRmsMediumChanger::CompareTo"), OLESTR("") );
try {
// Validate arguments - Okay if pResult is NULL
WsbAssertPointer( pCollectable );
// !!!!!
//
// IMPORTANT: The collectable coming in may not be a CRmsDrive if the collection
// is the unconfigured device list.
//
// !!!!!
CComQIPtr<IRmsComObject, &IID_IRmsComObject> pObject = pCollectable;
WsbAssertPointer( pObject );
switch ( m_findBy ) {
case RmsFindByDeviceInfo:
case RmsFindByDeviceAddress:
case RmsFindByDeviceName:
case RmsFindByDeviceType:
// Do CompareTo for device
hr = CRmsDevice::CompareTo( pCollectable, &result );
break;
case RmsFindByElementNumber:
case RmsFindByMediaSupported:
// Do CompareTo for changer element
hr = CRmsChangerElement::CompareTo( pCollectable, &result );
break;
case RmsFindByObjectId:
default:
// Do CompareTo for object
hr = CRmsComObject::CompareTo( pCollectable, &result );
break;
}
}
WsbCatch( hr );
if ( SUCCEEDED(hr) && (0 != pResult) ){
*pResult = result;
}
WsbTraceOut( OLESTR("CRmsMediumChanger::CompareTo"),
OLESTR("hr = <%ls>, result = <%ls>"),
WsbHrAsString( hr ), WsbPtrToShortAsString( pResult ) );
return hr;
}
STDMETHODIMP
CRmsMediumChanger::GetClassID(
OUT CLSID* pClsid
)
/*++
Implements:
IPersist::GetClassID
--*/
{
HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CRmsMediumChanger::GetClassID"), OLESTR(""));
try {
WsbAssert(0 != pClsid, E_POINTER);
*pClsid = CLSID_CRmsMediumChanger;
} WsbCatch(hr);
WsbTraceOut(OLESTR("CRmsMediumChanger::GetClassID"), OLESTR("hr = <%ls>, CLSID = <%ls>"), WsbHrAsString(hr), WsbGuidAsString(*pClsid));
return(hr);
}
STDMETHODIMP
CRmsMediumChanger::GetSizeMax(
OUT ULARGE_INTEGER* pcbSize
)
/*++
Implements:
IPersistStream::GetSizeMax
--*/
{
HRESULT hr = E_NOTIMPL;
// ULONG inProcessOperation;
WsbTraceIn(OLESTR("CRmsMediumChanger::GetSizeMax"), OLESTR(""));
// try {
// WsbAssert(0 != pcbSize, E_POINTER);
// inProcessOperation = SysStringByteLen(m_operation);
// // Get size
// pcbSize->QuadPart = WsbPersistSizeOf(LONG) + // m_isAutomatic
// WsbPersistSizeOf(LONG) + // m_canRotate
// WsbPersistSizeOf(LONG) + // m_operation length
// inProcessOperation; // m_operation
//// inProcessOperation + // m_operation
//// WsbPersistSizeOf(BYTE); // m_percentComplete
// } WsbCatch(hr);
WsbTraceOut(OLESTR("CRmsMediumChanger::GetSizeMax"), OLESTR("hr = <%ls>, Size = <%ls>"), WsbHrAsString(hr), WsbPtrToUliAsString(pcbSize));
return(hr);
}
STDMETHODIMP
CRmsMediumChanger::Load(
IN IStream* pStream
)
/*++
Implements:
IPersistStream::Load
--*/
{
HRESULT hr = S_OK;
ULONG ulBytes = 0;
WsbTraceIn(OLESTR("CRmsMediumChanger::Load"), OLESTR(""));
try {
WsbAssert(0 != pStream, E_POINTER);
WsbAffirmHr(CRmsDevice::Load(pStream));
// Load value
WsbAffirmHr(WsbLoadFromStream(pStream, &m_isAutomatic));
WsbAffirmHr(WsbLoadFromStream(pStream, &m_canRotate));
WsbAffirmHr(WsbBstrFromStream(pStream, &m_operation));
WsbAffirmHr(WsbLoadFromStream(pStream, &m_percentComplete));
if ( INVALID_HANDLE_VALUE == m_handle ) {
WsbAffirmHr( AcquireDevice() );
}
} WsbCatch(hr);
WsbTraceOut(OLESTR("CRmsMediumChanger::Load"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
return(hr);
}
STDMETHODIMP
CRmsMediumChanger::Save(
IN IStream *pStream,
IN BOOL clearDirty
)
/*++
Implements:
IPersistStream::Save
--*/
{
HRESULT hr = S_OK;
ULONG ulBytes = 0;
WsbTraceIn(OLESTR("CRmsMediumChanger::Save"), OLESTR("clearDirty = <%ls>"), WsbBoolAsString(clearDirty));
try {
WsbAssert(0 != pStream, E_POINTER);
WsbAffirmHr(CRmsDevice::Save(pStream, clearDirty));
// Save value
WsbAffirmHr(WsbSaveToStream(pStream, m_isAutomatic));
WsbAffirmHr(WsbSaveToStream(pStream, m_canRotate));
WsbAffirmHr(WsbBstrToStream(pStream, m_operation));
WsbAffirmHr(WsbSaveToStream(pStream, m_percentComplete));
// Do we need to clear the dirty bit?
if (clearDirty) {
m_isDirty = FALSE;
}
} WsbCatch(hr);
WsbTraceOut(OLESTR("CRmsMediumChanger::Save"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
return(hr);
}
STDMETHODIMP
CRmsMediumChanger::Test(
OUT USHORT *pPassed,
OUT USHORT *pFailed
)
/*++
Implements:
IWsbTestable::Test
--*/
{
HRESULT hr = S_OK;
CComPtr<IRmsMediumChanger> pChanger1;
CComPtr<IRmsMediumChanger> pChanger2;
CComPtr<IPersistFile> pFile1;
CComPtr<IPersistFile> pFile2;
// CRmsLocator locWork1;
// CRmsLocator locWork2;
CWsbBstrPtr bstrVal1 = OLESTR("5A5A5A");
CWsbBstrPtr bstrWork1;
CWsbBstrPtr bstrWork2;
WsbTraceIn(OLESTR("CRmsMediumChanger::Test"), OLESTR(""));
try {
// Get the Changer interface.
hr = S_OK;
try {
WsbAssertHr(((IUnknown*) (IRmsMediumChanger*) this)->QueryInterface(IID_IRmsMediumChanger, (void**) &pChanger1));
// Test SetHome & GetHome
// Test SetAutomatic & IsAutomatic to TRUE
hr = S_OK;
try{
WsbAffirmHr(SetAutomatic (TRUE));
WsbAffirmHr(IsAutomatic ());
} WsbCatch (hr);
if (hr == S_OK){
(*pPassed)++;
} else {
(*pFailed)++;
}
// Test SetAutomatic & IsAutomatic to FALSE
hr = S_OK;
try{
WsbAffirmHr(SetAutomatic (FALSE));
WsbAffirmHr(IsAutomatic ());
} WsbCatch (hr);
if (hr == S_OK){
(*pFailed)++;
} else {
(*pPassed)++;
}
// Test SetCanRotate & IsCanRotate to TRUE
hr = S_OK;
try{
WsbAffirmHr(SetCanRotate (TRUE));
WsbAffirmHr(CanRotate ());
} WsbCatch (hr);
if (hr == S_OK){
(*pPassed)++;
} else {
(*pFailed)++;
}
// Test SetCanRotate & IsCanRotate to FALSE
hr = S_OK;
try{
WsbAffirmHr(SetCanRotate (FALSE));
WsbAffirmHr(CanRotate ());
} WsbCatch (hr);
if (hr == S_OK){
(*pFailed)++;
} else {
(*pPassed)++;
}
// Test SetOperation & GetOperation interface
bstrWork1 = bstrVal1;
SetOperation(bstrWork1);
GetOperation(&bstrWork2);
if (bstrWork1 == bstrWork2){
(*pPassed)++;
} else {
(*pFailed)++;
}
// Test SetPercentComplete & GetPercentComplete
// Test ExportCartridge & ImportCartridge
// Test DismountCartridge & MountCartridge
// Test TestReady
// Test Home
} WsbCatch(hr);
// Tally up the results
hr = S_OK;
if (*pFailed) {
hr = S_FALSE;
}
} WsbCatch(hr);
WsbTraceOut(OLESTR("CRmsMediumChanger::Test"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
return(hr);
}
/////////////////////////////////////////////////////////////////////////////
//
// IRmsMediumChanger implementation
//
STDMETHODIMP
CRmsMediumChanger::GetHome(
LONG *pType,
LONG *pPos,
BOOL *pInvert
)
/*++
Implements:
IRmsMediumChanger::GetHome
--*/
{
GUID zero = {0,0,0,0,0,0,0,0,0,0,0};
LONG junk;
return m_home.GetLocation( pType,
&zero,
&zero,
pPos,
&junk,
&junk,
&junk,
pInvert );
}
STDMETHODIMP
CRmsMediumChanger::SetHome(
LONG type,
LONG pos,
BOOL invert
)
/*++
Implements:
IRmsMediumChanger::SetHome
--*/
{
GUID zero = {0,0,0,0,0,0,0,0,0,0,0};
LONG junk = 0;
m_isDirty = TRUE;
return m_home.SetLocation( type, zero, zero, pos, junk, junk, junk, invert );
}
STDMETHODIMP
CRmsMediumChanger::SetAutomatic(
BOOL flag
)
/*++
Implements:
IRmsMediumChanger::SetAutomatic
--*/
{
m_isAutomatic = flag;
m_isDirty = TRUE;
return S_OK;
}
STDMETHODIMP
CRmsMediumChanger::IsAutomatic(
void
)
/*++
Implements:
IRmsMediumChanger::IsAutomatic
--*/
{
HRESULT hr = S_FALSE;
if (m_isAutomatic){
hr = S_OK;
}
return (hr);
}
STDMETHODIMP
CRmsMediumChanger::SetCanRotate(
BOOL flag
)
/*++
Implements:
IRmsMediumChanger::SetCanRotate
--*/
{
m_canRotate = flag;
m_isDirty = TRUE;
return S_OK;
}
STDMETHODIMP
CRmsMediumChanger::CanRotate(
void
)
/*++
Implements:
IRmsMediumChanger::CanRotate
--*/
{
HRESULT hr = S_FALSE;
if (m_canRotate){
hr = S_OK;
}
return (hr);
}
STDMETHODIMP
CRmsMediumChanger::GetOperation(
BSTR *pOperation
)
/*++
Implements:
IRmsMediumChanger::GetOperation
--*/
{
WsbAssertPointer ( pOperation );
m_operation.CopyToBstr( pOperation );
return S_OK;
}
STDMETHODIMP
CRmsMediumChanger::SetOperation(
BSTR pOperation
)
/*++
Implements:
IRmsMediumChanger::SetOperation
--*/
{
m_operation = pOperation;
m_isDirty = TRUE;
return S_OK;
}
STDMETHODIMP
CRmsMediumChanger::GetPercentComplete(
BYTE *pPercent
)
/*++
Implements:
IRmsMediumChanger::GetPercentComplete
--*/
{
*pPercent = m_percentComplete;
return S_OK;
}
STDMETHODIMP
CRmsMediumChanger::SetPercentComplete(
BYTE percent
)
/*++
Implements:
IRmsMediumChanger::SetPercentComplete
--*/
{
m_percentComplete = percent;
m_isDirty = TRUE;
return S_OK;
}
STDMETHODIMP
CRmsMediumChanger::TestReady(
void
)
/*++
Implements:
IRmsMediumChanger::TestReady
--*/
{
return E_NOTIMPL;
}
STDMETHODIMP
CRmsMediumChanger::ImportCartridge(
IRmsCartridge** /*pCart*/
)
/*++
Implements:
IRmsMediumChanger::ImportCartridge
--*/
{
return E_NOTIMPL;
}
STDMETHODIMP
CRmsMediumChanger::ExportCartridge(
IRmsCartridge** /*pCart*/
)
/*++
Implements:
IRmsMediumChanger::ExportCartridge
--*/
{
return E_NOTIMPL;
}
STDMETHODIMP
CRmsMediumChanger::MoveCartridge(
IN IRmsCartridge *pSrcCart,
IN IUnknown *pDestElmt
)
/*++
Implements:
IRmsMediumChanger::MountCartridge
--*/
{
HRESULT hr = E_FAIL;
try {
CComPtr<IRmsCartridge> pCart2;
CComPtr<IRmsDrive> pDrive2;
GUID libId=GUID_NULL, mediaSetId=GUID_NULL;
LONG type=0, pos=0, alt1=0, alt2=0, alt3=0;
BOOL invert=0;
GUID destLibId=GUID_NULL, destMediaSetId=GUID_NULL;
LONG destType=0, destPos=0, destAlt1=0, destAlt2=0, destAlt3=0;
BOOL destInvert=0;
GUID dest2LibId=GUID_NULL, dest2MediaSetId=GUID_NULL;
LONG dest2Type=0, dest2Pos=0, dest2Alt1=0, dest2Alt2=0, dest2Alt3=0;
BOOL dest2Invert=0;
CHANGER_ELEMENT src, dest, dest2;
CComQIPtr<IRmsChangerElement, &IID_IRmsChangerElement> pElmt = pDestElmt;
WsbAssertPointer( pElmt );
// TODO: assert cartridge has same libId as changer
// Set up for SOURCE
WsbAffirmHr( pSrcCart->GetLocation( &type, &libId, &mediaSetId,
&pos, &alt1, &alt2, &alt3, &invert ));
src.ElementAddress = pos;
// Translate the RmsElement type to something the drive understands.
// TODO: make this a local method
switch ( (RmsElement) type ) {
case RmsElementUnknown:
WsbAssertHr( E_UNEXPECTED );
break;
case RmsElementStage:
case RmsElementStorage:
src.ElementType = ChangerSlot;
break;
case RmsElementShelf:
case RmsElementOffSite:
// not supported here!
WsbAssertHr( E_UNEXPECTED );
break;
case RmsElementDrive:
src.ElementType = ChangerDrive;
break;
case RmsElementChanger:
src.ElementType = ChangerTransport;
break;
case RmsElementIEPort:
src.ElementType = ChangerIEPort;
break;
default:
WsbAssertHr( E_UNEXPECTED );
break;
}
//
// Set up for DESTINATION
//
WsbAffirmHr( pElmt->GetLocation( &destType, &destLibId, &destMediaSetId,
&destPos, &destAlt1, &destAlt2, &destAlt3, &destInvert ));
dest.ElementAddress = destPos;
// Translate the Rms type to something the drive understands.
switch ( (RmsElement) destType) {
case RmsElementUnknown:
WsbAssertHr( E_UNEXPECTED );
break;
case RmsElementStage:
case RmsElementStorage:
dest.ElementType = ChangerSlot;
break;
case RmsElementShelf:
case RmsElementOffSite:
// not supported here!
WsbAssertHr( E_UNEXPECTED );
break;
case RmsElementDrive:
dest.ElementType = ChangerDrive;
break;
case RmsElementChanger:
dest.ElementType = ChangerTransport;
break;
case RmsElementIEPort:
dest.ElementType = ChangerIEPort;
break;
default:
WsbAssertHr( E_UNEXPECTED );
break;
}
//
// Do we need to do an exchange or a simple move?
//
BOOL destFull;
hr = pElmt->IsOccupied();
destFull = ( S_OK == hr ) ? TRUE : FALSE;
if ( destFull ) {
//
// Set up for second destination
//
pElmt->GetCartridge( &pCart2 );
pCart2->GetDrive( &pDrive2 );
if ( pDrive2 && ( m_parameters.Features0 & CHANGER_PREDISMOUNT_EJECT_REQUIRED ) ) {
pDrive2->Eject();
}
WsbAffirmHr( pCart2->GetHome( &dest2Type, &dest2LibId, &dest2MediaSetId,
&dest2Pos, &dest2Alt1, &dest2Alt2, &dest2Alt3, &dest2Invert ));
dest2.ElementAddress = dest2Pos;
// Translate the Rms type to something the drive understands.
switch ( (RmsElement) dest2Type) {
case RmsElementUnknown:
WsbAssertHr( E_UNEXPECTED );
break;
case RmsElementStage:
case RmsElementStorage:
dest2.ElementType = ChangerSlot;
break;
case RmsElementShelf:
case RmsElementOffSite:
// not supported here!
WsbAssertHr( E_UNEXPECTED );
break;
case RmsElementDrive:
WsbAssertHr( E_UNEXPECTED );
break;
case RmsElementChanger:
WsbAssertHr( E_UNEXPECTED );
break;
case RmsElementIEPort:
dest2.ElementType = ChangerIEPort;
break;
default:
WsbAssertHr( E_UNEXPECTED );
break;
}
WsbAffirmHr( ExchangeMedium( src, dest, dest2, FALSE, FALSE ));
// Update the Cartridge's Locator
WsbAffirmHr( pSrcCart->SetLocation( destType, libId, mediaSetId,
destPos, alt1, alt2, alt3, invert ));
WsbAffirmHr( pCart2->SetLocation( dest2Type, dest2LibId, dest2MediaSetId,
dest2Pos, dest2Alt1, dest2Alt2, dest2Alt3, dest2Invert ));
}
else {
// Call through to the medium changer driver to move the cartridge
// TODO: handle two sided media.
WsbAffirmHr( MoveMedium( src, dest, FALSE ));
// Update the Cartridge's Locator
WsbAffirmHr( pSrcCart->SetLocation( destType, libId, mediaSetId,
destPos, alt1, alt2, alt3, invert ));
}
hr = S_OK;
}
WsbCatch(hr);
return hr;
}
STDMETHODIMP
CRmsMediumChanger::HomeCartridge(
IN IRmsCartridge *pCart
)
/*++
Implements:
IRmsMediumChanger::HomeCartridge
--*/
{
HRESULT hr = E_FAIL;
try {
WsbAssertPointer( pCart );
GUID libId=GUID_NULL, mediaSetId=GUID_NULL;
LONG type=0, pos=0, alt1=0, alt2=0, alt3=0;
BOOL invert=0;
GUID destLibId=GUID_NULL, destMediaSetId=GUID_NULL;
LONG destType=0, destPos=0, destAlt1=0, destAlt2=0, destAlt3=0;
BOOL destInvert=0;
CHANGER_ELEMENT src, dest;
// TODO: assert cartridge has same libId as changer
// Set up for SOURCE
WsbAffirmHr( pCart->GetLocation( &type, &libId, &mediaSetId,
&pos, &alt1, &alt2, &alt3, &invert ));
src.ElementAddress = pos;
// Translate the RmsElement type to something the drive understands.
// TODO: make this a local method
switch ( (RmsElement) type ) {
case RmsElementUnknown:
WsbAssertHr( E_UNEXPECTED );
break;
case RmsElementStage:
case RmsElementStorage:
src.ElementType = ChangerSlot;
break;
case RmsElementShelf:
case RmsElementOffSite:
// not supported here!
WsbAssertHr( E_UNEXPECTED );
break;
case RmsElementDrive:
src.ElementType = ChangerDrive;
break;
case RmsElementChanger:
src.ElementType = ChangerTransport;
break;
case RmsElementIEPort:
src.ElementType = ChangerIEPort;
break;
default:
WsbAssertHr( E_UNEXPECTED );
break;
}
//
// Set up for DESTINATION
//
WsbAffirmHr( pCart->GetHome( &destType, &destLibId, &destMediaSetId,
&destPos, &destAlt1, &destAlt2, &destAlt3, &destInvert ));
dest.ElementAddress = destPos;
// Translate the Rms type to something the drive understands.
switch ( (RmsElement) destType) {
case RmsElementUnknown:
WsbAssertHr( E_UNEXPECTED );
break;
case RmsElementStage:
case RmsElementStorage:
dest.ElementType = ChangerSlot;
break;
case RmsElementShelf:
case RmsElementOffSite:
// not supported here!
WsbAssertHr( E_UNEXPECTED );
break;
case RmsElementDrive:
dest.ElementType = ChangerDrive;
break;
case RmsElementChanger:
dest.ElementType = ChangerTransport;
break;
case RmsElementIEPort:
dest.ElementType = ChangerIEPort;
break;
default:
WsbAssertHr( E_UNEXPECTED );
break;
}
WsbAffirmHr( MoveMedium( src, dest, FALSE ));
// Update the Cartridge's Locator
WsbAffirmHr( pCart->SetLocation( destType, libId, mediaSetId,
destPos, alt1, alt2, alt3, invert ));
hr = S_OK;
}
WsbCatch(hr);
return hr;
}
STDMETHODIMP
CRmsMediumChanger::Initialize(
void
)
/*++
Implements:
IRmsMediumChanger::Initialize
--*/
{
// TODO: Break this into some smaller methods for initializing slot, drives, ports, etc.
HRESULT hr = E_FAIL;
PREAD_ELEMENT_ADDRESS_INFO pElementInformation = 0;
try {
DWORD size;
WsbAffirmHr(AcquireDevice());
WsbAffirmHr(Status());
size = sizeof( CHANGER_PRODUCT_DATA );
CHANGER_PRODUCT_DATA productData;
WsbAffirmHr(GetProductData( &size, &productData ));
// Get device specific parameters.
size = sizeof( GET_CHANGER_PARAMETERS );
WsbAffirmHr(GetParameters(&size, &m_parameters));
// save some of the more common parameters
m_isAutomatic = TRUE;
if ( m_parameters.Features0 & CHANGER_MEDIUM_FLIP ) m_canRotate = TRUE;
// Initialize the changer elements
BOOL scan = TRUE;
CHANGER_ELEMENT_LIST list;
if ( m_parameters.Features0 & CHANGER_BAR_CODE_SCANNER_INSTALLED ) scan = TRUE;
list.NumberOfElements = 1;
list.Element.ElementType = AllElements;
list.Element.ElementAddress = 0;
WsbAffirmHr( InitializeElementStatus( list, scan ) );
list.NumberOfElements = m_parameters.NumberStorageElements;
list.Element.ElementType = ChangerSlot;
list.Element.ElementAddress = 0;
BOOL tag = ( m_parameters.Features0 & CHANGER_VOLUME_IDENTIFICATION ) ? TRUE : FALSE;
size = sizeof(READ_ELEMENT_ADDRESS_INFO) + (list.NumberOfElements - 1) * sizeof(CHANGER_ELEMENT_STATUS);
pElementInformation = (PREAD_ELEMENT_ADDRESS_INFO)WsbAlloc( size );
WsbAffirmPointer(pElementInformation);
memset(pElementInformation, 0, size);
WsbAffirmHr( GetElementStatus( list, tag, &size, pElementInformation ));
// Create storage slot objects for this changer, if required.
LONG type;
GUID libId, mediaSetId;
LONG pos, alt1, alt2, alt3;
BOOL invert;
m_location.GetLocation( &type, &libId, &mediaSetId, &pos, &alt1, &alt2, &alt3, &invert );
CComQIPtr<IRmsServer, &IID_IRmsServer> pServer = g_pServer;
CComPtr<IWsbIndexedCollection> pCarts;
CComPtr<IWsbIndexedCollection> pSlots;
CComPtr<IRmsLibrary> pLib;
CComPtr<IRmsStorageSlot> pSlot;
WsbAffirmHr( pServer->FindLibraryById( libId, &pLib ));
WsbAffirmHr( pLib->GetStorageSlots( &pSlots ));
WsbAffirmHr( pServer->GetCartridges( &pCarts ));
ULONG count = 0;
WsbAffirmHr( pSlots->GetEntries( &count ));
while ( count < pElementInformation->NumberOfElements ) {
// Add more slots objects to the library
WsbAffirmHr( hr = CoCreateInstance( CLSID_CRmsStorageSlot, 0, CLSCTX_SERVER,
IID_IRmsStorageSlot, (void **)&pSlot ));
WsbAffirmHr( pSlots->Add( pSlot ));
pSlot = 0;
count++;
}
// Populate the storage slot objects with information reported by the device
// TODO: We need to add lots more asserts of various conditions where the
// previous slot information is not consistant with what has been detected.
PCHANGER_ELEMENT_STATUS pElementStatus;
CComPtr<IWsbEnum> pEnumSlots;
WsbAffirmHr( pSlots->Enum( &pEnumSlots ));
WsbAssertPointer( pEnumSlots );
hr = pEnumSlots->First( IID_IRmsStorageSlot, (void **)&pSlot );
for ( ULONG i = 0; i < pElementInformation->NumberOfElements; i++ ) {
pElementStatus = &pElementInformation->ElementStatus[i];
WsbAssert( ChangerSlot == pElementStatus->Element.ElementType, E_UNEXPECTED );
WsbAssert( i == pElementStatus->Element.ElementAddress, E_UNEXPECTED );
CComQIPtr<IRmsChangerElement, &IID_IRmsChangerElement> pSlotElmt = pSlot;
// Is the unit of media inverted?
invert = ( ( pElementStatus->Flags & (ULONG)ELEMENT_STATUS_SVALID ) &&
( pElementStatus->Flags & (ULONG)ELEMENT_STATUS_INVERT ) ) ? TRUE : FALSE;
WsbAffirmHr( pSlotElmt->SetLocation( RmsElementStorage, libId, GUID_NULL, i, 0, 0, 0, invert ));
// Is the slot Full or Empty?
BOOL occupied = ( pElementStatus->Flags & (ULONG)ELEMENT_STATUS_FULL ) ? TRUE : FALSE;
WsbAffirmHr( pSlotElmt->SetIsOccupied( occupied ));
// Set the media type supported
WsbAffirmHr( pSlotElmt->SetMediaSupported( m_mediaSupported ));
// Set the storage flag
WsbAffirmHr( pSlotElmt->SetIsStorage( TRUE ));
// If there is a cartridge present fill in cartridge information
if ( occupied ) {
CComPtr<IRmsCartridge> pCart;
WsbAffirmHr( hr = CoCreateInstance( CLSID_CRmsCartridge, 0, CLSCTX_SERVER,
IID_IRmsCartridge, (void **)&pCart ));
WsbAffirmHr( pCart->SetLocation( RmsElementStorage, libId, GUID_NULL, i, 0, 0, 0, invert ));
WsbAffirmHr( pCart->SetLocation( RmsElementStorage, libId, GUID_NULL, i, 0, 0, 0, invert ));
WsbAffirmHr( pCart->SetHome( RmsElementStorage, libId, GUID_NULL, i, 0, 0, 0, invert ));
WsbAffirmHr( pCart->SetStatus( RmsStatusScratch ));
WsbAffirmHr( pCart->SetType( m_mediaSupported ));
WsbAffirmHr( pSlotElmt->SetCartridge( pCart ));
// Add cartridge to drive
WsbAffirmHr( pCarts->Add( pCart ));
if ( pElementStatus->Flags & (ULONG)ELEMENT_STATUS_PVOLTAG ) {
pElementStatus->PrimaryVolumeID[32] = '\0'; // This nulls the reserved byte
pElementStatus->PrimaryVolumeID[33] = '\0'; // This nulls the reserved byte
CWsbBstrPtr label( (char *)pElementStatus->PrimaryVolumeID );
// Fill in external label information
WsbAffirmHr( pCart->SetTagAndNumber( label, 0 ));
}
}
// Get the next slot
hr = pEnumSlots->Next( IID_IRmsStorageSlot, (void **)&pSlot );
}
// Now process drives.
// Read element status
list.NumberOfElements = m_parameters.NumberDataTransferElements;
list.Element.ElementType = ChangerDrive;
list.Element.ElementAddress = 0;
if ( m_parameters.Features0 & CHANGER_VOLUME_IDENTIFICATION ) tag = TRUE;
size = sizeof(READ_ELEMENT_ADDRESS_INFO) + (list.NumberOfElements - 1) * sizeof(CHANGER_ELEMENT_STATUS);
WsbFree( pElementInformation );
pElementInformation = (PREAD_ELEMENT_ADDRESS_INFO)WsbAlloc( size );
WsbAffirmPointer(pElementInformation);
memset(pElementInformation, 0, size);
WsbAffirmHr( GetElementStatus( list, tag, &size, pElementInformation ));
CComPtr<IWsbIndexedCollection> pDevices;
CComPtr<IWsbIndexedCollection> pDrives;
CComPtr<IRmsDrive> pDrive;
CComPtr<IRmsDrive> pFindDrive;
CComPtr<IRmsDevice> pFindDevice;
WsbAffirmHr( pServer->GetUnconfiguredDevices( &pDevices ));
WsbAffirmHr( pLib->GetDrives( &pDrives ));
// For each drive in the element status page, find the drive in the
// unconfigured list of devices.
for ( i = 0; i < pElementInformation->NumberOfElements; i++ ) {
pElementStatus = &pElementInformation->ElementStatus[i];
WsbAssert( ChangerDrive == pElementStatus->Element.ElementType, E_UNEXPECTED );
WsbAssert( i == pElementStatus->Element.ElementAddress, E_UNEXPECTED );
// set up a find template
WsbAffirmHr( CoCreateInstance( CLSID_CRmsDrive, 0, CLSCTX_SERVER,
IID_IRmsDrive, (void **)&pFindDrive ));
CComQIPtr<IRmsDevice, &IID_IRmsDevice> pFindDevice = pFindDrive;
CComQIPtr<IRmsComObject, &IID_IRmsComObject> pFindObject = pFindDrive;
BYTE port=0xff, bus=0xff, id=0xff, lun=0xff;
if ( pElementStatus->Flags & (ULONG)ELEMENT_STATUS_LUN_VALID )
lun = pElementStatus->Lun;
if ( pElementStatus->Flags & (ULONG)ELEMENT_STATUS_ID_VALID )
id = pElementStatus->TargetId;
if ( !(pElementStatus->Flags & (ULONG)ELEMENT_STATUS_NOT_BUS) ) {
bus = m_bus;
port = m_port;
}
WsbAffirmHr( pFindDevice->SetDeviceAddress( port, bus, id, lun ));
WsbAffirmHr( pFindObject->SetFindBy( RmsFindByDeviceAddress ));
// Find the drive
hr = pDevices->Find( pFindDrive, IID_IRmsDrive, (void **)&pDrive );
if ( S_OK == hr ) {
// Add the drive to the library
WsbAffirmHr( pDrives->Add( pDrive ));
// Remove the drive form the unconfigured list
WsbAffirmHr( pDevices->RemoveAndRelease( pDrive ));
// Fill in more drive information
CComQIPtr<IRmsChangerElement, &IID_IRmsChangerElement> pDriveElmt = pDrive;
// Is the unit of media inverted?
invert = ( ( pElementStatus->Flags & (ULONG)ELEMENT_STATUS_SVALID ) &&
( pElementStatus->Flags & (ULONG)ELEMENT_STATUS_INVERT ) ) ? TRUE : FALSE;
WsbAffirmHr( pDriveElmt->SetLocation( RmsElementDrive, libId, GUID_NULL, i, 0, 0, 0, invert ));
// Is the slot Full or Empty?
BOOL occupied = ( pElementStatus->Flags & (ULONG)ELEMENT_STATUS_FULL ) ? TRUE : FALSE;
WsbAffirmHr( pDriveElmt->SetIsOccupied( occupied ));
// Set the media type supported
WsbAffirmHr( pDriveElmt->SetMediaSupported( m_mediaSupported ));
// Set the storage flag
WsbAffirmHr( pDriveElmt->SetIsStorage( TRUE ));
// If there is a cartridge present fill in cartridge information
if ( occupied ) {
CComPtr<IRmsCartridge> pCart;
WsbAffirmHr( hr = CoCreateInstance( CLSID_CRmsCartridge, 0, CLSCTX_SERVER,
IID_IRmsCartridge, (void **)&pCart ));
WsbAffirmHr( pCart->SetLocation( RmsElementStorage, libId, GUID_NULL, i, 0, 0, 0, invert ));
if ( pElementStatus->Flags & (ULONG)ELEMENT_STATUS_SVALID ) {
try {
ULONG pos;
// pos = pElementStatus->SourceElementAddress[1];
// pos |= (pElementStatus->SourceElementAddress[0] << 8);
pos = pElementStatus->SrcElementAddress.ElementAddress;
//
// TODO: FIX THIS - This code incorrectly assumes source is a slot!!!
//
// I'll work on trying to get chuck to return element type and position
// in element status page.
//
WsbAffirm( pos >= m_parameters.FirstSlotNumber, E_UNEXPECTED );
pos = pos - m_parameters.FirstSlotNumber;
BOOL invert = ( pElementStatus->Flags & (ULONG)ELEMENT_STATUS_INVERT ) ? TRUE : FALSE;
WsbAffirmHr( pCart->SetHome( RmsElementStorage, libId, GUID_NULL, pos, 0, 0, 0, invert ));
}
WsbCatch(hr);
}
// TODO: if not ELEMENT_STATUS_SVALID we should set the home location to
// some empty slot. This handles the case where we we come up with
// unknown media in a drive.
WsbAffirmHr( pCart->SetStatus( RmsStatusScratch ));
WsbAffirmHr( pCart->SetType( m_mediaSupported ));
WsbAffirmHr( pCart->SetDrive( pDrive ));
// Add cartridge to drive
WsbAffirmHr( pCarts->Add( pCart ));
if ( pElementStatus->Flags & (ULONG)ELEMENT_STATUS_PVOLTAG ) {
pElementStatus->PrimaryVolumeID[32] = '\0'; // This nulls the reserved byte
pElementStatus->PrimaryVolumeID[33] = '\0'; // This nulls the reserved byte
CWsbBstrPtr label( (char *)pElementStatus->PrimaryVolumeID );
// Fill in external label information
WsbAffirmHr( pCart->SetTagAndNumber( label, 0 ));
}
}
}
}
// All done
hr = S_OK;
}
WsbCatch(hr);
if ( pElementInformation ) {
WsbFree( pElementInformation );
}
return hr;
}
STDMETHODIMP
CRmsMediumChanger::AcquireDevice(
void
)
/*++
Implements:
IRmsMediumChanger::AcquireDevice
--*/
{
HRESULT hr = E_FAIL;
HANDLE hChanger = INVALID_HANDLE_VALUE;
CWsbBstrPtr name;
try {
// Get the device name for this changer
GetDeviceName( &name );
// Create a handle
hChanger = CreateFile( name,
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
0,
NULL
);
WsbAffirmHandle( hChanger );
// Save the handle
m_handle = hChanger;
// Do any other initialization here
hr = S_OK;
}
WsbCatchAndDo( hr,
WsbTrace( OLESTR("\n\n !!!!! ERROR !!!!! Acquire() failed. name=<%ls>\n\n"), name );
if ( hChanger != INVALID_HANDLE_VALUE ) {
CloseHandle( hChanger );
} );
return hr;
}
STDMETHODIMP
CRmsMediumChanger::ReleaseDevice(
void
)
/*++
Implements:
IRmsMediumChanger::ReleaseDevice
--*/
{
HRESULT hr = E_FAIL;
try {
if ( INVALID_HANDLE_VALUE != m_handle ) {
WsbAffirmStatus( CloseHandle( m_handle ));
m_handle = INVALID_HANDLE_VALUE;
}
hr = S_OK;
}
WsbCatch( hr );
return hr;
}
////////////////////////////////////////////////////////////////////////////////
//
// IRmsMoveMedia Interface
//
STDMETHODIMP
CRmsMediumChanger::GetParameters(
IN OUT PDWORD pSize,
OUT PGET_CHANGER_PARAMETERS pParms
)
/*++
Implements:
IRmsMoveMedia::GetParameters
--*/
{
HRESULT hr = E_FAIL;
try
{
DWORD dwReturn;
WsbAssertPointer( pSize );
WsbAssertPointer( pParms );
WsbAssertHandle( m_handle );
pParms->Size = sizeof(GET_CHANGER_PARAMETERS);
WsbAssertStatus( DeviceIoControl( m_handle,
IOCTL_CHANGER_GET_PARAMETERS,
pParms,
sizeof(GET_CHANGER_PARAMETERS),
pParms,
sizeof(GET_CHANGER_PARAMETERS),
&dwReturn,
NULL ));
hr = S_OK;
}
WsbCatch( hr );
return hr;
}
STDMETHODIMP
CRmsMediumChanger::GetProductData(
IN OUT PDWORD pSize,
OUT PCHANGER_PRODUCT_DATA pData
)
/*++
Implements:
IRmsMoveMedia::GetProductData
--*/
{
HRESULT hr = E_FAIL;
try
{
DWORD dwReturn;
WsbAssertPointer( pSize );
WsbAssertPointer( pData );
WsbAssertHandle( m_handle );
WsbAssertStatus( DeviceIoControl( m_handle,
IOCTL_CHANGER_GET_PRODUCT_DATA,
NULL,
0,
pData,
sizeof(CHANGER_PRODUCT_DATA),
&dwReturn,
NULL ));
hr = S_OK;
}
WsbCatch( hr );
return hr;
}
STDMETHODIMP
CRmsMediumChanger::Status(
void
)
/*++
Implements:
IRmsMoveMedia::Status
--*/
{
HRESULT hr = E_FAIL;
try
{
DWORD dwReturn;
WsbAssertStatus( DeviceIoControl( m_handle,
IOCTL_CHANGER_GET_STATUS,
NULL,
0,
NULL,
0,
&dwReturn,
NULL) );
hr = S_OK;
}
WsbCatch( hr );
return hr;
}
STDMETHODIMP
CRmsMediumChanger::SetAccess(
IN CHANGER_ELEMENT element,
IN DWORD control
)
/*++
Implements:
IRmsMoveMedia::SetAccess
--*/
{
HRESULT hr = E_FAIL;
try
{
DWORD dwReturn;
CHANGER_SET_ACCESS setAccess;
setAccess.Element = element;
setAccess.Control = control;
WsbAssertStatus( DeviceIoControl( m_handle,
IOCTL_CHANGER_SET_ACCESS,
&setAccess,
sizeof(CHANGER_SET_ACCESS),
NULL,
0,
&dwReturn,
NULL ));
hr = S_OK;
}
WsbCatch( hr );
return hr;
}
STDMETHODIMP
CRmsMediumChanger::GetElementStatus(
IN CHANGER_ELEMENT_LIST elementList,
IN BOOL volumeTagInfo,
IN OUT PDWORD pSize,
OUT PREAD_ELEMENT_ADDRESS_INFO pElementInformation
)
/*++
Implements:
IRmsMoveMedia::GetElementStatus
--*/
{
HRESULT hr = E_FAIL;
try
{
DWORD dwReturn;
DWORD requiredSize;
CHANGER_READ_ELEMENT_STATUS readElementStatus;
PCHANGER_ELEMENT_STATUS pElementStatus = pElementInformation->ElementStatus;
WsbAssertPointer( pSize );
WsbAssertPointer( pElementInformation );
requiredSize = elementList.NumberOfElements * sizeof( CHANGER_ELEMENT_STATUS );
WsbAssert( *pSize >= requiredSize, E_INVALIDARG );
readElementStatus.ElementList = elementList;
readElementStatus.VolumeTagInfo = (BOOLEAN)( volumeTagInfo ? TRUE : FALSE );
WsbAssertStatus( DeviceIoControl( m_handle,
IOCTL_CHANGER_GET_ELEMENT_STATUS,
&readElementStatus,
sizeof(CHANGER_READ_ELEMENT_STATUS),
pElementStatus,
requiredSize,
&dwReturn,
NULL ));
pElementInformation->NumberOfElements = dwReturn / sizeof( CHANGER_ELEMENT_STATUS );
hr = S_OK;
}
WsbCatch( hr );
return hr;
}
STDMETHODIMP
CRmsMediumChanger::InitializeElementStatus(
IN CHANGER_ELEMENT_LIST elementList,
IN BOOL barCodeScan
)
/*++
Implements:
IRmsMoveMedia::InitializeElementStatus
--*/
{
HRESULT hr = E_FAIL;
try
{
DWORD dwReturn;
CHANGER_INITIALIZE_ELEMENT_STATUS initElementStatus;
initElementStatus.ElementList = elementList;
initElementStatus.BarCodeScan = (BOOLEAN)( barCodeScan ? TRUE : FALSE );
WsbAssertStatus( DeviceIoControl( m_handle,
IOCTL_CHANGER_INITIALIZE_ELEMENT_STATUS,
&initElementStatus,
sizeof(CHANGER_INITIALIZE_ELEMENT_STATUS),
NULL,
0,
&dwReturn,
NULL) );
hr = S_OK;
}
WsbCatch( hr );
return hr;
}
STDMETHODIMP
CRmsMediumChanger::ExchangeMedium(
IN CHANGER_ELEMENT source,
IN CHANGER_ELEMENT destination1,
IN CHANGER_ELEMENT destination2,
IN BOOL flip1,
IN BOOL flip2
)
/*++
Implements:
IRmsMoveMedia::ExchangeMedium
--*/
{
HRESULT hr = E_FAIL;
try
{
DWORD dwReturn;
CHANGER_EXCHANGE_MEDIUM exchangeMedium;
exchangeMedium.Transport.ElementType = ChangerTransport;
exchangeMedium.Transport.ElementAddress = 0; // default arm or thumb
exchangeMedium.Source = source;
exchangeMedium.Destination1 = destination1;
exchangeMedium.Destination2 = destination2;
exchangeMedium.Flip1 = (BOOLEAN)( flip1 ? TRUE : FALSE );
exchangeMedium.Flip2 = (BOOLEAN)( flip2 ? TRUE : FALSE );
WsbAssertStatus( DeviceIoControl( m_handle,
IOCTL_CHANGER_EXCHANGE_MEDIUM,
&exchangeMedium,
sizeof(CHANGER_EXCHANGE_MEDIUM),
NULL,
0,
&dwReturn,
NULL ));
hr = S_OK;
}
WsbCatch( hr );
return hr;
}
STDMETHODIMP
CRmsMediumChanger::MoveMedium(
IN CHANGER_ELEMENT source,
IN CHANGER_ELEMENT destination,
IN BOOL flip
)
/*++
Implements:
IRmsMoveMedia::MoveMedium
--*/
{
HRESULT hr = E_FAIL;
try
{
DWORD dwReturn;
CHANGER_MOVE_MEDIUM moveMedium;
moveMedium.Transport.ElementType = ChangerTransport;
moveMedium.Transport.ElementAddress = 0; // default arm or thumb
moveMedium.Source = source;
moveMedium.Destination = destination;
moveMedium.Flip = (BOOLEAN)( flip ? TRUE : FALSE );
WsbAssertStatus( DeviceIoControl( m_handle,
IOCTL_CHANGER_MOVE_MEDIUM,
&moveMedium,
sizeof(CHANGER_MOVE_MEDIUM),
NULL,
0,
&dwReturn,
NULL ));
hr = S_OK;
}
WsbCatch( hr );
return hr;
}
STDMETHODIMP
CRmsMediumChanger::Position(
IN CHANGER_ELEMENT destination,
IN BOOL flip
)
/*++
Implements:
IRmsMoveMedia::Position
--*/
{
HRESULT hr = E_FAIL;
try
{
DWORD dwReturn;
CHANGER_SET_POSITION positon;
positon.Transport.ElementType = ChangerTransport;
positon.Transport.ElementAddress = 0; // default arm or thumb
positon.Destination = destination;
positon.Flip = (BOOLEAN)( flip ? TRUE : FALSE );
WsbAssertStatus( DeviceIoControl( m_handle,
IOCTL_CHANGER_SET_POSITION,
&positon,
sizeof(CHANGER_SET_POSITION),
NULL,
0,
&dwReturn,
NULL ));
hr = S_OK;
}
WsbCatch( hr );
return hr;
}
STDMETHODIMP
CRmsMediumChanger::RezeroUnit(
void
)
/*++
Implements:
IRmsMoveMedia::RezeroUnit
--*/
{
HRESULT hr = E_FAIL;
try
{
DWORD dwReturn;
WsbAssertStatus( DeviceIoControl( m_handle,
IOCTL_CHANGER_REINITIALIZE_TRANSPORT,
NULL,
0,
NULL,
0,
&dwReturn,
NULL ));
hr = S_OK;
}
WsbCatch( hr );
return hr;
}
/*
HRESULT
CRmsMediumChanger::getDisplay(
OUT PCHANGER_DISPLAY pDisplay
)
{
HRESULT hr = E_FAIL;
try
{
DWORD dwReturn;
WsbAssertStatus( DeviceIoControl( m_handle,
IOCTL_CHANGER_GET_DISPLAY,
pDisplay,
sizeof(CHANGER_DISPLAY) + (pDisplay->LineCount - 1) * sizeof(SET_CHANGER_DISPLAY),
pDisplay,
sizeof(CHANGER_DISPLAY) + (pDisplay->LineCount - 1) * sizeof(SET_CHANGER_DISPLAY),
&dwReturn,
NULL ));
hr = S_OK;
}
WsbCatch( hr );
return hr;
}
HRESULT
CRmsMediumChanger::setDisplay(
IN PCHANGER_DISPLAY pDisplay
)
{
HRESULT hr = E_FAIL;
try
{
DWORD dwReturn;
WsbAssertStatus( DeviceIoControl( m_handle,
IOCTL_CHANGER_SET_DISPLAY,
pDisplay,
sizeof(CHANGER_DISPLAY) + (pDisplay->LineCount - 1) * sizeof(SET_CHANGER_DISPLAY),
NULL,
0,
&dwReturn,
NULL ));
hr = S_OK;
}
WsbCatch( hr );
return hr;
}
*/
STDMETHODIMP
CRmsMediumChanger::QueryVolumeTag(
IN CHANGER_ELEMENT startingElement,
IN DWORD actionCode,
IN PUCHAR pVolumeIDTemplate,
OUT PDWORD pNumberOfElementsReturned,
OUT PREAD_ELEMENT_ADDRESS_INFO pElementInformation
)
/*++
Implements:
IRmsMoveMedia::QueryVolumeTag
--*/
{
HRESULT hr = E_FAIL;
try
{
DWORD dwReturn;
CHANGER_SEND_VOLUME_TAG_INFORMATION tagInfo;
tagInfo.StartingElement = startingElement;
tagInfo.ActionCode = actionCode;
memcpy( &tagInfo.VolumeIDTemplate, pVolumeIDTemplate, sizeof(MAX_VOLUME_TEMPLATE_SIZE) );
WsbAssertStatus( DeviceIoControl( m_handle,
IOCTL_CHANGER_QUERY_VOLUME_TAGS,
&tagInfo,
sizeof(CHANGER_SEND_VOLUME_TAG_INFORMATION),
pElementInformation,
sizeof(READ_ELEMENT_ADDRESS_INFO) + (pElementInformation->NumberOfElements - 1) * sizeof(CHANGER_ELEMENT_STATUS),
&dwReturn,
NULL ));
*pNumberOfElementsReturned = pElementInformation->NumberOfElements;
hr = S_OK;
}
WsbCatch( hr );
return hr;
}