// @pymethod <o PyIPropertyStore>|propsys|PSCreatePropertyStoreFromPropertySetStorage|Wraps a <o PyIPropertySetStorage> interface in a <o PyIPropertyStore> object
// @comm This function does not work for the NTFS property storage implementation based on
//  alternate data streams.
static PyObject *PyPSCreatePropertyStoreFromPropertySetStorage(PyObject *self, PyObject *args)
{
	PyObject *obpss;
	IPropertySetStorage *pipss;
	DWORD mode;
	IID riid = IID_IPropertyStore;
	void *ret;
	// @pyparm <o PyIPropertySetStorage>|pss||Property container to be adapted
	// @pyparm int|Mode||Read or write mode, shellcon.STGM_*.  Must match mode used to open input interface. 
	// @pyparm <o PyIID>|riid|IID_IPropertyStore|The interface to create
	if (!PyArg_ParseTuple(args, "Ok|O&:PSCreatePropertyStoreFromPropertySetStorage",
		&obpss, &mode,
		PyWinObject_AsIID, &riid))
		return NULL;
	if (!PyCom_InterfaceFromPyInstanceOrObject(obpss, IID_IPropertySetStorage, (void **)&pipss, FALSE))
		return NULL;

	HRESULT hr;
	PY_INTERFACE_PRECALL;
	hr = PSCreateMemoryPropertyStore(riid, &ret);
	pipss->Release();
	PY_INTERFACE_POSTCALL;
	if (FAILED(hr))
		return PyCom_BuildPyException(hr);
	return PyCom_PyObjectFromIUnknown((IUnknown *) ret, riid);
};
Beispiel #2
0
/******************************************************************
 CreateUrl - Creates a shortcut via IUniformResourceLocatorW

*******************************************************************/
static HRESULT CreateUrl(
    __in_z LPCWSTR wzTarget,
    __in_z LPCWSTR wzShortcutPath,
    __in_z_opt LPCWSTR wzIconPath,
    __in int iconIndex
)
{
    HRESULT hr = S_OK;
    IUniformResourceLocatorW* piURL = NULL;
    IPersistFile* piPersistFile = NULL;
    IPropertySetStorage* piProperties = NULL;
    IPropertyStorage* piStorage = NULL;

    // create an internet shortcut object
    WcaLog(LOGMSG_STANDARD, "Creating IUniformResourceLocatorW shortcut '%ls' target '%ls'", wzShortcutPath, wzTarget);
    hr = ::CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_ALL, IID_IUniformResourceLocatorW, (void**)&piURL);
    ExitOnFailure(hr, "failed to create an instance of IUniformResourceLocatorW");

    // set shortcut target
    hr = piURL->SetURL(wzTarget, 0);
    ExitOnFailure2(hr, "failed to set shortcut '%ls' target '%ls'", wzShortcutPath, wzTarget);

    if (wzIconPath)
    {
        hr = piURL->QueryInterface(IID_IPropertySetStorage, (void **)&piProperties);
        ExitOnFailure1(hr, "failed to get IPropertySetStorage for shortcut '%ls'", wzShortcutPath);

        hr = piProperties->Open(FMTID_Intshcut, STGM_WRITE, &piStorage);
        ExitOnFailure1(hr, "failed to open storage for shortcut '%ls'", wzShortcutPath);

        PROPSPEC ppids[2] = { {PRSPEC_PROPID, PID_IS_ICONINDEX}, {PRSPEC_PROPID, PID_IS_ICONFILE} };
        PROPVARIANT ppvar[2];

        PropVariantInit(ppvar);
        PropVariantInit(ppvar + 1);

        ppvar[0].vt = VT_I4;
        ppvar[0].lVal = iconIndex;
        ppvar[1].vt = VT_LPWSTR;
        ppvar[1].pwszVal = (LPWSTR)wzIconPath;

        hr = piStorage->WriteMultiple(2, ppids, ppvar, 0);
        ExitOnFailure1(hr, "failed to write icon storage for shortcut '%ls'", wzShortcutPath);

        hr = piStorage->Commit(STGC_DEFAULT);
        ExitOnFailure1(hr, "failed to commit icon storage for shortcut '%ls'", wzShortcutPath);
    }

    // get an IPersistFile and save the shortcut
    hr = piURL->QueryInterface(IID_IPersistFile, (void**)&piPersistFile);
    ExitOnFailure1(hr, "failed to get IPersistFile for shortcut '%ls'", wzShortcutPath);

    hr = piPersistFile->Save(wzShortcutPath, TRUE);
    ExitOnFailure1(hr, "failed to save shortcut '%ls'", wzShortcutPath);

LExit:
    ReleaseObject(piPersistFile);
    ReleaseObject(piURL);
    ReleaseObject(piStorage);
    ReleaseObject(piProperties);

    return hr;
}
Beispiel #3
0
void App::GetProperties()
{
    LPSTORAGE				pStorage = NULL;
    IPropertySetStorage*	pPropertySetStorage = NULL;
    IPropertyStorage*		pSummaryInfoStorage = NULL;
    IPropertyStorage*		pDocumentSummaryInfoStorage = NULL;
    IPropertyStorage*		pUserDefinedPropertyStorage = NULL;
    wchar_t					wfilename[_MAX_PATH];
    char					szBuf[256];
    char					filename[MAX_PATH];

    SendMessage(GetDlgItem(hPropDialog, IDC_TITLE), WM_SETTEXT, 0, (LPARAM)"");
    SendMessage(GetDlgItem(hPropDialog, IDC_SUBJECT), WM_SETTEXT, 0, (LPARAM)"");
    SendMessage(GetDlgItem(hPropDialog, IDC_AUTHOR), WM_SETTEXT, 0, (LPARAM)"");
    SendMessage(GetDlgItem(hPropDialog, IDC_MANAGER), WM_SETTEXT, 0, (LPARAM)"");
    SendMessage(GetDlgItem(hPropDialog, IDC_COMPANY), WM_SETTEXT, 0, (LPARAM)"");
    SendMessage(GetDlgItem(hPropDialog, IDC_CATEGORY), WM_SETTEXT, 0, (LPARAM)"");
    SendMessage(GetDlgItem(hPropDialog, IDC_KEYWORDS), WM_SETTEXT, 0, (LPARAM)"");
    SendMessage(GetDlgItem(hPropDialog, IDC_COMMENTS), WM_SETTEXT, 0, (LPARAM)"");
    SendMessage(GetDlgItem(hPropDialog, IDC_CONTENTS), LB_RESETCONTENT, 0, 0);
    ListView_DeleteAllItems(GetDlgItem(hPropDialog, IDC_CUSTOM));

    int idx = SendMessage(hListBox, LB_GETCURSEL, 0, 0);

    SendMessage(hListBox, LB_GETTEXT, idx, (LPARAM)filename);
    SetWindowText(hPropDialog, filename);

    MultiByteToWideChar(CP_ACP, 0, filename, -1, wfilename, _MAX_PATH);
    HRESULT	res = StgOpenStorage(wfilename, (LPSTORAGE)0, STGM_DIRECT|STGM_READ|STGM_SHARE_EXCLUSIVE,	NULL,0,&pStorage);
    if (res!=S_OK) {
        return;
    }


    // Get the Storage interface
    if (S_OK != pStorage->QueryInterface(IID_IPropertySetStorage, (void**)&pPropertySetStorage)) {
        pStorage->Release();
        return;
    }

    // Get the SummaryInfo property set interface
    if (S_OK == pPropertySetStorage->Open(FMTID_SummaryInformation, STGM_READ|STGM_SHARE_EXCLUSIVE, &pSummaryInfoStorage)) {
        BOOL bFound = FALSE;

        PROPSPEC	PropSpec[5];
        PROPVARIANT	PropVar[5];

        PropSpec[0].ulKind = PRSPEC_PROPID;
        PropSpec[0].propid = PID_TITLE;

        PropSpec[1].ulKind = PRSPEC_PROPID;
        PropSpec[1].propid = PID_SUBJECT;

        PropSpec[2].ulKind = PRSPEC_PROPID;
        PropSpec[2].propid = PID_AUTHOR;

        PropSpec[3].ulKind = PRSPEC_PROPID;
        PropSpec[3].propid = PID_KEYWORDS;

        PropSpec[4].ulKind = PRSPEC_PROPID;
        PropSpec[4].propid = PID_COMMENTS;

        HRESULT hr = pSummaryInfoStorage->ReadMultiple(5, PropSpec, PropVar);
        if (S_OK == hr) {
            if (PropVar[0].vt == VT_LPSTR) {
                SendMessage(GetDlgItem(hPropDialog, IDC_TITLE), WM_SETTEXT, 0, (LPARAM)PropVar[0].pszVal);
            }
            if (PropVar[1].vt == VT_LPSTR) {
                SendMessage(GetDlgItem(hPropDialog, IDC_SUBJECT), WM_SETTEXT, 0, (LPARAM)PropVar[1].pszVal);
            }
            if (PropVar[2].vt == VT_LPSTR) {
                SendMessage(GetDlgItem(hPropDialog, IDC_AUTHOR), WM_SETTEXT, 0, (LPARAM)PropVar[2].pszVal);
            }
            if (PropVar[3].vt == VT_LPSTR) {
                SendMessage(GetDlgItem(hPropDialog, IDC_KEYWORDS), WM_SETTEXT, 0, (LPARAM)PropVar[3].pszVal);
            }
            if (PropVar[4].vt == VT_LPSTR) {
                SendMessage(GetDlgItem(hPropDialog, IDC_COMMENTS), WM_SETTEXT, 0, (LPARAM)PropVar[4].pszVal);
            }
        }

        FreePropVariantArray(5, PropVar);
        pSummaryInfoStorage->Release();
    }


    // Get the DocumentSummaryInfo property set interface
    if (S_OK == pPropertySetStorage->Open(FMTID_DocSummaryInformation, STGM_READ|STGM_SHARE_EXCLUSIVE, &pDocumentSummaryInfoStorage)) {
        BOOL bFound = FALSE;

        PROPSPEC	PropSpec[5];
        PROPVARIANT	PropVar[5];

        PropSpec[0].ulKind = PRSPEC_PROPID;
        PropSpec[0].propid = PID_MANAGER;

        PropSpec[1].ulKind = PRSPEC_PROPID;
        PropSpec[1].propid = PID_COMPANY;

        PropSpec[2].ulKind = PRSPEC_PROPID;
        PropSpec[2].propid = PID_CATEGORY;

        PropSpec[3].ulKind = PRSPEC_PROPID;
        PropSpec[3].propid = PID_HEADINGPAIR;

        PropSpec[4].ulKind = PRSPEC_PROPID;
        PropSpec[4].propid = PID_DOCPARTS;

        HRESULT hr = pDocumentSummaryInfoStorage->ReadMultiple(5, PropSpec, PropVar);
        if (S_OK == hr) {
            if (PropVar[0].vt == VT_LPSTR) {
                SendMessage(GetDlgItem(hPropDialog, IDC_MANAGER), WM_SETTEXT, 0, (LPARAM)PropVar[0].pszVal);
            }
            if (PropVar[1].vt == VT_LPSTR) {
                SendMessage(GetDlgItem(hPropDialog, IDC_COMPANY), WM_SETTEXT, 0, (LPARAM)PropVar[1].pszVal);
            }
            if (PropVar[2].vt == VT_LPSTR) {
                SendMessage(GetDlgItem(hPropDialog, IDC_CATEGORY), WM_SETTEXT, 0, (LPARAM)PropVar[2].pszVal);
            }
            if ((PropVar[3].vt == (VT_VARIANT | VT_VECTOR)) && (PropVar[4].vt == (VT_LPSTR | VT_VECTOR))) {
                CAPROPVARIANT*	pHeading = &PropVar[3].capropvar;
                CALPSTR*		pDocPart = &PropVar[4].calpstr;

                // Headings:
                // =========
                // 0  - General
                // 2  - Mesh Totals
                // 4  - Scene Totals
                // 6  - External Dependencies
                // 8  - Objects
                // 10 - Materials
                // 12 - Plug-Ins

                int nDocPart = 0;
                for (UINT i=0; i<pHeading->cElems; i+=2) {
                    SendMessage(GetDlgItem(hPropDialog, IDC_CONTENTS), LB_ADDSTRING, 0, (LPARAM)pHeading->pElems[i].pszVal);
                    for (int j=0; j<pHeading->pElems[i+1].lVal; j++) {
                        sprintf(szBuf, "\t%s", pDocPart->pElems[nDocPart]);
                        SendMessage(GetDlgItem(hPropDialog, IDC_CONTENTS), LB_ADDSTRING, 0, (LPARAM)szBuf);
                        nDocPart++;
                    }
                }

            }

        }

        FreePropVariantArray(5, PropVar);
        pDocumentSummaryInfoStorage->Release();
    }

    if (S_OK == pPropertySetStorage->Open(FMTID_UserDefinedProperties, STGM_READ|STGM_SHARE_EXCLUSIVE, &pUserDefinedPropertyStorage)) {
        int		numUserProps = 0;

        // First we need to count the properties
        IEnumSTATPROPSTG*	pIPropertyEnum;
        if (S_OK == pUserDefinedPropertyStorage->Enum(&pIPropertyEnum)) {
            STATPROPSTG property;
            while (pIPropertyEnum->Next(1, &property, NULL) == S_OK) {
                if (property.lpwstrName) {
                    CoTaskMemFree(property.lpwstrName);
                    property.lpwstrName = NULL;
                    numUserProps++;
                }
            }

            PROPSPEC* pPropSpec = new PROPSPEC[numUserProps];
            PROPVARIANT* pPropVar = new PROPVARIANT[numUserProps];

            ZeroMemory(pPropVar, numUserProps*sizeof(PROPVARIANT));
            ZeroMemory(pPropSpec, numUserProps*sizeof(PROPSPEC));

            pIPropertyEnum->Reset();
            int idx = 0;
            while (pIPropertyEnum->Next(1, &property, NULL) == S_OK) {
                if (property.lpwstrName) {
                    pPropSpec[idx].ulKind = PRSPEC_LPWSTR;
                    pPropSpec[idx].lpwstr = (LPWSTR)CoTaskMemAlloc(sizeof(wchar_t)*(wcslen(property.lpwstrName)+1));
                    wcscpy(pPropSpec[idx].lpwstr, property.lpwstrName);
                    idx++;
                    CoTaskMemFree(property.lpwstrName);
                    property.lpwstrName = NULL;
                }
            }
            pIPropertyEnum->Release();

            ListView_DeleteAllItems(GetDlgItem(hPropDialog, IDC_CUSTOM));
            HRESULT hr = pUserDefinedPropertyStorage->ReadMultiple(idx, pPropSpec, pPropVar);
            if (S_OK == hr) {
                for (int i=0; i<idx; i++) {
                    wcstombs(szBuf, pPropSpec[i].lpwstr, 255);
                    LV_ITEM item;
                    item.mask = LVIF_TEXT;
                    item.iItem = i;
                    item.iSubItem = 0;
                    item.pszText = szBuf;
                    item.cchTextMax = strlen(szBuf);
                    ListView_InsertItem(GetDlgItem(hPropDialog, IDC_CUSTOM), &item);

                    VariantToString(this, &pPropVar[i], szBuf, 255);
                    item.iSubItem = 1;
                    item.pszText = szBuf;
                    item.cchTextMax = strlen(szBuf);
                    ListView_SetItem(GetDlgItem(hPropDialog, IDC_CUSTOM), &item);

                    TypeNameFromVariant(this, &pPropVar[i], szBuf, 255);
                    item.iSubItem = 2;
                    item.pszText = szBuf;
                    item.cchTextMax = strlen(szBuf);
                    ListView_SetItem(GetDlgItem(hPropDialog, IDC_CUSTOM), &item);
                }
            }

            for (int i=0; i<idx; i++) {
                CoTaskMemFree(pPropSpec[i].lpwstr);
            }

            FreePropVariantArray(numUserProps, pPropVar);

            delete [] pPropSpec;
            delete [] pPropVar;
        }

        pUserDefinedPropertyStorage->Release();
    }

    pPropertySetStorage->Release();
    pStorage->Release();
}
Beispiel #4
0
BOOL CDocFile::Load(TCHAR* wszFilePath)
{
	IStorage *pStorage = NULL;
    IPropertySetStorage *pPropSetStg = NULL;
	IStream *pStream = NULL, *pTableStream = NULL;
    HRESULT hr;
	
	// Open the document as an OLE compound document.
	hr = ::StgOpenStorage(wszFilePath, NULL,
    STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &pStorage);
	if(FAILED(hr)) {
		_tprintf( L"A file is locked by another program: [%s]\n", wszFilePath);
		return FALSE;
	}

#ifdef CONTENT_EXTRACTION

	hr = pStorage->OpenStream(L"WordDocument", NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pStream);
	if(FAILED(hr)) {
		_tprintf( L"A file is invalid or damaged: [%s]\n", wszFilePath);
		pStorage->Release();
		return FALSE;
	}
	STATSTG stat;
	pStream->Stat(&stat, 0);
	UINT size = (UINT) stat.cbSize.QuadPart;
	BYTE *buffer = new BYTE[size];
	USHORT usFlag;
	INT	pdcOffset;
	UINT pdcLength;
	LARGE_INTEGER liTmpSeek;
	ULONG cbRead;
	liTmpSeek.QuadPart = 10;
	pStream->Seek(liTmpSeek, 0, NULL);
	pStream->Read(&usFlag, 2, &cbRead);
	liTmpSeek.QuadPart = 418;
	pStream->Seek(liTmpSeek, 0, NULL);
	pStream->Read(&pdcOffset, 4, &cbRead);
	pStream->Read(&pdcLength, 4, &cbRead);

	hr = pStorage->OpenStream((usFlag & (0x1 << 9)) ? L"1Table" : L"0Table", NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pTableStream);
	liTmpSeek.QuadPart = pdcOffset;
    pTableStream->Seek(liTmpSeek, 0, NULL);

	INT nCount = 0;
	INT *aOffsets = NULL;
	struct Desc {
		BYTE Flags;
		BYTE Fn;
		UINT32  Fc;
		SHORT Prm;
	} *aDescs = NULL;
	UINT nPointer = 0;

	while (nPointer < pdcLength)
	{
		BYTE nType = 0;
		pTableStream->Read(&nType, 1, &cbRead);
        
		switch(nType)
		{
		case 0:
			BYTE nTmp;
			pTableStream->Read(&nTmp, 1, &cbRead);
			nPointer++;
			break;

		case 1:
			{
			SHORT cbGrpprl;
			BYTE *grpprlData = NULL;
			pTableStream->Read(&cbGrpprl, 2, &cbRead);
			nPointer+=2;
			grpprlData = new BYTE[cbGrpprl];
			pTableStream->Read(grpprlData, cbGrpprl, &cbRead);
			nPointer+=cbGrpprl;
			delete grpprlData;
			break;
			}
		case 2:

			INT nTableLen = 0;
			pTableStream->Read(&nTableLen, 4, &cbRead);
			nPointer+=4;

			nCount = (nTableLen - 4) / (8 + 4) + 1;
			aOffsets = new INT[nCount];
			for(int i = 0; i < nCount; i++) {
				pTableStream->Read(&aOffsets[i], 4, &cbRead);
				nPointer +=4;
			}

			aDescs = new Desc[nCount-1];
			for(int i = 0; i < nCount-1; i++) {
				pTableStream->Read(&aDescs[i].Flags, 1, &cbRead);
				pTableStream->Read(&aDescs[i].Fn, 1, &cbRead);
				pTableStream->Read(&aDescs[i].Fc, 4, &cbRead);
				pTableStream->Read(&aDescs[i].Prm, 2, &cbRead);
				nPointer+=sizeof(struct Desc);
			}
			break;
		}
	}

	for (int i = 0; i < nCount - 1; i++)
	{
		UINT pieceStart = 0xffffffff;
		UINT pieceEnd = 0xffffffff;
		BOOL bUnicode = FALSE;

		bUnicode = (aDescs[i].Fc & (1 << 30)) == 0 ? 1 : 0;
		if (!bUnicode)
			pieceStart = (aDescs[i].Fc & ~(1 << 30)) / 2;
		else
			pieceStart = aDescs[i].Fc;

		UINT nLength = aOffsets[i + 1] - aOffsets[i];
		pieceEnd = pieceStart + nLength * (bUnicode ? 2 : 1);

		liTmpSeek.QuadPart = pieceStart;
		hr = pStream->Seek(liTmpSeek, 0, NULL);
		//m_wszContent += ReadString(documentReader, pieceEnd - pieceStart, isUnicode);
		if (nLength == 0)
			continue;

		for (UINT i = 0; i < nLength; i++)
		{
			if (!bUnicode)
			{
				BYTE ch = 0;
				pStream->Read(&ch, 1, NULL);
				m_wszContent += (CHAR)ch;
			}
			else
			{
				SHORT ch = 0;
				pStream->Read(&ch, 2, NULL);
				m_wszContent += (WCHAR)ch;
			}	
		}
	}
	pStream->Release();
	pTableStream->Release();

#endif

	// Obtain the IPropertySetStorage interface.
	hr = pStorage->QueryInterface(IID_IPropertySetStorage, (void **)&pPropSetStg);
	IPropertyStorage *pPropStg = NULL;

	struct pidsiStruct {
		TCHAR *name;
		LONG pid;
	} pidsiArr[] = {
		{L"Author",           PIDSI_AUTHOR},
		{L"Title",            PIDSI_TITLE},
		{L"Subject",          PIDSI_SUBJECT},
		{L"Keywords",         PIDSI_KEYWORDS},
		{L"Status",			  PIDMSI_STATUS},
		{L"AppName",          PIDSI_APPNAME}, 
		{L"Comments",         PIDSI_COMMENTS},
		{L"Template",         PIDSI_TEMPLATE},
		{L"Revision Number",  PIDSI_REVNUMBER},
		{L"Created",          PIDSI_CREATE_DTM},
		{L"Edit Time",        PIDSI_EDITTIME},
		{L"Last Saved",       PIDSI_LASTSAVE_DTM},
		{L"LastAuthor",       PIDSI_LASTAUTHOR},
		{L"Last printed",     PIDSI_LASTPRINTED},
		{L"Page Count",       PIDSI_PAGECOUNT},
		{L"Word Count",       PIDSI_WORDCOUNT},
		{L"Char Count",       PIDSI_CHARCOUNT},
		{L"Thumbnail",        PIDSI_THUMBNAIL},
		{L"Doc Security",     PIDSI_DOC_SECURITY},
		{0, 0}
	}, pidsdiArr[] = {
		{L"Company",		  PIDDSI_COMPANY},
		{L"Slide notes",      PIDDSI_SLIDECOUNT},
		{0, 0}
	};
	
	// Count elements in pidsiArr.
	INT nPidsi = 0, nPidsdi = 0;
	for(nPidsi=0; pidsiArr[nPidsi].name; nPidsi++);
	for(nPidsdi=0; pidsdiArr[nPidsdi].name; nPidsdi++);
	  
	// Initialize PROPSPEC for the properties you want.
	PROPSPEC *pPropSpec = new PROPSPEC [nPidsi];
	PROPVARIANT *pPropVar = new PROPVARIANT [nPidsi];
	PROPSPEC *pDocPropSpec = new PROPSPEC [nPidsdi];
	PROPVARIANT *pDocPropVar = new PROPVARIANT [nPidsdi];

	for(INT i=0; i<nPidsi; i++) {
		ZeroMemory(&pPropSpec[i], sizeof(PROPSPEC));
		pPropSpec[i].ulKind = PRSPEC_PROPID;
		pPropSpec[i].propid = pidsiArr[i].pid;
	}
	for(INT i=0; i<nPidsdi; i++) {
		ZeroMemory(&pDocPropSpec[i], sizeof(PROPSPEC));
		pDocPropSpec[i].ulKind = PRSPEC_PROPID;
		pDocPropSpec[i].propid = pidsdiArr[i].pid;
	}

	// Obtain meta infos from FMTID_SummaryInformation
	hr = pPropSetStg->Open(FMTID_SummaryInformation, STGM_READ | STGM_SHARE_EXCLUSIVE, &pPropStg);
	// Read properties.
	hr = pPropStg->ReadMultiple(nPidsi, pPropSpec, pPropVar);
	if(FAILED(hr)) {
         _tprintf(L"IPropertyStg::ReadMultiple() failed w/error %08lx",hr);
    }
	pPropStg->Release();
	pPropStg = NULL;

	// Obtain meta infos from FMTID_DocSummaryInformation
	hr = pPropSetStg->Open(FMTID_DocSummaryInformation, STGM_READ | STGM_SHARE_EXCLUSIVE, &pPropStg);
	// Read properties.
	hr = pPropStg->ReadMultiple(nPidsdi, pDocPropSpec, pDocPropVar);
	if(FAILED(hr)) {
         _tprintf(L"IPropertyStg::ReadMultiple() failed w/error %08lx",hr);
    }
	pPropStg->Release();

	// Copy Meta fields out from FMTID_SummaryInformation
	for(int i = 0; i < nPidsi; i++) {
		switch(pidsiArr[i].pid) {
		case PIDSI_AUTHOR:
			DumpPropVariant(pPropVar + i, m_wszAuthor, MAX_META_LEN);
			break;
		case PIDSI_TITLE:
			DumpPropVariant(pPropVar + i, m_wszTitle, MAX_META_LEN);
			break;
		case PIDSI_SUBJECT:
			DumpPropVariant(pPropVar + i, m_wszSubject, MAX_META_LEN);
			break;
		case PIDSI_KEYWORDS:
			DumpPropVariant(pPropVar + i, m_wszKeywords, MAX_META_LEN);
			break;
		case PIDSI_APPNAME:
			DumpPropVariant(pPropVar + i, m_wszApplication, MAX_META_LEN);
			break;
		case PIDSI_COMMENTS:
			DumpPropVariant(pPropVar + i, m_wszComments, MAX_META_LEN);
			break;
		case PIDSI_TEMPLATE:
			DumpPropVariant(pPropVar + i, m_wszTemplateUsed, MAX_META_LEN);
			break;
		case PIDSI_REVNUMBER:
			DumpPropVariant(pPropVar + i, m_wszRevisionNumber, MAX_META_LEN);
			break;
		case PIDSI_EDITTIME:
			DumpPropVariant(pPropVar + i, m_wszTotalEditingTime, MAX_META_LEN);
			break;
		case PIDSI_LASTSAVE_DTM:
			DumpPropVariant(pPropVar + i, m_wszLastSaved, MAX_META_LEN);
			break;
		case PIDSI_LASTAUTHOR:
			DumpPropVariant(pPropVar + i, m_wszLastEditedBy, MAX_META_LEN);
			break;
		case PIDSI_LASTPRINTED:
			DumpPropVariant(pPropVar + i, m_wszLastPrinted, MAX_META_LEN);
			break;
		case PIDSI_PAGECOUNT:
			DumpPropVariant(pPropVar + i, m_wszPageCount, MAX_META_LEN);
			break;
		case PIDSI_WORDCOUNT:
			DumpPropVariant(pPropVar + i, m_wszWordCount, MAX_META_LEN);
			break;
		case PIDSI_CHARCOUNT:
			DumpPropVariant(pPropVar + i, m_wszCharacterCount, MAX_META_LEN);
			break;
		}
	}

	// Copy Meta fields out from FMTID_DocSummaryInformation
	for(int i = 0; i < nPidsdi; i++) {
		switch(pidsdiArr[i].pid) {
		case PIDDSI_COMPANY:
			DumpPropVariant(pDocPropVar + i, m_wszCompany, MAX_META_LEN);
			break;
		}
	}

	// De-allocate memory.
	delete [] pPropVar;
	delete [] pPropSpec;
	delete [] pDocPropVar;
	delete [] pDocPropSpec;

	// Release obtained interface.
	pPropSetStg->Release();
    pStorage->Release();

	return TRUE;
}