PROPERTY.CPP
// ----------------------------------------------------------------------------- 
// Property.cpp: Implements methods for classes that works with IMAPIProp. 
// 
// Copyright (C) Microsoft Corp. 1986-1996.  All Rights Reserved. 
// ----------------------------------------------------------------------------- 
 
#include "edkafx.h" 
#include "property.h" 
#include "propdef.h"    // Include only here!  Contains static declarations. 
#include "ErrCpp.h" 
#include "property.chk" 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char BASED_CODE THIS_FILE[] = __FILE__; 
#endif 
 
// ----------------------------------------------------------------------------- 
// CONSTRUCTOR 
// ----------------------------------------------------------------------------- 
 
CProperty::CProperty() :  
    m_idlPropIDs( PropIDs, ARRAY_CNT( PropIDs)), 
    m_idlPropTypes( PropTypes, ARRAY_CNT( PropTypes)) 
{ 
    Init(); 
    m_bUnsigned = TRUE;     // Default treatment of int and long to unsigned. 
    m_sDblFmt = "%10.2g";   // Default format for printing doubles. 
} 
 
// ----------------------------------------------------------------------------- 
// Set the default sign format for int and long.  Used by szGetPrValue() when 
// caller does not provide a parameter. 
// ----------------------------------------------------------------------------- 
 
BOOL CProperty::bSetUnsigned( BOOL bUnsigned) 
{ 
    BOOL bOldVal = m_bUnsigned; 
    m_bUnsigned = bUnsigned; 
    return( bOldVal); 
} 
 
// ----------------------------------------------------------------------------- 
// Set the default format used for doubles and floats.  This would be in  
// printf() format. 
// ----------------------------------------------------------------------------- 
 
CString CProperty::SetDblFmt( LPSTR pszDblFmt) 
{ 
    CString sRetVal = m_sDblFmt; 
    m_sDblFmt = pszDblFmt; 
    return( m_sDblFmt); 
} 
 
// ----------------------------------------------------------------------------- 
// Frees the property list array. 
// ----------------------------------------------------------------------------- 
 
void CProperty::Free(  
    ULONG cValues,          // Count of new properties. 
    LPSPropValue pProps)    // Ptr to list of new properties. 
{    
    MAPIFREEBUFFER( m_pFirstProp);  // Free old list of properties. 
    Init( cValues, pProps);         // Initialize list with new properties. 
} 
 
// ----------------------------------------------------------------------------- 
// Gets the properties using an IMAPIProp interface. 
// ----------------------------------------------------------------------------- 
 
HRESULT CProperty::GetProps(  
    IMAPIProp*      imapiProp,  // MAPI interface to access properties with. 
    LPSPropTagArray pta,        // Ptr to property tag array. 
    ULONG           ulFlags)    // Optional flags, default to zero. 
{ 
    DEBUGPUBLIC( "CProperty::GetProps()\n"); 
    CHRESULT hr = CHK_CProperty_GetProps( imapiProp, pta, ulFlags); 
    if( FAILED( hr)) 
        RETURN( hr); 
 
    Free(); 
     
    // Get the properties using MAPI. 
    hr = imapiProp->GetProps( pta, ulFlags, &m_cValues, &m_pFirstProp); 
    if( FAILED( hr)) 
        RETURN( hr); 
     
    // Setup to transverse through list of properties. 
    m_pLastProp = m_pFirstProp + (m_cValues - 1);  
    First(); 
     
    return( NOERROR); 
} 
 
// ----------------------------------------------------------------------------- 
// Set current property to the next property. 
// ----------------------------------------------------------------------------- 
 
void CProperty::Next() 
{ 
    if( m_pCurProp == NULL) 
        m_pCurProp = m_pFirstProp; 
    else if( m_pCurProp == m_pLastProp) 
        m_pCurProp = NULL; 
    else 
        m_pCurProp ++; 
} 
 
// ----------------------------------------------------------------------------- 
// Get the current property ID as a ULONG. 
// ----------------------------------------------------------------------------- 
 
ULONG CProperty::ulGetPrID() 
{ 
    ASSERTERROR( m_pCurProp != NULL, "m_pCurProp is NULL!"); 
    if( m_pCurProp == NULL) 
        return( 0); 
     
    return( PROP_ID(m_pCurProp->ulPropTag)); 
} 
 
// ----------------------------------------------------------------------------- 
// Get the current property TYPE as a ULONG. 
// ----------------------------------------------------------------------------- 
 
ULONG CProperty::ulGetPrType() 
{ 
    ASSERTERROR( m_pCurProp != NULL, "m_pCurProp is NULL!"); 
    if( m_pCurProp == NULL) 
        return( 0); 
     
    return(PROP_TYPE( m_pCurProp->ulPropTag)); 
} 
 
// ----------------------------------------------------------------------------- 
// Get the current property VALUE as a union _PV as defined in MAPI. 
// ----------------------------------------------------------------------------- 
 
UPropVal CProperty::upvGetPrValue() 
{ 
    UPropVal upv; 
    upv.ul = 0;     // On error return this property value. 
 
    ASSERTERROR( m_pCurProp != NULL, "m_pCurProp is NULL!"); 
    if( m_pCurProp == NULL) 
        return( upv); 
     
    return( m_pCurProp->Value); 
} 
 
// ----------------------------------------------------------------------------- 
// Get the current property VALUE as a formated CString.  Pass TRUE to treat  
// ints or longs as unsigned, FALSE otherwise.  If no params passed in we 
// default to a value that may be set through bSetUnsigned(). 
// 
// NOTE: A number of the possible property types don't have a conversion at 
//       this time. 
// ----------------------------------------------------------------------------- 
 
CString CProperty::szGetPrValue( BOOL bUnsigned) 
{ 
    int         ii; 
    unsigned    ui; 
    double      dbl; 
    char        chBuf[4]; 
    LPBYTE      pByte; 
    CString     sRetVal; 
    FILETIME    LocalFT = {0}; 
    SYSTEMTIME  st = {0}; 
    UPropVal    upv = upvGetPrValue(); 
 
    if( bUnsigned == -1) 
        bUnsigned = m_bUnsigned; 
 
    switch( ulGetPrType()) 
    { 
        case PT_I2: 
            if( bUnsigned) 
            { 
                ui = (unsigned) upv.i; // Convert to short unsigned to regular unsigned. 
                sRetVal.Format( "%u", ui); 
            } 
            else 
            { 
                ii = upv.i;             // Convert to short int to regular int. 
                sRetVal.Format( "%d", ii); 
            } 
            break; 
         
        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
        case PT_LONG: 
            if( bUnsigned) 
                sRetVal.Format( "%lu", upv.ul); 
            else 
                sRetVal.Format( "%ld", upv.l); 
            break; 
 
        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
        case PT_R4: 
            dbl = upv.flt; 
            sRetVal.Format( m_sDblFmt, dbl); 
            break; 
 
        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
        case PT_DOUBLE: 
            sRetVal.Format( m_sDblFmt, upv.dbl); 
            break; 
 
        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
        case PT_BOOLEAN: 
            if( upv.b) 
                sRetVal = "TRUE"; 
            else 
                sRetVal = "FALSE"; 
            break; 
 
        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
        case PT_SYSTIME: 
            if( FileTimeToLocalFileTime( &upv.ft, &LocalFT)) 
            { 
                if( FileTimeToSystemTime( &LocalFT, &st)) 
                { 
                    sRetVal.Format( "%.2d:%.2d:%.2d %.2d/%.2d/%.2d", 
                        st.wHour, st.wMinute, st.wSecond, 
                        st.wMonth, st.wDay, st.wYear); 
                    break; 
                } 
            } 
 
            sRetVal.Format( "Error %lu converting file time to local or system time.", GetLastError()); 
            break; 
 
        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
        case PT_STRING8: 
            sRetVal.Format( "%s", upv.lpszA); 
            break; 
 
        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
        case PT_BINARY: 
            sRetVal.Format( "CB:%d 0x", upv.bin.cb);  // Format the count. 
             
            // Make sure we don't format more than 100 bytes. 
            if( upv.bin.cb > 100) 
                ii = 100; 
            else 
                ii = upv.bin.cb; 
             
            // Loop to format into hex digits. 
            pByte = upv.bin.lpb; 
            while( ii) 
            {   // Format a single byte into a hex value and add to sRetVal. 
                ui = *pByte; 
                sprintf( chBuf, "%.2x", ui); 
                sRetVal += chBuf; 
                 
                // Next byte. 
                pByte ++; 
                ii --; 
            } 
            break; 
 
        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
        case PT_ERROR: 
        { 
            CHRESULT hr = upv.err; 
            sRetVal.Format( "Error %s [%.8lx]", hr.Msg(), hr); 
            break; 
        } 
 
        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
        default:  
            sRetVal = szGetPrType(); 
            sRetVal += " has no conversion at this time."; 
            break; 
    } 
    return( sRetVal); 
} 
 
