Bump version to 5.0-14
[LibreOffice.git] / shell / source / win32 / shlxthandler / prophdl / propertyhdl.cxx
blobf3807062140642d302fbbb1ed5b5c03f4ed36912
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 "internal/global.hxx"
21 #include "internal/propertyhdl.hxx"
22 #include "internal/fileextensions.hxx"
23 #include "internal/metainforeader.hxx"
24 #include "internal/utilities.hxx"
25 #include "internal/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 "internal/stream_helper.hxx"
37 // Module global
39 long g_DllRefCnt = 0;
40 HINSTANCE g_hModule = NULL;
42 // Map of property keys to the locations of their value(s) in the .??? XML schema
43 struct PROPERTYMAP
45 PROPERTYKEY key;
46 PCWSTR pszXPathParent;
47 PCWSTR pszValueNodeName;
50 PROPERTYMAP g_rgPROPERTYMAP[] =
52 { PKEY_Title, L"LibreOffice", L"Title" },
53 { PKEY_Author, L"LibreOffice", L"Author" },
54 { PKEY_Subject, L"LibreOffice", L"Subject" },
55 { PKEY_Keywords, L"LibreOffice", L"Keyword" },
56 { PKEY_Comment, L"LibreOffice", L"Comments" },
59 size_t gPropertyMapTableSize = sizeof(g_rgPROPERTYMAP)/sizeof(g_rgPROPERTYMAP[0]);
63 CPropertyHdl::CPropertyHdl( long nRefCnt ) :
64 m_RefCnt( nRefCnt ),
65 m_pCache( NULL )
67 OutputDebugStringFormat( "CPropertyHdl: CTOR\n" );
68 InterlockedIncrement( &g_DllRefCnt );
73 CPropertyHdl::~CPropertyHdl()
75 if ( m_pCache )
77 m_pCache->Release();
78 m_pCache = NULL;
80 InterlockedDecrement( &g_DllRefCnt );
84 // IUnknown methods
86 HRESULT STDMETHODCALLTYPE CPropertyHdl::QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject)
88 *ppvObject = 0;
90 if (IID_IUnknown == riid || IID_IPropertyStore == riid)
92 OutputDebugStringFormat( "CPropertyHdl: QueryInterface (IID_IPropertyStore)\n" );
93 IUnknown* pUnk = static_cast<IPropertyStore*>(this);
94 pUnk->AddRef();
95 *ppvObject = pUnk;
96 return S_OK;
98 else if (IID_IPropertyStoreCapabilities == riid)
100 OutputDebugStringFormat( "CPropertyHdl: QueryInterface (IID_IPropertyStoreCapabilities)\n" );
101 IUnknown* pUnk = static_cast<IPropertyStore*>(this);
102 pUnk->AddRef();
103 *ppvObject = pUnk;
104 return S_OK;
106 else if (IID_IInitializeWithStream == riid)
108 OutputDebugStringFormat( "CPropertyHdl: QueryInterface (IID_IInitializeWithStream)\n" );
109 IUnknown* pUnk = static_cast<IInitializeWithStream*>(this);
110 pUnk->AddRef();
111 *ppvObject = pUnk;
112 return S_OK;
114 OutputDebugStringFormat( "CPropertyHdl: QueryInterface (something different)\n" );
116 return E_NOINTERFACE;
120 ULONG STDMETHODCALLTYPE CPropertyHdl::AddRef()
122 return InterlockedIncrement( &m_RefCnt );
126 ULONG STDMETHODCALLTYPE CPropertyHdl::Release()
128 long refcnt = InterlockedDecrement( &m_RefCnt );
130 if ( 0 == m_RefCnt )
131 delete this;
133 return refcnt;
137 // IPropertyStore
139 HRESULT STDMETHODCALLTYPE CPropertyHdl::GetCount( DWORD *pcProps )
141 HRESULT hr = E_UNEXPECTED;
142 if ( m_pCache && pcProps )
144 hr = m_pCache->GetCount( pcProps );
147 return hr;
151 HRESULT STDMETHODCALLTYPE CPropertyHdl::GetAt( DWORD iProp, PROPERTYKEY *pKey )
153 HRESULT hr = E_UNEXPECTED;
154 if ( m_pCache )
156 hr = m_pCache->GetAt( iProp, pKey );
159 return hr;
163 HRESULT STDMETHODCALLTYPE CPropertyHdl::GetValue( REFPROPERTYKEY key, PROPVARIANT *pPropVar )
165 HRESULT hr = E_UNEXPECTED;
166 if ( m_pCache )
168 hr = m_pCache->GetValue( key, pPropVar );
171 return hr;
175 HRESULT STDMETHODCALLTYPE
176 CPropertyHdl::SetValue(REFPROPERTYKEY /*key*/, REFPROPVARIANT /*propVar*/)
178 HRESULT hr = E_UNEXPECTED;
179 if ( m_pCache )
181 hr = STG_E_ACCESSDENIED;
183 return hr;
187 HRESULT STDMETHODCALLTYPE CPropertyHdl::Commit()
189 return S_OK;
193 // IPropertyStore
195 HRESULT STDMETHODCALLTYPE
196 CPropertyHdl::IsPropertyWritable(REFPROPERTYKEY /*key*/)
198 // We start with read only properties only
199 return S_FALSE;
203 // IInitializeWithStream
205 HRESULT STDMETHODCALLTYPE CPropertyHdl::Initialize( IStream *pStream, DWORD grfMode )
207 if ( grfMode & STGM_READWRITE )
208 return STG_E_ACCESSDENIED;
210 if ( !m_pCache )
212 #ifdef __MINGW32__
213 if ( FAILED( PSCreateMemoryPropertyStore( IID_IPropertyStoreCache, reinterpret_cast<void**>(&m_pCache) ) ) )
214 #else
215 if ( FAILED( PSCreateMemoryPropertyStore( IID_PPV_ARGS( &m_pCache ) ) ) )
216 #endif
217 OutputDebugStringFormat( "CPropertyHdl::Initialize: PSCreateMemoryPropertyStore failed" );
219 BufferStream tmpStream(pStream);
221 CMetaInfoReader *pMetaInfoReader = NULL;
225 pMetaInfoReader = new CMetaInfoReader( &tmpStream );
226 LoadProperties( pMetaInfoReader );
227 delete pMetaInfoReader;
229 catch (const std::exception& e)
231 OutputDebugStringFormat( "CPropertyHdl::Initialize: Caught exception [%s]", e.what() );
232 return E_FAIL;
236 return S_OK;
240 void CPropertyHdl::LoadProperties( CMetaInfoReader *pMetaInfoReader )
242 OutputDebugStringFormat( "CPropertyHdl: LoadProperties\n" );
243 PROPVARIANT propvarValues;
245 for ( UINT i = 0; i < (UINT)gPropertyMapTableSize; ++i )
247 PropVariantClear( &propvarValues );
248 HRESULT hr = GetItemData( pMetaInfoReader, i, &propvarValues);
249 if (hr == S_OK)
251 // coerce the value(s) to the appropriate type for the property key
252 hr = PSCoerceToCanonicalValue( g_rgPROPERTYMAP[i].key, &propvarValues );
253 if (SUCCEEDED(hr))
255 // cache the value(s) loaded
256 hr = m_pCache->SetValueAndState( g_rgPROPERTYMAP[i].key, &propvarValues, PSC_NORMAL );
263 HRESULT CPropertyHdl::GetItemData( CMetaInfoReader *pMetaInfoReader, UINT nIndex, PROPVARIANT *pVarData )
265 switch (nIndex) {
266 case 0: {
267 pVarData->vt = VT_BSTR;
268 pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_TITLE ).c_str() );
269 OutputDebugStringFormat( "CPropertyHdl::GetItemData: Title=%S.\n", pMetaInfoReader->getTagData( META_INFO_TITLE ).c_str() );
270 return S_OK;
272 case 1: {
273 pVarData->vt = VT_BSTR;
274 pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_AUTHOR ).c_str() );
275 OutputDebugStringFormat( "CPropertyHdl::GetItemData: Author=%S.\n", pMetaInfoReader->getTagData( META_INFO_AUTHOR ).c_str() );
276 return S_OK;
278 case 2: {
279 pVarData->vt = VT_BSTR;
280 pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_SUBJECT ).c_str() );
281 OutputDebugStringFormat( "CPropertyHdl::GetItemData: Subject=%S.\n", pMetaInfoReader->getTagData( META_INFO_SUBJECT ).c_str() );
282 return S_OK;
284 case 3: {
285 pVarData->vt = VT_BSTR;
286 pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_KEYWORDS ).c_str() );
287 OutputDebugStringFormat( "CPropertyHdl::GetItemData: Keywords=%S.\n", pMetaInfoReader->getTagData( META_INFO_KEYWORDS ).c_str() );
288 return S_OK;
290 case 4: {
291 pVarData->vt = VT_BSTR;
292 pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_DESCRIPTION ).c_str() );
293 OutputDebugStringFormat( "CPropertyHdl::GetItemData: Description=%S.\n", pMetaInfoReader->getTagData( META_INFO_DESCRIPTION ).c_str() );
294 return S_OK;
296 case 5: {
297 pVarData->vt = VT_BSTR;
298 pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagAttribute( META_INFO_DOCUMENT_STATISTIC, META_INFO_PAGES ).c_str() );
299 OutputDebugStringFormat( "CPropertyHdl::GetItemData: Pages=%S.\n", pMetaInfoReader->getTagAttribute( META_INFO_DOCUMENT_STATISTIC, META_INFO_PAGES ).c_str() );
300 return S_OK;
304 return S_FALSE;
308 // CClassFactory
311 long CClassFactory::s_ServerLocks = 0;
314 CClassFactory::CClassFactory( const CLSID& clsid ) :
315 m_RefCnt(1),
316 m_Clsid(clsid)
318 InterlockedIncrement( &g_DllRefCnt );
322 CClassFactory::~CClassFactory()
324 InterlockedDecrement( &g_DllRefCnt );
328 // IUnknown methods
330 HRESULT STDMETHODCALLTYPE CClassFactory::QueryInterface( REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject )
332 *ppvObject = 0;
334 if ( IID_IUnknown == riid || IID_IClassFactory == riid )
336 IUnknown* pUnk = this;
337 pUnk->AddRef();
338 *ppvObject = pUnk;
339 return S_OK;
342 return E_NOINTERFACE;
346 ULONG STDMETHODCALLTYPE CClassFactory::AddRef()
348 return InterlockedIncrement( &m_RefCnt );
352 ULONG STDMETHODCALLTYPE CClassFactory::Release()
354 long refcnt = InterlockedDecrement( &m_RefCnt );
356 if (0 == refcnt)
357 delete this;
359 return refcnt;
363 // IClassFactory methods
365 HRESULT STDMETHODCALLTYPE CClassFactory::CreateInstance(
366 IUnknown __RPC_FAR *pUnkOuter,
367 REFIID riid,
368 void __RPC_FAR *__RPC_FAR *ppvObject)
370 if ( pUnkOuter != NULL )
371 return CLASS_E_NOAGGREGATION;
373 IUnknown* pUnk = 0;
375 if ( CLSID_PROPERTY_HANDLER == m_Clsid )
376 pUnk = static_cast<IPropertyStore*>( new CPropertyHdl() );
378 if (0 == pUnk)
380 return E_OUTOFMEMORY;
383 HRESULT hr = pUnk->QueryInterface( riid, ppvObject );
385 // if QueryInterface failed the component will destroy itself
386 pUnk->Release();
388 return hr;
392 HRESULT STDMETHODCALLTYPE CClassFactory::LockServer( BOOL fLock )
394 if ( fLock )
395 InterlockedIncrement( &s_ServerLocks );
396 else
397 InterlockedDecrement( &s_ServerLocks );
399 return S_OK;
403 bool CClassFactory::IsLocked()
405 return ( s_ServerLocks > 0 );
409 extern "C" STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppv)
411 OutputDebugStringFormat( "DllGetClassObject.\n" );
412 *ppv = 0;
414 if ( rclsid != CLSID_PROPERTY_HANDLER )
415 return CLASS_E_CLASSNOTAVAILABLE;
417 if ( (riid != IID_IUnknown) && (riid != IID_IClassFactory) )
418 return E_NOINTERFACE;
420 IUnknown* pUnk = new CClassFactory( rclsid );
421 *ppv = pUnk;
422 return S_OK;
426 extern "C" STDAPI DllCanUnloadNow()
428 OutputDebugStringFormat( "DllCanUnloadNow.\n" );
429 if (CClassFactory::IsLocked() || g_DllRefCnt > 0)
430 return S_FALSE;
432 return S_OK;
436 BOOL WINAPI DllMain( HINSTANCE hInst, ULONG /*ul_reason_for_call*/, LPVOID /*lpReserved*/ )
438 OutputDebugStringFormat( "DllMain.\n" );
439 g_hModule = hInst;
440 return TRUE;
443 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */