1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_shell.hxx" 26 #include "internal/global.hxx" 27 #include "internal/PropertyHdl.hxx" 28 #include "internal/fileextensions.hxx" 29 #include "internal/metainforeader.hxx" 30 #include "internal/utilities.hxx" 31 #include "internal/config.hxx" 32 33 #include <propkey.h> 34 #include <propvarutil.h> 35 36 #include <malloc.h> 37 #include <strsafe.h> 38 39 #include "internal/stream_helper.hxx" 40 41 //--------------------------- 42 // Module global 43 //--------------------------- 44 long g_DllRefCnt = 0; 45 HINSTANCE g_hModule = NULL; 46 47 // 48 // Map of property keys to the locations of their value(s) in the .??? XML schema 49 // 50 struct PROPERTYMAP 51 { 52 PROPERTYKEY key; 53 PCWSTR pszXPathParent; 54 PCWSTR pszValueNodeName; 55 }; 56 57 PROPERTYMAP g_rgPROPERTYMAP[] = 58 { 59 { PKEY_Title, L"OpenOffice.org", L"Title" }, 60 { PKEY_Author, L"OpenOffice.org", L"Author" }, 61 { PKEY_Subject, L"OpenOffice.org", L"Subject" }, 62 { PKEY_Keywords, L"OpenOffice.org", L"Keyword" }, 63 { PKEY_Comment, L"OpenOffice.org", L"Comments" }, 64 }; 65 66 size_t gPropertyMapTableSize = sizeof(g_rgPROPERTYMAP)/sizeof(g_rgPROPERTYMAP[0]); 67 68 //---------------------------- 69 // 70 //---------------------------- 71 72 CPropertyHdl::CPropertyHdl( long nRefCnt ) : 73 m_RefCnt( nRefCnt ), 74 m_pCache( NULL ) 75 { 76 OutputDebugStringFormat( "CPropertyHdl: CTOR\n" ); 77 InterlockedIncrement( &g_DllRefCnt ); 78 } 79 80 //---------------------------- 81 // 82 //---------------------------- 83 84 CPropertyHdl::~CPropertyHdl() 85 { 86 if ( m_pCache ) 87 { 88 m_pCache->Release(); 89 m_pCache = NULL; 90 } 91 InterlockedDecrement( &g_DllRefCnt ); 92 } 93 94 //----------------------------- 95 // IUnknown methods 96 //----------------------------- 97 HRESULT STDMETHODCALLTYPE CPropertyHdl::QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject) 98 { 99 *ppvObject = 0; 100 101 if (IID_IUnknown == riid || IID_IPropertyStore == riid) 102 { 103 OutputDebugStringFormat( "CPropertyHdl: QueryInterface (IID_IPropertyStore)\n" ); 104 IUnknown* pUnk = static_cast<IPropertyStore*>(this); 105 pUnk->AddRef(); 106 *ppvObject = pUnk; 107 return S_OK; 108 } 109 else if (IID_IPropertyStoreCapabilities == riid) 110 { 111 OutputDebugStringFormat( "CPropertyHdl: QueryInterface (IID_IPropertyStoreCapabilities)\n" ); 112 IUnknown* pUnk = static_cast<IPropertyStore*>(this); 113 pUnk->AddRef(); 114 *ppvObject = pUnk; 115 return S_OK; 116 } 117 else if (IID_IInitializeWithStream == riid) 118 { 119 OutputDebugStringFormat( "CPropertyHdl: QueryInterface (IID_IInitializeWithStream)\n" ); 120 IUnknown* pUnk = static_cast<IInitializeWithStream*>(this); 121 pUnk->AddRef(); 122 *ppvObject = pUnk; 123 return S_OK; 124 } 125 OutputDebugStringFormat( "CPropertyHdl: QueryInterface (something different)\n" ); 126 127 return E_NOINTERFACE; 128 } 129 130 //---------------------------- 131 ULONG STDMETHODCALLTYPE CPropertyHdl::AddRef( void ) 132 { 133 return InterlockedIncrement( &m_RefCnt ); 134 } 135 136 //---------------------------- 137 ULONG STDMETHODCALLTYPE CPropertyHdl::Release( void ) 138 { 139 long refcnt = InterlockedDecrement( &m_RefCnt ); 140 141 if ( 0 == m_RefCnt ) 142 delete this; 143 144 return refcnt; 145 } 146 147 //----------------------------- 148 // IPropertyStore 149 //----------------------------- 150 HRESULT STDMETHODCALLTYPE CPropertyHdl::GetCount( DWORD *pcProps ) 151 { 152 HRESULT hr = E_UNEXPECTED; 153 if ( m_pCache && pcProps ) 154 { 155 hr = m_pCache->GetCount( pcProps ); 156 } 157 158 return hr; 159 } 160 161 //----------------------------- 162 HRESULT STDMETHODCALLTYPE CPropertyHdl::GetAt( DWORD iProp, PROPERTYKEY *pKey ) 163 { 164 HRESULT hr = E_UNEXPECTED; 165 if ( m_pCache ) 166 { 167 hr = m_pCache->GetAt( iProp, pKey ); 168 } 169 170 return hr; 171 } 172 173 //----------------------------- 174 HRESULT STDMETHODCALLTYPE CPropertyHdl::GetValue( REFPROPERTYKEY key, PROPVARIANT *pPropVar ) 175 { 176 HRESULT hr = E_UNEXPECTED; 177 if ( m_pCache ) 178 { 179 hr = m_pCache->GetValue( key, pPropVar ); 180 } 181 182 return hr; 183 } 184 185 //----------------------------- 186 HRESULT STDMETHODCALLTYPE CPropertyHdl::SetValue( REFPROPERTYKEY key, REFPROPVARIANT propVar ) 187 { 188 HRESULT hr = E_UNEXPECTED; 189 if ( m_pCache ) 190 { 191 hr = STG_E_ACCESSDENIED; 192 } 193 return hr; 194 } 195 196 //----------------------------- 197 HRESULT STDMETHODCALLTYPE CPropertyHdl::Commit() 198 { 199 return S_OK; 200 } 201 202 //----------------------------- 203 // IPropertyStore 204 //----------------------------- 205 HRESULT STDMETHODCALLTYPE CPropertyHdl::IsPropertyWritable( REFPROPERTYKEY key ) 206 { 207 // We start with read only properties only 208 return S_FALSE; 209 } 210 211 //----------------------------- 212 // IInitializeWithStream 213 //----------------------------- 214 HRESULT STDMETHODCALLTYPE CPropertyHdl::Initialize( IStream *pStream, DWORD grfMode ) 215 { 216 if ( grfMode & STGM_READWRITE ) 217 return STG_E_ACCESSDENIED; 218 219 if ( !m_pCache ) 220 { 221 #ifdef __MINGW32__ 222 if ( FAILED( PSCreateMemoryPropertyStore( IID_IPropertyStoreCache, reinterpret_cast<void**>(&m_pCache) ) ) ) 223 #else 224 if ( FAILED( PSCreateMemoryPropertyStore( IID_PPV_ARGS( &m_pCache ) ) ) ) 225 #endif 226 OutputDebugStringFormat( "CPropertyHdl::Initialize: PSCreateMemoryPropertyStore failed" ); 227 228 zlib_filefunc_def z_filefunc; 229 pStream = PrepareIStream( pStream, z_filefunc ); 230 231 CMetaInfoReader *pMetaInfoReader = NULL; 232 233 try 234 { 235 pMetaInfoReader = new CMetaInfoReader( (void*)pStream, &z_filefunc ); 236 LoadProperties( pMetaInfoReader ); 237 delete pMetaInfoReader; 238 } 239 catch (const std::exception& e) 240 { 241 OutputDebugStringFormat( "CPropertyHdl::Initialize: Caught exception [%s]", e.what() ); 242 return E_FAIL; 243 } 244 /* 245 // load extended properties and search content 246 _LoadExtendedProperties(); 247 _LoadSearchContent(); 248 */ 249 } 250 251 return S_OK; 252 } 253 254 //----------------------------- 255 void CPropertyHdl::LoadProperties( CMetaInfoReader *pMetaInfoReader ) 256 { 257 OutputDebugStringFormat( "CPropertyHdl: LoadProperties\n" ); 258 PROPVARIANT propvarValues; 259 260 for ( UINT i = 0; i < (UINT)gPropertyMapTableSize; ++i ) 261 { 262 PropVariantClear( &propvarValues ); 263 HRESULT hr = GetItemData( pMetaInfoReader, i, &propvarValues); 264 if (hr == S_OK) 265 { 266 // coerce the value(s) to the appropriate type for the property key 267 hr = PSCoerceToCanonicalValue( g_rgPROPERTYMAP[i].key, &propvarValues ); 268 if (SUCCEEDED(hr)) 269 { 270 // cache the value(s) loaded 271 hr = m_pCache->SetValueAndState( g_rgPROPERTYMAP[i].key, &propvarValues, PSC_NORMAL ); 272 } 273 } 274 } 275 } 276 277 //----------------------------- 278 HRESULT CPropertyHdl::GetItemData( CMetaInfoReader *pMetaInfoReader, UINT nIndex, PROPVARIANT *pVarData ) 279 { 280 switch (nIndex) { 281 case 0: { 282 pVarData->vt = VT_BSTR; 283 pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_TITLE ).c_str() ); 284 OutputDebugStringFormat( "CPropertyHdl::GetItemData: Title=%S.\n", pMetaInfoReader->getTagData( META_INFO_TITLE ).c_str() ); 285 return S_OK; 286 } 287 case 1: { 288 pVarData->vt = VT_BSTR; 289 pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_AUTHOR ).c_str() ); 290 OutputDebugStringFormat( "CPropertyHdl::GetItemData: Author=%S.\n", pMetaInfoReader->getTagData( META_INFO_AUTHOR ).c_str() ); 291 return S_OK; 292 } 293 case 2: { 294 pVarData->vt = VT_BSTR; 295 pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_SUBJECT ).c_str() ); 296 OutputDebugStringFormat( "CPropertyHdl::GetItemData: Subject=%S.\n", pMetaInfoReader->getTagData( META_INFO_SUBJECT ).c_str() ); 297 return S_OK; 298 } 299 case 3: { 300 pVarData->vt = VT_BSTR; 301 pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_KEYWORDS ).c_str() ); 302 OutputDebugStringFormat( "CPropertyHdl::GetItemData: Keywords=%S.\n", pMetaInfoReader->getTagData( META_INFO_KEYWORDS ).c_str() ); 303 return S_OK; 304 } 305 case 4: { 306 pVarData->vt = VT_BSTR; 307 pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_DESCRIPTION ).c_str() ); 308 OutputDebugStringFormat( "CPropertyHdl::GetItemData: Description=%S.\n", pMetaInfoReader->getTagData( META_INFO_DESCRIPTION ).c_str() ); 309 return S_OK; 310 } 311 case 5: { 312 pVarData->vt = VT_BSTR; 313 pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagAttribute( META_INFO_DOCUMENT_STATISTIC, META_INFO_PAGES ).c_str() ); 314 OutputDebugStringFormat( "CPropertyHdl::GetItemData: Pages=%S.\n", pMetaInfoReader->getTagAttribute( META_INFO_DOCUMENT_STATISTIC, META_INFO_PAGES ).c_str() ); 315 return S_OK; 316 } 317 } 318 319 return S_FALSE; 320 } 321 322 //----------------------------------------------------------------------------- 323 // CClassFactory 324 //----------------------------------------------------------------------------- 325 326 long CClassFactory::s_ServerLocks = 0; 327 328 //----------------------------------------------------------------------------- 329 CClassFactory::CClassFactory( const CLSID& clsid ) : 330 m_RefCnt(1), 331 m_Clsid(clsid) 332 { 333 InterlockedIncrement( &g_DllRefCnt ); 334 } 335 336 //----------------------------------------------------------------------------- 337 CClassFactory::~CClassFactory() 338 { 339 InterlockedDecrement( &g_DllRefCnt ); 340 } 341 342 //----------------------------------------------------------------------------- 343 // IUnknown methods 344 //----------------------------------------------------------------------------- 345 HRESULT STDMETHODCALLTYPE CClassFactory::QueryInterface( REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject ) 346 { 347 *ppvObject = 0; 348 349 if ( IID_IUnknown == riid || IID_IClassFactory == riid ) 350 { 351 IUnknown* pUnk = this; 352 pUnk->AddRef(); 353 *ppvObject = pUnk; 354 return S_OK; 355 } 356 357 return E_NOINTERFACE; 358 } 359 360 //----------------------------------------------------------------------------- 361 ULONG STDMETHODCALLTYPE CClassFactory::AddRef( void ) 362 { 363 return InterlockedIncrement( &m_RefCnt ); 364 } 365 366 //----------------------------------------------------------------------------- 367 ULONG STDMETHODCALLTYPE CClassFactory::Release( void ) 368 { 369 long refcnt = InterlockedDecrement( &m_RefCnt ); 370 371 if (0 == refcnt) 372 delete this; 373 374 return refcnt; 375 } 376 377 //----------------------------------------------------------------------------- 378 // IClassFactory methods 379 //----------------------------------------------------------------------------- 380 HRESULT STDMETHODCALLTYPE CClassFactory::CreateInstance( 381 IUnknown __RPC_FAR *pUnkOuter, 382 REFIID riid, 383 void __RPC_FAR *__RPC_FAR *ppvObject) 384 { 385 if ( pUnkOuter != NULL ) 386 return CLASS_E_NOAGGREGATION; 387 388 IUnknown* pUnk = 0; 389 390 if ( CLSID_PROPERTY_HANDLER == m_Clsid ) 391 pUnk = static_cast<IPropertyStore*>( new CPropertyHdl() ); 392 393 POST_CONDITION(pUnk != 0, "Could not create COM object"); 394 395 if (0 == pUnk) 396 return E_OUTOFMEMORY; 397 398 HRESULT hr = pUnk->QueryInterface( riid, ppvObject ); 399 400 // if QueryInterface failed the component will destroy itself 401 pUnk->Release(); 402 403 return hr; 404 } 405 406 //----------------------------------------------------------------------------- 407 HRESULT STDMETHODCALLTYPE CClassFactory::LockServer( BOOL fLock ) 408 { 409 if ( fLock ) 410 InterlockedIncrement( &s_ServerLocks ); 411 else 412 InterlockedDecrement( &s_ServerLocks ); 413 414 return S_OK; 415 } 416 417 //----------------------------------------------------------------------------- 418 bool CClassFactory::IsLocked() 419 { 420 return ( s_ServerLocks > 0 ); 421 } 422 423 //----------------------------------------------------------------------------- 424 extern "C" STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppv) 425 { 426 OutputDebugStringFormat( "DllGetClassObject.\n" ); 427 *ppv = 0; 428 429 if ( rclsid != CLSID_PROPERTY_HANDLER ) 430 return CLASS_E_CLASSNOTAVAILABLE; 431 432 if ( (riid != IID_IUnknown) && (riid != IID_IClassFactory) ) 433 return E_NOINTERFACE; 434 435 IUnknown* pUnk = new CClassFactory( rclsid ); 436 if ( 0 == pUnk ) 437 return E_OUTOFMEMORY; 438 439 *ppv = pUnk; 440 return S_OK; 441 } 442 443 //----------------------------------------------------------------------------- 444 extern "C" STDAPI DllCanUnloadNow( void ) 445 { 446 OutputDebugStringFormat( "DllCanUnloadNow.\n" ); 447 if (CClassFactory::IsLocked() || g_DllRefCnt > 0) 448 return S_FALSE; 449 450 return S_OK; 451 } 452 453 //----------------------------------------------------------------------------- 454 BOOL WINAPI DllMain( HINSTANCE hInst, ULONG /*ul_reason_for_call*/, LPVOID /*lpReserved*/ ) 455 { 456 OutputDebugStringFormat( "DllMain.\n" ); 457 g_hModule = hInst; 458 return TRUE; 459 } 460