/*++ © 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 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 pChanger1; CComPtr pChanger2; CComPtr pFile1; CComPtr 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 pCart2; CComPtr 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 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 pServer = g_pServer; CComPtr pCarts; CComPtr pSlots; CComPtr pLib; CComPtr 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 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 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 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 pDevices; CComPtr pDrives; CComPtr pDrive; CComPtr pFindDrive; CComPtr 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 pFindDevice = pFindDrive; CComQIPtr 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 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 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; }