/*++ © 1998 Seagate Software, Inc. All rights reserved. Module Name: SegDb.cpp Abstract: This component is an provides the collection that contains the HSM segment records. Author: Cat Brant [cbrant] 12-Nov-1996 Revision History: --*/ #include "stdafx.h" #include "metaint.h" #include "metaLib.h" #include "engine.h" #include "segdb.h" #undef WSB_TRACE_IS #define WSB_TRACE_IS WSB_TRACE_BIT_SEG // SEG_APPEND_OK returns TRUE if bag segment 2 can be appended to // segment 1 #define SEG_APPEND_OK(b1, s1, l1, b2, s2, l2) \ (IsEqualGUID(b1, b2) && (s1 + l1 == s2)) // SEG_EXPAND_OK returns TRUE if bag segment 2 can be added to // segment 1 #define SEG_EXPAND_OK(b1, s1, l1, b2, s2, l2) \ (IsEqualGUID(b1, b2) && (s1 + l1 <= s2)) // SEG_CONTAINS returns TRUE if bag segment 1 contains (the first // part of) segment 2 #define SEG_CONTAINS(b1, s1, l1, b2, s2, l2) \ (IsEqualGUID(b1, b2) && (s1 <= s2) && ((s1 + l1) > s2)) HRESULT CSegDb::BagHoleAdd ( IN IWsbDbSession* pDbSession, IN GUID BagId, IN LONGLONG SegStartLoc, IN LONGLONG SegLen ) /*++ Implements: ISegDb::BagHoleAdd --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CSegDb::BagHoleAdd"), OLESTR("GUID = <%ls>, SegStartLoc = <%I64u>, SegLen = <%I64u>"), WsbGuidAsString(BagId), SegStartLoc, SegLen); try { BOOL found = FALSE; CComPtr pBagHole; GUID l_BagId = GUID_NULL; LONGLONG l_SegStartLoc = 0; LONGLONG l_SegLen = 0; WsbAffirmHr(GetEntity(pDbSession, HSM_BAG_HOLE_REC_TYPE, IID_IBagHole, (void **)&pBagHole)); WsbAffirmHr(pBagHole->SetBagHole(BagId, SegStartLoc, 0)); // Look for a segment to which to append this one WsbTrace(OLESTR("Finding BagHole Record: <%ls>, <%I64u>, <%I64u>\n"), WsbGuidAsString(BagId), SegStartLoc, SegLen); hr = pBagHole->FindLTE(); if (WSB_E_NOTFOUND == hr) { hr = S_OK; } else { WsbAffirmHr(pBagHole->GetBagHole(&l_BagId, &l_SegStartLoc, &l_SegLen)); if (SEG_APPEND_OK(l_BagId, l_SegStartLoc, l_SegLen, BagId, SegStartLoc, SegLen)) { found = TRUE; } } if (found) { // Append this segment to the existing record l_SegLen += SegLen; } else { // Create a new record l_SegStartLoc = SegStartLoc; l_SegLen = SegLen; WsbAffirmHr(pBagHole->MarkAsNew()); } WsbAffirmHr(pBagHole->SetBagHole(BagId, l_SegStartLoc, l_SegLen)); WsbTrace(OLESTR("Writing BagHole Record: <%ls>, <%I64u>, <%I64u>\n"), WsbGuidAsString(BagId), l_SegStartLoc, l_SegLen); WsbAffirmHr(pBagHole->Write()); } WsbCatch(hr); WsbTraceOut(OLESTR("CSegDb::BagHoleAdd"), OLESTR("hr = <%ls>"),WsbHrAsString(S_OK)); return(hr); } HRESULT CSegDb::BagHoleFind ( IN IWsbDbSession* pDbSession, IN GUID BagId, IN LONGLONG SegStartLoc, IN LONGLONG SegLen, OUT IBagHole** ppIBagHole ) /*++ Implements: ISegDb::BagHoleFind --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CSegDb::BagHoleFind"), OLESTR("GUID = <%ls>, SegStartLoc = <%I64u>, SegLen = <%I64u>"), WsbGuidAsString(BagId), SegStartLoc, SegLen); try { CComPtr pBagHole; GUID l_BagId; LONGLONG l_SegStartLoc; LONGLONG l_SegLen; WsbAffirm(ppIBagHole != NULL, E_POINTER); WsbAffirmHr(GetEntity(pDbSession, HSM_BAG_HOLE_REC_TYPE, IID_IBagHole, (void **)&pBagHole)); WsbAffirmHr(pBagHole->SetBagHole(BagId, SegStartLoc, 0)); // Look for a segment that contains this one WsbTrace(OLESTR("Finding BagHole Record: <%ls>, <%I64u>, <%I64u>\n"), WsbGuidAsString(BagId), SegStartLoc, SegLen); WsbAffirmHr(pBagHole->FindLTE()); // We found a record, see if it's the right one WsbAffirmHr(pBagHole->GetBagHole(&l_BagId, &l_SegStartLoc, &l_SegLen)); if (SEG_CONTAINS(l_BagId, l_SegStartLoc, l_SegLen, BagId, SegStartLoc, SegLen)) { *ppIBagHole = pBagHole; pBagHole.p->AddRef(); } else { hr = WSB_E_NOTFOUND; } } WsbCatch(hr); WsbTraceOut(OLESTR("CSegDb::BagHoleFind"), OLESTR("hr = <%ls>"),WsbHrAsString(S_OK)); return(hr); } HRESULT CSegDb::BagHoleSubtract ( IN IWsbDbSession* pDbSession, IN GUID BagId, IN LONGLONG SegStartLoc, IN LONGLONG SegLen ) /*++ Implements: ISegDb::BagHoleSubtract --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CSegDb::BagHoleSubtract"), OLESTR("GUID = <%ls>, SegStartLoc = <%I64u>, SegLen = <%I64u>"), WsbGuidAsString(BagId), SegStartLoc, SegLen); try { GUID l_BagId; LONGLONG l_SegStartLoc; LONGLONG l_SegLen; CComPtr pBagHole; // Find the segment record WsbAffirmHr(BagHoleFind(pDbSession, BagId, SegStartLoc, SegLen, &pBagHole)); // Get the current data WsbAffirmHr(pBagHole->GetBagHole(&l_BagId, &l_SegStartLoc, &l_SegLen)); // Determine where the hole is if (l_SegStartLoc == SegStartLoc && l_SegLen == SegLen) { // Hole is the entire segment -- delete it WsbAffirmHr(pBagHole->Remove()); } else if (l_SegStartLoc == SegStartLoc) { // Hole is at the beginning of the segment. Just update the // existing segment l_SegStartLoc += SegLen; WsbAffirmHr(pBagHole->SetBagHole(BagId, l_SegStartLoc, l_SegLen)); WsbAffirmHr(pBagHole->Write()); } else if ((l_SegStartLoc + l_SegLen) == (SegStartLoc + SegLen)) { // Hole is at the end of the segment. Just update the // existing segment l_SegLen -= SegLen; WsbAffirmHr(pBagHole->SetBagHole(BagId, l_SegStartLoc, l_SegLen)); WsbAffirmHr(pBagHole->Write()); } else { // Hole is in the middle of the segment. Update the // existing record to be the first part. LONGLONG oldLen = l_SegLen; LONGLONG offset = (SegStartLoc + SegLen) - l_SegStartLoc; l_SegLen = SegStartLoc - l_SegStartLoc; WsbAffirmHr(pBagHole->SetBagHole(BagId, l_SegStartLoc, l_SegLen)); WsbAffirmHr(pBagHole->Write()); // Create a new record for the second part. l_SegLen -= offset; l_SegStartLoc += offset; WsbAffirmHr(BagHoleAdd(pDbSession, BagId, l_SegStartLoc, l_SegLen)); } } WsbCatch(hr); WsbTraceOut(OLESTR("CSegDb::BagHoleSubtract"), OLESTR("hr = <%ls>"),WsbHrAsString(S_OK)); return(hr); } HRESULT CSegDb::FinalConstruct( void ) /*++ Routine Description: This method does some initialization of the object that is necessary after construction. Arguments: None. Return Value: S_OK --*/ { HRESULT hr = S_OK; m_value = 0; try { WsbAssertHr(CWsbDb::FinalConstruct()); m_version = 1; } WsbCatch(hr); return(hr); } HRESULT CSegDb::FinalRelease( void ) /*++ Routine Description: This method does some termination of the object that is necessary before destruction. Arguments: None. Return Value: S_OK Anything returned by CWsbCollection::FinalDestruct(). --*/ { HRESULT hr = S_OK; CWsbDb::FinalRelease(); return(hr); } HRESULT CSegDb::Test ( OUT USHORT * pTestsPassed, OUT USHORT* pTestsFailed ) /*++ Routine Description: See IWsbTestable::Test(). Arguments: See IWsbTestable::Test(). Return Value: See IWsbTestable::Test(). --*/ { HRESULT hr = S_OK; #ifdef THIS_CODE_IS_WRONG // This is mostly wrong now ULONG entries; GUID lastBagId; LONGLONG lastStartLoc; GUID startBagId; LONGLONG startSegStartLoc; LONGLONG startSegLen; USHORT startSegType; GUID startPrimLoc; LONGLONG startSecLoc; USHORT testsRun = 0; CComPtr pColl; CComPtr pSegRec1; CComPtr pSegRec2; CComPtr pSegRec3; CComPtr pSegRec4; CComPtr pSegRec5; CComPtr pSegRec6; CComPtr pSegRec7; CComPtr pSegRec8; CComPtr pSegRec9; CComPtr pSegRec10; CComPtr pSegRec11; WsbTraceIn(OLESTR("CSegDb::Test"), OLESTR("")); *pTestsPassed = *pTestsFailed = 0; try { // Clear out any entries that might be present. hr = S_OK; try { WsbAssertHr(Erase()); } WsbCatch(hr); if (hr == S_OK) { (*pTestsPassed)++; } else { (*pTestsFailed)++; } // There shouldn't be any entries. hr = S_OK; try { WsbAssertHr(GetSegments(&pColl)); WsbAssertHr(pColl->GetEntries(&entries)); WsbAssert(0 == entries, E_FAIL); } WsbCatch(hr); if (hr == S_OK) { (*pTestsPassed)++; } else { (*pTestsFailed)++; } // It should be empty. hr = S_OK; try { WsbAssert(pColl->IsEmpty() == S_OK, E_FAIL); } WsbCatch(hr); if (hr == S_OK) { (*pTestsPassed)++; } else { (*pTestsFailed)++; } // We need some collectable items to exercise the collection. WsbAssertHr(GetEntity(pDbSession, HSM_SEG_REC_TYPE, IID_ISegRec, (void**) &pSegRec1)); WsbAssertHr(pSegRec1->SetSegmentRecord(CLSID_CWsbBool, 0, 6, 0, CLSID_CSegRec,0 )); // Add the item to the collection. hr = S_OK; try { WsbAssertHr(pSegRec1->Write()); } WsbCatch(hr); if (hr == S_OK) { (*pTestsPassed)++; } else { (*pTestsFailed)++; } // There should be 1 entry. hr = S_OK; try { WsbAssertHr(pColl->GetEntries(&entries)); WsbAssert(1 == entries, E_FAIL); } WsbCatch(hr); if (hr == S_OK) { (*pTestsPassed)++; } else { (*pTestsFailed)++; } // It should not be empty. hr = S_OK; try { WsbAssert(pColl->IsEmpty() == S_FALSE, E_FAIL); } WsbCatch(hr); if (hr == S_OK) { (*pTestsPassed)++; } else { (*pTestsFailed)++; } // Does it think it has the item? hr = S_OK; try { WsbAssertHr(GetEntity(pDbSession, HSM_SEG_REC_TYPE, IID_ISegRec, (void**) &pSegRec2)); WsbAssertHr(pSegRec2->SetSegmentRecord(CLSID_CWsbBool, 0, 6, 0, CLSID_CSegRec,0 )); WsbAssertHr(pSegRec2->FindEQ()); WsbAssert(pSegRec1->CompareToISegmentRecord(pSegRec2, NULL) == S_OK, E_FAIL); } WsbCatch(hr); if (hr == S_OK) { (*pTestsPassed)++; } else { (*pTestsFailed)++; } // Add some more items WsbAssertHr(pSegRec2->SetSegmentRecord(CLSID_CWsbGuid, 0, 5, 0, CLSID_CSegRec,0 )); WsbAssertHr(GetEntity(pDbSession, HSM_SEG_REC_TYPE, IID_ISegRec, (void**) &pSegRec3)); WsbAssertHr(pSegRec3->SetSegmentRecord(CLSID_CWsbGuid, 0, 5, 0, CLSID_CSegRec,0 )); // Add the items to the collection. hr = S_OK; try { WsbAssertHr(pSegRec2->Write()); WsbAssertHr(pSegRec3->Write()); } WsbCatch(hr); if (hr == S_OK) { (*pTestsPassed)++; } else { (*pTestsFailed)++; } // There should be 3 entries. hr = S_OK; try { WsbAssertHr(pColl->GetEntries(&entries)); WsbAssert(3 == entries, E_FAIL); WsbAssertHr(pColl->OccurencesOf(pSegRec3, &entries)); WsbAssert(2 == entries, E_FAIL); } WsbCatch(hr); if (hr == S_OK) { (*pTestsPassed)++; } else { (*pTestsFailed)++; } // Remove one of the two identical items. hr = S_OK; try { WsbAssertHr(pSegRec3->FindEQ()); WsbAssertHr(pSegRec3->Remove()); } WsbCatch(hr); if (hr == S_OK) { (*pTestsPassed)++; } else { (*pTestsFailed)++; } // There should be 2 entries. hr = S_OK; try { WsbAssertHr(pColl->GetEntries(&entries)); WsbAssert(2 == entries, E_FAIL); } WsbCatch(hr); if (hr == S_OK) { (*pTestsPassed)++; } else { (*pTestsFailed)++; } // How many copies does it have? hr = S_OK; try { WsbAssertHr(pColl->OccurencesOf(pSegRec1, &entries)); WsbAssert(1 == entries, E_FAIL); } WsbCatch(hr); if (hr == S_OK) { (*pTestsPassed)++; } else { (*pTestsFailed)++; } hr = S_OK; try { WsbAssertHr(pColl->OccurencesOf(pSegRec3, &entries)); WsbAssert(1 == entries, E_FAIL); } WsbCatch(hr); if (hr == S_OK) { (*pTestsPassed)++; } else { (*pTestsFailed)++; } // Can we find an entry? hr = S_OK; try { WsbAssertHr(pSegRec3->FindEQ()); } WsbCatch(hr); if (hr == S_OK) { (*pTestsPassed)++; } else { (*pTestsFailed)++; } // Does the collection still contain it? hr = S_OK; try { WsbAssert(pColl->Contains(pSegRec1) == S_OK, E_FAIL); } WsbCatch(hr); if (hr == S_OK) { (*pTestsPassed)++; } else { (*pTestsFailed)++; } // Remove the last of the record, and verify // that it can't be found. Then puit it back. hr = S_OK; try { WsbAssertHr(pSegRec1->FindEQ()); WsbAssertHr(pSegRec1->Remove()); WsbAssert(pColl->Contains(pSegRec1) == S_FALSE, E_FAIL); WsbAssertHr(pSegRec1->MarkAsNew()); WsbAssertHr(pSegRec1->Write()); } WsbCatch(hr); if (hr == S_OK) { (*pTestsPassed)++; } else { (*pTestsFailed)++; } try { WsbAssertHr(pColl->RemoveAllAndRelease()); } WsbCatch(hr); if (hr == S_OK) { (*pTestsPassed)++; } else { (*pTestsFailed)++; } // It should be empty. hr = S_OK; try { WsbAssert(pColl->IsEmpty() == S_OK, E_FAIL); } WsbCatch(hr); if (hr == S_OK) { (*pTestsPassed)++; } else { (*pTestsFailed)++; } hr = S_OK; try { WsbAssertHr(Erase()); } WsbCatch(hr); if (hr == S_OK) { (*pTestsPassed)++; } else { (*pTestsFailed)++; } try { WsbAssertHr(pSegRec1->SetSegmentRecord(CLSID_CWsbBool, 0, 6, 0, CLSID_CSegRec,0 )); WsbAssertHr(pSegRec2->SetSegmentRecord(CLSID_CWsbGuid, 0, 5, 0, CLSID_CSegRec,0 )); WsbAssertHr(pSegRec3->SetSegmentRecord(CLSID_CWsbGuid, 5, 5, 0, CLSID_CSegRec,0 )); WsbAssertHr(GetEntity(HSM_SEG_REC_TYPE, IID_ISegRec, (void**) &pSegRec4)); WsbAssertHr(pSegRec4->SetSegmentRecord(CLSID_CWsbGuid, 10, 5, 0, CLSID_CSegRec,0 )); WsbAssertHr(GetEntity(HSM_SEG_REC_TYPE, IID_ISegRec, (void**) &pSegRec5)); WsbAssertHr(pSegRec5->SetSegmentRecord(CLSID_CWsbGuid, 15, 5, 0, CLSID_CSegRec,0 )); WsbAssertHr(GetEntity(HSM_SEG_REC_TYPE, IID_ISegRec, (void**) &pSegRec6)); WsbAssertHr(pSegRec6->SetSegmentRecord(CLSID_CWsbGuid, 20, 5, 0, CLSID_CSegRec,0 )); WsbAssertHr(GetEntity(HSM_SEG_REC_TYPE, IID_ISegRec, (void**) &pSegRec7)); WsbAssertHr(pSegRec7->SetSegmentRecord(CLSID_CWsbGuid, 25, 5, 0, CLSID_CSegRec,0 )); WsbAssertHr(GetEntity(HSM_SEG_REC_TYPE, IID_ISegRec, (void**) &pSegRec8)); WsbAssertHr(pSegRec8->SetSegmentRecord(CLSID_CWsbGuid, 30, 5, 0, CLSID_CSegRec,0 )); WsbAssertHr(GetEntity(HSM_SEG_REC_TYPE, IID_ISegRec, (void**) &pSegRec9)); WsbAssertHr(pSegRec9->SetSegmentRecord(CLSID_CWsbGuid, 35, 5, 0, CLSID_CSegRec,0 )); WsbAssertHr(GetEntity(HSM_SEG_REC_TYPE, IID_ISegRec, (void**) &pSegRec10)); WsbAssertHr(pSegRec10->SetSegmentRecord(CLSID_CWsbGuid, 40, 5, 0, CLSID_CSegRec,0 )); // Add them in random order WsbAssertHr(pColl->Add(pSegRec5)); WsbAssertHr(pColl->Add(pSegRec4)); WsbAssertHr(pColl->Add(pSegRec1)); WsbAssertHr(pColl->Add(pSegRec6)); WsbAssertHr(pColl->Add(pSegRec7)); WsbAssertHr(pColl->Add(pSegRec8)); WsbAssertHr(pColl->Add(pSegRec1)); WsbAssertHr(pColl->Add(pSegRec2)); WsbAssertHr(pColl->Add(pSegRec3)); WsbAssertHr(pColl->Add(pSegRec9)); WsbAssertHr(pColl->Add(pSegRec3)); WsbAssertHr(pColl->Add(pSegRec4)); WsbAssertHr(pColl->Add(pSegRec10)); WsbAssertHr(pColl->Add(pSegRec5)); WsbAssertHr(pColl->Add(pSegRec8)); WsbAssertHr(pColl->Add(pSegRec1)); WsbAssertHr(pColl->Add(pSegRec5)); WsbAssertHr(pColl->Add(pSegRec6)); WsbAssertHr(pColl->Add(pSegRec7)); WsbAssertHr(pColl->Add(pSegRec1)); WsbAssertHr(pColl->Add(pSegRec7)); WsbAssertHr(pColl->Add(pSegRec2)); WsbAssertHr(pColl->Add(pSegRec7)); WsbAssertHr(pColl->Add(pSegRec8)); WsbAssertHr(pColl->Add(pSegRec2)); WsbAssertHr(pColl->Add(pSegRec8)); WsbAssertHr(pColl->Add(pSegRec3)); WsbAssertHr(pColl->Add(pSegRec6)); WsbAssertHr(pColl->Add(pSegRec3)); WsbAssertHr(pColl->Add(pSegRec9)); WsbAssertHr(pColl->Add(pSegRec4)); WsbAssertHr(pColl->Add(pSegRec6)); WsbAssertHr(pColl->Add(pSegRec9)); WsbAssertHr(pColl->Add(pSegRec9)); WsbAssertHr(pColl->Add(pSegRec10)); WsbAssertHr(pColl->Add(pSegRec4)); WsbAssertHr(pColl->Add(pSegRec10)); WsbAssertHr(pColl->Add(pSegRec5)); WsbAssertHr(pColl->Add(pSegRec10)); WsbAssertHr(pColl->Add(pSegRec2)); } WsbCatch(hr); if (hr == S_OK) { (*pTestsPassed)++; } else { (*pTestsFailed)++; } try { // Check that they're sorted WsbAssertHr(GetEntity(HSM_SEG_REC_TYPE, IID_ISegRec, (void**) &pSegRec11)); WsbAssertHr(pSegRec11->First()); WsbAssertHr(pSegRec11->GetSegmentRecord(&startBagId, &startSegStartLoc, &startSegLen, &startSegType, &startPrimLoc, &startSecLoc)); lastBagId = startBagId; lastStartLoc = startSegStartLoc; hr = S_OK; for ( ; ; ) { hr = pSegRec11->Next(); if (hr != S_OK) break; WsbAssertHr(pSegRec11->GetSegmentRecord(&startBagId, &startSegStartLoc, &startSegLen, &startSegType, &startPrimLoc, &startSecLoc)); WsbAssert(!IsEqualGUID(lastBagId, startBagId) || lastStartLoc <= startSegStartLoc, E_FAIL); lastBagId = startBagId; lastStartLoc = startSegStartLoc; } WsbAssert(hr == WSB_E_NOTFOUND, E_FAIL); hr = S_OK; } WsbCatch(hr); if (hr == S_OK) { (*pTestsPassed)++; } else { (*pTestsFailed)++; } try { // Check that the last one is what we expect WsbAssertHr(pSegRec11->Last()); WsbAssertHr(pSegRec11->CompareToISegmentRecord(pSegRec10, NULL)); // Look for a specific record WsbAssertHr(pSegRec5->FindEQ()); // Check for near misses WsbAssertHr(pSegRec11->SetSegmentRecord(CLSID_CWsbGuid, 23, 5, 0, CLSID_CSegRec,0 )); WsbAssertHr(pSegRec11->FindGT()); WsbAssertHr(pSegRec11->CompareToISegmentRecord(pSegRec7, NULL)); WsbAssertHr(pSegRec11->SetSegmentRecord(CLSID_CWsbGuid, 21, 5, 0, CLSID_CSegRec,0 )); WsbAssertHr(pSegRec11->FindLTE()); WsbAssertHr(pSegRec11->CompareToISegmentRecord(pSegRec6, NULL)); } WsbCatch(hr); if (hr == S_OK) { (*pTestsPassed)++; } else { (*pTestsFailed)++; } // Clear the DB so we can shut it down hr = S_OK; try { WsbAssertHr(Erase()); WsbAssertHr(Close()); } WsbCatch(hr); if (hr == S_OK) { (*pTestsPassed)++; } else { (*pTestsFailed)++; } } WsbCatch(hr); #else *pTestsPassed = *pTestsFailed = 0; #endif WsbTraceOut(OLESTR("CSegDb::Test"), OLESTR("hr = <%ls>"),WsbHrAsString(hr)); return(S_OK); } HRESULT CSegDb::Erase ( void ) /*++ Routine Description: See ISegDb::Erase Arguments: See ISegDb::Erase Return Value: See ISegDb::Erase --*/ { HRESULT hr = E_NOTIMPL; WsbTraceIn(OLESTR("CSegDb::Erase"),OLESTR("")); try { // To be done? } WsbCatch(hr); WsbTraceOut(OLESTR("CSegDb::Erase"), OLESTR("hr = <%ls>"),WsbHrAsString(hr)); return(hr); } HRESULT CSegDb::GetClassID( OUT CLSID* pClsid ) /*++ Implements: IPersist::GetClassID(). --*/ { HRESULT hr = S_OK; try { WsbAssert(0 != pClsid, E_POINTER); *pClsid = CLSID_CSegDb; } WsbCatch(hr); return(hr); } HRESULT CSegDb::Initialize( IN OLECHAR* root, IN IWsbDbSys* pDbSys, IN OUT BOOL* pCreateFlag ) /*++ Implements: ISegDb::Initialize(). --*/ { BOOL CreateFlag = FALSE; HRESULT hr = S_OK; CWsbStringPtr path; WsbTraceIn(OLESTR("CSegDb::Initialize"), OLESTR("root = <%ls>, CreateFlag = <%ls>"), WsbAbbreviatePath(root, 120), WsbPtrToBoolAsString(pCreateFlag)); if (pCreateFlag) { CreateFlag = *pCreateFlag; } try { path = root; WsbAffirmHr(path.Append(OLESTR("\\SegDb"))); m_pWsbDbSys = pDbSys; WsbAffirmPointer(m_pWsbDbSys); hr = Locate(path); if (hr == STG_E_FILENOTFOUND && CreateFlag){ ULONG memSize; hr = S_OK; m_nRecTypes = 5; memSize = m_nRecTypes * sizeof(IDB_REC_INFO); m_RecInfo = (IDB_REC_INFO*)WsbAlloc(memSize); WsbAffirm(0 != m_RecInfo, E_FAIL); ZeroMemory(m_RecInfo, memSize); // Segment records m_RecInfo[0].Type = HSM_SEG_REC_TYPE; m_RecInfo[0].EntityClassId = CLSID_CSegRec; m_RecInfo[0].Flags = 0; m_RecInfo[0].MinSize = 2 * WSB_BYTE_SIZE_GUID + 3 * WSB_BYTE_SIZE_LONGLONG + WSB_BYTE_SIZE_USHORT; m_RecInfo[0].MaxSize = m_RecInfo[0].MinSize; m_RecInfo[0].nKeys = 1; memSize = m_RecInfo[0].nKeys * sizeof(IDB_KEY_INFO); m_RecInfo[0].Key = (IDB_KEY_INFO*)WsbAlloc(memSize); WsbAffirm(0 != m_RecInfo[0].Key, E_FAIL); ZeroMemory(m_RecInfo[0].Key, memSize); m_RecInfo[0].Key[0].Type = SEG_KEY_TYPE; m_RecInfo[0].Key[0].Size = WSB_BYTE_SIZE_GUID + WSB_BYTE_SIZE_LONGLONG; m_RecInfo[0].Key[0].Flags = IDB_KEY_FLAG_DUP_ALLOWED; // Media information m_RecInfo[1].Type = HSM_MEDIA_INFO_REC_TYPE; m_RecInfo[1].EntityClassId = CLSID_CMediaInfo; m_RecInfo[1].Flags = 0; m_RecInfo[1].MinSize = 2 * (WSB_BYTE_SIZE_GUID + //Id WSB_BYTE_SIZE_GUID + //ntmsId WSB_BYTE_SIZE_GUID + //soragePoolId 4 + //nme 4 + //brCode WSB_BYTE_SIZE_SHORT+ //tpe WSB_BYTE_SIZE_FILETIME + //lastUpdate WSB_BYTE_SIZE_LONG + //lastError WSB_BYTE_SIZE_BOOL + //m_RecallOnly WSB_BYTE_SIZE_LONGLONG + //m_freeBytes WSB_BYTE_SIZE_LONGLONG + //m_Capacity WSB_BYTE_SIZE_SHORT) + //nextRemoteDataSet WSB_BYTE_SIZE_BOOL + //m_Recreate WSB_BYTE_SIZE_LONGLONG + //m_LocicalFreeSpace 3 * (WSB_BYTE_SIZE_GUID + //m_RmsMediaId 4 + //m_Name 4 + //m_BarCode WSB_BYTE_SIZE_FILETIME + //m_Update WSB_BYTE_SIZE_LONG + //m_LastError WSB_BYTE_SIZE_SHORT ); //nextRemoteDataSet // NOTE: // // The next line that calculates the max record size for media info has a BAD bug in it - Windows Bugs 407340. // The macro SEG_DB_MAX_MEDIA_NAME_LEN and SEG_DB_MAX_MEDIA_BAR_CODE_LEN are defined without parenthesis - see in segdb.h // As a result, the max size is only 711 bytes instead of 1751 as it should be !! // // It is NOT fixed since there are too many existing installations with the wrong record size... // This bug has implications around the code - look for "Windows Bugs 407340" comments throughout the HSM code // m_RecInfo[1].MaxSize = m_RecInfo[1].MinSize + 5 * SEG_DB_MAX_MEDIA_NAME_LEN + 5 * SEG_DB_MAX_MEDIA_BAR_CODE_LEN; m_RecInfo[1].nKeys = 1; memSize = m_RecInfo[1].nKeys * sizeof(IDB_KEY_INFO); m_RecInfo[1].Key = (IDB_KEY_INFO*)WsbAlloc(memSize); WsbAffirm(0 != m_RecInfo[1].Key, E_FAIL); ZeroMemory(m_RecInfo[1].Key, memSize); m_RecInfo[1].Key[0].Type = MEDIA_INFO_KEY_TYPE; m_RecInfo[1].Key[0].Size = WSB_BYTE_SIZE_GUID; m_RecInfo[1].Key[0].Flags = IDB_KEY_FLAG_PRIMARY; // Bag information m_RecInfo[2].Type = HSM_BAG_INFO_REC_TYPE; m_RecInfo[2].EntityClassId = CLSID_CBagInfo; m_RecInfo[2].Flags = 0; m_RecInfo[2].MinSize = (2 * WSB_BYTE_SIZE_GUID) + (2 * WSB_BYTE_SIZE_LONGLONG) + (2 * WSB_BYTE_SIZE_USHORT) + WSB_BYTE_SIZE_FILETIME + WSB_BYTE_SIZE_SHORT; m_RecInfo[2].MaxSize = m_RecInfo[2].MinSize; m_RecInfo[2].nKeys = 1; memSize = m_RecInfo[2].nKeys * sizeof(IDB_KEY_INFO); m_RecInfo[2].Key = (IDB_KEY_INFO*)WsbAlloc(memSize); WsbAffirm(0 != m_RecInfo[2].Key, E_FAIL); ZeroMemory(m_RecInfo[2].Key, memSize); m_RecInfo[2].Key[0].Type = BAG_INFO_KEY_TYPE; m_RecInfo[2].Key[0].Size = WSB_BYTE_SIZE_GUID; m_RecInfo[2].Key[0].Flags = IDB_KEY_FLAG_PRIMARY; // Bag holes m_RecInfo[3].Type = HSM_BAG_HOLE_REC_TYPE; m_RecInfo[3].EntityClassId = CLSID_CBagHole; m_RecInfo[3].Flags = 0; m_RecInfo[3].MinSize = WSB_BYTE_SIZE_GUID + 2 * WSB_BYTE_SIZE_LONGLONG; m_RecInfo[3].MaxSize = m_RecInfo[3].MinSize; m_RecInfo[3].nKeys = 1; memSize = m_RecInfo[3].nKeys * sizeof(IDB_KEY_INFO); m_RecInfo[3].Key = (IDB_KEY_INFO*)WsbAlloc(memSize); WsbAffirm(0 != m_RecInfo[3].Key, E_FAIL); ZeroMemory(m_RecInfo[3].Key, memSize); m_RecInfo[3].Key[0].Type = BAG_HOLE_KEY_TYPE; m_RecInfo[3].Key[0].Size = WSB_BYTE_SIZE_GUID + WSB_BYTE_SIZE_LONGLONG; m_RecInfo[3].Key[0].Flags = IDB_KEY_FLAG_DUP_ALLOWED; // Volume assignment m_RecInfo[4].Type = HSM_VOL_ASSIGN_REC_TYPE; m_RecInfo[4].EntityClassId = CLSID_CVolAssign; m_RecInfo[4].Flags = 0; m_RecInfo[4].MinSize = 2 * WSB_BYTE_SIZE_GUID + 2 * WSB_BYTE_SIZE_LONGLONG; m_RecInfo[4].MaxSize = m_RecInfo[4].MinSize; m_RecInfo[4].nKeys = 1; memSize = m_RecInfo[4].nKeys * sizeof(IDB_KEY_INFO); m_RecInfo[4].Key = (IDB_KEY_INFO*)WsbAlloc(memSize); WsbAffirm(0 != m_RecInfo[4].Key, E_FAIL); ZeroMemory(m_RecInfo[4].Key, memSize); m_RecInfo[4].Key[0].Type = VOL_ASSIGN_KEY_TYPE; m_RecInfo[4].Key[0].Size = WSB_BYTE_SIZE_GUID + WSB_BYTE_SIZE_LONGLONG; m_RecInfo[4].Key[0].Flags = IDB_KEY_FLAG_DUP_ALLOWED; // Create the new DB WsbAssertHr(Create(path)); CreateFlag = TRUE; } else if (hr == STG_E_FILENOTFOUND) { // DB doesn't exist, but we're not suppose to create it WsbLogEvent(WSB_MESSAGE_IDB_OPEN_FAILED, 0, NULL, WsbQuickString(WsbAbbreviatePath(path, 120)), NULL ); hr = WSB_E_IDB_FILE_NOT_FOUND; } } WsbCatch(hr); if (pCreateFlag) { *pCreateFlag = CreateFlag; } WsbTraceOut(OLESTR("CSegDb::Initialize"), OLESTR("hr = %ls, path = <%ls>, CreateFlag = <%ls>"), WsbHrAsString(hr), WsbAbbreviatePath(path, 120), WsbPtrToBoolAsString(pCreateFlag)); return(hr); } HRESULT CSegDb::Load( IN IStream* pStream ) /*++ Implements: IPersistStream::Load(). --*/ { HRESULT hr = S_OK; try { WsbAffirmHr(CWsbDb::Load(pStream)); } WsbCatch(hr); return(hr); } HRESULT CSegDb::Save( IN IStream* pStream, IN BOOL clearDirty ) /*++ Implements: IPersistStream::Save(). --*/ { HRESULT hr = S_OK; try { WsbAffirmHr(CWsbDb::Save(pStream, clearDirty)); } WsbCatch(hr); return(hr); } HRESULT CSegDb::SegAdd ( IN IWsbDbSession* pDbSession, IN GUID BagId, IN LONGLONG SegStartLoc, IN LONGLONG SegLen, IN GUID MediaId, IN LONGLONG mediaStart, IN BOOL indirectRecord ) /*++ Implements: ISegDb::SegAdd --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CSegDb::SegAdd"), OLESTR("GUID = %ls, SegStartLoc = %I64u, SegLen = %I64u"), WsbGuidAsString(BagId), SegStartLoc, SegLen); try { BOOL found = FALSE; CComPtr pSegRec; GUID l_BagId = GUID_NULL; LONGLONG l_SegStartLoc = 0; LONGLONG l_SegLen = 0; USHORT l_SegFlags = SEG_REC_NONE; GUID l_MediaId = GUID_NULL; LONGLONG l_MediaStart = 0; WsbAffirmHr(GetEntity(pDbSession, HSM_SEG_REC_TYPE, IID_ISegRec, (void **)&pSegRec)); WsbAffirmHr(pSegRec->SetSegmentRecord(BagId, SegStartLoc, 0, 0, GUID_NULL, 0 )); // Look for a segment to which to append this one hr = pSegRec->FindLTE(); if (WSB_E_NOTFOUND == hr) { hr = S_OK; } else { WsbAffirmHr(pSegRec->GetSegmentRecord(&l_BagId, &l_SegStartLoc, &l_SegLen, &l_SegFlags, &l_MediaId, &l_MediaStart)); if (SEG_EXPAND_OK(l_BagId, l_SegStartLoc, l_SegLen, BagId, SegStartLoc, SegLen) && IsEqualGUID(MediaId, l_MediaId)) { WsbTrace(OLESTR("CSegDb::SegAdd: Found SegmentRecord: StartLoc = %I64u, Len = %I64u\n"), l_SegStartLoc, l_SegLen); found = TRUE; } } if (found) { // Append this segment to the existing record l_SegLen = (SegStartLoc - l_SegStartLoc) + SegLen; WsbTrace(OLESTR("CSegDb::SegAdd: new SegLen = %I64u\n"), l_SegLen); } else { // Create a new segment record l_SegStartLoc = SegStartLoc; l_SegLen = SegLen; if (indirectRecord) { l_SegFlags = SEG_REC_INDIRECT_RECORD; } else { l_SegFlags = SEG_REC_NONE; } l_MediaId = MediaId; l_MediaStart = mediaStart; WsbAffirmHr(pSegRec->MarkAsNew()); WsbTrace(OLESTR("CSegDb::SegAdd: add new segment\n")); } WsbAffirmHr(pSegRec->SetSegmentRecord(BagId, l_SegStartLoc, l_SegLen, l_SegFlags, l_MediaId, l_MediaStart )); WsbAffirmHr(pSegRec->Write()); } WsbCatch(hr); WsbTraceOut(OLESTR("CSegDb::SegAdd"), OLESTR("hr = <%ls>"),WsbHrAsString(S_OK)); return(hr); } HRESULT CSegDb::SegFind ( IN IWsbDbSession* pDbSession, IN GUID BagId, IN LONGLONG SegStartLoc, IN LONGLONG SegLen, OUT ISegRec** ppISegRec ) /*++ Implements: ISegDb::SegFind --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CSegDb::SegFind"), OLESTR("GUID = <%ls>, SegStartLoc = <%I64u>, SegLen = <%I64u>"), WsbGuidAsString(BagId), SegStartLoc, SegLen); try { CComPtr pSegRec; GUID l_BagId; LONGLONG l_SegStartLoc; LONGLONG l_SegLen; USHORT l_SegFlags; GUID l_MediaId; LONGLONG l_MediaStart; WsbAffirm(ppISegRec != NULL, E_POINTER); WsbAffirmHr(GetEntity(pDbSession, HSM_SEG_REC_TYPE, IID_ISegRec, (void **)&pSegRec)); WsbAffirmHr(pSegRec->SetSegmentRecord(BagId, SegStartLoc, 0, 0, GUID_NULL, 0 )); // Look for a segment that contains this one WsbTrace(OLESTR("Finding SegmentRecord: <%ls>, <%I64u>, <%I64u>\n"), WsbGuidAsString(BagId), SegStartLoc, SegLen); WsbAffirmHr(pSegRec->FindLTE()); // We found a record, see if it's the right one WsbAffirmHr(pSegRec->GetSegmentRecord(&l_BagId, &l_SegStartLoc, &l_SegLen, &l_SegFlags, &l_MediaId, &l_MediaStart)); if (SEG_CONTAINS(l_BagId, l_SegStartLoc, l_SegLen, BagId, SegStartLoc, SegLen)) { *ppISegRec = pSegRec; pSegRec.p->AddRef(); } else { hr = WSB_E_NOTFOUND; } } WsbCatch(hr); WsbTraceOut(OLESTR("CSegDb::SegFind"), OLESTR("hr = <%ls>"),WsbHrAsString(S_OK)); return(hr); } HRESULT CSegDb::SegSubtract ( IN IWsbDbSession* pDbSession, IN GUID BagId, IN LONGLONG SegStartLoc, IN LONGLONG SegLen ) /*++ Implements: ISegDb::SegSubtract --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CSegDb::SegSubtract"), OLESTR("GUID = <%ls>, SegStartLoc = <%I64u>, SegLen = <%I64u>"), WsbGuidAsString(BagId), SegStartLoc, SegLen); try { GUID l_BagId; LONGLONG l_SegStartLoc; LONGLONG l_SegLen; USHORT l_SegFlags; GUID l_MediaId; LONGLONG l_MediaStart; CComPtr pSegRec; // Find the segment record WsbAffirmHr(SegFind(pDbSession, BagId, SegStartLoc, SegLen, &pSegRec)); // Get the current data WsbAffirmHr(pSegRec->GetSegmentRecord(&l_BagId, &l_SegStartLoc, &l_SegLen, &l_SegFlags, &l_MediaId, &l_MediaStart)); // Determine where the hole is if (l_SegStartLoc == SegStartLoc && l_SegLen == SegLen) { // Hole is the entire segment -- delete it WsbAffirmHr(pSegRec->Remove()); } else if (l_SegStartLoc == SegStartLoc) { // Hole is at the beginning of the segment. Just update the // existing segment l_SegStartLoc += SegLen; l_MediaStart += SegLen; WsbAffirmHr(pSegRec->SetSegmentRecord(BagId, l_SegStartLoc, l_SegLen, l_SegFlags, l_MediaId, l_MediaStart )); WsbAffirmHr(pSegRec->Write()); } else if ((l_SegStartLoc + l_SegLen) == (SegStartLoc + SegLen)) { // Hole is at the end of the segment. Just update the // existing segment l_SegLen -= SegLen; WsbAffirmHr(pSegRec->SetSegmentRecord(BagId, l_SegStartLoc, l_SegLen, l_SegFlags, l_MediaId, l_MediaStart )); WsbAffirmHr(pSegRec->Write()); } else { // Hole is in the middle of the segment. Update the // existing record to be the first part. LONGLONG oldLen = l_SegLen; LONGLONG offset = (SegStartLoc + SegLen) - l_SegStartLoc; BOOL bIndirect = FALSE; l_SegLen = SegStartLoc - l_SegStartLoc; WsbAffirmHr(pSegRec->SetSegmentRecord(BagId, l_SegStartLoc, l_SegLen, l_SegFlags, l_MediaId, l_MediaStart )); WsbAffirmHr(pSegRec->Write()); // Create a new record for the second part. l_SegLen -= offset; l_SegStartLoc += offset; l_MediaStart += offset; if (l_SegFlags & SEG_REC_INDIRECT_RECORD) { bIndirect = TRUE; } WsbAffirmHr(SegAdd(pDbSession, BagId, l_SegStartLoc, l_SegLen, l_MediaId, l_MediaStart, bIndirect)); } } WsbCatch(hr); WsbTraceOut(OLESTR("CSegDb::SegSubtract"), OLESTR("hr = <%ls>"),WsbHrAsString(S_OK)); return(hr); } HRESULT CSegDb::VolAssignAdd ( IN IWsbDbSession* pDbSession, IN GUID BagId, IN LONGLONG SegStartLoc, IN LONGLONG SegLen, IN GUID VolId ) /*++ Implements: ISegDb::VolAssignAdd --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CSegDb::VolAssignAdd"), OLESTR("GUID = <%ls>, SegStartLoc = <%I64u>, SegLen = <%I64u>"), WsbGuidAsString(BagId), SegStartLoc, SegLen); try { BOOL found = FALSE; CComPtr pVolAssign; GUID l_BagId = GUID_NULL; LONGLONG l_SegStartLoc = 0; LONGLONG l_SegLen = 0; GUID l_VolId = GUID_NULL; WsbAffirmHr(GetEntity(pDbSession, HSM_VOL_ASSIGN_REC_TYPE, IID_IVolAssign, (void **)&pVolAssign)); WsbAffirmHr(pVolAssign->SetVolAssign(BagId, SegStartLoc, 0, GUID_NULL)); // Look for a segment to which to append this one WsbTrace(OLESTR("Finding VolAssign Record: <%ls>, <%I64u>, <%I64u>\n"), WsbGuidAsString(BagId), SegStartLoc, SegLen); hr = pVolAssign->FindLTE(); if (WSB_E_NOTFOUND == hr) { hr = S_OK; } else { WsbAffirmHr(pVolAssign->GetVolAssign(&l_BagId, &l_SegStartLoc, &l_SegLen, &l_VolId)); if (SEG_APPEND_OK(l_BagId, l_SegStartLoc, l_SegLen, BagId, SegStartLoc, SegLen) && IsEqualGUID(l_VolId, VolId)) { found = TRUE; } } if (found) { // Append this segment to the existing record l_SegLen += SegLen; } else { // Create a new record l_SegStartLoc = SegStartLoc; l_SegLen = SegLen; l_VolId = VolId; WsbAffirmHr(pVolAssign->MarkAsNew()); } WsbAffirmHr(pVolAssign->SetVolAssign(BagId, l_SegStartLoc, l_SegLen, l_VolId)); WsbTrace(OLESTR("Writing VolAssign Record: <%ls>, <%I64u>, <%I64u>\n"), WsbGuidAsString(BagId), l_SegStartLoc, l_SegLen); WsbAffirmHr(pVolAssign->Write()); } WsbCatch(hr); WsbTraceOut(OLESTR("CSegDb::VolAssignAdd"), OLESTR("hr = <%ls>"),WsbHrAsString(S_OK)); return(hr); } HRESULT CSegDb::VolAssignFind ( IN IWsbDbSession* pDbSession, IN GUID BagId, IN LONGLONG SegStartLoc, IN LONGLONG SegLen, OUT IVolAssign** ppIVolAssign ) /*++ Implements: ISegDb::VolAssignFind --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CSegDb::VolAssignFind"), OLESTR("GUID = <%ls>, SegStartLoc = <%I64u>, SegLen = <%I64u>"), WsbGuidAsString(BagId), SegStartLoc, SegLen); try { CComPtr pVolAssign; GUID l_BagId; LONGLONG l_SegStartLoc; LONGLONG l_SegLen; GUID l_VolId; WsbAffirm(ppIVolAssign != NULL, E_POINTER); WsbAffirmHr(GetEntity(pDbSession, HSM_VOL_ASSIGN_REC_TYPE, IID_IVolAssign, (void **)&pVolAssign)); WsbAffirmHr(pVolAssign->SetVolAssign(BagId, SegStartLoc, 0, GUID_NULL)); // Look for a segment that contains this one WsbTrace(OLESTR("Finding VolAssign Record: <%ls>, <%I64u>, <%I64u>\n"), WsbGuidAsString(BagId), SegStartLoc, SegLen); WsbAffirmHr(pVolAssign->FindLTE()); // We found a record, see if it's the right one WsbAffirmHr(pVolAssign->GetVolAssign(&l_BagId, &l_SegStartLoc, &l_SegLen, &l_VolId)); if (SEG_CONTAINS(l_BagId, l_SegStartLoc, l_SegLen, BagId, SegStartLoc, SegLen)) { *ppIVolAssign = pVolAssign; pVolAssign.p->AddRef(); } else { hr = WSB_E_NOTFOUND; } } WsbCatch(hr); WsbTraceOut(OLESTR("CSegDb::VolAssignFind"), OLESTR("hr = <%ls>"),WsbHrAsString(S_OK)); return(hr); } HRESULT CSegDb::VolAssignSubtract ( IN IWsbDbSession* pDbSession, IN GUID BagId, IN LONGLONG SegStartLoc, IN LONGLONG SegLen ) /*++ Implements: ISegDb::VolAssignSubtract --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CSegDb::VolAssignSubtract"), OLESTR("GUID = <%ls>, SegStartLoc = <%I64u>, SegLen = <%I64u>"), WsbGuidAsString(BagId), SegStartLoc, SegLen); try { GUID l_BagId; LONGLONG l_SegStartLoc; LONGLONG l_SegLen; GUID l_VolId; CComPtr pVolAssign; // Find the segment record WsbAffirmHr(VolAssignFind(pDbSession, BagId, SegStartLoc, SegLen, &pVolAssign)); // Get the current data WsbAffirmHr(pVolAssign->GetVolAssign(&l_BagId, &l_SegStartLoc, &l_SegLen, &l_VolId)); // Determine where the hole is if (l_SegStartLoc == SegStartLoc && l_SegLen == SegLen) { // Hole is the entire segment -- delete it WsbAffirmHr(pVolAssign->Remove()); } else if (l_SegStartLoc == SegStartLoc) { // Hole is at the beginning of the segment. Just update the // existing segment l_SegStartLoc += SegLen; WsbAffirmHr(pVolAssign->SetVolAssign(BagId, l_SegStartLoc, l_SegLen, l_VolId)); WsbAffirmHr(pVolAssign->Write()); } else if ((l_SegStartLoc + l_SegLen) == (SegStartLoc + SegLen)) { // Hole is at the end of the segment. Just update the // existing segment l_SegLen -= SegLen; WsbAffirmHr(pVolAssign->SetVolAssign(BagId, l_SegStartLoc, l_SegLen, l_VolId)); WsbAffirmHr(pVolAssign->Write()); } else { // Hole is in the middle of the segment. Update the // existing record to be the first part. LONGLONG oldLen = l_SegLen; LONGLONG offset = (SegStartLoc + SegLen) - l_SegStartLoc; l_SegLen = SegStartLoc - l_SegStartLoc; WsbAffirmHr(pVolAssign->SetVolAssign(BagId, l_SegStartLoc, l_SegLen, l_VolId)); WsbAffirmHr(pVolAssign->Write()); // Create a new record for the second part. l_SegLen -= offset; l_SegStartLoc += offset; WsbAffirmHr(VolAssignAdd(pDbSession, BagId, l_SegStartLoc, l_SegLen, l_VolId)); } } WsbCatch(hr); WsbTraceOut(OLESTR("CSegDb::VolAssignSubtract"), OLESTR("hr = <%ls>"),WsbHrAsString(S_OK)); return(hr); }