📄 simplepointcursorhelper.cpp
字号:
// SimplePointCursorHelper.cpp : Implementation of CSimplePointCursorHelper
#include "stdafx.h"
#include "SimplePointVC.h"
#include "SimplePointCursorHelper.h"
/////////////////////////////////////////////////////////////////////////////
// CSimplePointCursorHelper
STDMETHODIMP CSimplePointCursorHelper::InterfaceSupportsErrorInfo(REFIID riid)
{
static const IID* arr[] =
{
&IID_ISimplePointCursorHelper
};
for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
if (InlineIsEqualGUID(*arr[i],riid))
return S_OK;
}
return S_FALSE;
}
HRESULT CSimplePointCursorHelper::FinalConstruct()
{
HRESULT hr;
m_lCurLineNum = 0;
m_lOID = -1;
hr = m_ipWorkPoint.CreateInstance(CLSID_Point);
if (FAILED(hr)) return hr;
ISpatialReferencePtr ipSR;
hr = ipSR.CreateInstance(CLSID_UnknownCoordinateSystem);
if (FAILED(hr)) return hr;
hr = m_ipWorkPoint->putref_SpatialReference(ipSR);
if (FAILED(hr)) return hr;
return S_OK;
}
void CSimplePointCursorHelper::FinalRelease()
{
if (m_fDataFile)
m_fDataFile.close();
SafeArrayUnaccessData(m_vFieldMap.parray);
}
// IPlugInCursorHelper
STDMETHODIMP CSimplePointCursorHelper::NextRecord()
{
HRESULT hr;
// We will take the line number in the file to be the OID of the feature,
// keep track of this in the m_lCurLineNum variable.
//
// E_FAIL is returned if there are no more records
// If we are searching by OID, skip to the correct line
if (m_lOID != -1)
{
for ( ; m_lCurLineNum < m_lOID && (!m_fDataFile.eof()); m_lCurLineNum++ )
{
m_fDataFile.getline(m_sCurrentRow, c_iMaxRowLen);
}
if (m_lCurLineNum != m_lOID) // i.e. EOF before OID found
{
m_sCurrentRow[0] = '\0';
return E_FAIL;
}
else
return S_OK;
}
// Read current row
if (!m_fDataFile.eof())
{
m_fDataFile.getline(m_sCurrentRow, c_iMaxRowLen);
m_lCurLineNum++;
}
else
{
m_sCurrentRow[0] = '\0';
return E_FAIL;
}
// If we are finding by envelope, check the current record
// if its not in the envelope, make a recursive call to move on to the next record
if (m_ipQueryEnv != NULL)
{
hr = QueryShape(m_ipWorkPoint);
if (FAILED(hr)) return hr;
IRelationalOperatorPtr ipRelOp = m_ipWorkPoint;
if (ipRelOp == NULL) return E_FAIL;
VARIANT_BOOL bWithin;
hr = ipRelOp->Within(m_ipQueryEnv, &bWithin);
if (FAILED(hr)) return hr;
if (!bWithin) // current feature is not within the query envelope
{
hr = NextRecord();
if (FAILED(hr)) return hr;
}
}
return S_OK;
}
STDMETHODIMP CSimplePointCursorHelper::IsFinished(VARIANT_BOOL *finished)
{
if (! finished) return E_POINTER;
*finished = (m_fDataFile.eof()) ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
STDMETHODIMP CSimplePointCursorHelper::QueryValues(IRowBuffer *Row, long *OID)
{
HRESULT hr;
if (! OID || ! Row) return E_POINTER;
// At end of file, return -1
if (m_sCurrentRow == '\0')
{
*OID = -1;
return S_OK;
}
// First, parse the attribute out of the current row.
// We know this data source has just one attribute, which is one char wide.
char sAtt[2];
strncpy(sAtt, m_sCurrentRow + 12, 1);
sAtt[1] = '\0'; // add null terminator
CComVariant vAtt = sAtt;
if (vAtt.vt == VT_ERROR) return E_FAIL;
// Check field map has same number of elements as there are fields
IFieldsPtr ipFields;
hr = Row->get_Fields(&ipFields);
if (FAILED(hr)) return hr;
long lNumFields;
hr = ipFields->get_FieldCount(&lNumFields);
if (FAILED(hr)) return hr;
long lUBound, lLBound;
hr = SafeArrayGetLBound(m_vFieldMap.parray, 1, &lLBound);
if (FAILED(hr)) return hr;
hr = SafeArrayGetUBound(m_vFieldMap.parray, 1, &lUBound);
if (FAILED(hr)) return hr;
if ( (lUBound - lLBound) + 1 != lNumFields)
{
AtlReportError(CLSID_SimplePointCursorHelper, L"SimplePoint Data Source: Unexepected situation: Number of elements in Fieldmap does not match number of fields", IID_IPlugInCursorHelper, E_FAIL);
return E_FAIL;
}
// For each field, copy its value into the row object.
// (don't copy shape, object ID or where the field map indicates no values required)
// Note, although we know there is only one attribute in the data source,
// this loop has been coded generically in case support needs to be added for more attributes
long i;
esriFieldType eFieldType;
for (i=0; i < lNumFields; i++)
{
IFieldPtr ipField;
hr = ipFields->get_Field(i, &ipField);
if (FAILED(hr)) return hr;
hr = ipField->get_Type(&eFieldType);
if (FAILED(hr)) return hr;
if (eFieldType != esriFieldTypeGeometry &&
eFieldType != esriFieldTypeOID &&
m_lFieldMap[i] != -1)
{
hr = Row->put_Value(i, vAtt);
if (FAILED(hr)) return hr;
}
}
// Return value is taken as the OID.
// Use the line number (stream will currently be pointing at next line)
*OID = m_lCurLineNum;
return S_OK;
}
STDMETHODIMP CSimplePointCursorHelper::QueryShape(IGeometry *pGeometry)
{
HRESULT hr;
if (! pGeometry) return E_POINTER;
// If there is no current row, set the geometry to be empty
if (m_sCurrentRow == '\0')
{
hr = pGeometry->SetEmpty();
if (FAILED(hr)) return hr;
return S_OK;
}
double x,y;
char* end;
char buf[6];
// Parse the X and Y values out of the current row and into the geometry
x = strtod(strncpy(buf, m_sCurrentRow, 6),&end);
y = strtod(strncpy(buf, m_sCurrentRow + 6, 6),&end);
IPointPtr ipPoint = pGeometry;
if (ipPoint == NULL) return E_FAIL;
hr = ipPoint->PutCoords(x,y);
if (FAILED(hr)) return hr;
// Note - in our case there is no need to handle the strictSearch test for a cursor
// created with FetchByEnvelope. We have already tested that the feature is within
// the envelope on the NextRecord call, so there is no possibility of the test
// failing here.
return S_OK;
}
// IPlugInFastQueryValues
STDMETHODIMP CSimplePointCursorHelper::FastQueryValues(long *Values)
{
HRESULT hr;
USES_CONVERSION;
if (! Values) return E_POINTER;
// If at end of file, return S_FALSE
if (m_sCurrentRow == '\0')
return S_FALSE;
// define the field value structure and cast the passed array
struct FieldValue
{
VARIANT m_value;
ULONG m_length;
DWORD m_status;
};
FieldValue* valueArray;
valueArray = (FieldValue*)Values;
// First, parse the attribute out of the current row.
// We know this data source has just one attribute, which is one char wide.
char sAtt[2];
strncpy(sAtt, m_sCurrentRow + 12, 1);
sAtt[1] = '\0'; // add null terminator
// For this sample, there is just one attribute field to handle,
// but for demonstration, more generic code follows:
if (m_ipFields == NULL) return E_FAIL;
IFieldPtr ipField;
esriFieldType eFieldType;
long lFieldCount;
hr = m_ipFields->get_FieldCount(&lFieldCount);
if (FAILED(hr)) return hr;
for (long lFieldIndex = 0; lFieldIndex < lFieldCount; lFieldIndex++)
{
// if the supplied value in the field map is -1 then this means
// that we don't have to populate it with data.
if (m_lFieldMap[lFieldIndex] == -1)
continue;
// If the field map indicator is not -1,
// it is the location in the FieldValue array that we should place our data.
// For instance field map array is 0,1,2,3,4 with values of 1,0,-1,4,3
// the returned field order (that of the valueArray array) would be:
// Field1,Field0,Field2=NULL,Field4,Field3
long lFieldLoc = m_lFieldMap[lFieldIndex];
hr = m_ipFields->get_Field(lFieldIndex, &ipField);
if (FAILED(hr)) return hr;
hr = ipField->get_Type(&eFieldType);
if (FAILED(hr)) return hr;
switch (eFieldType)
{
case esriFieldTypeSmallInteger:
valueArray[lFieldLoc].m_value.vt = VT_I2;
// following code is commented out - it just indicates the kind
// of code that would go in if there were lots of different attributes in
// the data source
// field value = GetFieldValue(lFieldIndex);
// valueArray[lngFieldLoc].m_value.iVal = field value;
break;
case esriFieldTypeInteger:
valueArray[lFieldLoc].m_value.vt = VT_I4;
// field value = GetFieldValue(lFieldIndex);
// valueArray[lngFieldLoc].m_value.lVal = field value;
break;
case esriFieldTypeSingle:
valueArray[lFieldLoc].m_value.vt = VT_R4;
// field value = GetFieldValue(lFieldIndex);
// valueArray[lngFieldLoc].m_value.fltVal = field value;
break;
case esriFieldTypeDouble:
valueArray[lFieldLoc].m_value.vt = VT_R8;
// field value = GetFieldValue(lFieldIndex);
// valueArray[lngFieldLoc].m_value.dblVal = field value;
break;
case esriFieldTypeDate:
valueArray[lFieldLoc].m_value.vt = VT_DATE;
// field value = GetFieldValue(lFieldIndex);
//valueArray[lngFieldLoc].m_value.date = some value;
break;
case esriFieldTypeString:
// if the string already exists then just reallocate it otherwise create
if (valueArray[lFieldLoc].m_value.bstrVal != NULL)
{
INT success = ::SysReAllocString(&(valueArray[lFieldLoc].m_value.bstrVal), A2COLE(sAtt) );
if (!success) return E_FAIL;
}
else
{
valueArray[lFieldLoc].m_value.bstrVal = ::SysAllocString(A2COLE(sAtt));
if (valueArray[lFieldLoc].m_value.bstrVal == NULL) return E_FAIL;
}
valueArray[lFieldLoc].m_value.vt = VT_BSTR;
break;
case esriFieldTypeGeometry:
// we should never copy the shape field, as QueryShape deals with that
valueArray[lFieldLoc].m_value.vt = VT_NULL;
valueArray[lFieldLoc].m_value.punkVal = 0;
break;
case esriFieldTypeOID:
valueArray[lFieldLoc].m_value.vt = VT_I4;
valueArray[lFieldLoc].m_value.lVal = m_lCurLineNum;
case esriFieldTypeBlob:
break;
}
}
return S_OK;
}
// ISimplePointCursorHelper methods
STDMETHODIMP CSimplePointCursorHelper::put_FilePath(BSTR newVal)
{
HRESULT hr;
USES_CONVERSION;
m_sFilePath = newVal;
// Open the text file for reading
m_fDataFile.open(OLE2CA(m_sFilePath));
if (!m_fDataFile)
{
CComBSTR sError(L"Could not open data file for reading: ");
sError.Append(m_sFilePath);
AtlReportError(CLSID_SimplePointCursorHelper, sError, IID_IPlugInCursorHelper, E_FAIL);
return E_FAIL;
}
// First record should be fetched on creation
hr = NextRecord();
if (FAILED(hr)) return hr;
return S_OK;
}
STDMETHODIMP CSimplePointCursorHelper::put_FieldMap(VARIANT fieldMap)
{
m_vFieldMap = fieldMap;
HRESULT hr = SafeArrayAccessData(m_vFieldMap.parray, (void HUGEP**)&m_lFieldMap);
if (FAILED(hr)) return hr;
return S_OK;
}
STDMETHODIMP CSimplePointCursorHelper::put_OID(long lOID)
{
m_lOID = lOID;
return S_OK;
}
STDMETHODIMP CSimplePointCursorHelper::putref_QueryEnvelope(IEnvelope* pEnvelope)
{
m_ipQueryEnv = pEnvelope;
return S_OK;
}
STDMETHODIMP CSimplePointCursorHelper::putref_Fields(IFields* pFields)
{
// This property exists so we can pass in the fields, to prevent FastQueryValues
// having to fetch them each time.
// We know that the fields will stay constant over the lifetime of the cursor.
m_ipFields = pFields;
return S_OK;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -