Update git submodules
[LibreOffice.git] / shell / source / win32 / shlxthandler / prophdl / propertyhdl.cxx
blob49a8b8d067f1b4fbdc13b6370794c280bbc3207e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <global.hxx>
21 #include <propertyhdl.hxx>
22 #include <fileextensions.hxx>
23 #include <metainforeader.hxx>
24 #include <utilities.hxx>
25 #include <config.hxx>
27 #include <propkey.h>
28 #include <propvarutil.h>
29 #include <sal/macros.h>
31 #include <malloc.h>
32 #include <strsafe.h>
34 #include <stream_helper.hxx>
37 // Module global
39 LONG g_DllRefCnt = 0;
40 static HINSTANCE g_hModule = nullptr;
42 const PROPERTYKEY g_rgPROPERTIES[] =
44 PKEY_Title,
45 PKEY_Author,
46 PKEY_Subject,
47 PKEY_Keywords,
48 PKEY_Comment
51 size_t const gPropertyTableSize = SAL_N_ELEMENTS(g_rgPROPERTIES);
54 CPropertyHdl::CPropertyHdl( LONG nRefCnt ) :
55 m_RefCnt( nRefCnt ),
56 m_pCache( nullptr )
58 OutputDebugStringFormatW( L"CPropertyHdl: CTOR\n" );
59 InterlockedIncrement( &g_DllRefCnt );
63 CPropertyHdl::~CPropertyHdl()
65 if ( m_pCache )
67 m_pCache->Release();
68 m_pCache = nullptr;
70 InterlockedDecrement( &g_DllRefCnt );
74 // IUnknown methods
76 HRESULT STDMETHODCALLTYPE CPropertyHdl::QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject)
78 *ppvObject = nullptr;
80 if (IID_IUnknown == riid || IID_IPropertyStore == riid)
82 OutputDebugStringFormatW( L"CPropertyHdl: QueryInterface (IID_IPropertyStore)\n" );
83 IUnknown* pUnk = static_cast<IPropertyStore*>(this);
84 pUnk->AddRef();
85 *ppvObject = pUnk;
86 return S_OK;
88 else if (IID_IPropertyStoreCapabilities == riid)
90 OutputDebugStringFormatW( L"CPropertyHdl: QueryInterface (IID_IPropertyStoreCapabilities)\n" );
91 IUnknown* pUnk = static_cast<IPropertyStore*>(this);
92 pUnk->AddRef();
93 *ppvObject = pUnk;
94 return S_OK;
96 else if (IID_IInitializeWithStream == riid)
98 OutputDebugStringFormatW( L"CPropertyHdl: QueryInterface (IID_IInitializeWithStream)\n" );
99 IUnknown* pUnk = static_cast<IInitializeWithStream*>(this);
100 pUnk->AddRef();
101 *ppvObject = pUnk;
102 return S_OK;
104 OutputDebugStringFormatW( L"CPropertyHdl: QueryInterface (something different)\n" );
106 return E_NOINTERFACE;
110 ULONG STDMETHODCALLTYPE CPropertyHdl::AddRef()
112 return InterlockedIncrement( &m_RefCnt );
116 ULONG STDMETHODCALLTYPE CPropertyHdl::Release()
118 LONG refcnt = InterlockedDecrement( &m_RefCnt );
120 if ( 0 == m_RefCnt )
121 delete this;
123 return refcnt;
127 // IPropertyStore
129 HRESULT STDMETHODCALLTYPE CPropertyHdl::GetCount( DWORD *pcProps )
131 HRESULT hr = E_UNEXPECTED;
132 if ( m_pCache && pcProps )
134 hr = m_pCache->GetCount( pcProps );
137 return hr;
141 HRESULT STDMETHODCALLTYPE CPropertyHdl::GetAt( DWORD iProp, PROPERTYKEY *pKey )
143 HRESULT hr = E_UNEXPECTED;
144 if ( m_pCache )
146 hr = m_pCache->GetAt( iProp, pKey );
149 return hr;
153 HRESULT STDMETHODCALLTYPE CPropertyHdl::GetValue( REFPROPERTYKEY key, PROPVARIANT *pPropVar )
155 HRESULT hr = E_UNEXPECTED;
156 if ( m_pCache )
158 hr = m_pCache->GetValue( key, pPropVar );
161 return hr;
165 HRESULT STDMETHODCALLTYPE
166 CPropertyHdl::SetValue(REFPROPERTYKEY /*key*/, REFPROPVARIANT /*propVar*/)
168 HRESULT hr = E_UNEXPECTED;
169 if ( m_pCache )
171 hr = STG_E_ACCESSDENIED;
173 return hr;
177 HRESULT STDMETHODCALLTYPE CPropertyHdl::Commit()
179 return S_OK;
183 // IPropertyStore
185 HRESULT STDMETHODCALLTYPE
186 CPropertyHdl::IsPropertyWritable(REFPROPERTYKEY /*key*/)
188 // We start with read only properties only
189 return S_FALSE;
193 // IInitializeWithStream
195 HRESULT STDMETHODCALLTYPE CPropertyHdl::Initialize( IStream *pStream, DWORD grfMode )
197 if ( grfMode & STGM_READWRITE )
198 return STG_E_ACCESSDENIED;
200 if ( !m_pCache )
202 if ( FAILED( PSCreateMemoryPropertyStore( IID_PPV_ARGS( &m_pCache ) ) ) )
203 OutputDebugStringFormatW( L"CPropertyHdl::Initialize: PSCreateMemoryPropertyStore failed" );
205 BufferStream tmpStream(pStream);
207 CMetaInfoReader *pMetaInfoReader = nullptr;
211 pMetaInfoReader = new CMetaInfoReader( &tmpStream );
212 LoadProperties( pMetaInfoReader );
213 delete pMetaInfoReader;
215 catch (const std::exception& e)
217 // To output 8-bit string using unicode version of formatting functions, use capital %S type
218 // see https://msdn.microsoft.com/en-us/library/hf4y5e3w
219 OutputDebugStringFormatW( L"CPropertyHdl::Initialize: Caught exception [%S]", e.what() );
220 return E_FAIL;
224 return S_OK;
227 namespace {
229 HRESULT GetItemData( CMetaInfoReader *pMetaInfoReader, UINT nIndex, PROPVARIANT *pVarData )
231 switch (nIndex) {
232 case 0: {
233 pVarData->vt = VT_BSTR;
234 pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_TITLE ).c_str() );
235 OutputDebugStringFormatW( L"CPropertyHdl::GetItemData: Title=%s.\n", pMetaInfoReader->getTagData( META_INFO_TITLE ).c_str() );
236 return S_OK;
238 case 1: {
239 pVarData->vt = VT_BSTR;
240 pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_AUTHOR ).c_str() );
241 OutputDebugStringFormatW( L"CPropertyHdl::GetItemData: Author=%s.\n", pMetaInfoReader->getTagData( META_INFO_AUTHOR ).c_str() );
242 return S_OK;
244 case 2: {
245 pVarData->vt = VT_BSTR;
246 pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_SUBJECT ).c_str() );
247 OutputDebugStringFormatW( L"CPropertyHdl::GetItemData: Subject=%s.\n", pMetaInfoReader->getTagData( META_INFO_SUBJECT ).c_str() );
248 return S_OK;
250 case 3: {
251 pVarData->vt = VT_BSTR;
252 pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_KEYWORDS ).c_str() );
253 OutputDebugStringFormatW( L"CPropertyHdl::GetItemData: Keywords=%s.\n", pMetaInfoReader->getTagData( META_INFO_KEYWORDS ).c_str() );
254 return S_OK;
256 case 4: {
257 pVarData->vt = VT_BSTR;
258 pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_DESCRIPTION ).c_str() );
259 OutputDebugStringFormatW( L"CPropertyHdl::GetItemData: Description=%s.\n", pMetaInfoReader->getTagData( META_INFO_DESCRIPTION ).c_str() );
260 return S_OK;
262 case 5: {
263 pVarData->vt = VT_BSTR;
264 pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagAttribute( META_INFO_DOCUMENT_STATISTIC, META_INFO_PAGES ).c_str() );
265 OutputDebugStringFormatW( L"CPropertyHdl::GetItemData: Pages=%s.\n", pMetaInfoReader->getTagAttribute( META_INFO_DOCUMENT_STATISTIC, META_INFO_PAGES ).c_str() );
266 return S_OK;
270 return S_FALSE;
275 void CPropertyHdl::LoadProperties( CMetaInfoReader *pMetaInfoReader )
277 OutputDebugStringFormatW( L"CPropertyHdl: LoadProperties\n" );
278 PROPVARIANT propvarValues;
280 for ( UINT i = 0; i < UINT(gPropertyTableSize); ++i )
282 PropVariantClear( &propvarValues );
283 HRESULT hr = GetItemData( pMetaInfoReader, i, &propvarValues);
284 if (hr == S_OK)
286 // coerce the value(s) to the appropriate type for the property key
287 hr = PSCoerceToCanonicalValue( g_rgPROPERTIES[i], &propvarValues );
288 if (SUCCEEDED(hr))
290 // cache the value(s) loaded
291 hr = m_pCache->SetValueAndState( g_rgPROPERTIES[i], &propvarValues, PSC_NORMAL );
297 // CClassFactory
300 LONG CClassFactory::s_ServerLocks = 0;
303 CClassFactory::CClassFactory( const CLSID& clsid ) :
304 m_RefCnt(1),
305 m_Clsid(clsid)
307 InterlockedIncrement( &g_DllRefCnt );
311 CClassFactory::~CClassFactory()
313 InterlockedDecrement( &g_DllRefCnt );
317 // IUnknown methods
319 HRESULT STDMETHODCALLTYPE CClassFactory::QueryInterface( REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject )
321 *ppvObject = nullptr;
323 if ( IID_IUnknown == riid || IID_IClassFactory == riid )
325 IUnknown* pUnk = this;
326 pUnk->AddRef();
327 *ppvObject = pUnk;
328 return S_OK;
331 return E_NOINTERFACE;
335 ULONG STDMETHODCALLTYPE CClassFactory::AddRef()
337 return InterlockedIncrement( &m_RefCnt );
341 ULONG STDMETHODCALLTYPE CClassFactory::Release()
343 LONG refcnt = InterlockedDecrement( &m_RefCnt );
345 if (0 == refcnt)
346 delete this;
348 return refcnt;
352 // IClassFactory methods
354 HRESULT STDMETHODCALLTYPE CClassFactory::CreateInstance(
355 IUnknown __RPC_FAR *pUnkOuter,
356 REFIID riid,
357 void __RPC_FAR *__RPC_FAR *ppvObject)
359 if ( pUnkOuter != nullptr )
360 return CLASS_E_NOAGGREGATION;
362 IUnknown* pUnk = nullptr;
364 if ( CLSID_PROPERTY_HANDLER == m_Clsid )
365 pUnk = static_cast<IPropertyStore*>( new CPropertyHdl() );
367 if (nullptr == pUnk)
369 return E_OUTOFMEMORY;
372 HRESULT hr = pUnk->QueryInterface( riid, ppvObject );
374 // if QueryInterface failed the component will destroy itself
375 pUnk->Release();
377 return hr;
381 HRESULT STDMETHODCALLTYPE CClassFactory::LockServer( BOOL fLock )
383 if ( fLock )
384 InterlockedIncrement( &s_ServerLocks );
385 else
386 InterlockedDecrement( &s_ServerLocks );
388 return S_OK;
392 bool CClassFactory::IsLocked()
394 return ( s_ServerLocks > 0 );
398 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
400 OutputDebugStringFormatW( L"DllGetClassObject.\n" );
401 *ppv = nullptr;
403 if ( rclsid != CLSID_PROPERTY_HANDLER )
404 return CLASS_E_CLASSNOTAVAILABLE;
406 if ( (riid != IID_IUnknown) && (riid != IID_IClassFactory) )
407 return E_NOINTERFACE;
409 IUnknown* pUnk = new CClassFactory( rclsid );
410 *ppv = pUnk;
411 return S_OK;
415 STDAPI DllCanUnloadNow()
417 OutputDebugStringFormatW( L"DllCanUnloadNow.\n" );
418 if (CClassFactory::IsLocked() || g_DllRefCnt > 0)
419 return S_FALSE;
421 return S_OK;
425 BOOL WINAPI DllMain( HINSTANCE hInst, ULONG /*ul_reason_for_call*/, LPVOID /*lpReserved*/ )
427 OutputDebugStringFormatW( L"DllMain.\n" );
428 g_hModule = hInst;
429 return TRUE;
432 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */