286 lines
6.8 KiB
C++
286 lines
6.8 KiB
C++
|
#include "priv.h"
|
||
|
#include "infotip.h"
|
||
|
#include "resource.h"
|
||
|
|
||
|
#include <mluisupp.h>
|
||
|
|
||
|
HRESULT ReadProp(IPropertyStorage *ppropstg, PROPID propid, PROPVARIANT *ppropvar)
|
||
|
{
|
||
|
PROPSPEC prspec = { PRSPEC_PROPID, propid };
|
||
|
|
||
|
return ppropstg->ReadMultiple(1, &prspec, ppropvar);
|
||
|
}
|
||
|
|
||
|
STDAPI GetStringProp(IPropertyStorage *ppropstg, PROPID propid, LPTSTR pszBuf, DWORD cchBuf)
|
||
|
{
|
||
|
PROPVARIANT propvar;
|
||
|
|
||
|
*pszBuf = 0;
|
||
|
|
||
|
if (S_OK == ReadProp(ppropstg, propid, &propvar))
|
||
|
{
|
||
|
if (VT_LPWSTR == propvar.vt)
|
||
|
{
|
||
|
SHUnicodeToTChar(propvar.pwszVal, pszBuf, cchBuf);
|
||
|
}
|
||
|
else if (VT_LPSTR == propvar.vt)
|
||
|
{
|
||
|
SHAnsiToTChar(propvar.pszVal, pszBuf, cchBuf);
|
||
|
}
|
||
|
PropVariantClear(&propvar);
|
||
|
}
|
||
|
|
||
|
return *pszBuf ? S_OK : S_FALSE;
|
||
|
}
|
||
|
|
||
|
STDAPI GetFileTimeProp(IPropertyStorage *ppropstg, PROPID propid, LPTSTR pszBuf, DWORD cchBuf)
|
||
|
{
|
||
|
PROPVARIANT propvar;
|
||
|
|
||
|
*pszBuf = 0;
|
||
|
|
||
|
if (S_OK == ReadProp(ppropstg, propid, &propvar))
|
||
|
{
|
||
|
if (VT_FILETIME == propvar.vt)
|
||
|
{
|
||
|
SHFormatDateTime(&propvar.filetime, NULL, pszBuf, cchBuf);
|
||
|
}
|
||
|
PropVariantClear(&propvar);
|
||
|
}
|
||
|
|
||
|
return *pszBuf ? S_OK : S_FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD AppendTipText(LPTSTR pszBuf, int cchBuf, UINT ids, ...)
|
||
|
{
|
||
|
DWORD dwRet;
|
||
|
TCHAR szFmt[64];
|
||
|
va_list ArgList;
|
||
|
|
||
|
if (ids == 0 || 0 == MLLoadString(ids, szFmt, SIZECHARS(szFmt)))
|
||
|
StrCpyN(szFmt, TEXT("%s%s"), ARRAYSIZE(szFmt));
|
||
|
|
||
|
va_start(ArgList, ids);
|
||
|
dwRet = wvnsprintf(pszBuf, cchBuf, szFmt, ArgList);
|
||
|
va_end(ArgList);
|
||
|
|
||
|
return dwRet;
|
||
|
}
|
||
|
|
||
|
STDAPI GetInfoTipFromStorage(IPropertySetStorage *ppropsetstg, const ITEM_PROP *pip, WCHAR **ppszTip)
|
||
|
{
|
||
|
TCHAR szTip[2048];
|
||
|
LPTSTR psz = szTip;
|
||
|
LPCTSTR pszCRLF = TEXT("");
|
||
|
UINT cch, cchMac = SIZECHARS(szTip);
|
||
|
const GUID *pfmtIdLast = NULL;
|
||
|
IPropertyStorage *ppropstg = NULL;
|
||
|
HRESULT hres = E_FAIL;
|
||
|
|
||
|
*ppszTip = NULL;
|
||
|
|
||
|
for (; pip->pfmtid; pip++)
|
||
|
{
|
||
|
// cache the last FMTID and reuse it if the next FMTID is the same
|
||
|
|
||
|
if (!ppropstg || !IsEqualGUID(*pfmtIdLast, *pip->pfmtid))
|
||
|
{
|
||
|
if (ppropstg)
|
||
|
{
|
||
|
ppropstg->Release();
|
||
|
ppropstg = NULL;
|
||
|
}
|
||
|
|
||
|
pfmtIdLast = pip->pfmtid;
|
||
|
ppropsetstg->Open(*pip->pfmtid, STGM_READ | STGM_SHARE_EXCLUSIVE, &ppropstg);
|
||
|
}
|
||
|
|
||
|
if (ppropstg)
|
||
|
{
|
||
|
TCHAR szT[256];
|
||
|
|
||
|
hres = pip->pfnRead(ppropstg, pip->idProp, szT, SIZECHARS(szT));
|
||
|
if (S_OK == hres)
|
||
|
{
|
||
|
cch = AppendTipText(psz, cchMac, pip->idFmtString, pszCRLF, szT);
|
||
|
psz += cch;
|
||
|
cchMac -= cch;
|
||
|
pszCRLF = TEXT("\r\n");
|
||
|
}
|
||
|
else if (hres != S_FALSE)
|
||
|
{
|
||
|
break; // error, exit for loop
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (ppropstg)
|
||
|
ppropstg->Release();
|
||
|
|
||
|
hres = S_FALSE; // assume no tooltip
|
||
|
|
||
|
if (psz != szTip)
|
||
|
{
|
||
|
hres = SHStrDup(szTip, ppszTip);
|
||
|
}
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
class CDocFileInfoTip : public IPersistFile, public IQueryInfo
|
||
|
{
|
||
|
public:
|
||
|
CDocFileInfoTip(void);
|
||
|
|
||
|
// IUnknown methods
|
||
|
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
|
||
|
STDMETHODIMP_(ULONG) AddRef(void);
|
||
|
STDMETHODIMP_(ULONG) Release(void);
|
||
|
|
||
|
// IPersist methods
|
||
|
|
||
|
STDMETHODIMP GetClassID(CLSID *pclsid);
|
||
|
|
||
|
// IPersistFile methods
|
||
|
|
||
|
STDMETHODIMP IsDirty(void);
|
||
|
STDMETHODIMP Save(LPCOLESTR pcwszFileName, BOOL bRemember);
|
||
|
STDMETHODIMP SaveCompleted(LPCOLESTR pcwszFileName);
|
||
|
STDMETHODIMP Load(LPCOLESTR pcwszFileName, DWORD dwMode);
|
||
|
STDMETHODIMP GetCurFile(LPOLESTR *ppwszFileName);
|
||
|
|
||
|
// IQueryInfo methods
|
||
|
|
||
|
STDMETHODIMP GetInfoTip(DWORD dwFlags, WCHAR **ppwszTip);
|
||
|
STDMETHODIMP GetInfoFlags(DWORD *pdwFlags);
|
||
|
|
||
|
private:
|
||
|
|
||
|
LONG m_cRef;
|
||
|
WCHAR m_szFile[MAX_PATH]; // Name of file we are working on
|
||
|
|
||
|
~CDocFileInfoTip(void); // Prevent this class from being allocated on the stack or it will fault.
|
||
|
};
|
||
|
|
||
|
|
||
|
CDocFileInfoTip::CDocFileInfoTip(void) : m_cRef(1)
|
||
|
{
|
||
|
DllAddRef();
|
||
|
}
|
||
|
|
||
|
CDocFileInfoTip::~CDocFileInfoTip(void)
|
||
|
{
|
||
|
DllRelease();
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CDocFileInfoTip::QueryInterface(REFIID riid, void **ppv)
|
||
|
{
|
||
|
static const QITAB qit[] = {
|
||
|
QITABENT(CDocFileInfoTip, IQueryInfo), // IID_IQueryInfo
|
||
|
QITABENT(CDocFileInfoTip, IPersistFile), // IID_IPersistFile
|
||
|
QITABENTMULTI(CDocFileInfoTip, IPersist, IPersistFile), // IID_IPersist
|
||
|
{ 0 },
|
||
|
};
|
||
|
return QISearch(this, qit, riid, ppv);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP_(ULONG) CDocFileInfoTip::AddRef()
|
||
|
{
|
||
|
InterlockedIncrement(&m_cRef);
|
||
|
return m_cRef;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP_(ULONG) CDocFileInfoTip::Release()
|
||
|
{
|
||
|
if (InterlockedDecrement(&m_cRef))
|
||
|
return m_cRef;
|
||
|
|
||
|
delete this;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// IPersist methods
|
||
|
|
||
|
STDMETHODIMP CDocFileInfoTip::GetClassID(CLSID *pclsid)
|
||
|
{
|
||
|
*pclsid = CLSID_DocFileInfoTip;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
// IPersistFile methods
|
||
|
|
||
|
STDMETHODIMP CDocFileInfoTip::IsDirty(void)
|
||
|
{
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CDocFileInfoTip::Save(LPCOLESTR pwszFile, BOOL bRemember)
|
||
|
{
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CDocFileInfoTip::SaveCompleted(LPCOLESTR pwszFile)
|
||
|
{
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CDocFileInfoTip::Load(const WCHAR *pwszFile, DWORD dwMode)
|
||
|
{
|
||
|
StrCpyNW(m_szFile, pwszFile, ARRAYSIZE(m_szFile));
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CDocFileInfoTip::GetCurFile(WCHAR **ppwszFile)
|
||
|
{
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
// IQueryInfo methods
|
||
|
|
||
|
const ITEM_PROP c_rgDocProps[] = {
|
||
|
{ &FMTID_SummaryInformation, PIDSI_AUTHOR, GetStringProp, IDS_AUTHOR },
|
||
|
{ &FMTID_SummaryInformation, PIDSI_TITLE, GetStringProp, IDS_DOCTITLE },
|
||
|
{ &FMTID_SummaryInformation, PIDSI_SUBJECT, GetStringProp, IDS_SUBJECT },
|
||
|
{ &FMTID_SummaryInformation, PIDSI_COMMENTS, GetStringProp, IDS_COMMENTS },
|
||
|
{ NULL, 0, 0, 0 },
|
||
|
};
|
||
|
|
||
|
|
||
|
STDMETHODIMP CDocFileInfoTip::GetInfoTip(DWORD dwFlags, WCHAR **ppwszTip)
|
||
|
{
|
||
|
*ppwszTip = NULL;
|
||
|
IStorage *pstg;
|
||
|
HRESULT hres = StgOpenStorage(m_szFile, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, NULL, 0, &pstg);
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
IPropertySetStorage *pprop;
|
||
|
hres = pstg->QueryInterface(IID_IPropertySetStorage, (void **)&pprop);
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
hres = GetInfoTipFromStorage(pprop, c_rgDocProps, ppwszTip);
|
||
|
pprop->Release();
|
||
|
}
|
||
|
pstg->Release();
|
||
|
}
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CDocFileInfoTip::GetInfoFlags(DWORD *pdwFlags)
|
||
|
{
|
||
|
*pdwFlags = 0;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
STDAPI CDocFileInfoTip_CreateInstance(IUnknown * punkOuter, IUnknown ** ppunk, LPCOBJECTINFO poi)
|
||
|
{
|
||
|
HRESULT hres = E_OUTOFMEMORY;
|
||
|
CDocFileInfoTip *pis = new CDocFileInfoTip();
|
||
|
if (pis)
|
||
|
{
|
||
|
*ppunk = SAFECAST(pis, IQueryInfo *);
|
||
|
hres = S_OK;
|
||
|
}
|
||
|
return hres;
|
||
|
}
|