Timestamper Class ExtensionTimestampClassExtension.cpp
// Copyright 2006 ESRI
//
// All rights reserved under the copyright laws of the United States
// and applicable international laws, treaties, and conventions.
//
// You may freely redistribute and use this sample code, with or
// without modification, provided you include the original copyright
// notice and use restrictions.
//
// See the use restrictions.
// TimestampClassExtension.cpp : Implementation of CTimestampClassExtension
#include "stdafx.h"
#include "Timestamper.h"
#include "TimestamperUtils.h"
#include "TimestampClassExtension.h"
#include <windows.h>
#include <oleauto.h>
/////////////////////////////////////////////////////////////////////////////
// CTimestampClassExtension
//////////////////////////////////////////////////////////
// ISupportErrorInfo
STDMETHODIMP CTimestampClassExtension::InterfaceSupportsErrorInfo(REFIID riid)
{
static const IID* arr[] =
{
&IID_ITimestampClassExtension
};
for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
if (InlineIsEqualGUID(*arr[i],riid))
return S_OK;
}
return S_FALSE;
}
//////////////////////////////////////////////////////////
// IClassExtension
STDMETHODIMP CTimestampClassExtension::Init(IClassHelper *pClassHelper, IPropertySet *pExtensionProperties)
{
HRESULT hr;
m_ipClassHelper = pClassHelper;
// initialize user name
CComBSTR sUserName;
hr = GetUsrName(&sUserName);
if (FAILED(hr)) return hr;
m_vUsrName = sUserName;
// If object class has been just created then, if the default fields are present,
// use them
if (pExtensionProperties == NULL)
{
hr = TryDefaultProperties();
if (FAILED(hr)) return hr;
}
else
{
// Load extension properties into the class variables
// If the property is not present the class variables
// are set to an empty string
CComVariant var;
hr = pExtensionProperties->GetProperty(g_sCreFieldPropName, &var);
if (FAILED(hr)) return hr;
if (var.vt == VT_BSTR)
m_sCreFieldName = var.bstrVal;
else
m_sCreFieldName = L"";
var.Clear();
hr = pExtensionProperties->GetProperty(g_sModFieldPropName, &var);
if (FAILED(hr)) return hr;
if (var.vt == VT_BSTR)
m_sModFieldName = var.bstrVal;
else
m_sModFieldName = L"";
var.Clear();
hr = pExtensionProperties->GetProperty(g_sUsrFieldPropName, &var);
if (FAILED(hr)) return hr;
if (var.vt == VT_BSTR)
m_sUsrFieldName = var.bstrVal;
else
m_sUsrFieldName = L"";
}
// Check that the required fields are there
hr = GetFieldPositions();
if (FAILED(hr)) return hr;
return S_OK;
}
STDMETHODIMP CTimestampClassExtension::Shutdown()
{
return S_OK;
}
//////////////////////////////////////////////////////////
// IObjectClassEvents
STDMETHODIMP CTimestampClassExtension::OnCreate(IObject *obj)
{
HRESULT hr;
// Set the creation date and user name
// NOTE: there is no need to call IRow::Store
//
// For Enterprise geodatabases, it is preferable to use the database
// date and username, but for simplicity this sample will just use the
// client OS date and username.
if (m_sCreFieldName.Length() > 0)
{
DATE dtimestamp;
hr = GetTimestamp(&dtimestamp);
if (FAILED(hr)) return hr;
CComVariant vTimestamp;
vTimestamp.date = dtimestamp;
vTimestamp.vt = VT_DATE;
hr = obj->put_Value(m_lCreField, vTimestamp);
if (FAILED(hr)) return hr;
}
if (m_sUsrFieldName.Length() > 0)
{
hr = obj->put_Value(m_lUsrField, m_vUsrName);
if (FAILED(hr)) return hr;
}
return S_OK;
}
STDMETHODIMP CTimestampClassExtension::OnChange(IObject *obj)
{
HRESULT hr;
// Set the modification date and user name
// NOTE: there is no need to call IRow::Store
//
// For Enterprise geodatabases, it is preferable to use the database
// date and username, but for simplicity this sample will just use the
// client OS date and username.
if (m_sModFieldName.Length() > 0)
{
DATE dtimestamp;
hr = GetTimestamp(&dtimestamp);
if (FAILED(hr)) return hr;
CComVariant vTimestamp;
vTimestamp.date = dtimestamp;
vTimestamp.vt = VT_DATE;
hr = obj->put_Value(m_lModField, vTimestamp);
if (FAILED(hr)) return hr;
}
if (m_sUsrFieldName.Length() > 0)
{
hr = obj->put_Value(m_lUsrField, m_vUsrName);
if (FAILED(hr)) return hr;
}
return S_OK;
}
STDMETHODIMP CTimestampClassExtension::OnDelete(IObject *obj)
{
return S_OK;
}
HRESULT CTimestampClassExtension::TryDefaultProperties()
{
// If any of the default fields are present then
// put them to an 'in-use' state and update the
// extension properties accordingly.
// No need for a schema lock as this is guaranteed to run straight after the
// object class is created (if no extension properties are provided).
HRESULT hr;
IClassPtr ipClass;
hr = m_ipClassHelper->get_Class(&ipClass);
if (FAILED(hr)) return hr;
long lFieldIndex;
hr = ipClass->FindField(g_sCreFieldDefaultName, &lFieldIndex);
if (FAILED(hr)) return hr;
if (lFieldIndex != -1)
m_sCreFieldName = g_sCreFieldDefaultName.Copy();
hr = ipClass->FindField(g_sModFieldDefaultName, &lFieldIndex);
if (FAILED(hr)) return hr;
if (lFieldIndex != -1)
m_sModFieldName = g_sModFieldDefaultName.Copy();
hr = ipClass->FindField(g_sUsrFieldDefaultName, &lFieldIndex);
if (FAILED(hr)) return hr;
if (lFieldIndex != -1)
m_sUsrFieldName = g_sUsrFieldDefaultName.Copy();
if (m_sCreFieldName.Length() > 0
|| m_sModFieldName.Length() > 0
|| m_sUsrFieldName.Length() > 0)
{
hr = UpdateProperties();
if (FAILED(hr)) return hr;
}
return S_OK;
}
HRESULT CTimestampClassExtension::GetFieldPositions()
{
HRESULT hr;
IClassPtr ipClass;
hr = m_ipClassHelper->get_Class(&ipClass);
if (FAILED(hr)) return hr;
if (m_sCreFieldName.Length() > 0)
{
hr = ipClass->FindField(m_sCreFieldName, &m_lCreField);
if (FAILED(hr)) return hr;
if (m_lCreField == -1)
{
CComBSTR sError(L"Creation timestamp field not found: ");
sError.Append(m_sCreFieldName);
AtlReportError(CLSID_TimestampClassExtension, sError, IID_ITimestampClassExtension, E_FAIL);
return E_FAIL;
}
}
else
m_lCreField = -1;
if (m_sModFieldName.Length() > 0)
{
hr = ipClass->FindField(m_sModFieldName, &m_lModField);
if (FAILED(hr)) return hr;
if (m_lModField == -1)
{
CComBSTR sError(L"Modification timestamp field not found: ");
sError.Append(m_sModFieldName);
AtlReportError(CLSID_TimestampClassExtension, sError, IID_ITimestampClassExtension, E_FAIL);
return E_FAIL;
}
}
else
m_lModField = -1;
if (m_sUsrFieldName.Length() > 0)
{
hr = ipClass->FindField(m_sUsrFieldName, &m_lUsrField);
if (FAILED(hr)) return hr;
if (m_lUsrField == -1)
{
CComBSTR sError(L"User timestamp field not found: ");
sError.Append(m_sUsrFieldName);
AtlReportError(CLSID_TimestampClassExtension, sError, IID_ITimestampClassExtension, E_FAIL);
return E_FAIL;
}
}
else
m_lUsrField = -1;
return S_OK;
}
HRESULT CTimestampClassExtension::GetTimestamp(DATE *dtimestamp)
{
SYSTEMTIME stimestamp;
::GetLocalTime(&stimestamp);
int success;
success = ::SystemTimeToVariantTime(&stimestamp, dtimestamp);
if (!success) return E_FAIL;
return S_OK;
}
HRESULT CTimestampClassExtension::GetUsrName(BSTR *sUserName)
{
USES_CONVERSION;
TCHAR buf[101];
LPTSTR tstr;
DWORD cchBuff = 100;
tstr = buf;
::GetUserName(tstr, &cchBuff);
*sUserName = T2BSTR(tstr);
return S_OK;
}
//////////////////////////////////////////////////////////
// ITimeStampClassExtension
STDMETHODIMP CTimestampClassExtension::get_CreationFieldName(BSTR *pVal)
{
if (!pVal)
return E_POINTER;
return m_sCreFieldName.CopyTo(pVal);
}
STDMETHODIMP CTimestampClassExtension::put_CreationFieldName(BSTR newVal)
{
m_sCreFieldName = newVal;
return S_OK;
}
STDMETHODIMP CTimestampClassExtension::get_ModificationFieldName(BSTR *pVal)
{
if (!pVal)
return E_POINTER;
return m_sModFieldName.CopyTo(pVal);
}
STDMETHODIMP CTimestampClassExtension::put_ModificationFieldName(BSTR newVal)
{
m_sModFieldName = newVal;
return S_OK;
}
STDMETHODIMP CTimestampClassExtension::get_UserFieldName(BSTR *pVal)
{
if (!pVal)
return E_POINTER;
return m_sUsrFieldName.CopyTo(pVal);
}
STDMETHODIMP CTimestampClassExtension::put_UserFieldName(BSTR newVal)
{
m_sUsrFieldName = newVal;
return S_OK;
}
STDMETHODIMP CTimestampClassExtension::UpdateProperties()
{
// Note that user ought to have an exclusive schema lock
// before calling this method
HRESULT hr;
// Check if the specified fields exist
hr = GetFieldPositions();
if (FAILED(hr)) return hr;
// Make the property set
IPropertySetPtr ipPropSet(CLSID_PropertySet);
CComVariant vFieldName(m_sCreFieldName);
hr = ipPropSet->SetProperty(g_sCreFieldPropName, vFieldName);
if (FAILED(hr)) return hr;
vFieldName.Clear();
vFieldName = m_sModFieldName;
hr = ipPropSet->SetProperty(g_sModFieldPropName, vFieldName);
if (FAILED(hr)) return hr;
vFieldName.Clear();
vFieldName = m_sUsrFieldName;
hr = ipPropSet->SetProperty(g_sUsrFieldPropName, vFieldName);
if (FAILED(hr)) return hr;
// Update the schema
IClassPtr ipClass;
hr = m_ipClassHelper->get_Class(&ipClass);
if (FAILED(hr)) return hr;
IClassSchemaEdit2Ptr ipClassSchemaEdit(ipClass);
hr = ipClassSchemaEdit->AlterClassExtensionProperties(ipPropSet);
if (FAILED(hr)) return hr;
return S_OK;
}