mirror of https://github.com/lianthony/NT4.0
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.
2401 lines
65 KiB
2401 lines
65 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
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "priv.h"
|
|
#pragma hdrstop
|
|
|
|
#ifndef WINNT
|
|
//#include <string.h>
|
|
#define INC_OLE2
|
|
#include "office.h"
|
|
// REVIEW: Fix the INITGUID stuff to not use pre-compiled headers.....
|
|
#define INITGUID
|
|
#include <initguid.h>
|
|
|
|
#include "proptype.h"
|
|
#include "internal.h"
|
|
#include "propmisc.h"
|
|
#include "debug.h"
|
|
#endif
|
|
|
|
static LPSTR PASCAL LpstzNameFromPID (LPDICT *rglpdict, DWORD dwPId);
|
|
static void PASCAL RemoveFromList (LPUDOBJ lpUDObj, LPUDPROP lpudprop);
|
|
static void PASCAL DeallocNode (LPUDOBJ lpUDObj, LPUDPROP lpudp);
|
|
static void PASCAL DeallocStrings (LPUDOBJ lpUDObj, LPUDPROP lpudp);
|
|
static DWORD PASCAL CbPropVal (LPUDPROP lpudprop);
|
|
static BOOL PASCAL FUpdateUdprop (LPUDOBJ lpUDObj, LPSTR lpszPropName, LPUDPROP lpudp, LPVOID lpv,
|
|
UDTYPES udtype, LPSTR lpszLinkMonik, BOOL fLink, BOOL fIMoniker);
|
|
|
|
#ifdef OLE_PROPS
|
|
|
|
// Access to the object must be cast up to a LPUSERPROP for OLE objects
|
|
#define lpDocObj ((LPUSERPROP) lpUDObj)
|
|
#define lpData ((LPUDINFO) ((LPUSERPROPS) lpUDObj)->m_lpData);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// HrPropExUdpQueryInterface
|
|
// (IUnknown::QueryInterface)
|
|
//
|
|
// Purpose:
|
|
// IUnknown method to query interfaces available.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT HRESULT
|
|
HrUserDefQueryInterface
|
|
(IUnknown FAR *lpUnk, // Pointer to the object
|
|
REFIID riid, // Pointer to interface Id
|
|
LPVOID FAR* ppvObj) // Interface to return.
|
|
{
|
|
|
|
*ppvObj = NULL;
|
|
|
|
return E_NOTIMPL;
|
|
|
|
} // HrUserDefQueryInterface
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// UlUserDefAddRef
|
|
// (IUnknown::AddRef)
|
|
//
|
|
// Purpose:
|
|
// Increments object reference count.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT ULONG
|
|
UlUserDefAddRef
|
|
(IUnknown FAR *lpUnk) // Pointer to the object
|
|
{
|
|
|
|
return 0;
|
|
|
|
} // UlUserDefAddRef
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// UlUserDefRelease
|
|
// (IUnknown::Release)
|
|
//
|
|
// Purpose:
|
|
// Decrements reference count, possibly freeing object.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT ULONG
|
|
UlUserDefRelease
|
|
(IUnkown FAR *lpUnk) // Pointer to object
|
|
{
|
|
|
|
return 0;
|
|
|
|
} // UlUserDefRelease
|
|
|
|
#else // !OLE_PROPS
|
|
|
|
// Do nothing for non-OLE code....
|
|
#define lpDocObj lpUDObj
|
|
#define lpData ((LPUDINFO) lpUDObj->m_lpData)
|
|
|
|
#endif // OLE_PROPS
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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;
|
|
DeallocNode (lpUDObj, lpudpT);
|
|
}
|
|
|
|
if (fTmp)
|
|
{
|
|
lpData->lpudpTmpCache = NULL;
|
|
lpData->lpudpTmpHead = NULL;
|
|
lpData->dwcTmpProps = 0;
|
|
lpData->dwcTmpLinks = 0;
|
|
lpData->dwcTmpIMonikers = 0;
|
|
}
|
|
else
|
|
{
|
|
lpData->lpudpCache = NULL;
|
|
lpData->lpudpHead = NULL;
|
|
lpData->dwcProps = 0;
|
|
lpData->dwcLinks = 0;
|
|
lpData->dwcIMonikers = 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 = PvMemAlloc(sizeof(USERPROP))) == NULL)
|
|
{
|
|
// REVIEW: Add alert
|
|
return FALSE;
|
|
}
|
|
|
|
lpDocObj = *lplpUDObj;
|
|
|
|
// If alloc fails, free the original object too.
|
|
if ((lpData = PvMemAlloc(sizeof (UDINFO))) == NULL)
|
|
{
|
|
// REVIEW: Add alert
|
|
VFreeMemP(*lplpUDObj, sizeof(USERPROP));
|
|
return FALSE;
|
|
}
|
|
|
|
FillBuf ((void *) lpData, (int) 0, sizeof(UDINFO) );
|
|
|
|
// Save the fnc's for code page convert, SzToNum, NumToSz
|
|
lpData->lpfnFCPConvert = (BOOL (*)(LPSTR, DWORD, DWORD, BOOL)) prglpfn[ifnCPConvert];
|
|
lpData->lpfnFSzToNum = (BOOL (*)(NUM *, LPSTR)) prglpfn[ifnFSzToNum];
|
|
lpData->lpfnFNumToSz = (BOOL (*)(NUM *, LPSTR, DWORD)) prglpfn[ifnFNumToSz];
|
|
|
|
OfficeDirtyUDObj (*lplpUDObj, FALSE);
|
|
|
|
return TRUE;
|
|
|
|
} // FUserDefCreate
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUserDefDestroy
|
|
//
|
|
// Purpose:
|
|
// Destroy a User-defined property exchange object.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
FUserDefDestroy
|
|
(LPUDOBJ FAR *lplpUDObj) // Pointer to pointer to object
|
|
{
|
|
#define lpUDData ((LPUDINFO)(((LPUDOBJ) *lplpUDObj)->m_lpData))
|
|
|
|
DWORD irg;
|
|
|
|
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);
|
|
|
|
if (lpUDData->cbUnkMac > 0)
|
|
FreeRglpUnk(lpUDData->rglpUnk, lpUDData->cbUnkMac);
|
|
|
|
if (lpUDData->rglpUnk != NULL)
|
|
VFreeMemP(lpUDData->rglpUnk, lpUDData->cbUnkMac*sizeof(PROPIDTYPELP));
|
|
|
|
if (lpUDData->rglpFIdOffData != NULL)
|
|
{
|
|
for (irg = 0; irg < lpUDData->cSect; ++irg)
|
|
{
|
|
if (lpUDData->rglpFIdOffData[irg] != NULL)
|
|
VFreeMemP(lpUDData->rglpFIdOffData[irg], lpUDData->rglpSect[irg].cb-sizeof(SECTION));
|
|
}
|
|
VFreeMemP(lpUDData->rglpFIdOffData, lpUDData->cSect*sizeof(LPVOID));
|
|
}
|
|
|
|
if (lpUDData->rglpFIdOff != NULL)
|
|
VFreeMemP(lpUDData->rglpFIdOff, lpUDData->cSect*sizeof(IDOFFSET));
|
|
if (lpUDData->rglpSect != NULL)
|
|
VFreeMemP(lpUDData->rglpSect, lpUDData->cSect*sizeof(SECTION));
|
|
|
|
VFreeMemP((*lplpUDObj)->m_lpData, sizeof(UDINFO));
|
|
}
|
|
|
|
VFreeMemP(*lplpUDObj, sizeof(USERPROP));
|
|
*lplpUDObj = NULL;
|
|
return TRUE;
|
|
|
|
#undef lpUDData
|
|
} // 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.
|
|
FillBuf ((void *) lpData, (int) 0, (sizeof (UDINFO) - ifnUDMax*(sizeof (void *))));
|
|
|
|
OfficeDirtyUDObj (lpUDObj, TRUE);
|
|
return TRUE;
|
|
|
|
} // FUserDefClear
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FreeRgDictionary
|
|
//
|
|
// Purpose:
|
|
// Frees an array of dictionaries.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void PASCAL
|
|
FreeRgDictionary
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
LPDICT *rglpDict) // Array of dict entries
|
|
{
|
|
int irg;
|
|
LPDICT lpDictT, lpDict;
|
|
|
|
for (irg = 0; irg < DICTHASHMAX; irg++)
|
|
{
|
|
if (rglpDict[irg] != NULL)
|
|
{
|
|
lpDict = rglpDict[irg];
|
|
while (lpDict != NULL)
|
|
{
|
|
lpDictT = lpDict;
|
|
lpDict = (LPDICT) lpDict->llist.lpllistNext;
|
|
VFreeMemP(lpDictT->lpstz, CBBUF(lpDictT->lpstz));
|
|
VFreeMemP(lpDictT, sizeof(DICT));
|
|
}
|
|
}
|
|
}
|
|
} // FreeRgDictionary
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FCreateUserDefPIdTable
|
|
//
|
|
// Purpose:
|
|
// Calculate the Property Id-offset table for the User-defined object
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
FCreateUserDefPIdTable
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
LPPIDOFFSET *lprgPO, // PId-offset table
|
|
DWORD *lpirgPOMac, // Number of elements in lprgPO
|
|
DWORD *pcb, // Size of the section
|
|
LPDICT *lplpdict) // The dictionary.
|
|
{
|
|
DWORD dwcEntriesMac;
|
|
DWORD irgPO;
|
|
DWORD irg;
|
|
DWORD dwOffset;
|
|
DWORD dwDictSize;
|
|
DWORD dwPId;
|
|
LPDICT lpdictcur;
|
|
LPDICT lpdictprev;
|
|
LPUDPROP lpudp;
|
|
|
|
if ((lpDocObj == NULL) ||
|
|
(lpData == NULL) ||
|
|
(lprgPO == NULL) ||
|
|
(lplpdict == NULL) ||
|
|
(pcb == NULL) ||
|
|
(lpirgPOMac == NULL))
|
|
return FALSE;
|
|
|
|
// Figure out the maximum number of things we have to write out
|
|
dwcEntriesMac = lpData->dwcProps+lpData->dwcLinks+lpData->dwcIMonikers+lpData->cbUnkMac;
|
|
|
|
// If there's no data, we're NOT going to save.
|
|
if (!(dwcEntriesMac))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Create the biggest PropId-offset table we might need - don't forget to add
|
|
// a slot for the dictionary and codepage
|
|
dwcEntriesMac += 2;
|
|
*lpirgPOMac = dwcEntriesMac;
|
|
*lprgPO = PvMemAlloc(sizeof(PIDOFFSET)*(dwcEntriesMac));
|
|
if (*lprgPO == NULL)
|
|
{
|
|
// REVIEW: add alert
|
|
return FALSE;
|
|
}
|
|
|
|
*lplpdict = lpdictcur = lpdictprev = NULL;
|
|
|
|
// Insert the dictionary first in the PO table (it must be first)
|
|
(*lprgPO)[0].Id = PID_DICT;
|
|
(*lprgPO)[0].dwOffset = 0;
|
|
|
|
// Add in the codepage for this file second
|
|
(*lprgPO)[1].Id = PID_CODEPAGE;
|
|
(*lprgPO)[1].dwOffset = 0;
|
|
irgPO = 2;
|
|
dwOffset = 2*sizeof(DWORD);
|
|
|
|
dwDictSize = sizeof(DWORD); // All dicts have DWORD count of entries
|
|
dwPId = 2; // PIds must be >= 2
|
|
|
|
// Since we bail if there are not properties, there must be at least
|
|
// one at this point. Create the first dictionary entry.
|
|
lpdictprev = NULL;
|
|
lpdictcur = *lplpdict = PvMemAlloc(sizeof(DICT));
|
|
if (*lplpdict == NULL)
|
|
{
|
|
goto SaveFail;
|
|
}
|
|
|
|
// Traverse the list, adding up everything. Fill out the dictionary too.
|
|
lpudp = lpData->lpudpHead;
|
|
while (lpudp != NULL)
|
|
{
|
|
// Add this property to the dictionary. Don't bother making the
|
|
// dictionary doubly-linked.
|
|
if (lpdictcur == NULL)
|
|
{
|
|
lpdictcur = PvMemAlloc(sizeof(DICT));
|
|
if (lpdictcur == NULL)
|
|
{
|
|
goto SaveFail;
|
|
}
|
|
|
|
Assert ((lpdictprev != NULL));
|
|
lpdictprev->llist.lpllistNext = (LPLLIST) lpdictcur;
|
|
}
|
|
|
|
lpdictcur->lpstz = lpudp->lpstzName;
|
|
lpdictcur->dwPId = (*lprgPO)[irgPO].Id = dwPId;
|
|
lpdictcur->llist.lpllistNext = NULL;
|
|
lpdictprev = lpdictcur;
|
|
lpdictcur = NULL;
|
|
|
|
// The size of each entry is the length of the string + the size
|
|
// of the Id (DWORD) and the count of chars in the string (DWORD)
|
|
dwDictSize += CBSTR (lpudp->lpstzName) + 2*sizeof(DWORD);
|
|
|
|
(*lprgPO)[irgPO].dwOffset = dwOffset;
|
|
|
|
switch (lpudp->udtype)
|
|
{
|
|
case wUDlpsz :
|
|
Assert ((lpudp->lpvValue != NULL));
|
|
dwOffset += 2*sizeof(DWORD) + CBSTR ((LPSTR) lpudp->lpvValue);
|
|
dwOffset += CBALIGN32 (dwOffset);
|
|
break;
|
|
|
|
case wUDdate :
|
|
case wUDfloat :
|
|
// Both Date and double are stored as 64-bit values in the stream,
|
|
// and are the same size in 32-bit land.
|
|
AssertSz ((sizeof(NUM) == 8), "Ok, who changed the sizes of basic types?");
|
|
AssertSz ((sizeof(FILETIME) == 8), "Ok, who changed the sizes of basic types?");
|
|
dwOffset += sizeof(DWORD) + sizeof(NUM);
|
|
break;
|
|
|
|
case wUDdw :
|
|
case wUDbool :
|
|
// In OLE, VT_BOOL is stored as a WORD, but must be aligned
|
|
// on a 32-bit boundary, so it gets rounded up to a DWORD anyway.
|
|
dwOffset += 2*sizeof(DWORD);
|
|
break;
|
|
|
|
default :
|
|
AssertSz (0, "We're hosed - map lpData->rglpupd is corrupt.");
|
|
|
|
} // switch
|
|
|
|
// If we have link data, it doesn't go in the dictionary,
|
|
// but it will go in the stream as a separate property
|
|
if (lpudp->lpstzLink != NULL)
|
|
{
|
|
irgPO++;
|
|
(*lprgPO)[irgPO].Id = dwPId | PID_LINKMASK;
|
|
(*lprgPO)[irgPO].dwOffset = dwOffset;
|
|
dwOffset += 2*sizeof(DWORD) + CBSTR ((LPSTR) lpudp->lpstzLink);
|
|
dwOffset += CBALIGN32 (dwOffset);
|
|
}
|
|
// Same goes for IMoniker data
|
|
if (lpudp->lpstzIMoniker != NULL)
|
|
{
|
|
irgPO++;
|
|
(*lprgPO)[irgPO].Id = dwPId | PID_IMONIKERMASK;
|
|
(*lprgPO)[irgPO].dwOffset = dwOffset;
|
|
dwOffset += 2*sizeof(DWORD) + CBSTR ((LPSTR) lpudp->lpstzIMoniker);
|
|
dwOffset += CBALIGN32 (dwOffset);
|
|
}
|
|
|
|
irgPO++;
|
|
dwPId++;
|
|
lpudp = (LPUDPROP) lpudp->llist.lpllistNext;
|
|
|
|
} // while
|
|
|
|
// Now go back and adjust the offsets to start after the dictionary....
|
|
// Remember that the first entry in the table is the dictionary, so
|
|
// start after it.....
|
|
for (irg = 1; irg < irgPO; irg++)
|
|
{
|
|
(*lprgPO)[irg].dwOffset += dwDictSize;
|
|
}
|
|
dwOffset += dwDictSize;
|
|
|
|
// Now do all the ones we didn't understand.
|
|
for (irg = 0; irg < lpData->cbUnkMac; irg++)
|
|
{
|
|
(*lprgPO)[irgPO].Id = lpData->rglpUnk[irg].dwId;
|
|
(*lprgPO)[irgPO].dwOffset = dwOffset;
|
|
dwOffset += lpData->rglpUnk[irg].dwSize + sizeof (DWORD);
|
|
dwOffset += CBALIGN32 (dwOffset);
|
|
irgPO++;
|
|
}
|
|
|
|
*pcb = dwOffset;
|
|
return TRUE;
|
|
|
|
SaveFail :
|
|
|
|
if (lpdictcur != NULL)
|
|
VFreeMemP(lpdictcur,sizeof(DICT));
|
|
|
|
return FALSE;
|
|
|
|
} // FCreateUserDefPIdTable
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FreeDictionaryAlone
|
|
//
|
|
// Purpose:
|
|
// Free's the dictionary, but not the strings in it (because they are
|
|
// only pointers to data stored in the map, not actual copies)
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void PASCAL
|
|
FreeDictionaryAlone
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
LPDICT lpDict) // Pointer to the dictionary
|
|
{
|
|
LPDICT lpd;
|
|
|
|
while (lpDict != NULL)
|
|
{
|
|
lpd = lpDict;
|
|
lpDict = (LPDICT) lpDict->llist.lpllistNext;
|
|
VFreeMemP(lpd, sizeof(DICT));
|
|
}
|
|
} // FreeDictionaryAlone
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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
|
|
|
|
|
|
#ifdef UNUSED
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUserDefIsEmpty
|
|
//
|
|
// Purpose:
|
|
// Indicates that the object is empty.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT BOOL
|
|
FUserDefIsEmpty
|
|
(LPUDOBJ lpUDObj) // Pointer to object
|
|
{
|
|
if (lpUDObj == NULL)
|
|
return TRUE;
|
|
|
|
return lpDocObj->m_fObjEmpty;
|
|
|
|
} // FUserDefIsEmpty
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUserDefSetPropString
|
|
//
|
|
// Purpose:
|
|
// Set the string for the given Property String (lpszOld) to the new
|
|
// string (lpszNew).
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT BOOL
|
|
FUserDefSetPropString
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
LPSTR lpszOld, // Old prop string
|
|
LPSTR lpszNew) // New prop string
|
|
{
|
|
LPUDPROP lpudprop;
|
|
|
|
if ((lpUDObj == NULL) ||
|
|
(lpData == NULL) ||
|
|
(lpszOld == NULL) ||
|
|
(lpszNew == NULL))
|
|
return FALSE;
|
|
|
|
// Find the old one
|
|
lpudprop = LpudpropFindMatchingName (lpUDObj, lpszOld);
|
|
if (lpudprop == NULL)
|
|
return FALSE;
|
|
|
|
// Update the node
|
|
lpudprop->lpstzName = LpstzUpdateString (&(lpudprop->lpstzName), lpszNew, TRUE);
|
|
|
|
OfficeDirtyUDObj (lpUDObj, TRUE);
|
|
return TRUE;
|
|
|
|
} // FUserDefSetPropString
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FCUserDefNumProps
|
|
//
|
|
// Purpose:
|
|
// Determine the number of user-defined properties for the object.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT BOOL
|
|
FCUserDefNumProps
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
DWORD *pdw)
|
|
{
|
|
if ((lpUDObj == NULL) ||
|
|
(lpData == NULL))
|
|
return FALSE;
|
|
|
|
*pdw = lpData->dwcProps;
|
|
return TRUE;
|
|
|
|
} // CUserDefNumProps
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FCbUserDefPropVal
|
|
//
|
|
// Purpose:
|
|
// Determine the size of the Property Value for the given Property string
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT BOOL
|
|
FCbUserDefPropVal
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
LPSTR lpsz, // Pointer to string
|
|
DWORD dwMask, // Mask telling what value to get cb for
|
|
DWORD *pdw) // Pointer to dword
|
|
{
|
|
LPUDPROP lpudprop;
|
|
|
|
if ((lpUDObj == NULL) ||
|
|
(lpData == NULL) ||
|
|
(lpsz == NULL))
|
|
return FALSE;
|
|
|
|
// Find the node that has this name.
|
|
lpudprop = LpudpropFindMatchingName (lpUDObj, lpsz);
|
|
if (lpudprop == NULL)
|
|
return FALSE;
|
|
|
|
// Return the size based on the flags.
|
|
if (dwMask & UD_LINK)
|
|
{
|
|
if (lpudprop->lpstzLink == NULL)
|
|
return(FALSE);
|
|
*pdw = CBSTR (lpudprop->lpstzLink);
|
|
}
|
|
else if (dwMask & UD_IMONIKER)
|
|
{
|
|
if (lpudprop->lpstzIMoniker == NULL)
|
|
return(FALSE);
|
|
*pdw = CBSTR (lpudprop->lpstzIMoniker);
|
|
}
|
|
else
|
|
*pdw = CbPropVal (lpudprop);
|
|
|
|
return(TRUE);
|
|
|
|
} // FCbUserDefPropVal
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// UdtypesUserDefType
|
|
//
|
|
// Purpose:
|
|
// Returns the type of the given Property Value from the string
|
|
//
|
|
// Returns wUDInvalid on error
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT UDTYPES
|
|
UdtypesUserDefType
|
|
(LPUDOBJ lpUDObj,
|
|
LPSTR 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)
|
|
return wUDinvalid;
|
|
|
|
return lpudprop->udtype;
|
|
|
|
} // UdtypesUserDefType
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// LpvoidUserDefGetPropVal
|
|
//
|
|
// Purpose:
|
|
// This will return the Property Value for the given Property String.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT LPVOID
|
|
LpvoidUserDefGetPropVal
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
LPSTR lpszProp, // Property string
|
|
DWORD cbMax, // Size of lpv
|
|
LPVOID lpv, // Buffer for prop val
|
|
DWORD dwMask, // Mask for what value is needed
|
|
BOOL *pfLink, // Indicates a link
|
|
BOOL *pfIMoniker, // Indicates an IMoniker
|
|
BOOL *pfLinkInvalid) // Is the link invalid
|
|
{
|
|
LPUDPROP lpudprop;
|
|
|
|
if ((lpUDObj == NULL) ||
|
|
(lpData == NULL) ||
|
|
(lpszProp == NULL) ||
|
|
(cbMax == 0) ||
|
|
(pfLink == NULL) ||
|
|
(pfIMoniker == NULL)||
|
|
(pfLinkInvalid == NULL) ||
|
|
((lpv == NULL) && (!(dwMask & UD_PTRWIZARD))))
|
|
return NULL;
|
|
|
|
// Find the node that has this name.
|
|
lpudprop = LpudpropFindMatchingName (lpUDObj, lpszProp);
|
|
if (lpudprop == NULL)
|
|
return NULL;
|
|
|
|
*pfLink = (lpudprop->lpstzLink != NULL);
|
|
*pfIMoniker = (lpudprop->lpstzIMoniker != NULL);
|
|
*pfLinkInvalid = lpudprop->fLinkInvalid;
|
|
|
|
// Return based on the type and flags
|
|
if (dwMask & UD_LINK)
|
|
{
|
|
if (dwMask & UD_PTRWIZARD)
|
|
{
|
|
if (lpudprop->lpstzLink != NULL)
|
|
return((LPVOID) (PSTR (lpudprop->lpstzLink)));
|
|
return(NULL);
|
|
}
|
|
|
|
if (lpudprop->lpstzLink != NULL)
|
|
return(FCopyValueToBuf(lpv, cbMax, (LPVOID) lpudprop->lpstzLink, wUDlpsz) ? lpv : NULL);
|
|
else
|
|
return(NULL);
|
|
}
|
|
|
|
if (dwMask & UD_IMONIKER)
|
|
{
|
|
if (dwMask & UD_PTRWIZARD)
|
|
{
|
|
if (lpudprop->lpstzIMoniker != NULL)
|
|
return((LPVOID) (PSTR (lpudprop->lpstzIMoniker)));
|
|
return(NULL);
|
|
}
|
|
|
|
if (lpudprop->lpstzIMoniker != NULL)
|
|
return(FCopyValueToBuf(lpv, cbMax, (LPVOID) lpudprop->lpstzIMoniker, wUDlpsz) ? lpv : NULL);
|
|
else
|
|
return(NULL);
|
|
}
|
|
|
|
if (dwMask & UD_PTRWIZARD)
|
|
return (lpudprop->udtype == wUDlpsz) ? ((LPVOID) (PSTR ((LPSTR) lpudprop->lpvValue))) : lpudprop->lpvValue;
|
|
|
|
return(FCopyValueToBuf(lpv, cbMax, lpudprop->lpvValue, lpudprop->udtype) ? lpv : NULL);
|
|
|
|
} // LpvoidUserDefGetPropVal
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUserDefIteratorChangeVal
|
|
//
|
|
// Purpose:
|
|
// Changes the value of the data stored.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLFUNC BOOL OFC_CALLTYPE
|
|
FUserDefChangeVal
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
LPSTR lpszProp, // Property string
|
|
UDTYPES udtype, // Type of new value
|
|
LPVOID lpv, // New value.
|
|
BOOL fLinkInvalid) // Is the link still valid?
|
|
{
|
|
LPUDPROP lpudp;
|
|
|
|
if ((lpUDObj == NULL) ||
|
|
(lpData == NULL) ||
|
|
(lpszProp == NULL))
|
|
return FALSE;
|
|
|
|
// Find the node that has this name.
|
|
lpudp = LpudpropFindMatchingName (lpUDObj, lpszProp);
|
|
if (lpudp == NULL)
|
|
return FALSE;
|
|
|
|
if (fLinkInvalid)
|
|
{
|
|
if (lpudp->lpstzLink == NULL)
|
|
return FALSE;
|
|
lpudp->fLinkInvalid = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
lpudp->fLinkInvalid = FALSE;
|
|
|
|
// Dealloc the currently stored value.
|
|
DeallocValue (&(lpudp->lpvValue), lpudp->udtype);
|
|
|
|
// Copy the new value in. Passing udtype as wUDinvalid just tells
|
|
// us not to modify the type.
|
|
if (udtype != wUDinvalid)
|
|
lpudp->udtype = udtype;
|
|
|
|
lpudp->lpvValue =
|
|
LpvCopyValue (&(lpudp->lpvValue), 0, lpv,lpudp->udtype, FALSE, TRUE);
|
|
|
|
OfficeDirtyUDObj (lpUDObj, TRUE);
|
|
return TRUE;
|
|
|
|
} // FUserDefChangeVal
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUserDefAddProp
|
|
//
|
|
// Purpose:
|
|
// This will add a new Property to the set, with the given
|
|
// Property string, type and data.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT BOOL
|
|
FUserDefAddProp
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
LPSTR lpszPropName, // Property string
|
|
LPVOID lpv, // Property value
|
|
UDTYPES udtype, // Property type
|
|
LPSTR lpszLinkMonik, // The link/imoniker name
|
|
BOOL fLink, // Indicates the property is a link
|
|
BOOL fHidden, // Indicates the property is hidden
|
|
BOOL fIMoniker) // Indicates the property is a moniker.
|
|
{
|
|
LPUDPROP lpudprop;
|
|
LPUDPROP lpudpropMatch;
|
|
BOOL fCreated;
|
|
|
|
if ((lpUDObj == NULL) ||
|
|
(lpData == NULL) ||
|
|
(lpszPropName == NULL) ||
|
|
(*lpszPropName == 0) ||
|
|
(lpv == NULL) ||
|
|
(fLink && fIMoniker) ||
|
|
(fLink && (lpszLinkMonik == NULL)) ||
|
|
(fIMoniker && (lpszLinkMonik == NULL)) ||
|
|
(udtype == wUDinvalid))
|
|
return FALSE;
|
|
|
|
lpudprop = PvMemAlloc(sizeof(UDPROP));
|
|
if (lpudprop == NULL)
|
|
return FALSE;
|
|
FillBuf (lpudprop, 0, sizeof(UDPROP));
|
|
if(!FUpdateUdprop (lpUDObj, lpszPropName, lpudprop, lpv, udtype, lpszLinkMonik, fLink, fIMoniker))
|
|
{
|
|
DeallocNode(lpUDObj, 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++;
|
|
if (fIMoniker)
|
|
lpData->dwcIMonikers++;
|
|
lpData->dwcProps++;
|
|
AddNodeToList (lpUDObj, lpudprop);
|
|
}
|
|
else
|
|
{
|
|
DeallocStrings(lpUDObj, lpudpropMatch);
|
|
DeallocValue(&(lpudpropMatch->lpvValue), lpudpropMatch->udtype);
|
|
lpudprop->llist=lpudpropMatch->llist;
|
|
PbMemCopy(lpudpropMatch, lpudprop, sizeof(UDPROP));
|
|
VFreeMemP(lpudprop, sizeof(UDPROP));
|
|
}
|
|
// If the client asked for a hidden property, do it if
|
|
// the name was the real name, not a link or IMoniker
|
|
if ((fHidden) && (!(fLink || fIMoniker)))
|
|
{
|
|
fCreated=FUserDefMakeHidden (lpUDObj, lpszPropName); // Should never return false
|
|
Assert(fCreated);
|
|
}
|
|
|
|
OfficeDirtyUDObj (lpUDObj, TRUE);
|
|
return TRUE;
|
|
|
|
} // FUserDefAddProp
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUserDefDeleteProp
|
|
//
|
|
// Purpose:
|
|
// This will delete a Property from the set given a Property string.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT BOOL
|
|
FUserDefDeleteProp
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
LPSTR 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--;
|
|
|
|
if (lpudprop->lpstzIMoniker != NULL)
|
|
lpData->dwcIMonikers--;
|
|
|
|
RemoveFromList (lpUDObj, lpudprop);
|
|
DeallocNode (lpUDObj, 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 = PvMemAlloc(sizeof(UDITER));
|
|
if (lpudi == NULL)
|
|
return(NULL);
|
|
|
|
FillBuf (lpudi, 0, sizeof (UDITER));
|
|
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;
|
|
|
|
VFreeMemP(*lplpUDIter, sizeof(UDITER));
|
|
*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
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUserDefIteratorIsLinkInvalid
|
|
//
|
|
// Purpose:
|
|
// Returns TRUE if the iterator is an invalid link, FALSE otherwise
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT BOOL
|
|
FUserDefIteratorIsLinkInvalid
|
|
(LPUDITER lpUDIter) // Pointer to iterator
|
|
{
|
|
if ((lpUDIter == NULL) || (lpUDIter->lpudp == NULL))
|
|
return(FALSE);
|
|
|
|
if (lpUDIter->lpudp->lpstzLink == NULL)
|
|
return(FALSE);
|
|
|
|
return(lpUDIter->lpudp->fLinkInvalid);
|
|
|
|
} // FUserDefIteratorIsLinkInvalid
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FCbUserDefIteratorVal
|
|
//
|
|
// Purpose:
|
|
// Determine the size of the Property Value for the given iterator
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT BOOL
|
|
FCbUserDefIteratorVal
|
|
(LPUDITER lpUDIter, // Pointer to iterator
|
|
DWORD dwMask, // Mask indicating cb to get
|
|
DWORD *pcb)
|
|
{
|
|
if ((lpUDIter == NULL) ||
|
|
(lpUDIter->lpudp == NULL))
|
|
return FALSE;
|
|
|
|
// Return the size based on the flags.
|
|
if (dwMask & UD_LINK)
|
|
{
|
|
if (lpUDIter->lpudp->lpstzLink == NULL)
|
|
return FALSE;
|
|
*pcb = CBSTR (lpUDIter->lpudp->lpstzLink);
|
|
}
|
|
else if (dwMask & UD_IMONIKER)
|
|
{
|
|
if (lpUDIter->lpudp->lpstzIMoniker == NULL)
|
|
return FALSE;
|
|
*pcb = CBSTR (lpUDIter->lpudp->lpstzIMoniker);
|
|
}
|
|
else
|
|
*pcb = CbPropVal (lpUDIter->lpudp);
|
|
|
|
return TRUE;
|
|
|
|
} // FCbUserDefIteratorVal
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// UdtypesUserDefIteratorType
|
|
//
|
|
// Purpose:
|
|
// Returns the type of the given Property Value from the iterator
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT UDTYPES
|
|
UdtypesUserDefIteratorType
|
|
(LPUDITER lpUDIter) // Pointer to iterator
|
|
{
|
|
if ((lpUDIter == NULL) ||
|
|
(lpUDIter->lpudp == NULL))
|
|
return wUDinvalid;
|
|
|
|
return lpUDIter->lpudp->udtype;
|
|
|
|
} // UdtypesUserDefIteratorType
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// LpvoidUserDefGetIteratorVal
|
|
//
|
|
// Purpose:
|
|
// This will return the Property Value for the given iterator
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT LPVOID
|
|
LpvoidUserDefGetIteratorVal
|
|
(LPUDITER lpUDIter, // Pointer to iterator
|
|
DWORD cbMax, // Max size of lpv
|
|
LPVOID lpv, // Buffer to copy data value to
|
|
DWORD dwMask, // Mask indicating the value to get
|
|
BOOL *pfLink, // Flag indicating the link is desired
|
|
BOOL *pfIMoniker, // Flag indicating the moniker is desired
|
|
BOOL *pfLinkInvalid) // Flag indicating if the is invalid
|
|
{
|
|
if ((cbMax == 0) ||
|
|
((lpv == NULL) && (!(dwMask & UD_PTRWIZARD))) ||
|
|
(lpUDIter == NULL) ||
|
|
(pfLink == NULL) ||
|
|
(pfIMoniker == NULL)||
|
|
(lpUDIter->lpudp == NULL))
|
|
return NULL;
|
|
|
|
*pfLink = (lpUDIter->lpudp->lpstzLink != NULL);
|
|
*pfIMoniker = (lpUDIter->lpudp->lpstzIMoniker != NULL);
|
|
*pfLinkInvalid = lpUDIter->lpudp->fLinkInvalid;
|
|
|
|
// Return based on the type and flags
|
|
if (dwMask & UD_LINK)
|
|
{
|
|
if (dwMask & UD_PTRWIZARD)
|
|
{
|
|
if (lpUDIter->lpudp->lpstzLink != NULL)
|
|
return((LPVOID) (PSTR (lpUDIter->lpudp->lpstzLink)));
|
|
return(NULL);
|
|
}
|
|
|
|
if (lpUDIter->lpudp->lpstzLink != NULL)
|
|
return(FCopyValueToBuf(lpv, cbMax, (LPVOID) lpUDIter->lpudp->lpstzLink, wUDlpsz) ? lpv : NULL);
|
|
else
|
|
return(NULL);
|
|
}
|
|
|
|
if (dwMask & UD_IMONIKER)
|
|
{
|
|
if (dwMask & UD_PTRWIZARD)
|
|
{
|
|
if (lpUDIter->lpudp->lpstzIMoniker != NULL)
|
|
return((LPVOID) (PSTR (lpUDIter->lpudp->lpstzIMoniker)));
|
|
return(NULL);
|
|
}
|
|
|
|
if (lpUDIter->lpudp->lpstzIMoniker != NULL)
|
|
return(FCopyValueToBuf(lpv, cbMax, (LPVOID) lpUDIter->lpudp->lpstzIMoniker, wUDlpsz) ? lpv : NULL);
|
|
else
|
|
return(NULL);
|
|
}
|
|
|
|
if (dwMask & UD_PTRWIZARD)
|
|
return (lpUDIter->lpudp->udtype == wUDlpsz) ? ((LPVOID) (PSTR ((LPSTR) lpUDIter->lpudp->lpvValue)))
|
|
: lpUDIter->lpudp->lpvValue;
|
|
|
|
return(FCopyValueToBuf(lpv, cbMax, lpUDIter->lpudp->lpvValue, lpUDIter->lpudp->udtype) ? lpv : NULL);
|
|
|
|
} // LpvoidUserDefGetIteratorVal
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FCbUserDefIteratorName
|
|
//
|
|
// Purpose:
|
|
// This will return the size of the Property string for the property
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT BOOL
|
|
FCbUserDefIteratorName
|
|
(LPUDITER lpUDIter, // Pointer to iterator
|
|
DWORD *pcb)
|
|
{
|
|
if ((lpUDIter == NULL) ||
|
|
(lpUDIter->lpudp == NULL))
|
|
return FALSE;
|
|
|
|
*pcb = CBSTR (lpUDIter->lpudp->lpstzName);
|
|
return(TRUE);
|
|
|
|
} // FCbUserDefIteratorName
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// LpszUserDefIteratorName
|
|
//
|
|
// Purpose:
|
|
// This will return the Property String (name) for the property
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT LPSTR
|
|
LpszUserDefIteratorName
|
|
(LPUDITER lpUDIter, // Pointer to iterator
|
|
DWORD cbMax, // Max size of lpsz
|
|
LPSTR lpsz) // Buffer to copy into
|
|
{
|
|
if ((cbMax == 0) ||
|
|
(lpsz == NULL) ||
|
|
(lpUDIter == NULL) ||
|
|
(lpUDIter->lpudp == NULL))
|
|
return NULL;
|
|
|
|
if ((int) lpsz == UD_PTRWIZARD)
|
|
{
|
|
AssertSz ((IsBadReadPtr (lpsz, sizeof(LPSTR))), "UD_PTRWIZARD should be a bogus pointer value!");
|
|
return (PSTR (lpUDIter->lpudp->lpstzName));
|
|
}
|
|
|
|
PbSzNCopy (lpsz, PSTR (lpUDIter->lpudp->lpstzName), cbMax-1);
|
|
lpsz[cbMax-1] = '\0';
|
|
|
|
return lpsz;
|
|
} // LpszUserDefIteratorName
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUserDefIteratorSetPropString
|
|
//
|
|
// Purpose:
|
|
// Sets the name of the iterator.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLFUNC BOOL OFC_CALLTYPE
|
|
FUserDefIteratorSetPropString
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
LPUDITER lpUDIter, // Pointer to iterator
|
|
LPSTR lpszNew) // Pointer to new name
|
|
{
|
|
if ((lpUDObj == NULL) ||
|
|
(lpData == NULL) ||
|
|
(lpszNew == NULL) ||
|
|
(lpUDIter == NULL) ||
|
|
(lpUDIter->lpudp == NULL))
|
|
return FALSE;
|
|
|
|
// Update the node
|
|
lpUDIter->lpudp->lpstzName =
|
|
LpstzUpdateString (&(lpUDIter->lpudp->lpstzName), lpszNew, TRUE);
|
|
|
|
OfficeDirtyUDObj (lpUDObj, TRUE);
|
|
return TRUE;
|
|
|
|
} // FUserDefIteratorSetPropString
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUserDefIteratorChangeVal
|
|
//
|
|
// Purpose:
|
|
// Changes the value of the data stored.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLFUNC BOOL OFC_CALLTYPE
|
|
FUserDefIteratorChangeVal
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
LPUDITER lpUDIter, // Pointer to iterator
|
|
UDTYPES udtype, // Type of new value
|
|
LPVOID lpv, // New value.
|
|
BOOL fLinkInvalid) // Is the link still valid?
|
|
{
|
|
if ((lpUDObj == NULL) ||
|
|
(lpData == NULL) ||
|
|
(lpUDIter == NULL) ||
|
|
(lpUDIter->lpudp == NULL))
|
|
return FALSE;
|
|
|
|
if (fLinkInvalid)
|
|
{
|
|
if (lpUDIter->lpudp->lpstzLink == NULL)
|
|
return FALSE;
|
|
lpUDIter->lpudp->fLinkInvalid = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
lpUDIter->lpudp->fLinkInvalid = FALSE;
|
|
|
|
// Dealloc the currently stored value.
|
|
DeallocValue (&(lpUDIter->lpudp->lpvValue), lpUDIter->lpudp->udtype);
|
|
|
|
// Copy the new value in. Passing udtype as wUDinvalid just tells
|
|
// us not to modify the type.
|
|
if (udtype != wUDinvalid)
|
|
lpUDIter->lpudp->udtype = udtype;
|
|
|
|
lpUDIter->lpudp->lpvValue =
|
|
LpvCopyValue (&(lpUDIter->lpudp->lpvValue), 0, lpv,
|
|
lpUDIter->lpudp->udtype, FALSE, TRUE);
|
|
|
|
OfficeDirtyUDObj (lpUDObj, TRUE);
|
|
return TRUE;
|
|
|
|
} // FUserDefIteratorChangeVal
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUserDefIteratorSetLink
|
|
//
|
|
// Purpose:
|
|
// Sets the link value for a property. This is NOT a public API.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL PASCAL
|
|
FUserDefIteratorSetLink
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
LPUDITER lpUDIter, // Pointer to iterator
|
|
LPSTR lpszLink) // New link name
|
|
{
|
|
if ((lpUDObj == NULL) ||
|
|
(lpData == NULL) ||
|
|
(lpUDIter == NULL) ||
|
|
(lpUDIter->lpudp == NULL))
|
|
return FALSE;
|
|
|
|
Assert(lpszLink != NULL);
|
|
Assert(*lpszLink != '\0');
|
|
// Should already be a link
|
|
Assert(lpUDIter->lpudp->lpstzLink != NULL);
|
|
lpUDIter->lpudp->lpstzLink =
|
|
LpstzUpdateString (&(lpUDIter->lpudp->lpstzLink), lpszLink, FALSE);
|
|
|
|
return TRUE;
|
|
|
|
} // FUserDefIteratorSetLink
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// LpudiUserDefCreateIterFromLpudp
|
|
//
|
|
// Purpose:
|
|
// Creates an iterator object from a node. This is not a public API.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
LPUDITER PASCAL
|
|
LpudiUserDefCreateIterFromLpudp
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
LPUDPROP lpudp) // Pointer to node
|
|
{
|
|
LPUDITER lpudi;
|
|
|
|
if ((lpUDObj == NULL) ||
|
|
(lpData == NULL) ||
|
|
(lpudp == NULL))
|
|
return NULL;
|
|
|
|
lpudi = LpudiUserDefCreateIterator (lpUDObj);
|
|
if (lpudi != NULL)
|
|
lpudi->lpudp = lpudp;
|
|
|
|
return lpudi;
|
|
|
|
} // LpudiUserDefCreateIterFromLpudp
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUserDefIsHidden
|
|
//
|
|
// Purpose:
|
|
// Determine if a Property string is hidden.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT BOOL
|
|
FUserDefIsHidden
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
LPSTR lpsz) // Property string
|
|
{
|
|
if (lpsz == NULL)
|
|
return FALSE;
|
|
|
|
// We don't really need the object, we can tell from the name
|
|
return (lpsz[0] == HIDDENPREFIX);
|
|
|
|
} // FUserDefIsHidden
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUserDefMakeVisible
|
|
//
|
|
// Purpose:
|
|
// Make a property visible based on the Property string
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT BOOL
|
|
FUserDefMakeVisible
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
LPSTR lpsz) // String to hide.
|
|
{
|
|
LPUDPROP lpudprop;
|
|
|
|
if ((lpUDObj == NULL) ||
|
|
(lpData == NULL) ||
|
|
(lpsz == NULL))
|
|
return FALSE;
|
|
|
|
// Find the name
|
|
lpudprop = LpudpropFindMatchingName (lpUDObj, lpsz);
|
|
if (lpudprop == NULL)
|
|
return FALSE;
|
|
|
|
// Make the string non-hidden by simplying copying the string over
|
|
// itself, minus the first char.
|
|
lpudprop->lpstzName =
|
|
LpstzUpdateString (&(lpudprop->lpstzName), &((PSTR (lpudprop->lpstzName))[1]), TRUE);
|
|
|
|
OfficeDirtyUDObj (lpUDObj, TRUE);
|
|
return TRUE;
|
|
|
|
} // FUserDefMakeVisible
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUserDefMakeHidden
|
|
//
|
|
// Purpose:
|
|
// Hide a Property based on the Property string.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
DLLEXPORT BOOL
|
|
FUserDefMakeHidden
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
LPSTR lpsz) // String to hide
|
|
{
|
|
LPUDPROP lpudprop;
|
|
LPSTR lpstzT;
|
|
|
|
if ((lpUDObj == NULL) ||
|
|
(lpData == NULL) ||
|
|
(lpsz == NULL))
|
|
return FALSE;
|
|
|
|
// Find the name
|
|
lpudprop = LpudpropFindMatchingName (lpUDObj, lpsz);
|
|
if (lpudprop == NULL)
|
|
return FALSE;
|
|
|
|
// First copy the original string to a temp buffer, then put the
|
|
// hidden prefix in the char at the beginning. This is safe
|
|
// because we copied into an lpstz. Then copy the temp back to
|
|
// the original and clean up.
|
|
lpstzT = LpstzUpdateString (&lpstzT, PSTR (lpudprop->lpstzName), TRUE);
|
|
(PSTR (lpstzT))[-1] = HIDDENPREFIX;
|
|
lpudprop->lpstzName =
|
|
LpstzUpdateString (&(lpudprop->lpstzName), &((PSTR (lpstzT))[-1]), TRUE);
|
|
VFreeMemP(lpstzT,CBBUF(lpstzT));
|
|
|
|
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
|
|
LPSTR lpsz) // String to search for
|
|
{
|
|
LPUDPROP lpudprop;
|
|
char sz[256];
|
|
BOOL fCopy = FALSE;
|
|
|
|
if ((lpUDObj == NULL) || (lpData == NULL))
|
|
return(NULL);
|
|
|
|
if (CchSzLen(lpsz) > 255)
|
|
{
|
|
PbSzNCopy(sz, lpsz, 255);
|
|
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, PSTR (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, PSTR (lpudprop->lpstzName))))
|
|
{
|
|
// Set the cache to the last node found
|
|
lpData->lpudpCache = lpudprop;
|
|
return lpudprop;
|
|
}
|
|
|
|
lpudprop = (LPUDPROP) lpudprop->llist.lpllistNext;
|
|
|
|
} // while
|
|
|
|
return NULL;
|
|
|
|
} // LpudpropFindMatchingName
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// LpstzNameFromPID
|
|
//
|
|
// Purpose:
|
|
// Finds the name for the given PId in the dictionary.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
static LPSTR PASCAL
|
|
LpstzNameFromPID
|
|
(LPDICT *rglpdict, // The dictionary
|
|
DWORD dwPId) // The PId to find the name for
|
|
{
|
|
LPDICT lpdict;
|
|
|
|
// Find the bucket the PId should be in
|
|
lpdict = rglpdict[dwPId % DICTHASHMAX];
|
|
|
|
while (lpdict != NULL)
|
|
{
|
|
if (lpdict->dwPId == dwPId)
|
|
{
|
|
return lpdict->lpstz;
|
|
}
|
|
lpdict = (LPDICT) lpdict->llist.lpllistNext;
|
|
}
|
|
|
|
return NULL;
|
|
|
|
} // LpstzNameFromPID
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FAddPropToList
|
|
//
|
|
// Purpose:
|
|
// Adds the given object to the list. The type and value must
|
|
// be filled in before calling this.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL PASCAL
|
|
FAddPropToList
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
LPDICT *rglpdict, // The dictionary
|
|
DWORD dwPId, // PId of the property
|
|
LPUDPROP lpudprop, // Property to add
|
|
BOOL *pfAdded) // Was property added or simple updated
|
|
{
|
|
LPSTR lpstz;
|
|
LPUDPROP lpudpT;
|
|
BOOL fLink;
|
|
BOOL fIMoniker;
|
|
|
|
Assert(lpUDObj != NULL);
|
|
Assert(lpudprop != NULL); // Is this a bogus assert?
|
|
// If the PId has one of the special masks, strip it off
|
|
// so the PId will match the normal value.
|
|
fLink = dwPId & PID_LINKMASK;
|
|
dwPId = dwPId & ~PID_LINKMASK;
|
|
|
|
fIMoniker = dwPId & PID_IMONIKERMASK;
|
|
dwPId = dwPId & ~PID_IMONIKERMASK;
|
|
|
|
Assert(!(fLink && fIMoniker));
|
|
|
|
// Find the name for this PId.
|
|
lpstz = LpstzNameFromPID (rglpdict, dwPId);
|
|
if (lpstz == NULL)
|
|
{
|
|
DebugSzdw ("No name for property id %d", dwPId);
|
|
return FALSE;
|
|
}
|
|
|
|
// Check to make sure that the name is not already in the list
|
|
if ((lpudpT = LpudpropFindMatchingName (lpUDObj, PSTR (lpstz))) == NULL)
|
|
{
|
|
// Copy the name into the node and link it in.
|
|
lpudprop->lpstzName = LpstzUpdateString (&(lpudprop->lpstzName), PSTR (lpstz), TRUE);
|
|
if (lpudprop->lpstzName == NULL)
|
|
return(FALSE);
|
|
|
|
lpData->dwcProps++;
|
|
AddNodeToList (lpUDObj, lpudprop);
|
|
*pfAdded = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Update one of the string values for the node, depending
|
|
// on if its' a link, IMoniker or neither.
|
|
|
|
if (fLink)
|
|
{
|
|
Assert(lpudpT->lpstzLink == NULL);
|
|
LpstzUpdateString(&(lpudpT->lpstzLink), PSTR((LPSTR)lpudprop->lpvValue), FALSE);
|
|
if (lpudpT->lpstzLink == NULL)
|
|
return(FALSE);
|
|
lpData->dwcLinks++;
|
|
}
|
|
else if (fIMoniker)
|
|
{
|
|
Assert(lpudpT->lpstzIMoniker == NULL);
|
|
LpstzUpdateString(&(lpudpT->lpstzIMoniker), PSTR((LPSTR)lpudprop->lpvValue), FALSE);
|
|
if (lpudpT->lpstzIMoniker == NULL)
|
|
return(FALSE);
|
|
lpData->dwcIMonikers++;
|
|
}
|
|
#ifdef DEBUG
|
|
else
|
|
{ // No need to update string
|
|
Assert(lstrcmp(PSTR(lpstz),PSTR(lpudpT->lpstzName)) == 0);
|
|
}
|
|
#endif
|
|
|
|
// If it was just a normal node, copy the other val's too.
|
|
if (!(fLink || fIMoniker))
|
|
{
|
|
lpudpT->lpvValue = lpudprop->lpvValue;
|
|
lpudpT->udtype = lpudprop->udtype;
|
|
}
|
|
*pfAdded = FALSE;
|
|
}
|
|
|
|
return(TRUE);
|
|
} // 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), "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
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FCopyValueToBuf
|
|
//
|
|
// Purpose:
|
|
// Copy the value stored in the node to the given buffer.
|
|
//
|
|
// Assumption:
|
|
//
|
|
// When copying strings, we are assuming that the src string is a OLE Prop
|
|
// string, i.e. 2 DWORDS, then actually strings. And dst string is assumed
|
|
// to be a simple sz.
|
|
//
|
|
// THIS FUNCTION SHOULD BE USED WHEN THE SOURCE BUFFER IS PROVIDED BY THE APP
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL PASCAL
|
|
FCopyValueToBuf
|
|
(LPVOID lpvBuf, // Buffer to copy into
|
|
DWORD cbMax, // Max size of buffer
|
|
LPVOID lpv, // The buffer to copy from
|
|
UDTYPES udtype) // Type of the data
|
|
{
|
|
DWORD cb;
|
|
|
|
switch (udtype)
|
|
{
|
|
case wUDdate :
|
|
case wUDfloat :
|
|
Assert(sizeof(FILETIME) == sizeof(NUM));
|
|
if (cbMax < sizeof(NUM))
|
|
return(FALSE);
|
|
|
|
PbMemCopy (lpvBuf, lpv, sizeof(NUM));
|
|
break;
|
|
|
|
// Ignore cbMax, since both of these will fit in an LPVOID
|
|
case wUDbool :
|
|
if (cbMax < sizeof(WORD))
|
|
return(FALSE);
|
|
*(WORD *)lpvBuf = (WORD)lpv;
|
|
break;
|
|
|
|
case wUDdw :
|
|
if (cbMax < sizeof(DWORD))
|
|
return(FALSE);
|
|
*(DWORD *)lpvBuf = (DWORD)lpv;
|
|
break;
|
|
|
|
case wUDlpsz :
|
|
cb = min(CBSTR ((LPSTR) lpv),cbMax-1);
|
|
if (cb > 0)
|
|
PbMemCopy(lpvBuf, PSTR((LPSTR)lpv), cb);
|
|
((LPSTR)lpvBuf)[cb] = '\0';
|
|
break;
|
|
|
|
default :
|
|
AssertSz (0, "Type is hosed!");
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
} // FCopyValueToBuf
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// LpvCopyValue
|
|
//
|
|
// Purpose:
|
|
// Copy the value stored in the node to the given buffer.
|
|
//
|
|
// THIS FUNCTION SHOULD ONLY BE USED INTERNALLY, I.E. WHEN THE BUFFER IS SUPPLIED
|
|
// BY OFFICE
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
LPVOID PASCAL
|
|
LpvCopyValue
|
|
(LPVOID *lplpvBuf, // Buffer to copy into
|
|
DWORD cbMax, // Max size of buffer
|
|
LPVOID lpv, // The buffer to copy from
|
|
UDTYPES udtype, // Type of the data
|
|
BOOL fFromLpstz, // Indicates that lpv could be an lpstz
|
|
BOOL fToLpstz) // Indicates return val could be lpstz
|
|
{
|
|
DWORD cbLen;
|
|
|
|
switch (udtype)
|
|
{
|
|
case wUDdate :
|
|
case wUDfloat :
|
|
Assert(sizeof(FILETIME) == sizeof(NUM));
|
|
if (!cbMax)
|
|
{
|
|
*lplpvBuf = PvMemAlloc(sizeof(NUM));
|
|
if (*lplpvBuf == NULL)
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
if (cbMax < sizeof(NUM))
|
|
return NULL;
|
|
}
|
|
PbMemCopy (*lplpvBuf, lpv, sizeof(NUM));
|
|
return *lplpvBuf;
|
|
|
|
case wUDdw :
|
|
(DWORD) *lplpvBuf = (DWORD)(*(DWORD *)lpv);
|
|
return *lplpvBuf;
|
|
case wUDbool :
|
|
// AssertSz (((sizeof(LPVOID) >= sizeof(DWORD)) && (sizeof(LPVOID) >= sizeof(WORD))),
|
|
// "Sizes of basic types have changed!");
|
|
(DWORD) *lplpvBuf = (DWORD)((*(DWORD *)lpv) & 0x0000FFFF); // Strip off hiword
|
|
return *lplpvBuf;
|
|
|
|
// Ok, if the result needs to be alloc'd, make it big enough to hold
|
|
// the result in the right form, either LPSTR or LPSTZ. Then
|
|
// do the appropriate copies & such.
|
|
case wUDlpsz :
|
|
if (!cbMax)
|
|
{
|
|
cbLen = (fFromLpstz) ? CBSTR ((LPSTR) lpv) : CchSzLen ((LPSTR) lpv) + 1;
|
|
if (cbLen > 256) // Only allow 255 chars (+1 for zero-terminator)
|
|
cbLen = 256;
|
|
|
|
cbMax = (fToLpstz) ? cbLen + 2*sizeof(DWORD) + CBALIGN32 (cbLen) : cbLen;
|
|
|
|
*lplpvBuf = PvMemAlloc(cbMax);
|
|
if (*lplpvBuf == NULL)
|
|
return NULL;
|
|
|
|
if (fToLpstz)
|
|
CBBUF ((LPSTR) *lplpvBuf) = cbMax;
|
|
}
|
|
else
|
|
{
|
|
Assert(fFalse); // Should we ever get here? If so, I want to know!
|
|
cbLen = cbMax;
|
|
}
|
|
|
|
PbSzNCopy ((fToLpstz) ? PSTR ((LPSTR) *lplpvBuf) : (LPSTR) *lplpvBuf,
|
|
(fFromLpstz) ? PSTR ((LPSTR) lpv) : (LPSTR) lpv,
|
|
cbLen-1);
|
|
|
|
if (fToLpstz)
|
|
(PSTR((LPSTR)(*lplpvBuf)))[cbLen-1] = 0;
|
|
else
|
|
((LPSTR)*lplpvBuf)[cbLen-1] = 0;
|
|
|
|
if (fToLpstz)
|
|
CBSTR ((LPSTR) *lplpvBuf) = cbLen;
|
|
|
|
return *lplpvBuf;
|
|
|
|
default :
|
|
AssertSz (0, "Type is hosed!");
|
|
return NULL;
|
|
}
|
|
} // LpvCopyValue
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// DeallocValue
|
|
//
|
|
// Purpose:
|
|
// Deallocates the value in the buffer.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void PASCAL
|
|
DeallocValue
|
|
(LPVOID *lplpvBuf, // Pointer to buffer to dealloc
|
|
UDTYPES udtype) // Type stored in buffer
|
|
{
|
|
DWORD cb=0;
|
|
|
|
if (*lplpvBuf == NULL)
|
|
return;
|
|
|
|
switch (udtype)
|
|
{
|
|
case wUDdate :
|
|
case wUDfloat :
|
|
Assert(sizeof(FILETIME) == sizeof(NUM));
|
|
cb = sizeof(NUM);
|
|
break;
|
|
|
|
case wUDlpsz :
|
|
cb = CBBUF((LPSTR)*lplpvBuf);
|
|
break;
|
|
|
|
case wUDbool:
|
|
case wUDdw:
|
|
AssertSz (((sizeof(LPVOID) >= sizeof(DWORD)) && (sizeof(LPVOID) >= sizeof(WORD))),
|
|
"Sizes of basic types have changed!");
|
|
return;
|
|
|
|
default:
|
|
Assert(fFalse);
|
|
return;
|
|
}
|
|
|
|
|
|
VFreeMemP(*lplpvBuf,cb);
|
|
*lplpvBuf = NULL;
|
|
|
|
} // DeallocValue
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// DeallocStrings
|
|
//
|
|
// Purpose:
|
|
// Frees a node
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
static void PASCAL
|
|
DeallocStrings
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
LPUDPROP lpudp) // Pointer to node
|
|
{
|
|
if (lpudp->lpstzName != NULL)
|
|
VFreeMemP(lpudp->lpstzName,CBBUF(lpudp->lpstzName));
|
|
if (lpudp->lpstzLink != NULL)
|
|
VFreeMemP(lpudp->lpstzLink,CBBUF(lpudp->lpstzLink));
|
|
if (lpudp->lpstzIMoniker != NULL)
|
|
VFreeMemP(lpudp->lpstzIMoniker,CBBUF(lpudp->lpstzIMoniker));
|
|
|
|
} // DeallocStrings
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// DeallocNode
|
|
//
|
|
// Purpose:
|
|
// Frees a node
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
static void PASCAL
|
|
DeallocNode
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
LPUDPROP lpudp) // Pointer to node
|
|
{
|
|
DeallocStrings (lpUDObj, lpudp);
|
|
DeallocValue (&(lpudp->lpvValue), lpudp->udtype);
|
|
VFreeMemP(lpudp, sizeof(UDPROP));
|
|
} // DeallocNode
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CbPropVal
|
|
//
|
|
// Purpose:
|
|
// Gets the size of the stored data
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
static DWORD PASCAL
|
|
CbPropVal
|
|
(LPUDPROP lpudprop) // Node to find size of
|
|
{
|
|
// The size depends on the value stored.....
|
|
switch (lpudprop->udtype)
|
|
{
|
|
case wUDdate :
|
|
case wUDfloat :
|
|
Assert(sizeof(FILETIME) == sizeof(NUM));
|
|
return sizeof(NUM);
|
|
case wUDdw :
|
|
return sizeof(DWORD);
|
|
case wUDbool :
|
|
return sizeof(WORD);
|
|
case wUDlpsz :
|
|
return CBSTR ((LPSTR) lpudprop->lpvValue);
|
|
default :
|
|
AssertSz (0, "Node is hosed!");
|
|
return 0;
|
|
}
|
|
} // CbPropVal
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FUpdateUdprop
|
|
//
|
|
// Purpose:
|
|
// Updates the given node with the given data
|
|
//
|
|
// It's the caller's responsibility to free lpudp if this function
|
|
// fails.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
static BOOL PASCAL
|
|
FUpdateUdprop
|
|
(LPUDOBJ lpUDObj, // Pointer to object
|
|
LPSTR lpszPropName, // The new property name
|
|
LPUDPROP lpudp, // Node to update
|
|
LPVOID lpvValue, // The new value
|
|
UDTYPES udtype, // The new type
|
|
LPSTR lpszLinkMonik, // The new link/imoniker name
|
|
BOOL fLink, // Indicates a link
|
|
BOOL fIMoniker) // Indicates an IMoniker
|
|
{
|
|
|
|
if ((lpUDObj == NULL) ||
|
|
(lpData == NULL) ||
|
|
(lpszPropName == NULL) ||
|
|
(lpvValue == NULL) ||
|
|
(fLink && fIMoniker) ||
|
|
(fLink && (lpszLinkMonik == NULL)) ||
|
|
(fIMoniker && (lpszLinkMonik == NULL)) ||
|
|
(udtype == wUDinvalid))
|
|
return FALSE;
|
|
|
|
// Update the property name
|
|
lpudp->lpstzName = LpstzUpdateString (&(lpudp->lpstzName), lpszPropName, TRUE);
|
|
if (lpudp->lpstzName == NULL)
|
|
return(FALSE);
|
|
|
|
DeallocValue (&(lpudp->lpvValue), lpudp->udtype);
|
|
lpudp->udtype = udtype;
|
|
LpvCopyValue(&(lpudp->lpvValue), 0, lpvValue, udtype, FALSE, TRUE);
|
|
|
|
if (!fLink && (lpudp->lpstzLink != NULL)) // Property already existed as a link
|
|
{
|
|
VFreeMemP(lpudp->lpstzLink,CBBUF(lpudp->lpstzLink));
|
|
lpudp->lpstzLink=NULL;
|
|
lpData->dwcLinks--;
|
|
}
|
|
else if (fLink)
|
|
{
|
|
lpudp->lpstzLink = LpstzUpdateString (&(lpudp->lpstzLink), lpszLinkMonik, FALSE);
|
|
if (lpudp->lpstzLink == NULL)
|
|
return(FALSE);
|
|
}
|
|
|
|
if (!fIMoniker && (lpudp->lpstzIMoniker != NULL))
|
|
{ // Property already existed as a imoniker
|
|
VFreeMemP(lpudp->lpstzIMoniker,CBBUF(lpudp->lpstzIMoniker));
|
|
lpudp->lpstzIMoniker=NULL;
|
|
lpData->dwcIMonikers--;
|
|
}
|
|
else if (fIMoniker)
|
|
{
|
|
lpudp->lpstzIMoniker = LpstzUpdateString (&(lpudp->lpstzIMoniker), lpszLinkMonik, FALSE);
|
|
if (lpudp->lpstzIMoniker == NULL)
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
|
|
} // FUpdateUdprop
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FMakeTmpUDProps
|
|
//
|
|
// Purpose:
|
|
// Create a temporary copy of the User-Defined property data
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
FMakeTmpUDProps
|
|
(LPUDOBJ lpUDObj) // Pointer to object
|
|
{
|
|
LPUDPROP lpudpCur;
|
|
LPUDPROP lpudpTmpCur;
|
|
DWORD dw;
|
|
LPVOID lpv;
|
|
|
|
if ((lpUDObj == NULL) ||
|
|
(lpData == NULL))
|
|
return FALSE;
|
|
|
|
FDeleteTmpUDProps (lpUDObj);
|
|
|
|
// Move all the original list data to the tmp list
|
|
lpData->dwcTmpLinks = lpData->dwcLinks;
|
|
lpData->dwcTmpIMonikers = lpData->dwcIMonikers;
|
|
lpData->dwcTmpProps = lpData->dwcProps;
|
|
lpData->lpudpTmpHead = lpData->lpudpHead;
|
|
lpData->lpudpTmpCache = lpData->lpudpCache;
|
|
|
|
// Reinitialize the object data
|
|
lpData->dwcLinks = 0;
|
|
lpData->dwcIMonikers = 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)
|
|
{
|
|
lpudpTmpCur = PvMemAlloc(sizeof(UDPROP));
|
|
if (lpudpTmpCur == NULL)
|
|
goto CopyFail;
|
|
|
|
FillBuf (lpudpTmpCur, 0, sizeof(UDPROP));
|
|
|
|
lpudpTmpCur->lpstzName = LpstzUpdateString(&(lpudpTmpCur->lpstzName),PSTR (lpudpCur->lpstzName), TRUE);
|
|
if (lpudpTmpCur->lpstzName == NULL)
|
|
goto CopyFail;
|
|
|
|
|
|
if (lpudpCur->lpstzLink != NULL)
|
|
{
|
|
lpudpTmpCur->lpstzLink = LpstzUpdateString(&(lpudpTmpCur->lpstzLink),PSTR (lpudpCur->lpstzLink), FALSE);
|
|
if (lpudpTmpCur->lpstzLink == NULL)
|
|
goto CopyFail;
|
|
lpData->dwcLinks++;
|
|
}
|
|
|
|
if (lpudpCur->lpstzIMoniker != NULL)
|
|
{
|
|
lpudpTmpCur->lpstzIMoniker = LpstzUpdateString(&(lpudpTmpCur->lpstzIMoniker),
|
|
PSTR (lpudpCur->lpstzIMoniker), FALSE);
|
|
if (lpudpTmpCur->lpstzIMoniker == NULL)
|
|
goto CopyFail;
|
|
lpData->dwcIMonikers++;
|
|
}
|
|
|
|
lpudpTmpCur->udtype = lpudpCur->udtype;
|
|
switch (lpudpCur->udtype)
|
|
{
|
|
case wUDdw:
|
|
case wUDbool:
|
|
dw = (DWORD)lpudpCur->lpvValue;
|
|
lpv = &dw;
|
|
break;
|
|
default:
|
|
lpv = lpudpCur->lpvValue;
|
|
break;
|
|
}
|
|
lpudpTmpCur->lpvValue = LpvCopyValue (&(lpudpTmpCur->lpvValue), 0, lpv, lpudpCur->udtype,
|
|
TRUE, TRUE);
|
|
lpudpTmpCur->fLinkInvalid = lpudpCur->fLinkInvalid;
|
|
|
|
AddNodeToList (lpUDObj, lpudpTmpCur);
|
|
lpData->dwcProps++;
|
|
lpudpCur = (LPUDPROP) lpudpCur->llist.lpllistNext;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
CopyFail:
|
|
|
|
// Put everything back and deallocate any stuff we created
|
|
FSwapTmpUDProps (lpUDObj);
|
|
FDeleteTmpUDProps (lpUDObj);
|
|
|
|
return FALSE;
|
|
|
|
} // 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->dwcIMonikers;
|
|
lpData->dwcIMonikers = lpData->dwcTmpIMonikers;
|
|
lpData->dwcTmpIMonikers = 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
|