// $--CProperty::Init()--------------------------------------------------------- 
// Initializes property counters and pointers. 
// ----------------------------------------------------------------------------- 
 
void CProperty::Init( ULONG cValues, LPSPropValue pProps) 
{ 
    m_cValues = cValues; 
    m_pFirstProp = pProps; 
    m_pLastProp = m_pFirstProp + (m_cValues - 1); 
    m_pCurProp = NULL; 
} 
 
// ----------------------------------------------------------------------------- 
// CONSTRUCTOR 
// ----------------------------------------------------------------------------- 
 
CPropertyRows::CPropertyRows() 
{ 
    m_pRowSet = NULL;                   // No property row set. 
    m_ulCurRowIndex = PR_ROW_SET_END;   // No current row. 
} 
 
// ----------------------------------------------------------------------------- 
// Frees the rows of properties then initializes the base class values since we 
// don't want it trying to free a single row of properties that no longer exists. 
// ----------------------------------------------------------------------------- 
 
void CPropertyRows::Free() 
{ 
    if( !m_pRowSet) 
        return; 
 
    FreeProws( m_pRowSet); 
    m_pRowSet = NULL; 
    m_ulCurRowIndex = PR_ROW_SET_END;   // No current row. 
 
    Init( 0, NULL); 
} 
 
// ----------------------------------------------------------------------------- 
// Gets a row of properties from a MAPI table. 
// ----------------------------------------------------------------------------- 
 
HRESULT CPropertyRows::HrGetTblRows( // RETURNS: return code 
    LPMAPITABLE lpTable,        // Ptr to a mapi table. 
    ULONG       cMaxNRows)      // Max.# of rows to return 
{ 
    DEBUGPUBLIC( "CPropertyRows::HrGetTblRows()\n"); 
    CHRESULT hr = CHK_CPropertyRows_HrGetTblRows( lpTable, cMaxNRows); 
    if( FAILED( hr)) 
        RETURN( hr); 
 
    // Free last row set before trying to get another. 
    Free();      
 
    // Get the next list of messages in the folder 
    hr = lpTable->QueryRows( cMaxNRows, 0L, &m_pRowSet); 
    if( FAILED( hr)) 
        RETURN( hr); 
 
    // Make sure we received a valid pointer. 
    if( !m_pRowSet) 
        RETURN( E_FAIL); 
     
    // Have we reached the end of the row list? 
    if( m_pRowSet->cRows == 0) 
        RETURN( EDK_E_END_OF_FILE);    // YES, since no rows found return EDK_E_END_OF_FILE. 
 
    FirstRow(); 
 
    return( NOERROR); 
} 
 
// $--CPropertyRows::SetCurRow()------------------------------------------------ 
// Set currency to either the first or the next row of properties. 
// ----------------------------------------------------------------------------- 
 
void CPropertyRows::SetCurRow( BOOL bFirst) // TRUE sets to first row, FALSE sets to next row. 
{ 
    if( !m_pRowSet) 
        return; // There is no row set. 
 
    // Were we requested to set to the first row, or were we at the end of the row list? 
    if( bFirst || m_ulCurRowIndex == PR_ROW_SET_END) 
        m_ulCurRowIndex = 0;    // YES, so set to first row. 
    else 
        m_ulCurRowIndex ++;     // NO, so set to the next row. 
        
    if( bAtEndOfRows()) 
    {    
        m_ulCurRowIndex = PR_ROW_SET_END; 
        return; 
    } 
 
    // Initialize base class so that it's first and current property  
    // point to the first one in this row. 
    Init( m_pRowSet->aRow[ m_ulCurRowIndex].cValues, m_pRowSet->aRow[ m_ulCurRowIndex].lpProps);  
    First();    // First property of this row. 
} 
 
// -----------------------------------------------------------------------------