SUMINFO.CPP

/************************************************************************* 
**
** OLE 2.0 Property Set Utilities
**
** suminfo.cpp
**
** This file contains functions that are useful for the manipulation
** of OLE 2.0 Property Sets particularly to manage the Summary Info
** property set.
**
** (c) Copyright Microsoft Corp. 1990 - 1996 All Rights Reserved
**
*************************************************************************/

// Note: this file is designed to be stand-alone; it includes a
// carefully chosen, minimal set of headers.
//
// For conditional compilation we use the ole2 conventions,
// _MAC = mac
// WIN32 = Win32 (NT really)
// <nothing> = defaults to Win16

// REVIEW: the following needs to modified to handle _MAC
#define STRICT

#include <string.h>
#include <windows.h>
#include <ole2.h>
#include "ansiapi.h"

#ifdef WIN32
#define _fmemset memset
#define _fmemcpy memcpy
#define _fmemcmp memcmp
#define _fstrcpy strcpy
#define _fstrlen strlen
#endif

/* A LPSUMINFO variable is a pointer to an instance of an abstract data
** type. There can be an arbitrary number of SummaryInfo streams open
** simultaneously (subject to available memory); each must have its
** own LPSUMINFO instance. Each LPSUMINFO instance must
** be initialized prior to use by calling Init and freed after its
** last use by calling Free. The param argument to Init is reserved
** for future expansion and should be zero initially. Once a LPSUMINFO
** instance is allocated (by Init), the user can call the Set
** procedures to initialize fields. A copy of the arguments is made
** in every case except SetThumbnail where control of the storage
** occupied by the METAFILEPICT is merely transferred. When the
** Free routine is called, all storage will be deallocated including
** that of the thumbnail. The arguments to SetThumbNail and the
** return values from GetThumbNail correspond to the OLE2.0 spec.
** Note that on input, the thumbnail is read on demand but all the
** other properties are pre-loaded. The thumbnail is manipulated as
** a windows handle to a METAFILEPICT structure, which in turn
** contains a handle to the METAFILE. The transferClip argument on
** GetThumbNail, when set to true, transfers responsibility for
** storage management of the thumbnail to the caller; that is, after
** Free has been called, the handle is still valid. Clear can be
** used to free storage for all the properties but then you must
** call Read to load them again. All the code is based on FAR
** pointers.
** CoInitialize MUST be called PRIOR to calling OleStdInitSummaryInfo.
** Memory is allocated using the currently active IMalloc*
** allocator (as is returned by call CoGetMalloc(MEMCTX_TASK) ).
**
** Common scenarios:
** Read SummaryInfo
** ----------------
** OleStdInitSummaryInfo()
** OleStdReadSummaryInfo()
** . . . . .
** call different Get routines
** . . . . .
** OleStdFreeSummaryInfo()
**
** Create SummaryInfo
** ------------------
** OleStdInitSummaryInfo()
** call different Set routines
** OleStdWriteSummaryInfo()
** OleStdFreeSummaryInfo()
**
** Update SummaryInfo
** ------------------
** OleStdInitSummaryInfo()
** OleStdReadSummaryInfo()
** OleStdGetThumbNailProperty(necessary only if no SetThumb)
** call different Set routines
** OleStdWriteSummaryInfo()
** OleStdFreeSummaryInfo()
*/

#define CHAR unsigned char
#define fTrue 1
#define fFalse 0
#define BYTE unsigned char
#define WORD unsigned short
#define DWORD unsigned long
#define LPVOID void FAR *
#define uchar unsigned char
#define ulong unsigned long
#define BOOL unsigned char
#define BF unsigned int

#include "suminfo.h"
#include "wn_dos.h"

#if defined( _DEBUG )
// following is from compobj.dll (ole2)
#define ASSERT(x) (!(x) ? FnAssert(#x, NULL, __FILE__, __LINE__) : 0)
#else
#define ASSERT(x)
#endif


typedef struct _RSUMINFO
{
WORD byteOrder;
WORD formatVersion;
WORD getOSVersion;
WORD osVersion;
CLSID classId; //from compobj.h
DWORD cSections;
PROPSETLIST rgPropSet[1/*cSections*/]; //one section in standard summary info
STANDARDSECINMEM section;
ULONG fileOffset; //offset for thumbnail to support demand read
} RSUMINFO;

typedef RSUMINFO FAR * LPRSI;

typedef union _foo{
ULARGE_INTEGER uli;
struct {
DWORD dw;
DWORD dwh;
};
struct {
WORD w0;
WORD w1;
WORD w2;
WORD w3;
};
} Foo;



/* MemAlloc
** ---------
** allocate memory using the currently active IMalloc* allocator
*/
static LPVOID MemAlloc(ULONG ulSize)
{
LPVOID pout;
LPMALLOC pmalloc;

if (CoGetMalloc(MEMCTX_TASK, &pmalloc) != NOERROR) {
ASSERT(pmalloc);
return NULL;
}

pout = (LPVOID)pmalloc->Alloc(ulSize);

if (pmalloc != NULL) {
ULONG refs = pmalloc->Release();
}

return pout;
}


/* MemFree
** -------
** free memory using the currently active IMalloc* allocator
*/
static void MemFree(LPVOID pmem)
{
LPMALLOC pmalloc;

if (pmem == NULL)
return;

if (CoGetMalloc(MEMCTX_TASK, &pmalloc) != NOERROR) {
ASSERT(pmalloc);
return;
}

pmalloc->Free(pmem);

if (pmalloc != NULL) {
ULONG refs = pmalloc->Release();
}
}

// Replace the first argument with the product of itself and the multiplier
static void ulargeMultiply(ULARGE_INTEGER FAR *ul, USHORT m)
{
Foo out, in;
in.uli = *ul;
out.dw = (ULONG)m * in.w0; in.w0 = out.w0;
out.dw = (ULONG)m * in.w1 + out.w1; in.w1 = out.w0;
out.dw = (ULONG)m * in.w2 + out.w1; in.w2 = out.w0;
out.dw = (ULONG)m * in.w3 + out.w1; in.w3 = out.w0;
*ul = in.uli;
}

// Replace the first argument with the product of itself and the multiplier
static void ulargeDivide(ULARGE_INTEGER FAR *ul, USHORT m)
{
Foo out, in;
DWORD i;
in.uli = *ul;
out.dwh = in.dwh/(ULONG)m;
i = in.dwh%(ULONG)m;
in.w2 = in.w1;
in.w3 = (WORD)i;
out.w1 = (WORD)(in.dwh/(ULONG)m);
in.w1 = (WORD)(in.dwh%(ULONG)m);
out.w0 = (WORD)(in.dw/(ULONG)m);
*ul = out.uli;
}


static void setStandard(LPRSI lprsi)
{
int i;
lprsi->cSections = 1;
SetSumInfFMTID(&lprsi->rgPropSet[0].formatID);
_fmemcpy(&lprsi->classId, &lprsi->rgPropSet[0].formatID, sizeof(FMTID));
lprsi->rgPropSet[0].byteOffset = cbNewSummaryInfo(1);
for (i=0; i<cPIDSI_STANDARD; i++)
lprsi->section.rgPropId[i].propertyID = PIDSI_TITLE+i;
lprsi->section.cProperties = cPIDSI_STANDARD; //always; do null test to check validity
}

extern "C" {

/*************************************************************************
**
** OleStdInitSummaryInfo
**
** Purpose:
** Initialize a Summary Info structure.
**
** Parameters:
** int reserved - reserverd for future use. must be 0.
**
** Return Value:
** LPSUMINFO
**
** Comments:
** CoInitialize MUST be called PRIOR to calling OleStdInitSummaryInfo.
** Memory is allocated using the currently active IMalloc*
** allocator (as is returned by call CoGetMalloc(MEMCTX_TASK) ).
** Each LPSUMINFO instance must be initialized prior to use by
** calling OleStdInitSummaryInfo. Once a LPSUMINFO instance is allocated
** (by OleStdInitSummaryInfo), the user can call the Set procedures to
** initialize fields.
*************************************************************************/

STDAPI_(LPSUMINFO) OleStdInitSummaryInfo(int reserved)
{
LPRSI lprsi;

if ((lprsi = (LPRSI)MemAlloc(sizeof(RSUMINFO))) != NULL)
{
ClearSumInf(lprsi, sizeof(RSUMINFO));
} else return NULL;

setStandard(lprsi);
return (LPSUMINFO)lprsi;
}


/*************************************************************************
**
** OleStdFreeSummaryInfo
**
** Purpose:
** Free a Summary Info structure.
**
** Parameters:
** LPSUMINFO FAR *lp - pointer to open Summary Info struct
**
** Return Value:
** void
**
** Comments:
** Memory is freed using the currently active IMalloc*
** allocator (as is returned by call CoGetMalloc(MEMCTX_TASK) ).
** Every LPSUMINFO struct must be freed after its last use.
** When the OleStdFreeSummaryInfo routine is called, all storage will be
** deallocated including that of the thumbnail (unless ownership of
** the thumbnail has been transfered to the caller -- see
** description of transferClip in GetThumbnail API).
**
*************************************************************************/

STDAPI_(void) OleStdFreeSummaryInfo(LPSUMINFO FAR *lplp)
{
if (lplp==NULL||*lplp==NULL) return;
OleStdClearSummaryInfo(*lplp);
MemFree(*lplp);
*lplp = NULL;
}


/*************************************************************************
**
** OleStdClearSummaryInfo
**
** Purpose:
** Free storage (memory) for all the properties of the LPSUMINFO.
**
** Parameters:
** LPSUMINFO FAR *lp - pointer to open Summary Info struct
**
** Return Value:
** void
**
** Comments:
** After calling OleStdClearSummaryInfo you must call OleStdReadSummaryInfo to
** load them again.
**
*************************************************************************/

STDAPI_(void) OleStdClearSummaryInfo(LPSUMINFO lp)
{
OleStdSetStringProperty(lp, PIDSI_TITLE, NULL);
OleStdSetStringProperty(lp, PIDSI_SUBJECT, NULL);
OleStdSetStringProperty(lp, PIDSI_AUTHOR, NULL);
OleStdSetStringProperty(lp, PIDSI_KEYWORDS, NULL);
OleStdSetStringProperty(lp, PIDSI_COMMENTS, NULL);
OleStdSetStringProperty(lp, PIDSI_TEMPLATE, NULL);
OleStdSetStringProperty(lp, PIDSI_REVNUMBER, NULL);
OleStdSetStringProperty(lp, PIDSI_APPNAME, NULL);
OleStdSetThumbNailProperty(NULL, lp, VT_CF_EMPTY, 0, NULL, NULL, 0);
ClearSumInf((LPRSI)lp, sizeof(RSUMINFO));
}


/*************************************************************************
**
** OleStdReadSummaryInfo
**
** Purpose:
** Read all Summary Info properties into memory (except thumbnail
** which is demand loaded).
**
** Parameters:
** LPSTREAM lps - open SummaryInfo IStream*
** LPSUMINFO FAR *lp - pointer to open Summary Info struct
**
** Return Value:
** int - 1 for success
** - 0 if error occurs
** Comments:
**
*************************************************************************/
/*
STDAPI_(int) OleStdReadSummaryInfo(LPSTREAM lpStream, LPSUMINFO lp)
{
STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;
LPRSI lpSumInfo = (LPRSI)lp;
SCODE sc;
ULONG cbRead,i,sectionOffset;
LARGE_INTEGER a;
ULARGE_INTEGER b;
int j,k,l;
union {
RSUMINFO rsi;
STDZ stdz;
};
OleStdClearSummaryInfo(lp);
LISet32(a, 0);
sc = GetScode(lpStream->Seek(a, STREAM_SEEK_SET, &b));
if (FAILED(sc)) goto fail;
sectionOffset = cbNewSummaryInfo(1);
sc = GetScode(lpStream->Read(&rsi, sectionOffset, &cbRead));
if (FAILED(sc)||cbRead<sectionOffset) goto fail;
if (!FIntelOrder(&rsi)||rsi.formatVersion!=0) goto fail;
j = (int)rsi.cSections;
while (j-->0) {
if (FEqSumInfFMTID(&rsi.rgPropSet[0].formatID)) {
sectionOffset = rsi.rgPropSet[0].byteOffset;
break;
} else {
sc = GetScode(lpStream->Read(&rsi.rgPropSet[0].formatID, sizeof(PROPSETLIST), &cbRead));
if (FAILED(sc)||cbRead!=sizeof(PROPSETLIST)) goto fail;
}
if (j<=0) goto fail;
}

LISet32(a, sectionOffset);
sc = GetScode(lpStream->Seek(a, STREAM_SEEK_SET, &b));
if (FAILED(sc)) goto fail;
sc = GetScode(lpStream->Read(&rsi.section, cbNewSection(1), &cbRead));
if (FAILED(sc)||cbRead!=cbNewSection(1)) goto fail;
i = rsi.section.cBytes+sectionOffset;
j = (int)rsi.section.cProperties;
if (j>cPIDSI_STANDARD) goto fail;
k = 0;
while (j-->0) {
k++;
switch (l=(int)rsi.section.rgPropId[0].propertyID) {
case PIDSI_PAGECOUNT:
case PIDSI_WORDCOUNT:
case PIDSI_CHARCOUNT:
case PIDSI_DOC_SECURITY:
if (l==PIDSI_DOC_SECURITY) l=3; else l-=PIDSI_PAGECOUNT;
cbRead = sectionOffset+rsi.section.rgPropId[0].byteOffset;
if (cbRead>=i) goto fail;
LISet32(a, cbRead);
sc = GetScode(lpStream->Seek(a, STREAM_SEEK_SET, &b));
if (FAILED(sc)) goto fail;
sc = GetScode(lpStream->Read(&lpSSIM->rgInts[l], sizeof(INTS), &cbRead));
if (FAILED(sc)||cbRead!=sizeof(INTS)) goto fail;
if (lpSSIM->rgInts[l].vtType==VT_EMPTY) break;
if (lpSSIM->rgInts[l].vtType!=VT_I4) goto fail;
break;
case PIDSI_EDITTIME:
case PIDSI_LASTPRINTED:
case PIDSI_CREATE_DTM:
case PIDSI_LASTSAVE_DTM:
l-=PIDSI_EDITTIME;
cbRead = sectionOffset+rsi.section.rgPropId[0].byteOffset;
if (cbRead>=i) goto fail;
LISet32(a, cbRead);
sc = GetScode(lpStream->Seek(a, STREAM_SEEK_SET, &b));
if (FAILED(sc)) goto fail;
sc = GetScode(lpStream->Read(&lpSSIM->rgTime[l], sizeof(TIME), &cbRead));
if (FAILED(sc)||cbRead!=sizeof(TIME)) goto fail;
if (lpSSIM->rgTime[l].vtType==VT_EMPTY) break;
if (lpSSIM->rgTime[l].vtType!=VT_FILETIME) goto fail;
break;
case PIDSI_TITLE:
case PIDSI_SUBJECT:
case PIDSI_AUTHOR:
case PIDSI_KEYWORDS:
case PIDSI_COMMENTS:
case PIDSI_TEMPLATE:
case PIDSI_LASTAUTHOR:
case PIDSI_REVNUMBER:
case PIDSI_APPNAME:
cbRead = sectionOffset+rsi.section.rgPropId[0].byteOffset;
if (cbRead>=i) goto fail;
LISet32(a, cbRead);
sc = GetScode(lpStream->Seek(a, STREAM_SEEK_SET, &b));
if (FAILED(sc)) goto fail;
sc = GetScode(lpStream->Read(&stdz, sizeof(STDZ), &cbRead));
if (FAILED(sc)||cbRead<sizeof(DWORD)*2) goto fail;
if (stdz.vtType==VT_EMPTY||stdz.vtByteCount<=1) break;
if (stdz.vtType!=VT_LPSTR||stdz.vtByteCount>WORDMAX) goto fail;
stdz.rgchars[(int)stdz.vtByteCount-1] = '\0';
OleStdSetStringProperty(lp, (DWORD)l, (LPSTR)&stdz.rgchars[0]);
break;
case PIDSI_THUMBNAIL:
cbRead = sectionOffset+rsi.section.rgPropId[0].byteOffset;
if (cbRead>=i) goto fail;
LISet32(a, cbRead);
sc = GetScode(lpStream->Seek(a, STREAM_SEEK_SET, &b));
if (FAILED(sc)) goto fail;
lpSumInfo->fileOffset = cbRead+sizeof(DWORD)*3;
sc = GetScode(lpStream->Read(&lpSSIM->thumb, sizeof(DWORD)*4, &cbRead));
if (FAILED(sc)||cbRead!=sizeof(DWORD)*4) {
lpSSIM->thumb.vtType = VT_EMPTY;
goto fail;
}
if (lpSSIM->thumb.vtType == VT_EMPTY) {
lpSSIM->thumb.cBytes = 0;
break;
}
if (lpSSIM->thumb.vtType != VT_CF) {
lpSSIM->thumb.vtType = VT_EMPTY;
goto fail;
}
lpSSIM->thumb.cBytes -= sizeof(DWORD); //for selector
if (lpSSIM->thumb.selector==VT_CF_WIN||lpSSIM->thumb.selector==VT_CF_MAC) {
lpSumInfo->fileOffset += sizeof(DWORD);
lpSSIM->thumb.cBytes -= sizeof(DWORD); //for format val
}
break;
default: ;
}
if (j<=0)
{
// We should fail if the document is password-protected.
if(OleStdGetSecurityProperty(lp)==fSecurityPassworded)
goto fail;
return 1;
}
LISet32(a, sectionOffset+sizeof(DWORD)*2+k*sizeof(PROPIDLIST));
sc = GetScode(lpStream->Seek(a, STREAM_SEEK_SET, &b));
if (FAILED(sc)) goto fail;
sc = GetScode(lpStream->Read(&rsi.section.rgPropId[0], sizeof(PROPIDLIST), &cbRead));
if (FAILED(sc)||cbRead!=sizeof(PROPIDLIST)) goto fail;
}

fail:
OleStdClearSummaryInfo(lpSumInfo);
return 0;
}
*/

/*************************************************************************
**
** OleStdWriteSummaryInfo
**
** Purpose:
** Write all Summary Info properties to a IStream*
**
** Parameters:
** LPSTREAM lps - open SummaryInfo IStream*
** LPSUMINFO FAR *lp - pointer to open Summary Info struct
**
** Return Value:
** int - 1 for success
** - 0 if error occurs
** Comments:
**
*************************************************************************/

STDAPI_(int) OleStdWriteSummaryInfo(LPSTREAM lpStream, LPSUMINFO lp)
{
STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;
// REVIEW: localization issues for propert sets
// do we need to include a code page and dictionary?

LPRSI lpSumInfo = (LPRSI)lp;
SCODE sc;
ULONG cbWritten;
ULONG cBytes, oBytes, k,l,m,n;
LARGE_INTEGER a;
ULARGE_INTEGER b;
LPOLESTR lps;
LPMETAFILEPICT lpmfp;
int i,j,s;

setStandard(lpSumInfo);
oBytes = cbNewSection(cPIDSI_STANDARD); //offsets are relative to the section
cBytes = cbNewSection(cPIDSI_STANDARD)+(sizeof(TIME)*MAXTIME)+(sizeof(INTS)*MAXINTS);

lpSSIM->rgPropId[PIDSI_EDITTIME-2].byteOffset = oBytes;
lpSSIM->rgPropId[PIDSI_LASTPRINTED-2].byteOffset = oBytes+sizeof(TIME);
lpSSIM->rgPropId[PIDSI_CREATE_DTM-2].byteOffset = oBytes+sizeof(TIME)*2;
lpSSIM->rgPropId[PIDSI_LASTSAVE_DTM-2].byteOffset = oBytes+sizeof(TIME)*3;

lpSSIM->rgPropId[PIDSI_PAGECOUNT-2].byteOffset = oBytes+(sizeof(TIME)*MAXTIME);
lpSSIM->rgPropId[PIDSI_WORDCOUNT-2].byteOffset = oBytes+(sizeof(TIME)*MAXTIME+sizeof(INTS));
lpSSIM->rgPropId[PIDSI_CHARCOUNT-2].byteOffset = oBytes+(sizeof(TIME)*MAXTIME+sizeof(INTS)*2);
lpSSIM->rgPropId[PIDSI_DOC_SECURITY-2].byteOffset = oBytes+(sizeof(TIME)*MAXTIME+sizeof(INTS)*3);
oBytes += sizeof(TIME)*MAXTIME + sizeof(INTS)*MAXINTS;

lpSSIM->rgPropId[PIDSI_THUMBNAIL-2].byteOffset = oBytes;
l = 0;
if (lpSSIM->thumb.vtType==VT_EMPTY) k = sizeof(DWORD);
else {
l = ((lpSSIM->thumb.cBytes+4-1)>>2)<<2;
if (lpSSIM->thumb.selector==VT_CF_BYTES) k = sizeof(DWORD)*3;
else if (lpSSIM->thumb.selector==VT_CF_FMTID) {k = sizeof(DWORD)*3; l += sizeof(FMTID); }
else if (lpSSIM->thumb.selector==VT_CF_NAME) {k = sizeof(DWORD)*3; l += (((*lpSSIM->thumb.lpstzName+1+3)>>2)<<2);}
else k = sizeof(DWORD)*4;
}
cBytes += k+l;
oBytes += k+l;

for (i=0; i<MAXSTDZ; i++) {
j = 0;
if (lpSSIM->rglpsz[i]!=NULL) {
j = lpSSIM->rglpsz[i]->VTCB+1/*null*/;
lpSSIM->rglpsz[i]->vtByteCount = j;
j = (((j+4-1)>>2)<<2)+sizeof(DWORD);
cBytes += j;
}
if (i!=MAXSTDZ-1) lpSSIM->rgPropId[i].byteOffset = oBytes;
else lpSSIM->rgPropId[PIDSI_APPNAME-2].byteOffset = oBytes;
oBytes += j+sizeof(DWORD);
cBytes += sizeof(DWORD); //type
}
lpSSIM->cBytes = cBytes;


LISet32(a, 0);
sc = GetScode(lpStream->Seek(a, STREAM_SEEK_SET, &b));
if (FAILED(sc)) return 0;
sc = GetScode(lpStream->Write(lpSumInfo, cbNewSummaryInfo(1), &cbWritten));
if (FAILED(sc)||cbWritten!=cbNewSummaryInfo(1)) return 0;
sc = GetScode(lpStream->Write(lpSSIM, cbNewSection(cPIDSI_STANDARD)+sizeof(TIME)*MAXTIME+sizeof(INTS)*MAXINTS, &cbWritten));
if (FAILED(sc)||cbWritten!=cbNewSection(cPIDSI_STANDARD)+sizeof(TIME)*MAXTIME+sizeof(INTS)*MAXINTS) return 0;

m = lpSSIM->thumb.cBytes;
if (lpSSIM->thumb.lpstzName!=NULL) s = *lpSSIM->thumb.lpstzName;
else s = 0;
if (m!=0) {
lpSSIM->thumb.cBytes = (k-sizeof(DWORD)*2)+
(((lpSSIM->thumb.cBytes+4-1)>>2)<<2)+(((s+4-1)>>2)<<2);
n = lpSSIM->thumb.selector;
lps = lpSSIM->thumb.lpByte;
ASSERT(lps!=NULL); //maybe a GetThumbNail here
ASSERT(n!=VT_CF_NAME);
if (n==VT_CF_WIN) { //bytes are in global memory
lpmfp = (LPMETAFILEPICT)GlobalLock((HANDLE)(DWORD)lps);
if (lpmfp==NULL) goto fail;
lps = (LPOLESTR)GlobalLock(lpmfp->hMF);
}
if (n==VT_CF_NAME) lpSSIM->thumb.selector = *lpSSIM->thumb.lpstzName+1/*null*/;
}
sc = GetScode(lpStream->Write(&lpSSIM->thumb, k, &cbWritten));
if (FAILED(sc)||cbWritten!=k) goto fail;
if (s!=0) {
k = ((s+1+4-1)>>2)<<2;
sc = GetScode(lpStream->Write(lpSSIM->thumb.lpstzName+1, k, &cbWritten));
if (FAILED(sc)||cbWritten!=k) goto fail;
}
if (m!=0) {
k = ((m+3)>>2)<<2;
if (n==VT_CF_WIN||VT_CF_NAME) { //bytes are in global memory
sc = GetScode(lpStream->Write(lpmfp, sizeof(METAFILEPICT), &cbWritten));
k -= sizeof(METAFILEPICT);
}
sc = GetScode(lpStream->Write(lps, k, &cbWritten));
if (FAILED(sc)||cbWritten!=k) goto fail;
if (n==VT_CF_WIN||VT_CF_NAME) { //bytes are in global memory
GlobalUnlock(lpmfp->hMF);
GlobalUnlock((HANDLE)(DWORD)lpSSIM->thumb.lpByte);
}
}
lpSSIM->thumb.cBytes = m; //restore in mem value
lpSSIM->thumb.selector = n;

k = VT_EMPTY;
for (i=0; i<MAXSTDZ; i++) {
if (lpSSIM->rglpsz[i]!=NULL) {
l = lpSSIM->rglpsz[i]->vtByteCount;
j = ((((int)l+4-1)/4)*4)+sizeof(DWORD)*2;
sc = GetScode(lpStream->Write(lpSSIM->rglpsz[i], j, &cbWritten));
if (FAILED(sc)||cbWritten!=(ULONG)j) return 0;
lpSSIM->rglpsz[i]->vtByteCount = 0; //restore stz count convention
lpSSIM->rglpsz[i]->VTCB = (int)l;
} else {
sc = GetScode(lpStream->Write(&k, sizeof(DWORD), &cbWritten));
if (FAILED(sc)||cbWritten!=sizeof(DWORD)) return 0;
}
}
return 1;
fail:
lpSSIM->thumb.cBytes = m; //restore in mem value
lpSSIM->thumb.selector = n;
if (m!=0&&(n==VT_CF_WIN||VT_CF_NAME)) { //bytes are in global memory
GlobalUnlock((HANDLE)(DWORD)lps);
}
return 0;
}


/*************************************************************************
**
** OleStdGetSecurityProperty
**
** Purpose:
** Retrieve the Security Property
**
** Parameters:
** LPSUMINFO FAR *lp - pointer to open Summary Info struct
**
** Return Value:
** DWORD - security level
** AllSecurityFlagsEqNone 0 - no security
** fSecurityPassworded 1 - password required
** fSecurityRORecommended 2 - read-only is recommended
** fSecurityRO 4 - read-only is required
** fSecurityLockedForAnnotations 8 - locked for annotations
**
** Comments:
** by noting the (suggested; that is, application-enforced) security
** level on the document, an application other than the originator
** of the document can adjust its user interface to the properties
** appropriately. An application should not display any of the
** information about a password protected document, and should not
** allow modifications to enforced read-only or locked for
** annotations documents. It should warn the user about read-only
** recommended if the user attempts to modify properties.
**
*************************************************************************/

STDAPI_(DWORD) OleStdGetSecurityProperty(LPSUMINFO lp)
{
STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;
if (lpSSIM->rgInts[3].vtType == VT_I4) return lpSSIM->rgInts[3].value;
return 0;
}


/*************************************************************************
**
** OleStdSetSecurityProperty
**
** Purpose:
** Set the Security Property
**
** Parameters:
** LPSUMINFO FAR *lp - pointer to open Summary Info struct
** DWORD security - security level
** AllSecurityFlagsEqNone 0 - no security
** fSecurityPassworded 1 - password required
** fSecurityRORecommended 2 - read-only is recommended
** fSecurityRO 4 - read-only is required
** fSecurityLockedForAnnotations 8 - locked for annotations
**
** Return Value:
** int - 1 for success
** - 0 if error occurs
** (there are no errors)
**
** Comments:
** by noting the (suggested; that is, application-enforced) security
** level on the document, an application other than the originator
** of the document can adjust its user interface to the properties
** appropriately. An application should not display any of the
** information about a password protected document, and should not
** allow modifications to enforced read-only or locked for
** annotations documents. It should warn the user about read-only
** recommended if the user attempts to modify properties.
**
*************************************************************************/

STDAPI_(int) OleStdSetSecurityProperty(LPSUMINFO lp, DWORD security)
{
STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;

// REVIEW: check valid transitions; how do we know APP called us?

if (security==0) {
lpSSIM->rgInts[3].vtType = VT_EMPTY;
return 1;
}
lpSSIM->rgInts[3].vtType = VT_I4;
lpSSIM->rgInts[3].value = security;
return 1;
}


/*************************************************************************
**
** OleStdGetStringProperty
**
** Purpose:
** Retrieve a String Propety.
** (returns zero terminated string -- C string)
**
** Parameters:
** LPSUMINFO FAR *lp - pointer to open Summary Info struct
** DWORD pid - ID of String Property
**
** Return Value:
** LPSTR - value of String Property
** (zero terminated string--C string)
**
** Comments:
** String should NOT be freed by caller. Memory for string will be
** freed when OleStdFreeSummaryInfo is called.
*************************************************************************/

STDAPI_(LPSTR) OleStdGetStringProperty(LPSUMINFO lp, DWORD pid)
{
LPSTR l = OleStdGetStringZProperty(lp,pid);
if (l==NULL) return NULL; else return l+1;
}


/*************************************************************************
**
** OleStdSetStringProperty
**
** Purpose:
** Set a String Propety
** (takes zero terminated string -- C string)
**
** Parameters:
** LPSUMINFO FAR *lp - pointer to open Summary Info struct
** DWORD pid - ID of String Property
** LPSTR lpsz - new value for String Property.
** zero terminated string -- C string.
** May be NULL, in which case the
** propery is cleared.
**
** Return Value:
** int - 1 if successful
** - 0 invalid property id
**
** Comments:
** The input string is copied.
**
*************************************************************************/

STDAPI_(int) OleStdSetStringProperty(LPSUMINFO lp, DWORD pid, LPOLESTR lpsz)
{
LPRSI lprsi=(LPRSI)lp;
STANDARDSECINMEM FAR* lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;
int i;
if (pid==PIDSI_APPNAME) {
pid = MAXSTDZ-1;
} else if (pid<PIDSI_TITLE || pid>PIDSI_REVNUMBER) return 0; else pid -= 2;
ASSERT(lpSSIM);
if (lpSSIM->rglpsz[pid]) MemFree(lpSSIM->rglpsz[pid]);
if ((lpsz==NULL)||(*lpsz==0)) {
lpSSIM->rglpsz[pid] = NULL;
return (1);
}
i = OLESTRLEN(lpsz);
lpSSIM->rglpsz[pid] = (STDZ FAR*)MemAlloc(i+1/*null*/+sizeof(DWORD)*2);
if (lpSSIM->rglpsz[pid]==NULL) return 0;
W2A(lpsz, (LPSTR)&lpSSIM->rglpsz[pid]->rgchars, sizeof(&lpSSIM->rglpsz[pid]->rgchars));
lpSSIM->rglpsz[pid]->vtType = VT_LPSTR;
lpSSIM->rglpsz[pid]->vtByteCount = 0;
lpSSIM->rglpsz[pid]->VTCB = i;
return (1);
}


/*************************************************************************
**
** OleStdGetStringZProperty
**
** Purpose:
** Retrieve a String Propety.
** (returns zero-terminated with leading byte count string)
**
** Parameters:
** LPSUMINFO FAR *lp - pointer to open Summary Info struct
** DWORD pid - ID of Property
**
** Return Value:
** LPSTZR - value of String Property
** (zero-terminated with leading
** byte count)

** 
** Comments:
** String should NOT be freed by caller. Memory for string will be
** freed when OleStdFreeSummaryInfo is called.
*************************************************************************/

STDAPI_(LPSTZR) OleStdGetStringZProperty(LPSUMINFO lp, DWORD pid)
{
STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;
if (pid==PIDSI_APPNAME) {
pid = MAXSTDZ-1;
} else if (pid<PIDSI_TITLE || pid>PIDSI_REVNUMBER) return NULL; else pid -= 2;
if (lpSSIM->rglpsz[pid]!=NULL) {
return (LPSTR)&lpSSIM->rglpsz[pid]->VTCB;
}
return NULL;
}


/*************************************************************************
**
** OleStdGetDocProperty
**
** Purpose:
** Retrieve document properties (no. pages, no. words, no. characters)
**
** Parameters:
** LPSUMINFO FAR *lp - pointer to open Summary Info struct
** DWORD FAR *nPage - (OUT) number of pages in document
** DWORD FAR *nWords - (OUT) number of words in document
** DWORD FAR *nChars - (OUT) number of charactrs in doc
**
** Return Value:
** void
**
** Comments:
**
*************************************************************************/

STDAPI_(void) OleStdGetDocProperty(
LPSUMINFO lp,
DWORD FAR* nPage,
DWORD FAR* nWords,
DWORD FAR* nChars
)
{
STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;
*nPage=0; *nWords=0; *nChars=0;
if (lpSSIM->rgInts[0].vtType == VT_I4) *nPage = lpSSIM->rgInts[0].value;
if (lpSSIM->rgInts[1].vtType == VT_I4) *nWords = lpSSIM->rgInts[1].value;
if (lpSSIM->rgInts[2].vtType == VT_I4) *nChars = lpSSIM->rgInts[2].value;
}


/*************************************************************************
**
** OleStdSetDocProperty
**
** Purpose:
** Set document properties (no. pages, no. words, no. characters)
**
** Parameters:
** LPSUMINFO FAR *lp - pointer to open Summary Info struct
** DWORD nPage - number of pages in document
** DWORD nWords - number of words in document
** DWORD nChars - number of charactrs in doc
**
** Return Value:
** int - 1 for success
** - 0 if error occurs
** (there are no errors)
**
** Comments:
**
*************************************************************************/

STDAPI_(int) OleStdSetDocProperty(
LPSUMINFO lp,
DWORD nPage,
DWORD nWords,
DWORD nChars
)
{
DWORD vttype=VT_I4;
STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;
if ((nPage|nWords|nChars)==0) {
vttype = VT_EMPTY;
nPage=0; nWords=0; nChars=0;
}
lpSSIM->rgInts[0].vtType = vttype;
lpSSIM->rgInts[1].vtType = vttype;
lpSSIM->rgInts[2].vtType = vttype;
lpSSIM->rgInts[0].value = nPage;
lpSSIM->rgInts[1].value = nWords;
lpSSIM->rgInts[2].value = nChars;
return 1;
}


/*************************************************************************
**
** OleStdGetThumbNailProperty
**
** Purpose:
** Retrieve a Thumbnail Property
**
** Parameters:
** LPSTREAM lps
** LPSUMINFO FAR *lp - pointer to open Summary Info struct
** DWORD FAR* clipFormatNo - clipboard format for thumbnail
** (type of value depends on vtcf
** return value.)
** NOTE: ONLY VT_CF_WIN is
** implemented, so clipFormatNo
** will be CF_METAFILEPICT
** LPSTR FAR* lpszName - format name if VT_CF_NAME is
** returned
** NOTE: NOT IMPLEMENTED
** THUMBNAIL FAR* clip - handle to thumbnail
** for VT_CF_WIN clip will be
** handle to MetafilePict
** NOTE: only VT_CF_WIN IMPLEMENTED
** DWORD FAR* byteCount - size of thumbnail stream
** for VT_CF_WIN case this should
** be combined size of both the
** Metafile as well as the
** MetafilePict structure.
** BOOL transferClip - transfer ownership of thumbnail
** to caller. (see comment)
**
** Return Value:
** int vtcfNo - OLE thumbnail selector value
** VT_CF_WIN - Windows thumbnail
** (interpret clipFormatNo as
** Windows clipboard format)
** VT_CF_FMTID - (NOT IMPLEMENTED)
** thumbnail format is specified
** by ID. use clipFormatNo.
** (but NOT a Windows format ID)
**
** VT_CF_NAME - (NOT IMPLEMENTED)
** thumbnail format is specified
** by name. use lpszName.
** VT_CF_EMPTY - blank thumbnail
** (clip will be NULL)
** VT_CF_OOM - Memory allocation failure
**
** Comments:
** NOTE: Currently there is only proper support for VT_CF_WIN.
** OleStdSetThumbNailProperty does implement VT_CF_FMTID and VT_CF_NAME,
** however, OleStdGetThumbNailProperty, OleStdReadSummaryInfo and
** OleStdWriteSummaryInfo only support VT_CF_WIN.
**
** Note that on input, the thumbnail is read on demand while all the
** other properties are pre-loaded. The thumbnail is manipulated as
** a windows handle to a METAFILEPICT structure, which in turn
** contains a handle to the METAFILE. The transferClip argument on
** GetThumbNail, when set to true, transfers responsibility for
** storage management of the thumbnail to the caller; that is, after
** OleStdFreeSummaryInfo has been called, the handle is still valid.
*************************************************************************/

STDAPI_(int) OleStdGetThumbNailProperty(
LPSTREAM lps,
LPSUMINFO lp,
DWORD FAR* clipFormatNo,
LPOLESTR FAR* lpszName,
THUMBNAIL FAR* clip,
DWORD FAR* byteCount,
BOOL transferClip
)
{
int i;
LPRSI lprsi=(LPRSI)lp;
STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;
ULONG cbRead, cbToRead;
LARGE_INTEGER a;
ULARGE_INTEGER b;
LPOLESTR lpst;
LPMETAFILEPICT lpmfp;
HANDLE hst, hmfp;
SCODE sc;
*byteCount = 0;
if (lpSSIM->thumb.cBytes==0) return VT_CF_EMPTY;
if (lpSSIM->thumb.lpByte==NULL) {
LISet32(a, lprsi->fileOffset);
sc = GetScode(lps->Seek(a, STREAM_SEEK_SET, &b));
if (FAILED(sc)) return VT_CF_EMPTY;
i = (int) lpSSIM->thumb.selector;
if (i>0||i==VT_CF_FMTID) {
if (i>255) return VT_CF_EMPTY;
else if (i==VT_CF_FMTID) i = sizeof(FMTID);
else lpSSIM->thumb.selector = (DWORD) VT_CF_NAME;
cbToRead = ((i+3)>>2)<<2;
lpSSIM->thumb.lpstzName=(LPOLESTR)MemAlloc(i+1/*n*/+1);
if (lpSSIM->thumb.lpstzName==NULL) return VT_CF_OOM;
sc = GetScode(lps->Read(lpSSIM->thumb.lpstzName+1, cbToRead, &cbRead));
if (FAILED(sc)||cbRead!=cbToRead) return VT_CF_EMPTY;
*lpSSIM->thumb.lpstzName = i;
*(lpSSIM->thumb.lpstzName+i) = 0;
lpSSIM->thumb.cBytes -= cbToRead+sizeof(DWORD);
}
i = (int) lpSSIM->thumb.selector;
cbToRead = lpSSIM->thumb.cBytes;
if (cbToRead>65535) return VT_CF_OOM;
ASSERT(i!=VT_CF_NAME);
if (i==VT_CF_WIN) {
cbToRead -= sizeof(METAFILEPICT);
hmfp = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT));
if (hmfp==NULL) return VT_CF_OOM;
hst = GlobalAlloc(GMEM_MOVEABLE, cbToRead);
if (hst==NULL) {
GlobalFree(hmfp);
return VT_CF_OOM;
}
lpmfp = (LPMETAFILEPICT)GlobalLock(hmfp);
sc = GetScode(lps->Read(lpmfp, sizeof(METAFILEPICT), &cbRead));
if (FAILED(sc)||cbRead!=sizeof(METAFILEPICT)) {
GlobalUnlock(hmfp);
GlobalFree(hmfp);
GlobalFree(hst);
return VT_CF_EMPTY;
}
lpst = (LPOLESTR)GlobalLock(hst);
lpmfp->hMF = (HMETAFILE)hst;
lpSSIM->thumb.lpByte = (LPOLESTR)hmfp;
} else {
lpst = (LPOLESTR)MemAlloc((int)cbToRead);
if (lpst==NULL) return VT_CF_OOM;
lpSSIM->thumb.lpByte = lpst;
}
sc = GetScode(lps->Read(lpst, cbToRead, &cbRead));
if (i==VT_CF_WIN) {
GlobalUnlock(hst);
GlobalUnlock(hmfp);
}
if (FAILED(sc)||cbRead!=cbToRead) {
if (i==VT_CF_WIN) {
GlobalFree(hst);
GlobalFree(hmfp);
} else MemFree(lpst);
lpSSIM->thumb.lpByte = NULL;
if ((i==VT_CF_NAME||i==VT_CF_FMTID)&&(lpSSIM->thumb.lpstzName!=NULL))
MemFree(lpSSIM->thumb.lpstzName);
return VT_CF_EMPTY;
}
}
*clipFormatNo = lpSSIM->thumb.clipFormat;
*byteCount = lpSSIM->thumb.cBytes;
if(lpszName!=NULL)
*lpszName = (LPOLESTR)lpSSIM->thumb.lpstzName+1;
*clip = (char FAR*)lpSSIM->thumb.lpByte;
if (transferClip) lpSSIM->thumb.lpByte=NULL;
return (int)lpSSIM->thumb.selector;
}


/*************************************************************************
**
** OleStdSetThumbNailProperty
**
** Purpose:
** Set a Thumbnail Property
**
** Parameters:
** LPSTREAM lps - open SummaryInfo IStream*
** LPSUMINFO FAR *lp - pointer to open Summary Info struct
** int vtcfNo - OLE thumbnail selector value
** VT_CF_WIN - Windows thumbnail
** (interpret clipFormatNo as
** Windows clipboard format)
** VT_CF_FMTID - thumbnail format is specified
** by ID. use clipFormatNo.
** (but NOT a Windows format ID)
**
** VT_CF_NAME - thumbnail format is specified
** by name. use lpszName.
** VT_CF_EMPTY - blank thumbnail
** (clip will be NULL)
**
** DWORD FAR* clipFormatNo - clipboard format for thumbnail
** used if vtcfNo is VT_CF_WIN or
** VT_CF_FMTID. interpretation of
** value depends on vtcfNo specified.
** (normally vtcfNo==VT_CF_WIN and
** clipFormatNo==CF_METAFILEPICT)
** LPSTR FAR* lpszName - format name if vtcfNo is VT_CF_NAME
** THUMBNAIL clip - handle to thumbnail
** for VT_CF_WIN clip will be
** handle to MetafilePict
** DWORD FAR* byteCount - size of thumbnail stream
** for VT_CF_WIN case this should
** be combined size of both the
** Metafile as well as the
** MetafilePict structure.
**
** Return Value:
** int - 1 for success
** - 0 if error occurs
**
** Comments:
** NOTE: Currently there is only proper support for VT_CF_WIN.
** OleStdSetThumbNailProperty does implement VT_CF_FMTID and VT_CF_NAME,
** however, OleStdGetThumbNailProperty, OleStdReadSummaryInfo and
** OleStdWriteSummaryInfo only support VT_CF_WIN.
**
** This function copies lpszName but saves the "clip" handle passed.
**
** NOTE: overwriting or emptying frees space for clip and name.
** The thumbnail is manipulated as a windows handle to a
** METAFILEPICT structure, which in turn contains a handle to the
** METAFILE.
*************************************************************************/

STDAPI_(int) OleStdSetThumbNailProperty(
LPSTREAM lps,
LPSUMINFO lp,
int vtcfNo,
DWORD clipFormatNo,
LPOLESTR lpszName,
THUMBNAIL clip,
DWORD byteCount
)
{
int i;
LPRSI lprsi=(LPRSI)lp;
STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;
LPMETAFILEPICT lpmfp;
if (lpSSIM==NULL||vtcfNo>0||vtcfNo<VT_CF_EMPTY||(vtcfNo==VT_CF_NAME&&(lpszName==NULL||*lpszName==0))) {
return 0;
}
if (vtcfNo!=VT_CF_EMPTY&&(clip==0||byteCount==0)) return 0;
i = (int) lpSSIM->thumb.vtType;
if (i!=VT_EMPTY) {
i = (int) lpSSIM->thumb.selector;
ASSERT(i!=VT_CF_NAME);
if (i==VT_CF_WIN) {
if (lpSSIM->thumb.lpByte!=NULL) {
lpmfp = (LPMETAFILEPICT)GlobalLock((HANDLE)(DWORD)lpSSIM->thumb.lpByte);
GlobalFree(lpmfp->hMF);
GlobalUnlock((HANDLE)(DWORD)lpSSIM->thumb.lpByte);
GlobalFree((HANDLE)(DWORD)lpSSIM->thumb.lpByte);
}
} else {
MemFree(lpSSIM->thumb.lpByte);
}
if ((i==VT_CF_NAME||i==VT_CF_FMTID)&&(lpSSIM->thumb.lpstzName!=NULL))
MemFree(lpSSIM->thumb.lpstzName);
lpSSIM->thumb.lpstzName = NULL;
lpSSIM->thumb.lpByte = NULL;
}
if (vtcfNo==VT_CF_EMPTY) {
lpSSIM->thumb.vtType = VT_EMPTY;
lpSSIM->thumb.cBytes = 0;
} else {
lpSSIM->thumb.vtType = VT_CF;
lpSSIM->thumb.selector = vtcfNo;
lpSSIM->thumb.cBytes = byteCount;
lpSSIM->thumb.clipFormat = clipFormatNo;
lpSSIM->thumb.lpByte = (LPOLESTR)clip; //just save the hnadle
if (vtcfNo==VT_CF_NAME||vtcfNo==VT_CF_FMTID) {
i = OLESTRLEN(lpszName);
if (vtcfNo==VT_CF_FMTID) ASSERT(i==sizeof(FMTID));
lpSSIM->thumb.lpstzName =
(LPOLESTR)MemAlloc(i+1/*n*/+1/*null*/);
if (lpSSIM->thumb.lpstzName==NULL) {
lpSSIM->thumb.vtType = VT_EMPTY;
return 0;
}
W2A (lpszName, (char FAR*)lpSSIM->thumb.lpstzName+1, sizeof(lpSSIM->thumb.lpstzName+1));
*lpSSIM->thumb.lpstzName = i;
}
}
return 1;
}


/*************************************************************************
**
** OleStdGetDateProperty
**
** Purpose:
** Retrieve Data Property
**
** Parameters:
** LPSUMINFO FAR *lp - pointer to open Summary Info struct
** DWORD pid - ID of Property
** int FAR *yr - (OUT) year
** int FAR *mo - (OUT) month
** int FAR *dy - (OUT) day
** DWORD FAR *sc - (OUT) seconds
**
** Return Value:
** void
**
** Comments:
**
*************************************************************************/

STDAPI_(void) OleStdGetDateProperty(
LPSUMINFO lp,
DWORD pid,
int FAR* yr,
int FAR* mo,
int FAR* dy,
DWORD FAR* sc
)
{
STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;
SFFS sffs;
pid -= PIDSI_EDITTIME;
*yr = 0; *mo = 0; *dy = 0; *sc = 0;
if (pid<0||pid>=MAXTIME) return;
if (lpSSIM->rgTime[pid].vtType == VT_FILETIME) {
if (pid==0) {
//convert from 100ns to seconds
ulargeDivide((ULARGE_INTEGER FAR*)&lpSSIM->rgTime[0].time, 10000);
ulargeDivide((ULARGE_INTEGER FAR*)&lpSSIM->rgTime[0].time, 1000);
pid = lpSSIM->rgTime[0].time.dwLowDateTime;
*sc = pid%((DWORD)60*60*24);
pid /= (DWORD)60*60*24;
*dy = (int)(pid%(DWORD)30);
pid /= (DWORD)30;
*mo = (int)(pid%(DWORD)12);
*yr = (int)(pid/(DWORD)12);
} else {
if (CoFileTimeToDosDateTime(&lpSSIM->rgTime[pid].time,
&sffs.dateVariable, &sffs.timeVariable)) {
*yr = sffs.yr+1980;
*mo = sffs.mon;
*dy = sffs.dom;
*sc = (DWORD)sffs.hr*3600+sffs.mint*60+sffs.sec*2;
}
}
}
return;
}



/*************************************************************************
**
** OleStdSetDateProperty
**
** Purpose:
** Set Data Property
**
** Parameters:
** LPSUMINFO FAR *lp - pointer to open Summary Info struct
** DWORD pid - ID of Property
** int yr - year
** int mo - month
** int dy - day
** DWORD sc - seconds
**
** Return Value:
** int - 1 for success
** - 0 if error occurs
**
** Comments:
** Use all zeros to clear.
** The following is an example of valid input:
** yr=1993 mo=1(Jan) dy=1(1st) hr=12(noon) mn=30 sc=23
** for PIDSI_EDITTIME property, the values are a zero-origin duration
** of time.
**
*************************************************************************/

STDAPI_(int) OleStdSetDateProperty(
LPSUMINFO lp,
DWORD pid,
int yr,
int mo,
int dy,
int hr,
int mn,
int sc
)
{
STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;
SFFS sffs;
pid -= PIDSI_EDITTIME;
if (pid<0||pid>=MAXTIME) return 0;
if ((yr|mo|dy|hr|mn|sc)==0) { //all must be zero
lpSSIM->rgTime[pid].vtType = VT_EMPTY;
return 1;
}
lpSSIM->rgTime[pid].vtType = VT_FILETIME;
if (pid==0) {
lpSSIM->rgTime[0].time.dwLowDateTime =
(((((DWORD)yr*365+mo*30)+dy)*24+hr)*60+mn)*60+sc;
lpSSIM->rgTime[0].time.dwHighDateTime = 0;
//10^7 nanoseconds/second
ulargeMultiply((ULARGE_INTEGER FAR*)&lpSSIM->rgTime[0].time, 10000);
//convert to units of 100 ns
ulargeMultiply((ULARGE_INTEGER FAR*)&lpSSIM->rgTime[0].time, 1000);
} else {
sffs.yr = max(yr-1980,0);
sffs.mon = mo;
sffs.dom = dy;
sffs.hr = hr;
sffs.mint= mn;
sffs.sec = sc/2; //dos is 2 second intervals
if (!CoDosDateTimeToFileTime(sffs.date, sffs.time,
&lpSSIM->rgTime[pid].time)) {
lpSSIM->rgTime[pid].vtType = VT_EMPTY;
return 0;
}
}
return 1;
}

} //END C