You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1923 lines
49 KiB
1923 lines
49 KiB
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// UserDef.c
|
|
//
|
|
// MS Office User Defined Property Information
|
|
//
|
|
// Notes:
|
|
// To make this file useful for OLE objects, define OLE_PROPS.
|
|
//
|
|
// The macro lpDocObj must be used for all methods to access the
|
|
// object data to ensure that this will compile with OLE_PROPS defined.
|
|
//
|
|
// Data structures:
|
|
// The dictionary is stored internally as a map, mapping PIDs
|
|
// to the string names.
|
|
//
|
|
// The properties themselves are stored internally as a linked list
|
|
//
|
|
// Change history:
|
|
//
|
|
// Date Who What
|
|
// --------------------------------------------------------------------------
|
|
// 06/27/94 B. Wentz Created file
|
|
// 07/03/94 B. Wentz Added Iterator support
|
|
// 07/20/94 M. Jansson Updated include statements, due to changes in PDK
|
|
// 07/26/94 B. Wentz Changed Load & Save to use Document Summary stream
|
|
// 07/08/96 MikeHill Ignore UserDef properties that aren't UDTYPEs.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "priv.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
static void PASCAL RemoveFromList (LPUDOBJ lpUDObj, LPUDPROP lpudprop);
|
|
static void PASCAL DeallocNode (LPUDOBJ lpUDObj, LPUDPROP lpudp);
|
|
|
|
static void PASCAL VUdpropFreeString (LPUDPROP lpudp, BOOL fName);
|
|
static BOOL PASCAL FUdpropUpdate (LPUDPROP lpudp, LPUDOBJ lpUDObj, LPTSTR lpszPropName, LPTSTR lpszLinkMonik, LPVOID lpvValue, UDTYPES udtype, BOOL fLink);
|
|
static BOOL PASCAL FUdpropSetString (LPUDPROP lpudp, LPTSTR lptstr, BOOL fLimitLength, BOOL fName);
|
|
static BOOL PASCAL FUserDefMakeHidden (LPUDOBJ lpUDObj, LPTSTR lpsz);
|
|
static BOOL PASCAL FUdpropMakeHidden (LPUDPROP lpudprop);
|
|
|
|
#define lpDocObj (lpUDObj)
|
|
#define lpData ((LPUDINFO) lpUDObj->m_lpData)
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OfficeDirtyUDObj
|
|
//
|
|
// Purpose:
|
|
// Sets object state to dirty or clean.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT VOID OfficeDirtyUDObj
|
|
(LPUDOBJ lpUDObj, // The object
|
|
BOOL fDirty) // Flag indicating if the object is dirty.
|
|
{
|
|
Assert(lpUDObj != NULL);
|
|
lpUDObj->m_fObjChanged = fDirty;
|
|
} // OfficeDirtyUDObj
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FreeUDData
|
|
//
|
|
// Purpose:
|
|
// Deallocates all the member data for the object
|
|
//
|
|
// Note:
|
|
// Assumes object is valid.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void PASCAL
|
|
FreeUDData
|
|
(LPUDOBJ lpUDObj, // Pointer to valid object
|
|
BOOL fTmp) // Indicates tmp data should be freed
|
|
{
|
|
LPUDPROP lpudp;
|
|
LPUDPROP lpudpT;
|
|
|
|
|
|
lpudp = (fTmp) ? lpData->lpudpTmpHead : lpData->lpudpHead;
|
|
|
|
while (lpudp != NULL)
|
|
{
|
|
lpudpT = lpudp;
|
|
lpudp = (LPUDPROP) lpudp->llist.lpllistNext;
|
|
VUdpropFree(&lpudpT);
|
|
}
|
|
|
|
if (fTmp)
|
|
{
|
|
lpData->lpudpTmpCache = NULL;
|
|
lpData->lpudpTmpHead = NULL;
|
|
lpData->dwcTmpProps = 0;
|
|
lpData->dwcTmpLinks = 0;
|
|
}
|
|
else
|
|
{
|
|
lpData->lpudpCache = NULL;
|
|
lpData->lpudpHead = NULL;
|
|
lpData->dwcProps = 0;
|
|
lpData->dwcLinks = 0;
|
|
}
|
|
|
|
} // FreeUDData
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUserDefCreate
|
|
//
|
|
// Purpose:
|
|
// Create a User-defined property exchange object.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
FUserDefCreate
|
|
(LPUDOBJ FAR *lplpUDObj, // Pointer to pointer to object
|
|
void *prglpfn[]) // Pointer to functions
|
|
{
|
|
LPUDOBJ lpUDObj; // Hack - a temp, must call it "lpUdObj" for macros to work!
|
|
|
|
if (lplpUDObj == NULL)
|
|
return(TRUE);
|
|
|
|
// Make sure we get valid args before we start alloc'ing
|
|
if ((prglpfn == NULL) || (prglpfn[ifnCPConvert] == NULL) ||
|
|
((prglpfn[ifnFSzToNum] == NULL) && (prglpfn[ifnFNumToSz] != NULL)) ||
|
|
((prglpfn[ifnFSzToNum] != NULL) && (prglpfn[ifnFNumToSz] == NULL))
|
|
)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if ((*lplpUDObj = LocalAlloc(LPTR, sizeof(USERPROP))) == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
lpDocObj = *lplpUDObj;
|
|
|
|
//
|
|
// If alloc fails, free the original object too.
|
|
//
|
|
if ((lpData = LocalAlloc(LPTR, sizeof (UDINFO))) == NULL)
|
|
{
|
|
LocalFree(*lplpUDObj);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Save the fnc's for code page convert, SzToNum, NumToSz
|
|
//
|
|
lpData->lpfnFCPConvert = (BOOL (*)(LPTSTR, DWORD, DWORD, BOOL)) prglpfn[ifnCPConvert];
|
|
lpData->lpfnFSzToNum = (BOOL (*)(NUM *, LPTSTR)) prglpfn[ifnFSzToNum];
|
|
lpData->lpfnFNumToSz = (BOOL (*)(NUM *, LPTSTR, DWORD)) prglpfn[ifnFNumToSz];
|
|
|
|
OfficeDirtyUDObj (*lplpUDObj, FALSE);
|
|
(*lplpUDObj)->m_hPage = NULL;
|
|
|
|
return TRUE;
|
|
|
|
} // FUserDefCreate
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUserDefDestroy
|
|
//
|
|
// Purpose:
|
|
// Destroy a User-defined property exchange object.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
FUserDefDestroy
|
|
(LPUDOBJ FAR *lplpUDObj) // Pointer to pointer to object
|
|
{
|
|
DWORD irg;
|
|
LPUDINFO lpUDData;
|
|
|
|
lpUDData = (LPUDINFO)(((LPUDOBJ) *lplpUDObj)->m_lpData);
|
|
|
|
if ((lplpUDObj == NULL) || (*lplpUDObj == NULL))
|
|
return TRUE;
|
|
|
|
if (lpUDData != NULL)
|
|
{
|
|
FreeUDData (*lplpUDObj, FALSE);
|
|
FreeUDData (*lplpUDObj, TRUE);
|
|
|
|
//
|
|
// Invalidate any OLE Automation DocumentProperty objects we might have
|
|
//
|
|
InvalidateVBAObjects(NULL, NULL, *lplpUDObj);
|
|
|
|
LocalFree((*lplpUDObj)->m_lpData);
|
|
}
|
|
|
|
LocalFree(*lplpUDObj);
|
|
*lplpUDObj = NULL;
|
|
return TRUE;
|
|
|
|
} // FUserDefDestroy
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUserDefClear
|
|
//
|
|
// Purpose:
|
|
// Clears a User-defined property object without destroying it. All stored
|
|
// data is lost.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
FUserDefClear(LPUDOBJ lpUDObj) // Pointer to object
|
|
{
|
|
if ((lpDocObj == NULL) || (lpData == NULL))
|
|
return TRUE;
|
|
|
|
FreeUDData (lpDocObj, FALSE);
|
|
FreeUDData (lpDocObj, TRUE);
|
|
|
|
//
|
|
// Invalidate any OLE Automation DocumentProperty objects we might have
|
|
//
|
|
InvalidateVBAObjects(NULL, NULL, lpUDObj);
|
|
|
|
//
|
|
// Clear the data, don't blt over the fn's stored at the end.
|
|
//
|
|
ZeroMemory( lpData, sizeof (UDINFO) - ifnUDMax * sizeof(void *) );
|
|
|
|
OfficeDirtyUDObj (lpUDObj, TRUE);
|
|
return TRUE;
|
|
|
|
} // FUserDefClear
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUserDefShouldSave
|
|
//
|
|
// Purpose:
|
|
// Indicates if the data has changed, meaning a write is needed.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT BOOL
|
|
FUserDefShouldSave
|
|
(LPUDOBJ lpUDObj) // Pointer to object
|
|
{
|
|
if (lpUDObj == NULL)
|
|
return FALSE;
|
|
|
|
return lpDocObj->m_fObjChanged;
|
|
|
|
} // FUserDefShouldSave
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// UdtypesUserDefType
|
|
//
|
|
// Purpose:
|
|
// Returns the type of the given Property Value from the string
|
|
//
|
|
// Returns wUDInvalid on error
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT UDTYPES
|
|
UdtypesUserDefType
|
|
(LPUDOBJ lpUDObj,
|
|
LPTSTR lpsz)
|
|
{
|
|
LPUDPROP lpudprop;
|
|
|
|
if ((lpUDObj == NULL) ||
|
|
(lpData == NULL) ||
|
|
(lpsz == NULL)
|
|
)
|
|
{
|
|
return wUDinvalid;
|
|
}
|
|
|
|
//
|
|
// Find the node that has this name.
|
|
//
|
|
lpudprop = LpudpropFindMatchingName (lpUDObj, lpsz);
|
|
if (lpudprop == NULL || lpudprop->lppropvar == NULL)
|
|
return wUDinvalid;
|
|
|
|
// Return the VarType (which is a UDTYPE)
|
|
|
|
return (lpudprop->lppropvar->vt);
|
|
|
|
} // UdtypesUserDefType
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// LpvoidUserDefGetPropVal
|
|
//
|
|
// Purpose:
|
|
// This will return the Property Value for the given Property String.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
DLLEXPORT LPVOID
|
|
LpvoidUserDefGetPropVal
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
LPTSTR lpszProp, // Property string
|
|
DWORD dwMask, // Mask for what value is needed
|
|
BOOL *pfLink, // Indicates a link
|
|
BOOL *pfLinkInvalid) // Is the link invalid
|
|
{
|
|
LPUDPROP lpudprop;
|
|
|
|
if ((lpUDObj == NULL) ||
|
|
(lpData == NULL) ||
|
|
(lpszProp == NULL) ||
|
|
(pfLink == NULL) ||
|
|
(pfLinkInvalid == NULL)
|
|
)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Find the node that has this name.
|
|
//
|
|
|
|
lpudprop = LpudpropFindMatchingName (lpUDObj, lpszProp);
|
|
if (lpudprop == NULL)
|
|
return NULL;
|
|
Assert (lpudprop->lppropvar != NULL);
|
|
|
|
*pfLink = (lpudprop->lpstzLink != NULL);
|
|
|
|
// Links are always invalid in the shell (there's no app to update the data).
|
|
|
|
*pfLinkInvalid = lpudprop->fLinkInvalid = TRUE;
|
|
|
|
//
|
|
// Return based on the type and flags
|
|
//
|
|
|
|
if (dwMask & UD_LINK)
|
|
{
|
|
if (dwMask & UD_PTRWIZARD)
|
|
{
|
|
if (lpudprop->lpstzLink != NULL)
|
|
{
|
|
return (LPVOID) lpudprop->lpstzLink;
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
if (dwMask & UD_PTRWIZARD)
|
|
{
|
|
// If this is a string, return it's pointer from the
|
|
// PropVariant. Otherwise, return a pointer into
|
|
// the data of the PropVariant.
|
|
|
|
return (lpudprop->lppropvar->vt == VT_LPTSTR) ?
|
|
(LPVOID) lpudprop->lppropvar->pszVal :
|
|
(LPVOID) &lpudprop->lppropvar->lVal;
|
|
}
|
|
|
|
// Copy the property from the PropVariant to the caller-provided
|
|
// buffer.
|
|
|
|
return( NULL );
|
|
|
|
} // LpvoidUserDefGetPropVal
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// LppropvarUserDefAddProp
|
|
//
|
|
// Purpose:
|
|
// This will add a new Property to the set, with the given
|
|
// Property string, type, and data.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
DLLEXPORT LPPROPVARIANT
|
|
LppropvarUserDefAddProp
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
LPTSTR lpszPropName, // Property string
|
|
LPVOID lpvVal, // Property value
|
|
UDTYPES udtype, // Property type
|
|
LPTSTR lpszLinkMonik, // Link name
|
|
BOOL fLink, // Indicates the property is a link
|
|
BOOL fHidden) // Indicates the property is hidden
|
|
{
|
|
LPUDPROP lpudprop;
|
|
LPUDPROP lpudpropMatch;
|
|
BOOL fCreated;
|
|
|
|
if ((lpUDObj == NULL) ||
|
|
(lpData == NULL) ||
|
|
(lpszPropName == NULL) ||
|
|
(*lpszPropName == 0) ||
|
|
(lpvVal == NULL) ||
|
|
(!ISUDTYPE(udtype)) ||
|
|
(fLink && (lpszLinkMonik == NULL))
|
|
)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Create a UDPROP to be added to the linked-list.
|
|
|
|
lpudprop = LpudpropCreate();
|
|
if (lpudprop == NULL)
|
|
return FALSE;
|
|
|
|
// Put the data into the UDPROP.
|
|
|
|
if (!FUdpropUpdate( lpudprop,
|
|
lpUDObj,
|
|
lpszPropName,
|
|
lpszLinkMonik,
|
|
lpvVal,
|
|
udtype,
|
|
fLink)
|
|
)
|
|
{
|
|
VUdpropFree (&lpudprop);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Find this node
|
|
//
|
|
|
|
lpudpropMatch = LpudpropFindMatchingName (lpUDObj, lpszPropName);
|
|
if (lpudpropMatch==NULL)
|
|
{
|
|
//
|
|
// Create a node and put it in the list
|
|
// If a new node was created, it must be added to the list...
|
|
//
|
|
|
|
if (fLink)
|
|
lpData->dwcLinks++;
|
|
|
|
lpData->dwcProps++;
|
|
AddNodeToList (lpUDObj, lpudprop);
|
|
|
|
} // if (lpudpropMatch==NULL)
|
|
|
|
else
|
|
{
|
|
// We must replace the existing UDPROP with the new
|
|
// value.
|
|
|
|
// Free any existing property name and link name in this
|
|
// UDPROP, and free its value.
|
|
|
|
VUdpropFreeString (lpudpropMatch, TRUE);
|
|
VUdpropFreeString (lpudpropMatch, FALSE);
|
|
PropVariantClear (lpudpropMatch->lppropvar);
|
|
CoTaskMemFree (lpudpropMatch->lppropvar);
|
|
lpudpropMatch->lppropvar = NULL;
|
|
|
|
// Put the linked-list pointer in the existing UDPROP into
|
|
// the new UDPROP, then copy the new UDPROP back over
|
|
// the matching PROP (this way, we don't have to
|
|
// update the UDPROP that points to the match).
|
|
|
|
lpudprop->llist=lpudpropMatch->llist;
|
|
CopyMemory(lpudpropMatch, lpudprop, sizeof(UDPROP));
|
|
|
|
// Clear out the caller-provided UDPROP, free it, but
|
|
// then set the pointer to the matching entry and clear
|
|
// the match pointer. Thus, after we're done and whether
|
|
// there was a match or not, lpudprop will point to the
|
|
// correct UDPROP.
|
|
|
|
ZeroMemory(lpudprop, sizeof(UDPROP));
|
|
VUdpropFree (&lpudprop);
|
|
lpudprop = lpudpropMatch;
|
|
lpudpropMatch = NULL;
|
|
|
|
} // if (lpudpropMatch==NULL) ... else
|
|
|
|
//
|
|
// If the client asked for a hidden property, do it if
|
|
// the name was the real name, not a link
|
|
//
|
|
|
|
if (fHidden && !fLink)
|
|
{
|
|
fCreated=FUserDefMakeHidden (lpUDObj, lpszPropName); // Should never return false
|
|
Assert(fCreated);
|
|
}
|
|
|
|
OfficeDirtyUDObj (lpUDObj, TRUE);
|
|
|
|
// If successful, return a pointer to the PropVariant with the value.
|
|
if (lpudprop)
|
|
return lpudprop->lppropvar;
|
|
else
|
|
return NULL;
|
|
|
|
} // LppropvarUserDefAddProp
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUserDefDeleteProp
|
|
//
|
|
// Purpose:
|
|
// This will delete a Property from the set given a Property string.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT BOOL
|
|
FUserDefDeleteProp
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
LPTSTR lpsz) // String to delete
|
|
{
|
|
LPUDPROP lpudprop;
|
|
|
|
if ((lpUDObj == NULL) ||
|
|
(lpData == NULL) ||
|
|
(lpsz == NULL))
|
|
return FALSE;
|
|
|
|
// Find the node
|
|
lpudprop = LpudpropFindMatchingName (lpUDObj, lpsz);
|
|
if (lpudprop == NULL)
|
|
return FALSE;
|
|
|
|
lpData->dwcProps--;
|
|
if (lpudprop->lpstzLink != NULL)
|
|
lpData->dwcLinks--;
|
|
|
|
RemoveFromList (lpUDObj, lpudprop);
|
|
VUdpropFree (&lpudprop);
|
|
|
|
OfficeDirtyUDObj (lpUDObj, TRUE);
|
|
return TRUE;
|
|
|
|
} // FUserDefDeleteProp
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// LpudiUserDefCreateIterator
|
|
//
|
|
// Purpose:
|
|
// Create a User-defined Properties iterator
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT LPUDITER
|
|
LpudiUserDefCreateIterator
|
|
(LPUDOBJ lpUDObj) // Pointer to object
|
|
{
|
|
LPUDITER lpudi;
|
|
|
|
if ((lpUDObj == NULL) ||
|
|
(lpData == NULL) ||
|
|
(lpData->lpudpHead == NULL)) // No custom props
|
|
return NULL;
|
|
|
|
|
|
// Create & Init the iterator
|
|
lpudi = LocalAlloc(LPTR, sizeof(UDITER));
|
|
if (lpudi == NULL)
|
|
return(NULL);
|
|
|
|
lpudi->lpudp = lpData->lpudpHead;
|
|
|
|
return lpudi;
|
|
|
|
} // LpudiUserDefCreateIterator
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUserDefDestroyIterator
|
|
//
|
|
// Purpose:
|
|
// Destroy a User-defined Properties iterator
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT BOOL
|
|
FUserDefDestroyIterator
|
|
(LPUDITER *lplpUDIter) // Pointer to iterator
|
|
{
|
|
if ((lplpUDIter == NULL) || (*lplpUDIter == NULL))
|
|
return TRUE;
|
|
|
|
LocalFree(*lplpUDIter);
|
|
*lplpUDIter = NULL;
|
|
|
|
return TRUE;
|
|
|
|
} // FUserDefDestroyIterator
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUserDefIteratorValid
|
|
//
|
|
// Purpose:
|
|
// Determine if an iterator is still valid
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT BOOL
|
|
FUserDefIteratorValid
|
|
(LPUDITER lpUDIter) // Pointer to iterator
|
|
{
|
|
if (lpUDIter == NULL)
|
|
return FALSE;
|
|
|
|
return (lpUDIter->lpudp != NULL);
|
|
|
|
} // FUserDefIteratorValid
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUserDefIteratorNext
|
|
//
|
|
// Purpose:
|
|
// Iterate to the next element
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT BOOL
|
|
FUserDefIteratorNext
|
|
(LPUDITER lpUDIter) // Pointer to iterator
|
|
{
|
|
if (lpUDIter == NULL)
|
|
return FALSE;
|
|
|
|
// Move to the next node, if possible.
|
|
#ifdef OLD
|
|
if (lpUDIter->lpudp != NULL)
|
|
lpUDIter->lpudp = (LPUDPROP) lpUDIter->lpudp->llist.lpllistNext;
|
|
|
|
return TRUE;
|
|
#endif
|
|
|
|
if (lpUDIter->lpudp == NULL)
|
|
return FALSE;
|
|
|
|
lpUDIter->lpudp = (LPUDPROP) lpUDIter->lpudp->llist.lpllistNext;
|
|
|
|
return(lpUDIter->lpudp != NULL);
|
|
|
|
} // FUserDefIteratorNext
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUserDefIteratorIsLink
|
|
//
|
|
// Purpose:
|
|
// Returns TRUE if the iterator is a link, FALSE otherwise
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT BOOL
|
|
FUserDefIteratorIsLink
|
|
(LPUDITER lpUDIter) // Pointer to iterator
|
|
{
|
|
if ((lpUDIter == NULL) || (lpUDIter->lpudp == NULL))
|
|
return FALSE;
|
|
|
|
return(lpUDIter->lpudp->lpstzLink != NULL);
|
|
|
|
} // FUserDefIteratorIsLink
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// LpszUserDefIteratorName
|
|
//
|
|
// Purpose:
|
|
// This will return the Property String (name) for the property
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT LPTSTR
|
|
LpszUserDefIteratorName(
|
|
LPUDITER lpUDIter // Pointer to iterator
|
|
)
|
|
{
|
|
if ((lpUDIter == NULL) ||
|
|
(lpUDIter->lpudp == NULL))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return (lpUDIter->lpudp->lpstzName);
|
|
|
|
} // LpszUserDefIteratorName
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUserDefMakeHidden
|
|
//
|
|
// Purpose:
|
|
// Hide a Property based on the Property string.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
static BOOL PASCAL
|
|
FUserDefMakeHidden
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
LPTSTR lpsz) // String to hide
|
|
{
|
|
LPUDPROP lpudprop;
|
|
LPTSTR lpstzT;
|
|
|
|
if ((lpUDObj == NULL) ||
|
|
(lpData == NULL) ||
|
|
(lpsz == NULL))
|
|
return FALSE;
|
|
|
|
// Find the name
|
|
lpudprop = LpudpropFindMatchingName (lpUDObj, lpsz);
|
|
if (lpudprop == NULL)
|
|
return FALSE;
|
|
|
|
if (!FUdpropMakeHidden (lpudprop))
|
|
return FALSE;
|
|
|
|
OfficeDirtyUDObj (lpUDObj, TRUE);
|
|
return TRUE;
|
|
|
|
} // FUserDefMakeHidden
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// LpudpropFindMatchingName
|
|
//
|
|
// Purpose:
|
|
// Returns a node with a matching name, NULL otherwise.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
LPUDPROP PASCAL
|
|
LpudpropFindMatchingName
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
LPTSTR lpsz) // String to search for
|
|
{
|
|
LPUDPROP lpudprop;
|
|
TCHAR sz[256];
|
|
BOOL fCopy = FALSE;
|
|
|
|
if ((lpUDObj == NULL) || (lpData == NULL))
|
|
return(NULL);
|
|
|
|
if (lstrlen(lpsz) > 255)
|
|
{
|
|
// Truncate on purpose
|
|
StringCchCopy( sz, ARRAYSIZE(sz), lpsz );
|
|
sz[255] = 0;
|
|
fCopy = TRUE;
|
|
}
|
|
|
|
// Check the cache first
|
|
if (lpData->lpudpCache != NULL)
|
|
{
|
|
Assert ((lpData->lpudpCache->lpstzName != NULL));
|
|
|
|
// lstrcmpi returns 0 if 2 strings are equal.....
|
|
if ( !lstrcmpi( fCopy ? sz : lpsz, lpData->lpudpCache->lpstzName ))
|
|
{
|
|
return lpData->lpudpCache;
|
|
}
|
|
}
|
|
|
|
lpudprop = lpData->lpudpHead;
|
|
|
|
while (lpudprop != NULL)
|
|
{
|
|
Assert ((lpudprop->lpstzName != NULL));
|
|
|
|
// lstrcmpi returns 0 if 2 strings are equal.....
|
|
if ( !lstrcmpi( fCopy ? sz : lpsz, lpudprop->lpstzName ))
|
|
{
|
|
// Set the cache to the last node found
|
|
lpData->lpudpCache = lpudprop;
|
|
return lpudprop;
|
|
}
|
|
|
|
lpudprop = (LPUDPROP) lpudprop->llist.lpllistNext;
|
|
|
|
} // while
|
|
|
|
return NULL;
|
|
|
|
} // LpudpropFindMatchingName
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// LpudpropFindMatchingPID
|
|
//
|
|
// Purpose:
|
|
// Searches the linked-list in the caller-provided UDINFO structure
|
|
// for a UDPROP with the requested PropID.
|
|
//
|
|
// Inputs:
|
|
// LPUDOBJ - The UDINFO structure
|
|
// PROPID - The PID to search for.
|
|
//
|
|
// Output:
|
|
// The requested LPUDPROP, or NULL if not found.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
LPUDPROP PASCAL
|
|
LpudpropFindMatchingPID
|
|
(LPUDOBJ lpUDObj,
|
|
PROPID propid)
|
|
{
|
|
// ------
|
|
// Locals
|
|
// ------
|
|
|
|
LPUDPROP lpudprop = NULL;
|
|
BOOL fCopy = FALSE;
|
|
|
|
// -----
|
|
// Begin
|
|
// -----
|
|
|
|
// Validate the inputs.
|
|
|
|
if ((lpUDObj == NULL) || (lpData == NULL))
|
|
{
|
|
AssertSz (0, TEXT("Invalid inputs"));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
// Check the cache first
|
|
|
|
if (lpData->lpudpCache != NULL
|
|
&&
|
|
lpData->lpudpCache->propid == propid)
|
|
{
|
|
lpudprop = lpData->lpudpCache;
|
|
goto Exit;
|
|
}
|
|
|
|
// Search the linked-list.
|
|
|
|
lpudprop = lpData->lpudpHead;
|
|
while (lpudprop != NULL)
|
|
{
|
|
if (lpudprop->propid == propid)
|
|
{
|
|
lpData->lpudpCache = lpudprop;
|
|
goto Exit;
|
|
}
|
|
|
|
lpudprop = (LPUDPROP) lpudprop->llist.lpllistNext;
|
|
|
|
}
|
|
|
|
// ----
|
|
// Exit
|
|
// ----
|
|
|
|
Exit:
|
|
|
|
return lpudprop;
|
|
|
|
|
|
} // LpudpropFindMatchingPID
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FAddPropToList
|
|
//
|
|
// Purpose:
|
|
// Adds the given object to the list. The type and value must
|
|
// be filled in before calling this.
|
|
//
|
|
// The linked-list we're adding to has one entry for each of
|
|
// the user-defined properties. Each entry has the property
|
|
// value, it's PID, and it's name. If the property is linked
|
|
// to document content, the link name (e.g. a Bookmark name
|
|
// in Word) is also in this entry. Note that the property set
|
|
// stores the property value as one property, with its name in the
|
|
// dictionary, and it stores the link name as a second property.
|
|
// Consequently, this routine will be called twice for such
|
|
// properties: on the first call we'll create a new entry in the
|
|
// linked-list, adding the property ID, name, and value; on the
|
|
// second call we'll pull out that entry, and add the link name.
|
|
//
|
|
// On success, the input lppropvar & lpstatpropstg are cleared.
|
|
// On error, all inputs are left unmodified.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL PASCAL
|
|
FAddPropToList
|
|
(LPUDOBJ lpUDObj,
|
|
LPPROPVARIANT lppropvar,
|
|
STATPROPSTG *lpstatpropstg,
|
|
LPUDPROP lpudprop) // Property to add
|
|
{
|
|
// ------
|
|
// Locals
|
|
// ------
|
|
|
|
BOOL fSuccess = FALSE;
|
|
LPTSTR lpstz;
|
|
LPUDPROP lpudpT;
|
|
BOOL fLink;
|
|
|
|
Assert(lpUDObj != NULL);
|
|
Assert(lpudprop != NULL); // Is this a bogus assert?
|
|
Assert(lppropvar != NULL && lpstatpropstg != NULL);
|
|
|
|
// If the PId has one of the special masks, strip it off
|
|
// so the PId will match the normal value.
|
|
|
|
fLink = lpstatpropstg->propid & PID_LINKMASK;
|
|
lpstatpropstg->propid &= ~PID_LINKMASK;
|
|
|
|
|
|
// ------------------------------------------------------------
|
|
// See if we can find this property already in the linked-list.
|
|
// If we have a name, use that, otherwise use the PID.
|
|
// ------------------------------------------------------------
|
|
|
|
if (lpstatpropstg->lpwstrName != NULL)
|
|
{
|
|
// Search by name.
|
|
|
|
// [scotthan] Re: bogus cast to TCHAR in propio.c when this thing
|
|
// was read out of the file. If this is an ANSI build, it's going to store
|
|
// a TCHAR* value!. So we need to reciprocate the cast...
|
|
lpudpT = LpudpropFindMatchingName (lpUDObj, (LPTSTR)lpstatpropstg->lpwstrName );
|
|
}
|
|
else
|
|
{
|
|
// Search by PID
|
|
lpudpT = LpudpropFindMatchingPID (lpUDObj, lpstatpropstg->propid);
|
|
}
|
|
|
|
// --------------------------------------------------------------
|
|
// If this property isn't already in the linked-list, add it now.
|
|
// --------------------------------------------------------------
|
|
|
|
if (lpudpT == NULL)
|
|
{
|
|
// This should be a named property. If it's not
|
|
// named, then it should be a link, and the property
|
|
// it links should have been in the linked-list already
|
|
// (i.e., the lpudpT should have been non-NULL).
|
|
|
|
if (lpstatpropstg->lpwstrName == NULL)
|
|
{
|
|
AssertSz (0, TEXT("Missing name in User-Defined properties"));
|
|
goto Exit;
|
|
}
|
|
|
|
// Allocate memory for the property value.
|
|
|
|
lpudprop->lppropvar = CoTaskMemAlloc (sizeof(PROPVARIANT));
|
|
if (lpudprop->lppropvar == NULL)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Load the property ID, name, and value.
|
|
// Note that if we had an error before here, we left
|
|
// the caller's inputs un-touched. Since no more errors
|
|
// can occur, we'll never have half-modified data in an
|
|
// error case.
|
|
|
|
lpudprop->propid = lpstatpropstg->propid;
|
|
|
|
// [scotthan] Re: bogus cast to TCHAR in propio.c when this thing
|
|
// was read out of the file. If this is an ANSI build, it's going to store
|
|
// a TCHAR* value!. So we need to reciprocate the cast...
|
|
lpudprop->lpstzName = (LPTSTR)lpstatpropstg->lpwstrName;
|
|
lpstatpropstg->lpwstrName = NULL;
|
|
|
|
*lpudprop->lppropvar = *lppropvar;
|
|
PropVariantInit (lppropvar);
|
|
|
|
lpData->dwcProps++;
|
|
AddNodeToList (lpUDObj, lpudprop);
|
|
|
|
} // if ((lpudpT = LpudpropFindMatchingName (lpUDInfo, lpstatpropstg->lpwsz)) == NULL)
|
|
|
|
|
|
// --------------------------------------------------------
|
|
// Otherwise (this property is already in the linked-list),
|
|
// add this new link name or value to the UDPROP.
|
|
// --------------------------------------------------------
|
|
|
|
else
|
|
{
|
|
// If this is a link being added, then update the link-name in the
|
|
// extant property.
|
|
|
|
if (fLink)
|
|
{
|
|
// lpudpT points to the entry in our linked-list for this
|
|
// property. But it shouldn't already have a link-name (there
|
|
// can only be one link-name per property).
|
|
|
|
if (lpudpT->lpstzLink != NULL)
|
|
{
|
|
AssertSz (0, TEXT("Invalid property set - link name defined twice"));
|
|
goto Exit;
|
|
}
|
|
|
|
// Since this is a link-name, it should be a string.
|
|
|
|
if (lppropvar->vt != VT_LPTSTR)
|
|
{
|
|
AssertSz (0, TEXT("Invalid property set - link name isn't a string"));
|
|
goto Exit;
|
|
}
|
|
|
|
// Point the UDPROP to the link name, and take ownership
|
|
// of it by clearing the caller's pointer.
|
|
|
|
Assert (lppropvar->pszVal != NULL);
|
|
|
|
lpudpT->lpstzLink = (LPTSTR) lppropvar->pszVal;
|
|
PropVariantInit (lppropvar);
|
|
|
|
lpData->dwcLinks++;
|
|
|
|
} // if (fLink)
|
|
|
|
// Otherwise, this isn't a link name, it's a value. So point the
|
|
// UDPROP to it's data.
|
|
|
|
else
|
|
{
|
|
*lpudpT->lppropvar = *lppropvar;
|
|
PropVariantInit (lppropvar);
|
|
|
|
} // if (fLink) ... else
|
|
|
|
} // if ((lpudpT = LpudpropFindMatchingName ... else
|
|
|
|
fSuccess = TRUE;
|
|
|
|
Exit:
|
|
|
|
// Just in case we were given a name that we didn't
|
|
// need, clear it now so that the caller knows that
|
|
// on success, they needn't worry about the buffers
|
|
// pointed to by lppropvar & lpstatpropstg.
|
|
|
|
if (fSuccess)
|
|
{
|
|
if (lpstatpropstg->lpwstrName != NULL)
|
|
{
|
|
CoTaskMemFree (lpstatpropstg->lpwstrName);
|
|
lpstatpropstg->lpwstrName = NULL;
|
|
}
|
|
}
|
|
|
|
return(fSuccess);
|
|
|
|
} // FAddPropToList
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// AddNodeToList
|
|
//
|
|
// Purpose:
|
|
// Adds the given node to the list.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void PASCAL
|
|
AddNodeToList
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
LPUDPROP lpudprop) // Node to add
|
|
{
|
|
// Put the new node at the end
|
|
|
|
if (lpData->lpudpHead != NULL)
|
|
{
|
|
if (lpData->lpudpHead->llist.lpllistPrev != NULL)
|
|
{
|
|
((LPUDPROP) lpData->lpudpHead->llist.lpllistPrev)->llist.lpllistNext = (LPLLIST) lpudprop;
|
|
lpudprop->llist.lpllistPrev = lpData->lpudpHead->llist.lpllistPrev;
|
|
}
|
|
else
|
|
{
|
|
lpData->lpudpHead->llist.lpllistNext = (LPLLIST) lpudprop;
|
|
lpudprop->llist.lpllistPrev = (LPLLIST) lpData->lpudpHead;
|
|
}
|
|
lpData->lpudpHead->llist.lpllistPrev = (LPLLIST) lpudprop;
|
|
}
|
|
else
|
|
{
|
|
lpData->lpudpHead = lpudprop;
|
|
lpudprop->llist.lpllistPrev = NULL;
|
|
}
|
|
|
|
lpudprop->llist.lpllistNext = NULL;
|
|
lpData->lpudpCache = lpudprop;
|
|
|
|
} // AddNodeToList
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// RemoveFromList
|
|
//
|
|
// Purpose:
|
|
// Removes the given node from the list
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
static void PASCAL
|
|
RemoveFromList
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
LPUDPROP lpudprop) // The node itself.
|
|
{
|
|
AssertSz ((lpData->lpudpHead != NULL), TEXT("List is corrupt"));
|
|
|
|
// If we're removing the cached node, invalidate the cache
|
|
if (lpudprop == lpData->lpudpCache)
|
|
{
|
|
lpData->lpudpCache = NULL;
|
|
}
|
|
|
|
// Be sure the head gets updated, if the node is at the front
|
|
if (lpudprop == lpData->lpudpHead)
|
|
{
|
|
lpData->lpudpHead = (LPUDPROP) lpudprop->llist.lpllistNext;
|
|
|
|
if (lpData->lpudpHead != NULL)
|
|
{
|
|
lpData->lpudpHead->llist.lpllistPrev = lpudprop->llist.lpllistPrev;
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Update the links
|
|
if (lpudprop->llist.lpllistNext != NULL)
|
|
{
|
|
((LPUDPROP) lpudprop->llist.lpllistNext)->llist.lpllistPrev = lpudprop->llist.lpllistPrev;
|
|
}
|
|
|
|
if (lpudprop->llist.lpllistPrev != NULL)
|
|
{
|
|
((LPUDPROP) lpudprop->llist.lpllistPrev)->llist.lpllistNext = lpudprop->llist.lpllistNext;
|
|
}
|
|
|
|
// If it is the last node in the list, be sure the head is updated
|
|
if (lpudprop == (LPUDPROP) lpData->lpudpHead->llist.lpllistPrev)
|
|
{
|
|
lpData->lpudpHead->llist.lpllistPrev = lpudprop->llist.lpllistPrev;
|
|
}
|
|
|
|
} // RemoveFromList
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// VUdpropFree
|
|
//
|
|
// Purpose:
|
|
// Free a UDPROP (which is in a linked-list).
|
|
//
|
|
// Inputs:
|
|
// LPUDPROP * - A pointer-to-pointer-to a UDPROP object.
|
|
//
|
|
// Output:
|
|
// None.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
VUdpropFree
|
|
(LPUDPROP *lplpudp)
|
|
{
|
|
// Validate the inputs.
|
|
|
|
if (lplpudp == NULL || *lplpudp == NULL )
|
|
goto Exit;
|
|
|
|
// If this property has a name, free that buffer.
|
|
|
|
if ((*lplpudp)->lpstzName)
|
|
{
|
|
CoTaskMemFree ((*lplpudp)->lpstzName);
|
|
}
|
|
|
|
// If this property has a link-name, free it too.
|
|
|
|
if ((*lplpudp)->lpstzLink)
|
|
{
|
|
CoTaskMemFree ((*lplpudp)->lpstzLink);
|
|
}
|
|
|
|
// Clear the property value, which will free any associated
|
|
// buffer. Then free the PropVariant itself.
|
|
|
|
PropVariantClear ((*lplpudp)->lppropvar);
|
|
CoTaskMemFree ((*lplpudp)->lppropvar);
|
|
CoTaskMemFree (*lplpudp);
|
|
|
|
*lplpudp = NULL;
|
|
|
|
Exit:
|
|
|
|
return;
|
|
|
|
} // VUdpropFree
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUdpropUpdate
|
|
//
|
|
// Purpose:
|
|
// Updates the given node with the given data
|
|
//
|
|
// It's the caller's responsibility to free lpudp if this function
|
|
// fails.
|
|
//
|
|
// Inputs:
|
|
// LPUDPROP - The node in the linked-list for this property.
|
|
// LPUDOBJ - All User-Defined data (including the properties)
|
|
// LPTSTR - The property name.
|
|
// LPTSTR - The link-name
|
|
// LPVOID - The new value
|
|
// UDTYPES - The type of the value.
|
|
// BOOL - TRUE if this is a link.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
static BOOL PASCAL
|
|
FUdpropUpdate
|
|
(LPUDPROP lpudp,
|
|
LPUDOBJ lpUDObj,
|
|
LPTSTR lpszPropName,
|
|
LPTSTR lpszLinkMonik,
|
|
LPVOID lpvValue,
|
|
UDTYPES udtype,
|
|
BOOL fLink)
|
|
{
|
|
// ------
|
|
// Locals
|
|
// ------
|
|
|
|
BOOL fSuccess = FALSE;
|
|
|
|
// -----
|
|
// Begin
|
|
// -----
|
|
|
|
|
|
// Validate the inputs.
|
|
|
|
if ((lpudp == NULL) ||
|
|
(lpszPropName == NULL) ||
|
|
(lpvValue == NULL) ||
|
|
(fLink && (lpszLinkMonik == NULL)) ||
|
|
(!ISUDTYPE(udtype)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Update the property name
|
|
|
|
if (!FUdpropSetString (lpudp, lpszPropName, TRUE, TRUE))
|
|
goto Exit;
|
|
|
|
// If necessary, allocate a PropVariant for the UDPROPS
|
|
|
|
if (lpudp->lppropvar == NULL)
|
|
{
|
|
lpudp->lppropvar = CoTaskMemAlloc (sizeof(PROPVARIANT));
|
|
if (lpudp->lppropvar == NULL)
|
|
goto Exit;
|
|
}
|
|
|
|
// Put the property value into the PropVariant
|
|
|
|
PropVariantClear (lpudp->lppropvar);
|
|
if (!FPropVarLoad (lpudp->lppropvar, (VARTYPE)udtype, lpvValue))
|
|
goto Exit;
|
|
|
|
// Update the link name if this is a link, otherwise
|
|
// free any existing link name.
|
|
|
|
if (fLink)
|
|
{
|
|
if(!FUdpropSetString (lpudp, lpszLinkMonik, FALSE, FALSE))
|
|
goto Exit;
|
|
}
|
|
else
|
|
{
|
|
VUdpropFreeString (lpudp, FALSE);
|
|
lpData->dwcLinks--;
|
|
}
|
|
|
|
// ----
|
|
// Exit
|
|
// ----
|
|
|
|
fSuccess = TRUE;
|
|
|
|
Exit:
|
|
|
|
return(fSuccess);
|
|
|
|
} // FUdpropUpdate
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FMakeTmpUDProps
|
|
//
|
|
// Purpose:
|
|
// Create a temporary copy of the User-Defined property data
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
FMakeTmpUDProps
|
|
(LPUDOBJ lpUDObj) // Pointer to object
|
|
{
|
|
// ------
|
|
// Locals
|
|
// ------
|
|
|
|
BOOL fSuccess = FALSE;
|
|
|
|
LPUDPROP lpudpCur;
|
|
LPUDPROP lpudpTmpCur;
|
|
DWORD dw;
|
|
LPVOID lpv;
|
|
|
|
// -----
|
|
// Begin
|
|
// -----
|
|
|
|
// Validate the inputs.
|
|
|
|
if ( lpUDObj == NULL || lpData == NULL )
|
|
goto Exit;
|
|
|
|
FDeleteTmpUDProps (lpUDObj);
|
|
|
|
// Move all the original list data to the tmp list
|
|
lpData->dwcTmpLinks = lpData->dwcLinks;
|
|
lpData->dwcTmpProps = lpData->dwcProps;
|
|
lpData->lpudpTmpHead = lpData->lpudpHead;
|
|
lpData->lpudpTmpCache = lpData->lpudpCache;
|
|
|
|
// Reinitialize the object data
|
|
lpData->dwcLinks = 0;
|
|
lpData->dwcProps = 0;
|
|
lpData->lpudpCache = NULL;
|
|
lpudpTmpCur = lpData->lpudpHead = NULL;
|
|
|
|
// Remember that we just put all the original data in the tmp ptrs.
|
|
lpudpCur = lpData->lpudpTmpHead;
|
|
|
|
// Loop through the old data and copy to the temp list
|
|
|
|
while (lpudpCur != NULL)
|
|
{
|
|
// Create a new UDPROP
|
|
|
|
lpudpTmpCur = LpudpropCreate();
|
|
if (lpudpTmpCur == NULL)
|
|
goto Exit;
|
|
|
|
// Set the name in the UDPROP
|
|
|
|
if (!FUdpropSetString (lpudpTmpCur, lpudpCur->lpstzName, FALSE, TRUE))
|
|
goto Exit;
|
|
|
|
// If we have a link-name, set it too in the UDPROP
|
|
|
|
if (lpudpCur->lpstzLink != NULL)
|
|
{
|
|
if (!FUdpropSetString (lpudpTmpCur, lpudpCur->lpstzLink, FALSE, FALSE))
|
|
goto Exit;
|
|
|
|
lpData->dwcLinks++;
|
|
}
|
|
|
|
// Allocate a PropVariant to hold the property value.
|
|
|
|
lpudpTmpCur->lppropvar = CoTaskMemAlloc (sizeof(PROPVARIANT));
|
|
if (lpudpTmpCur->lppropvar == NULL)
|
|
goto Exit;
|
|
|
|
// Copy the PropVariant into the temporary UDPROP.
|
|
|
|
PropVariantCopy (lpudpTmpCur->lppropvar, lpudpCur->lppropvar);
|
|
|
|
// Also show if this is an invalid link or not.
|
|
|
|
lpudpTmpCur->fLinkInvalid = lpudpCur->fLinkInvalid;
|
|
|
|
// Add this new temporary UDPROP to the linked-list.
|
|
|
|
AddNodeToList (lpUDObj, lpudpTmpCur);
|
|
lpData->dwcProps++;
|
|
|
|
// Move on to the next property.
|
|
|
|
lpudpCur = (LPUDPROP) lpudpCur->llist.lpllistNext;
|
|
|
|
} // while (lpudpCur != NULL)
|
|
|
|
|
|
// ----
|
|
// Exit
|
|
// ----
|
|
|
|
fSuccess = TRUE;
|
|
|
|
Exit:
|
|
|
|
|
|
// If there was an error, put everything back and deallocate anything we created
|
|
|
|
if (!fSuccess)
|
|
{
|
|
FSwapTmpUDProps (lpUDObj);
|
|
FDeleteTmpUDProps (lpUDObj);
|
|
}
|
|
|
|
|
|
return fSuccess;
|
|
|
|
} // FMakeTmpUDProps
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FSwapTmpUDProps
|
|
//
|
|
// Purpose:
|
|
// Swap the "temp" copy with the real copy of User-Defined property data
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
FSwapTmpUDProps
|
|
(LPUDOBJ lpUDObj)
|
|
{
|
|
DWORD dwT;
|
|
LPUDPROP lpudpT;
|
|
|
|
if ( lpUDObj == NULL || lpData == NULL )
|
|
return FALSE;
|
|
|
|
dwT = lpData->dwcLinks;
|
|
lpData->dwcLinks = lpData->dwcTmpLinks;
|
|
lpData->dwcTmpLinks = dwT;
|
|
|
|
dwT = lpData->dwcProps;
|
|
lpData->dwcProps = lpData->dwcTmpProps;
|
|
lpData->dwcTmpProps = dwT;
|
|
|
|
lpudpT = lpData->lpudpHead;
|
|
lpData->lpudpHead = lpData->lpudpTmpHead;
|
|
lpData->lpudpTmpHead = lpudpT;
|
|
|
|
lpudpT = lpData->lpudpCache;
|
|
lpData->lpudpCache = lpData->lpudpTmpCache;
|
|
lpData->lpudpTmpCache = lpudpT;
|
|
|
|
return TRUE;
|
|
|
|
} // FSwapTmpUDProps
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FDeleteTmpUDProps
|
|
//
|
|
// Purpose:
|
|
// Delete the "temp" copy of the data
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
FDeleteTmpUDProps
|
|
(LPUDOBJ lpUDObj)
|
|
{
|
|
if ((lpUDObj == NULL) ||
|
|
(lpData == NULL))
|
|
return FALSE;
|
|
|
|
FreeUDData (lpUDObj, TRUE);
|
|
|
|
return TRUE;
|
|
|
|
} // FDeleteTmpU
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUdpropMakeHidden
|
|
//
|
|
// Purpose:
|
|
// Convert a property in a UDPROP so that it is a hidden
|
|
// property. Properties are considered hidden if the
|
|
// first character in their name is an "_".
|
|
//
|
|
// Inputs:
|
|
// LPUDPROP - The UDPROP to convert.
|
|
//
|
|
// Output:
|
|
// TRUE if successful.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static BOOL PASCAL
|
|
FUdpropMakeHidden (LPUDPROP lpudprop)
|
|
{
|
|
// ------
|
|
// Locals
|
|
// ------
|
|
|
|
BOOL fSuccess = FALSE;
|
|
ULONG cch;
|
|
LPTSTR lpstzOld = NULL;
|
|
|
|
// -----
|
|
// Begin
|
|
// -----
|
|
|
|
// Intialize
|
|
|
|
Assert (lpudprop != NULL);
|
|
|
|
if (lpudprop->lpstzName == NULL)
|
|
goto Exit;
|
|
|
|
// Keep the old name.
|
|
|
|
lpstzOld = lpudprop->lpstzName;
|
|
|
|
// How many characters do we need in the new string?
|
|
|
|
cch = lstrlen(lpstzOld) + 2; // Includes the NULL & prefix
|
|
|
|
// Allocate the memory.
|
|
|
|
lpudprop->lpstzName = CoTaskMemAlloc (cch * sizeof(TCHAR));
|
|
if (lpudprop->lpstzName == NULL)
|
|
goto Exit;
|
|
|
|
// Set the "_" prefix to indicate this is a hidden property.
|
|
|
|
lpudprop->lpstzName[0] = HIDDENPREFIX;
|
|
|
|
// Copy the original property name after the prefix in the UDPROP.
|
|
|
|
StringCchCopy( &lpudprop->lpstzName[1], cch - 1, lpstzOld ); // One chacter less than cch to accout for hidden prefix.
|
|
|
|
// Free the old buffer
|
|
|
|
CoTaskMemFree (lpstzOld);
|
|
|
|
// ----
|
|
// Exit
|
|
// ----
|
|
|
|
fSuccess = TRUE;
|
|
|
|
Exit:
|
|
|
|
// If there was an error, ensure that the UDPROP is left as
|
|
// we found it.
|
|
|
|
if (!fSuccess)
|
|
{
|
|
if (lpstzOld != NULL)
|
|
{
|
|
if (lpudprop->lpstzName != NULL)
|
|
{
|
|
CoTaskMemFree (lpudprop->lpstzName);
|
|
}
|
|
lpudprop->lpstzName = lpstzOld;
|
|
}
|
|
}
|
|
|
|
return (fSuccess);
|
|
|
|
} // FUdpropMakeHidden
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUdpropSetString
|
|
//
|
|
// Purpose:
|
|
// Set the name or link-name string in a UDPROP.
|
|
// If the UDPROP already contains the string, free
|
|
// it.
|
|
//
|
|
// Inputs:
|
|
// LPUDPROP - A UDPROP (a property in the linked-list)
|
|
// LPTSTR - The new name or link-name
|
|
// BOOL - True => limit the length of the string to BUFMAX characters
|
|
// (including the NULL terminator)
|
|
// BOOL - True => set the (property) name, False => set the link-name
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static BOOL PASCAL
|
|
FUdpropSetString
|
|
(LPUDPROP lpudp,
|
|
LPTSTR lptstr,
|
|
BOOL fLimitLength,
|
|
BOOL fName)
|
|
{
|
|
// ------
|
|
// Locals
|
|
// ------
|
|
|
|
BOOL fSuccess = FALSE; // Return value
|
|
LPTSTR lptstrNew = NULL; // Pointed to be the UDPROP.
|
|
ULONG cch, cb;
|
|
|
|
// ----------
|
|
// Initialize
|
|
// ----------
|
|
|
|
// Validate the inputs.
|
|
|
|
if (lpudp == NULL || lptstr == NULL)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// ----------------
|
|
// Set the new name
|
|
// ----------------
|
|
|
|
// Calculate the sizes.
|
|
|
|
cch = lstrlen(lptstr);
|
|
if (fLimitLength && cch >= BUFMAX)
|
|
{
|
|
cch = BUFMAX - 1;
|
|
}
|
|
cb = (cch + 1) * sizeof(TCHAR); // Leave room for the NULL.
|
|
|
|
// Allocate new memory.
|
|
|
|
lptstrNew = CoTaskMemAlloc (cb);
|
|
if (lptstrNew == NULL)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Copy the buffer (the buffer size is cch+1 including the NULL)
|
|
// Also, terminate the target string, since it may be a truncation
|
|
// of the source string.
|
|
|
|
// Purposely truncate
|
|
StringCchCopy( lptstrNew, cch + 1, lptstr );
|
|
lptstrNew[cch] = TEXT('\0');
|
|
|
|
// Put this new buffer in the UDPROP.
|
|
|
|
if (fName)
|
|
{
|
|
lpudp->lpstzName = lptstrNew;
|
|
}
|
|
else
|
|
{
|
|
lpudp->lpstzLink = lptstrNew;
|
|
}
|
|
|
|
lptstrNew = NULL;
|
|
|
|
// ----
|
|
// Exit
|
|
// ----
|
|
|
|
fSuccess = TRUE;
|
|
|
|
Exit:
|
|
|
|
if (lptstrNew != NULL)
|
|
{
|
|
CoTaskMemFree (lptstrNew);
|
|
}
|
|
|
|
return (fSuccess);
|
|
|
|
} // FUdpropSetString
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// VUdpropFreeString
|
|
//
|
|
// Purpose:
|
|
// Free one of the two strings in a UDPROP - the
|
|
// name string or the link-name string. It is not
|
|
// considered an error if either the UDPROP or the
|
|
// string doesn't exist.
|
|
//
|
|
// Inputs:
|
|
// LPUDPROP - The UDPROP containing the strings.
|
|
// BOOL - TRUE indicates we should free the
|
|
// name, FALSE indicates we should free
|
|
// the link name.
|
|
//
|
|
// Output:
|
|
// None.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void PASCAL
|
|
VUdpropFreeString
|
|
(LPUDPROP lpudp,
|
|
BOOL fName)
|
|
{
|
|
|
|
// Is this really a UDPROP?
|
|
|
|
if (lpudp != NULL)
|
|
{
|
|
// Should we delete the name?
|
|
|
|
if (fName && lpudp->lpstzName)
|
|
{
|
|
CoTaskMemFree (lpudp->lpstzName);
|
|
lpudp->lpstzName = NULL;
|
|
}
|
|
|
|
// Should we delete the link name?
|
|
|
|
else if (!fName && lpudp->lpstzLink)
|
|
{
|
|
CoTaskMemFree (lpudp->lpstzLink);
|
|
lpudp->lpstzLink = NULL;
|
|
}
|
|
|
|
} // if (lpudp != NULL)
|
|
|
|
return;
|
|
|
|
} // VUdpropFreeString
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// LpudpropCreate
|
|
//
|
|
// Purpose:
|
|
// Create a new UDPROP structure (an element of a linked-
|
|
// list, and holds information about a single property).
|
|
//
|
|
// Inputs:
|
|
// None
|
|
//
|
|
// Output:
|
|
// A LPUDPROP if successful, NULL otherwise.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
LPUDPROP
|
|
LpudpropCreate ( void )
|
|
{
|
|
// Create a buffer for the UDPROP
|
|
|
|
LPUDPROP lpudp = CoTaskMemAlloc (sizeof(UDPROP));
|
|
|
|
// Zero the buffer.
|
|
|
|
if (lpudp != NULL)
|
|
{
|
|
ZeroMemory(lpudp, sizeof(UDPROP));
|
|
}
|
|
|
|
return (lpudp);
|
|
|
|
} // LpudpropCreate
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// LppropvarUserDefGetPropVal
|
|
//
|
|
// Purpose:
|
|
// Return a PropVariant pointer for the requested
|
|
// property (requested by property name).
|
|
//
|
|
// Inputs:
|
|
// LPUDOBJ - All UD data (including properties)
|
|
// LPTSTR - The name of the desired property
|
|
// BOOL * - True if this is a link.
|
|
// BOOL * - True if this link is invalid.
|
|
//
|
|
// Output:
|
|
// An LPPROPVARINT, or NULL if there was an error.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
DLLEXPORT LPPROPVARIANT
|
|
LppropvarUserDefGetPropVal
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
LPTSTR lpszProp, // Property string
|
|
BOOL *pfLink, // Indicates a link
|
|
BOOL *pfLinkInvalid) // Is the link invalid
|
|
{
|
|
// ------
|
|
// Locals
|
|
// ------
|
|
|
|
LPUDPROP lpudprop;
|
|
LPPROPVARIANT lppropvar;
|
|
|
|
// --------------
|
|
// Initialization
|
|
// --------------
|
|
|
|
if ((lpUDObj == NULL) ||
|
|
(lpData == NULL) ||
|
|
(lpszProp == NULL))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// ---------------------------------
|
|
// Find the node that has this name.
|
|
// ---------------------------------
|
|
|
|
lpudprop = LpudpropFindMatchingName (lpUDObj, lpszProp);
|
|
if (lpudprop == NULL)
|
|
return NULL;
|
|
|
|
// Is this a link?
|
|
if (pfLink != NULL)
|
|
{
|
|
*pfLink = (lpudprop->lpstzLink != NULL);
|
|
}
|
|
|
|
// Is this an invalid link? (In the Shell, all properties are
|
|
// invalid).
|
|
|
|
if (pfLinkInvalid != NULL)
|
|
{
|
|
*pfLinkInvalid = lpudprop->fLinkInvalid = TRUE;
|
|
}
|
|
|
|
// ----
|
|
// Exit
|
|
// ----
|
|
|
|
return (lpudprop->lppropvar);
|
|
|
|
} // LppropvarUserDefGetPropVal
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// LppropvarUserDefGetIteratorVal
|
|
//
|
|
// Purpose:
|
|
// Given an iterator value, get the property value.
|
|
//
|
|
// Inputs:
|
|
// LPUDITER - The Iterator value.
|
|
// BOOL * - Set to True if this value is a link.
|
|
// BOLL * - Set to True if this value is invalid link.
|
|
//
|
|
// Outputs:
|
|
// LPPROPVARIANT of the property value.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
DLLEXPORT LPPROPVARIANT
|
|
LppropvarUserDefGetIteratorVal
|
|
(LPUDITER lpUDIter,
|
|
BOOL *pfLink,
|
|
BOOL *pfLinkInvalid )
|
|
{
|
|
// Validate the inputs
|
|
|
|
if ((lpUDIter == NULL) ||
|
|
(lpUDIter->lpudp == NULL))
|
|
return NULL;
|
|
|
|
// Is this a Link?
|
|
|
|
if (pfLink != NULL)
|
|
{
|
|
*pfLink = (lpUDIter->lpudp->lpstzLink != NULL);
|
|
}
|
|
|
|
// Is this an invalid link?
|
|
|
|
if (pfLinkInvalid != NULL)
|
|
{
|
|
*pfLinkInvalid = lpUDIter->lpudp->fLinkInvalid;
|
|
}
|
|
|
|
// Return a pointer to the PropVariant
|
|
|
|
return (lpUDIter->lpudp->lppropvar);
|
|
|
|
} // LpvoidUserDefGetIteratorVal
|