1 /*************************************************************************
2  *
3  *  $RCSfile: ooofilt.cxx,v $
4  *
5  *  $Revision: 1.2 $
6  *
7  *  last change: $Author: hr $ $Date: 2004-09-08 14:32:56 $
8  *
9  *  The Contents of this file are made available subject to the terms of
10  *  either of the following licenses
11  *
12  *         - GNU Lesser General Public License Version 2.1
13  *         - Sun Industry Standards Source License Version 1.1
14  *
15  *  Sun Microsystems Inc., October, 2000
16  *
17  *  GNU Lesser General Public License Version 2.1
18  *  =============================================
19  *  Copyright 2000 by Sun Microsystems, Inc.
20  *  901 San Antonio Road, Palo Alto, CA 94303, USA
21  *
22  *  This library is free software; you can redistribute it and/or
23  *  modify it under the terms of the GNU Lesser General Public
24  *  License version 2.1, as published by the Free Software Foundation.
25  *
26  *  This library is distributed in the hope that it will be useful,
27  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
28  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
29  *  Lesser General Public License for more details.
30  *
31  *  You should have received a copy of the GNU Lesser General Public
32  *  License along with this library; if not, write to the Free Software
33  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
34  *  MA  02111-1307  USA
35  *
36  *
37  *  Sun Industry Standards Source License Version 1.1
38  *  =================================================
39  *  The contents of this file are subject to the Sun Industry Standards
40  *  Source License Version 1.1 (the "License"); You may not use this file
41  *  except in compliance with the License. You may obtain a copy of the
42  *  License at http://www.openoffice.org/license.html.
43  *
44  *  Software provided under this License is provided on an "AS IS" basis,
45  *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
46  *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
47  *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
48  *  See the License for the specific provisions governing your rights and
49  *  obligations concerning the Software.
50  *
51  *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
52  *
53  *  Copyright: 2000 by Sun Microsystems, Inc.
54  *
55  *  All Rights Reserved.
56  *
57  *  Contributor(s): _______________________________________
58  *
59  *
60  ************************************************************************/
61 
62 //--------------------------------------------------------------------------
63 //  File:       ooofilt.cxx
64 //
65 //  Contents:   Filter Implementation for OpenOffice.Org Document using
66 //              Indexing Service
67 //
68 //  Summary:    The OpenOffice.org filter reads OpenOffice.org files (with the
69 //              extension .sxw .sxi, etc) and extract their content, author,
70 //              keywords,subject,comments and title to be filtered.
71 //
72 //  Platform:   Windows 2000, Windows XP
73 //
74 //--------------------------------------------------------------------------
75 
76 #ifndef CONTENTREADER_HXX_INCLUDED
77 #include "internal/contentreader.hxx"
78 #endif
79 
80 #ifndef METAINFOREADER_HXX_INCLUDED
81 #include "internal/metainforeader.hxx"
82 #endif
83 
84 #ifndef UTILITIES_HXX_INCLUDED
85 #include "internal/utilities.hxx"
86 #endif
87 
88 #ifndef REGISTRY_HXX_INCLUDED
89 #include "internal/registry.hxx"
90 #endif
91 
92 #ifndef FILEEXTENSIONS_HXX_INCLUDED
93 #include "internal/fileextensions.hxx"
94 #endif
95 
96 //--------------------------------------------------------------------------
97 //
98 //  Include file    Purpose
99 //
100 //  windows.h       Win32 declarations
101 //  string.h        string wstring declarations
102 //  filter.h        IFilter interface declarations
103 //  filterr.h       FACILITY_ITF error definitions for IFilter
104 //  ntquery.h       Indexing Service declarations
105 //  assert.h        assertion function.
106 //  ooofilt.hxx     OpenOffice.org filter declarations
107 //  propspec.hxx    PROPSPEC
108 //
109 //--------------------------------------------------------------------------
110 
111 #include <windows.h>
112 #include <string.h>
113 #include <filter.h>
114 #include <filterr.h>
115 #include <ntquery.h>
116 #include "assert.h"
117 #include "ooofilt.hxx"
118 #include "propspec.hxx"
119 
120 
121 //C-------------------------------------------------------------------------
122 //
123 //  Class:      COooFilter
124 //
125 //  Summary:    Implements OpenOffice.org filter class
126 //
127 //--------------------------------------------------------------------------
128 //M-------------------------------------------------------------------------
129 //
130 //  Method:     COooFilter::COooFilter
131 //
132 //  Summary:    Class constructor
133 //
134 //  Arguments:  void
135 //
136 //  Purpose:    Manages global instance count
137 //
138 //--------------------------------------------------------------------------
139 COooFilter::COooFilter() :
140     m_lRefs(1),
141     m_pContentReader(NULL),
142     m_pMetaInfoReader(NULL),
143     m_eState(FilteringContent),
144     m_ulUnicodeBufferLen(0),
145     m_ulUnicodeCharsRead(0),
146     m_ulPropertyNum(0),
147     m_ulCurrentPropertyNum(0),
148     m_ulChunkID(1),
149     m_fContents(FALSE),
150     m_fEof(FALSE),
151     m_ChunkPosition(0),
152     m_cAttributes(0),
153     m_pAttributes(0)
154 {
155     InterlockedIncrement( &g_lInstances );
156 }
157 //M-------------------------------------------------------------------------
158 //
159 //  Method:     COooFilter::~COooFilter
160 //
161 //  Summary:    Class destructor
162 //
163 //  Arguments:  void
164 //
165 //  Purpose:    Manages global instance count and file handle
166 //
167 //--------------------------------------------------------------------------
168 COooFilter::~COooFilter()
169 {
170     delete [] m_pAttributes;
171 
172     if (m_pContentReader)
173         delete m_pContentReader;
174     if (m_pMetaInfoReader)
175         delete m_pMetaInfoReader;
176 
177     InterlockedDecrement( &g_lInstances );
178 }
179 
180 //M-------------------------------------------------------------------------
181 //
182 //  Method:     COooFilter::QueryInterface      (IUnknown::QueryInterface)
183 //
184 //  Summary:    Queries for requested interface
185 //
186 //  Arguments:  riid
187 //              [in] Reference IID of requested interface
188 //              ppvObject
189 //              [out] Address that receives requested interface pointer
190 //
191 //  Returns:    S_OK
192 //              Interface is supported
193 //              E_NOINTERFACE
194 //              Interface is not supported
195 //
196 //--------------------------------------------------------------------------
197 SCODE STDMETHODCALLTYPE COooFilter::QueryInterface(
198     REFIID riid,
199     void  ** ppvObject)
200 {
201     IUnknown *pUnkTemp = 0;
202     if ( IID_IFilter == riid )
203         pUnkTemp = (IUnknown *)(IFilter *)this;
204     else if ( IID_IPersistFile == riid )
205         pUnkTemp = (IUnknown *)(IPersistFile *)this;
206     else if ( IID_IPersist == riid )
207         pUnkTemp = (IUnknown *)(IPersist *)(IPersistFile *)this;
208     else if ( IID_IUnknown == riid )
209         pUnkTemp = (IUnknown *)(IPersist *)(IPersistFile *)this;
210     else
211     {
212         *ppvObject = NULL;
213         return E_NOINTERFACE;
214     }
215     *ppvObject = (void  *)pUnkTemp;
216     pUnkTemp->AddRef();
217     return S_OK;
218 }
219 //M-------------------------------------------------------------------------
220 //
221 //  Method:     COooFilter::AddRef              (IUnknown::AddRef)
222 //
223 //  Summary:    Increments interface refcount
224 //
225 //  Arguments:  void
226 //
227 //  Returns:    Value of incremented interface refcount
228 //
229 //--------------------------------------------------------------------------
230 ULONG STDMETHODCALLTYPE COooFilter::AddRef()
231 {
232     return InterlockedIncrement( &m_lRefs );
233 }
234 //M-------------------------------------------------------------------------
235 //
236 //  Method:     COooFilter::Release             (IUnknown::Release)
237 //
238 //  Summary:    Decrements interface refcount, deleting if unreferenced
239 //
240 //  Arguments:  void
241 //
242 //  Returns:    Value of decremented interface refcount
243 //
244 //--------------------------------------------------------------------------
245 ULONG STDMETHODCALLTYPE COooFilter::Release()
246 {
247     ULONG ulTmp = InterlockedDecrement( &m_lRefs );
248 
249     if ( 0 == ulTmp )
250         delete this;
251     return ulTmp;
252 }
253 //M-------------------------------------------------------------------------
254 //
255 //  Method:     COooFilter::Init                (IFilter::Init)
256 //
257 //  Summary:    Initializes OpenOffice.org filter instance
258 //
259 //  Arguments:  grfFlags
260 //                  [in] Flags for filter behavior
261 //              cAttributes
262 //                  [in] Number attributes in array aAttributes
263 //              aAttributes
264 //                  [in] Array of requested attribute strings
265 //              pFlags
266 //                  [out] Pointer to return flags for additional properties
267 //
268 //  Returns:    S_OK
269 //                  Initialization succeeded
270 //              E_FAIL
271 //                  File not previously loaded
272 //              E_INVALIDARG
273 //                  Count and contents of attributes do not agree
274 //              FILTER_E_ACCESS
275 //                  Unable to access file to be filtered
276 //              FILTER_E_PASSWORD
277 //                  (not implemented)
278 //
279 //--------------------------------------------------------------------------
280 const int COUNT_ATTRIBUTES = 5;
281 
282 SCODE STDMETHODCALLTYPE COooFilter::Init(
283     ULONG grfFlags,
284     ULONG cAttributes,
285     FULLPROPSPEC const * aAttributes,
286     ULONG * pFlags)
287 {
288     // Enumerate OLE properties, since any NTFS file can have them
289     *pFlags = IFILTER_FLAGS_OLE_PROPERTIES;
290     try
291     {
292         m_fContents = FALSE;
293         m_ulPropertyNum = 0;
294         m_ulCurrentPropertyNum = 0;
295         if ( m_cAttributes > 0 )
296         {
297             delete[] m_pAttributes;
298             m_pAttributes = 0;
299             m_cAttributes = 0;
300         }
301         if( 0 < cAttributes )
302         {
303             // Filter properties specified in aAttributes
304             if ( 0 == aAttributes )
305                 return E_INVALIDARG;
306             m_pAttributes = new CFullPropSpec[cAttributes];
307             m_cAttributes = cAttributes;
308             // Is caller want to filter contents?
309             CFullPropSpec *pAttrib = (CFullPropSpec *) aAttributes;
310             ULONG ulNumAttr;
311             for ( ulNumAttr = 0 ; ulNumAttr < cAttributes; ulNumAttr++ )
312             {
313                 if ( pAttrib[ulNumAttr].IsPropertyPropid() &&
314                      pAttrib[ulNumAttr].GetPropertyPropid() == PID_STG_CONTENTS &&
315                      pAttrib[ulNumAttr].GetPropSet() == guidStorage )
316                 {
317                     m_fContents = TRUE;
318                 }
319                 // save the requested properties.
320                 m_pAttributes[ulNumAttr] = pAttrib[ulNumAttr];
321             }
322         }
323         else if ( grfFlags & IFILTER_INIT_APPLY_INDEX_ATTRIBUTES )
324         {
325             // Filter contents and all pseudo-properties
326             m_fContents = TRUE;
327 
328             m_pAttributes = new CFullPropSpec[COUNT_ATTRIBUTES];
329             m_cAttributes = COUNT_ATTRIBUTES;
330             m_pAttributes[0].SetPropSet( FMTID_SummaryInformation );
331             m_pAttributes[0].SetProperty( PIDSI_AUTHOR );
332             m_pAttributes[1].SetPropSet( FMTID_SummaryInformation );
333             m_pAttributes[1].SetProperty( PIDSI_TITLE );
334             m_pAttributes[2].SetPropSet( FMTID_SummaryInformation );
335             m_pAttributes[2].SetProperty( PIDSI_SUBJECT );
336             m_pAttributes[3].SetPropSet( FMTID_SummaryInformation );
337             m_pAttributes[3].SetProperty( PIDSI_KEYWORDS );
338             m_pAttributes[4].SetPropSet( FMTID_SummaryInformation );
339             m_pAttributes[4].SetProperty( PIDSI_COMMENTS );
340         }
341         else if ( 0 == grfFlags )
342         {
343             // Filter only contents
344             m_fContents = TRUE;
345         }
346         else
347             m_fContents = FALSE;
348         // Re-initialize
349         if ( m_fContents )
350         {
351             m_fEof = FALSE;
352             m_eState = FilteringContent;
353             m_ulUnicodeCharsRead = 0;
354             m_ChunkPosition = 0;
355         }
356         else
357         {
358             m_fEof = TRUE;
359             m_eState = FilteringProperty;
360         }
361         m_ulChunkID = 1;
362     }
363     catch (const std::exception&)
364     {
365         return E_FAIL;
366     }
367 
368     return S_OK;
369 }
370 //M-------------------------------------------------------------------------
371 //
372 //  Method:     COooFilter::GetChunk            (IFilter::GetChunk)
373 //
374 //  Summary:    Gets the next chunk
375 //
376 //  Arguments:  ppStat
377 //                  [out] Pointer to description of current chunk
378 //  Returns:    S_OK
379 //                  Chunk was successfully retrieved
380 //              E_FAIL
381 //                  Character conversion failed
382 //              FILTER_E_ACCESS
383 //                  General access failure occurred
384 //              FILTER_E_END_OF_CHUNKS
385 //                  Previous chunk was the last chunk
386 //              FILTER_E_EMBEDDING_UNAVAILABLE
387 //                  (not implemented)
388 //              FILTER_E_LINK_UNAVAILABLE
389 //                  (not implemented)
390 //              FILTER_E_PASSWORD
391 //                  (not implemented)
392 //
393 //--------------------------------------------------------------------------
394 SCODE STDMETHODCALLTYPE COooFilter::GetChunk(STAT_CHUNK * pStat)
395 {
396     for(;;)
397     {
398         switch ( m_eState )
399         {
400         case FilteringContent:
401         {
402             // Read Unicodes from buffer.
403             if( m_ChunkPosition == m_pContentReader ->getChunkBuffer().size() )
404             {
405                 m_ulUnicodeBufferLen=0;
406                 m_fEof = TRUE;
407             }
408 
409             if ( !m_fContents || m_fEof )
410             {
411                 m_eState = FilteringProperty;
412                 continue;
413             }
414             m_pwsBuffer = m_pContentReader -> getChunkBuffer()[m_ChunkPosition].second;
415             m_ulUnicodeBufferLen = m_pwsBuffer.length();
416             DWORD ChunkLCID = LocaleSetToLCID( m_pContentReader -> getChunkBuffer()[m_ChunkPosition].first );
417             // Set chunk description
418             pStat->idChunk   = m_ulChunkID;
419             pStat->breakType = CHUNK_NO_BREAK;
420             pStat->flags     = CHUNK_TEXT;
421             pStat->locale    = ChunkLCID;
422             pStat->attribute.guidPropSet       = guidStorage;
423             pStat->attribute.psProperty.ulKind = PRSPEC_PROPID;
424             pStat->attribute.psProperty.propid = PID_STG_CONTENTS;
425             pStat->idChunkSource  = m_ulChunkID;
426             pStat->cwcStartSource = 0;
427             pStat->cwcLenSource   = 0;
428             m_ulUnicodeCharsRead = 0;
429             m_ulChunkID++;
430             m_ChunkPosition++;
431             return S_OK;
432         }
433         case FilteringProperty:
434         {
435             if ( m_cAttributes ==  0 )
436                 return FILTER_E_END_OF_CHUNKS;
437             while(  !( ( m_pAttributes[m_ulPropertyNum].IsPropertyPropid() ) &&
438                        ( m_pAttributes[m_ulPropertyNum].GetPropSet() == FMTID_SummaryInformation ) )||
439                      ( ( m_pAttributes[m_ulPropertyNum].GetPropertyPropid() != PIDSI_AUTHOR ) &&
440                        ( m_pAttributes[m_ulPropertyNum].GetPropertyPropid() != PIDSI_TITLE ) &&
441                        ( m_pAttributes[m_ulPropertyNum].GetPropertyPropid() != PIDSI_SUBJECT ) &&
442                        ( m_pAttributes[m_ulPropertyNum].GetPropertyPropid() != PIDSI_KEYWORDS ) &&
443                        ( m_pAttributes[m_ulPropertyNum].GetPropertyPropid() != PIDSI_COMMENTS ) ) )
444             {
445                 if ( m_ulPropertyNum <  m_cAttributes )
446                     m_ulPropertyNum++;
447                 else
448                     break;
449             }
450             if ( m_ulPropertyNum ==  m_cAttributes)
451                 return FILTER_E_END_OF_CHUNKS;
452             else
453             {
454                 // Set chunk description
455                 pStat->idChunk = m_ulChunkID;
456                 pStat->breakType = CHUNK_EOS;
457                 pStat->flags = CHUNK_VALUE;
458                 pStat->locale = GetSystemDefaultLCID();
459                 pStat->attribute.guidPropSet = FMTID_SummaryInformation;
460                 pStat->attribute.psProperty.ulKind = PRSPEC_PROPID;
461                 pStat->attribute.psProperty.propid = m_pAttributes[m_ulPropertyNum].GetPropertyPropid();
462                 pStat->idChunkSource = m_ulChunkID;
463                 pStat->cwcStartSource = 0;
464                 pStat->cwcLenSource = 0;
465                 m_ulCurrentPropertyNum = m_ulPropertyNum;
466                 m_ulPropertyNum++;
467                 m_ulChunkID++;
468                 return S_OK;
469             }
470         }
471         default:
472             return E_FAIL;
473         }//switch(...)
474     }//for(;;)
475 }
476 //M-------------------------------------------------------------------------
477 //
478 //  Method:     COooFilter::GetText             (IFilter::GetText)
479 //
480 //  Summary:    Retrieves UNICODE text for index
481 //
482 //  Arguments:  pcwcBuffer
483 //                  [in] Pointer to size of UNICODE buffer
484 //                  [out] Pointer to count of UNICODE characters returned
485 //              awcBuffer
486 //                  [out] Pointer to buffer to receive UNICODE text
487 //
488 //  Returns:    S_OK
489 //                  Text successfully retrieved, but text remains in chunk
490 //              FILTER_E_NO_MORE_TEXT
491 //                  All of the text in the current chunk has been returned
492 //              FILTER_S_LAST_TEXT
493 //                  Next call to GetText will return FILTER_E_NO_MORE_TEXT
494 //
495 //--------------------------------------------------------------------------
496 SCODE STDMETHODCALLTYPE COooFilter::GetText(ULONG * pcwcBuffer, WCHAR * awcBuffer)
497 {
498     switch ( m_eState )
499     {
500     case FilteringProperty:
501         return FILTER_E_NO_TEXT;
502     case FilteringContent:
503     {
504         if ( !m_fContents || 0 == m_ulUnicodeBufferLen )
505         {
506             *pcwcBuffer = 0;
507             return FILTER_E_NO_MORE_TEXT;
508         }
509         // Copy UNICODE characters in chunk buffer to output UNICODE buffer
510         ULONG ulToCopy = min( *pcwcBuffer, m_ulUnicodeBufferLen - m_ulUnicodeCharsRead );
511         ZeroMemory(awcBuffer, sizeof(awcBuffer));
512         wmemcpy( awcBuffer, m_pwsBuffer.c_str() + m_ulUnicodeCharsRead, ulToCopy );
513         m_ulUnicodeCharsRead += ulToCopy;
514         *pcwcBuffer = ulToCopy;
515         if ( m_ulUnicodeBufferLen == m_ulUnicodeCharsRead )
516         {
517             m_ulUnicodeCharsRead = 0;
518             m_ulUnicodeBufferLen = 0;
519             return FILTER_S_LAST_TEXT;
520         }
521         return S_OK;
522     }
523     default:
524         return E_FAIL;
525     }
526 }
527 //M-------------------------------------------------------------------------
528 //
529 //  Method:     GetMetaInfoNameFromPropertyId
530 //
531 //  Summary:    helper function to convert PropertyID into respective
532 //              MetaInfo names.
533 //
534 //  Arguments:  ulPropID
535 //                  [in] property ID
536 //
537 //  Returns:    corresponding metainfo names.
538 //
539 //--------------------------------------------------------------------------
540 
541 ::std::wstring GetMetaInfoNameFromPropertyId( ULONG ulPropID )
542 {
543     switch ( ulPropID )
544     {
545         case PIDSI_AUTHOR:   return META_INFO_AUTHOR;
546         case PIDSI_TITLE:    return META_INFO_TITLE;
547         case PIDSI_SUBJECT:  return META_INFO_SUBJECT;
548         case PIDSI_KEYWORDS: return META_INFO_KEYWORDS;
549         case PIDSI_COMMENTS: return META_INFO_DESCRIPTION;
550         default:             return EMPTY_STRING;
551     }
552 }
553 //M-------------------------------------------------------------------------
554 //
555 //  Method:     COooFilter::GetValue            (IFilter::GetValue)
556 //
557 //  Summary:    Retrieves properites for index
558 //
559 //  Arguments:  ppPropValue
560 //                  [out] Address that receives pointer to property value
561 //
562 //  Returns:    FILTER_E_NO_VALUES
563 //                  Always
564 //              FILTER_E_NO_MORE_VALUES
565 //                  (not implemented)
566 //
567 //--------------------------------------------------------------------------
568 
569 SCODE STDMETHODCALLTYPE COooFilter::GetValue(PROPVARIANT ** ppPropValue)
570 {
571     if (m_eState == FilteringContent)
572         return FILTER_E_NO_VALUES;
573     else if (m_eState == FilteringProperty)
574     {
575         if ( m_cAttributes == 0 || ( m_ulCurrentPropertyNum == m_ulPropertyNum ) )
576             return FILTER_E_NO_MORE_VALUES;
577         PROPVARIANT *pPropVar = (PROPVARIANT *) CoTaskMemAlloc( sizeof PROPVARIANT );
578         if ( pPropVar == 0 )
579             return E_OUTOFMEMORY;
580         ::std::wstring wsTagName= GetMetaInfoNameFromPropertyId( m_pAttributes[m_ulCurrentPropertyNum].GetPropertyPropid() );
581         if ( wsTagName == EMPTY_STRING )
582             return FILTER_E_NO_VALUES;
583         ::std::wstring wsTagData = m_pMetaInfoReader->getTagData(wsTagName);
584         pPropVar->vt = VT_LPWSTR;
585         size_t cw = wsTagData.length() + 1; // reserve one for the '\0'
586         pPropVar->pwszVal = static_cast<WCHAR*>( CoTaskMemAlloc(cw*sizeof(WCHAR)) );
587         if (pPropVar->pwszVal == 0)
588         {
589             CoTaskMemFree(pPropVar);
590             return E_OUTOFMEMORY;
591         }
592         wmemcpy(pPropVar->pwszVal, wsTagData.c_str(), cw);
593         *ppPropValue = pPropVar;
594         m_ulCurrentPropertyNum = m_ulPropertyNum;
595         return S_OK;
596     }
597     else
598         return E_FAIL;
599 }
600 //M-------------------------------------------------------------------------
601 //
602 //  Method:     COooFilter::BindRegion          (IFilter::BindRegion)
603 //
604 //  Summary:    Creates moniker or other interface for indicated text
605 //
606 //  Arguments:  origPos
607 //                  [in] Description of text location and extent
608 //              riid
609 //                  [in] Reference IID of specified interface
610 //              ppunk
611 //                  [out] Address that receives requested interface pointer
612 //
613 //  Returns:    E_NOTIMPL
614 //                  Always
615 //              FILTER_W_REGION_CLIPPED
616 //                  (not implemented)
617 //
618 //--------------------------------------------------------------------------
619 
620 SCODE STDMETHODCALLTYPE COooFilter::BindRegion(
621     FILTERREGION /*origPos*/,
622     REFIID /*riid*/,
623     void ** /*ppunk*/)
624 {
625     // BindRegion is currently reserved for future use
626     return E_NOTIMPL;
627 }
628 //M-------------------------------------------------------------------------
629 //
630 //  Method:     COooFilter::GetClassID          (IPersist::GetClassID)
631 //
632 //  Summary:    Retrieves the class id of the filter class
633 //
634 //  Arguments:  pClassID
635 //                  [out] Pointer to the class ID of the filter
636 //
637 //  Returns:    S_OK
638 //                  Always
639 //              E_FAIL
640 //                  (not implemented)
641 //--------------------------------------------------------------------------
642 SCODE STDMETHODCALLTYPE COooFilter::GetClassID(CLSID * pClassID)
643 {
644     *pClassID = CLSID_COooFilter;
645     return S_OK;
646 }
647 //M-------------------------------------------------------------------------
648 //
649 //  Method:     COooFilter::IsDirty             (IPersistFile::IsDirty)
650 //
651 //  Summary:    Checks whether file has changed since last save
652 //
653 //  Arguments:  void
654 //
655 //  Returns:    S_FALSE
656 //                  Always
657 //              S_OK
658 //                  (not implemented)
659 //
660 //--------------------------------------------------------------------------
661 SCODE STDMETHODCALLTYPE COooFilter::IsDirty()
662 {
663     // File is opened read-only and never changes
664     return S_FALSE;
665 }
666 //M-------------------------------------------------------------------------
667 //
668 //  Method:     COooFilter::Load                (IPersistFile::Load)
669 //
670 //  Summary:    Opens and initializes the specified file
671 //
672 //  Arguments:  pszFileName
673 //                  [in] Pointer to zero-terminated string
674 //                       of absolute path of file to open
675 //              dwMode
676 //                  [in] Access mode to open the file
677 //
678 //  Returns:    S_OK
679 //                  File was successfully loaded
680 //              E_OUTOFMEMORY
681 //                  File could not be loaded due to insufficient memory
682 //              E_FAIL
683 //                  (not implemented)
684 //
685 //--------------------------------------------------------------------------
686 SCODE STDMETHODCALLTYPE COooFilter::Load(LPCWSTR pszFileName, DWORD /*dwMode*/)
687 {
688     // Load just sets the filename for GetChunk to read and ignores the mode
689     m_pwszFileName = pszFileName;
690     // Open the file previously specified in call to IPersistFile::Load and get content.
691     try
692     {
693         if (m_pMetaInfoReader)
694             delete m_pMetaInfoReader;
695         m_pMetaInfoReader = new CMetaInfoReader(WStringToString(m_pwszFileName));
696 
697         if (m_pContentReader)
698             delete m_pContentReader;
699         m_pContentReader = new CContentReader(WStringToString(m_pwszFileName), m_pMetaInfoReader->getDefaultLocale());
700     }
701     catch (const std::exception&)
702     {
703         return E_FAIL;
704     }
705     return S_OK;
706 }
707 //M-------------------------------------------------------------------------
708 //
709 //  Method:     COooFilter::Save                (IPersistFile::Save)
710 //
711 //  Summary:    Saves a copy of the current file being filtered
712 //
713 //  Arguments:  pszFileName
714 //                  [in] Pointer to zero-terminated string of
715 //                       absolute path of where to save file
716 //              fRemember
717 //                  [in] Whether the saved copy is made the current file
718 //
719 //  Returns:    E_FAIL
720 //                  Always
721 //              S_OK
722 //                  (not implemented)
723 //
724 //--------------------------------------------------------------------------
725 SCODE STDMETHODCALLTYPE COooFilter::Save(LPCWSTR /*pszFileName*/, BOOL /*fRemember*/)
726 {
727     // File is opened read-only; saving it is an error
728     return E_FAIL;
729 }
730 //M-------------------------------------------------------------------------
731 //
732 //  Method:     COooFilter::SaveCompleted      (IPersistFile::SaveCompleted)
733 //
734 //  Summary:    Determines whether a file save is completed
735 //
736 //  Arguments:  pszFileName
737 //                  [in] Pointer to zero-terminated string of
738 //                       absolute path where file was previously saved
739 //
740 //  Returns:    S_OK
741 //                  Always
742 //
743 //--------------------------------------------------------------------------
744 SCODE STDMETHODCALLTYPE COooFilter::SaveCompleted(LPCWSTR /*pszFileName*/)
745 {
746     // File is opened read-only, so "save" is always finished
747     return S_OK;
748 }
749 //M-------------------------------------------------------------------------
750 //
751 //  Method:     COooFilter::GetCurFile          (IPersistFile::GetCurFile)
752 //
753 //  Summary:    Returns a copy of the current file name
754 //
755 //  Arguments:  ppszFileName
756 //                  [out] Address to receive pointer to zero-terminated
757 //                        string for absolute path to current file
758 //
759 //  Returns:    S_OK
760 //                  A valid absolute path was successfully returned
761 //              S_FALSE
762 //                  (not implemented)
763 //              E_OUTOFMEMORY
764 //                  Operation failed due to insufficient memory
765 //              E_FAIL
766 //                  Operation failed due to some reason
767 //                  other than insufficient memory
768 //
769 //-------------------------------------------------------------------------
770 SCODE STDMETHODCALLTYPE COooFilter::GetCurFile(LPWSTR * ppszFileName)
771 {
772     if ( EMPTY_STRING == m_pwszFileName )
773         return E_FAIL;
774     else
775         *ppszFileName = (LPWSTR)m_pwszFileName.c_str();
776     return S_OK;
777 }
778 
779 //M-------------------------------------------------------------------------
780 //
781 //  Method:     COooFilterCF::COooFilterCF
782 //
783 //  Summary:    Class factory constructor
784 //
785 //  Arguments:  void
786 //
787 //  Purpose:    Manages global instance count
788 //
789 //--------------------------------------------------------------------------
790 COooFilterCF::COooFilterCF() :
791     m_lRefs(1)
792 {
793     InterlockedIncrement( &g_lInstances );
794 }
795 //M-------------------------------------------------------------------------
796 //
797 //  Method:     COooFilterCF::~COooFilterCF
798 //
799 //  Summary:    Class factory destructor
800 //
801 //  Arguments:  void
802 //
803 //  Purpose:    Manages global instance count
804 //
805 //--------------------------------------------------------------------------
806 COooFilterCF::~COooFilterCF()
807 {
808    InterlockedDecrement( &g_lInstances );
809 }
810 //M-------------------------------------------------------------------------
811 //
812 //  Method:     COooFilterCF::QueryInterface    (IUnknown::QueryInterface)
813 //
814 //  Summary:    Queries for requested interface
815 //
816 //  Arguments:  riid
817 //                  [in] Reference IID of requested interface
818 //              ppvObject
819 //                  [out] Address that receives requested interface pointer
820 //
821 //  Returns:    S_OK
822 //                  Interface is supported
823 //              E_NOINTERFACE
824 //                  Interface is not supported
825 //
826 //--------------------------------------------------------------------------
827 SCODE STDMETHODCALLTYPE COooFilterCF::QueryInterface(REFIID riid, void  ** ppvObject)
828 {
829     IUnknown *pUnkTemp;
830 
831     if ( IID_IClassFactory == riid )
832         pUnkTemp = (IUnknown *)(IClassFactory *)this;
833     else if ( IID_IUnknown == riid )
834         pUnkTemp = (IUnknown *)this;
835     else
836     {
837         *ppvObject = NULL;
838         return E_NOINTERFACE;
839     }
840     *ppvObject = (void  *)pUnkTemp;
841     pUnkTemp->AddRef();
842     return S_OK;
843 }
844 //M-------------------------------------------------------------------------
845 //
846 //  Method:     COooFilterCF::AddRef            (IUknown::AddRef)
847 //
848 //  Summary:    Increments interface refcount
849 //
850 //  Arguments:  void
851 //
852 //  Returns:    Value of incremented interface refcount
853 //
854 //-------------------------------------------------------------------------
855 ULONG STDMETHODCALLTYPE COooFilterCF::AddRef()
856 {
857    return InterlockedIncrement( &m_lRefs );
858 }
859 //M-------------------------------------------------------------------------
860 //
861 //  Method:     COooFilterCF::Release           (IUnknown::Release)
862 //
863 //  Summary:    Decrements interface refcount, deleting if unreferenced
864 //
865 //  Arguments:  void
866 //
867 //  Returns:    Value of decremented refcount
868 //
869 //--------------------------------------------------------------------------
870 ULONG STDMETHODCALLTYPE COooFilterCF::Release()
871 {
872     ULONG ulTmp = InterlockedDecrement( &m_lRefs );
873 
874     if ( 0 == ulTmp )
875         delete this;
876     return ulTmp;
877 }
878 //M-------------------------------------------------------------------------
879 //
880 //  Method:     COooFilterCF::CreateInstance (IClassFactory::CreateInstance)
881 //
882 //  Summary:    Creates new OpenOffice.org filter object
883 //
884 //  Arguments:  pUnkOuter
885 //                  [in] Pointer to IUnknown interface of aggregating object
886 //              riid
887 //                  [in] Reference IID of requested interface
888 //              ppvObject
889 //                  [out] Address that receives requested interface pointer
890 //
891 //  Returns:    S_OK
892 //                  OpenOffice.org filter object was successfully created
893 //              CLASS_E_NOAGGREGATION
894 //                  pUnkOuter parameter was non-NULL
895 //              E_NOINTERFACE
896 //                  (not implemented)
897 //              E_OUTOFMEMORY
898 //                  OpenOffice.org filter object could not be created
899 //                  due to insufficient memory
900 //              E_UNEXPECTED
901 //                  Unsuccessful due to an unexpected condition
902 //
903 //--------------------------------------------------------------------------
904 SCODE STDMETHODCALLTYPE COooFilterCF::CreateInstance(
905     IUnknown * pUnkOuter,
906     REFIID riid,
907     void  * * ppvObject)
908 {
909     COooFilter *pIUnk = 0;
910     if ( 0 != pUnkOuter )
911         return CLASS_E_NOAGGREGATION;
912     pIUnk = new COooFilter();
913     if ( 0 != pIUnk )
914     {
915         if ( SUCCEEDED( pIUnk->QueryInterface( riid , ppvObject ) ) )
916         {
917             // Release extra refcount from QueryInterface
918             pIUnk->Release();
919         }
920         else
921         {
922             delete pIUnk;
923             return E_UNEXPECTED;
924         }
925     }
926     else
927         return E_OUTOFMEMORY;
928     return S_OK;
929 }
930 
931 //M-------------------------------------------------------------------------
932 //
933 //  Method:     COooFilterCF::LockServer        (IClassFactory::LockServer)
934 //
935 //  Summary:    Forces/allows filter class to remain loaded/be unloaded
936 //
937 //  Arguments:  fLock
938 //                  [in] TRUE to lock, FALSE to unlock
939 //
940 //  Returns:    S_OK
941 //                  Always
942 //              E_FAIL
943 //                  (not implemented)
944 //              E_OUTOFMEMORY
945 //                  (not implemented)
946 //              E_UNEXPECTED
947 //                  (not implemented)
948 //
949 //--------------------------------------------------------------------------
950 SCODE STDMETHODCALLTYPE COooFilterCF::LockServer(BOOL fLock)
951 {
952     if( fLock )
953         InterlockedIncrement( &g_lInstances );
954     else
955         InterlockedDecrement( &g_lInstances );
956     return S_OK;
957 }
958 //+-------------------------------------------------------------------------
959 //
960 //  DLL:        ooofilt.dll
961 //
962 //  Summary:    Implements Dynamic Link Library functions for OpenOffice.org filter
963 //
964 //--------------------------------------------------------------------------
965 //F-------------------------------------------------------------------------
966 //
967 //  Function:   DllMain
968 //
969 //  Summary:    Called from C-Runtime on process/thread attach/detach
970 //
971 //  Arguments:  hInstance
972 //                  [in] Handle to the DLL
973 //              fdwReason
974 //                  [in] Reason for calling DLL entry point
975 //              lpReserve
976 //                  [in] Details of DLL initialization and cleanup
977 //
978 //  Returns:    TRUE
979 //                  Always
980 //
981 //--------------------------------------------------------------------------
982 extern "C" BOOL WINAPI DllMain(
983     HINSTANCE hInstance,
984     DWORD     fdwReason,
985     LPVOID    /*lpvReserved*/
986 )
987 {
988    if ( DLL_PROCESS_ATTACH == fdwReason )
989         DisableThreadLibraryCalls( hInstance );
990     return TRUE;
991 }
992 //F-------------------------------------------------------------------------
993 //
994 //  Function:   DllGetClassObject
995 //
996 //  Summary:    Create OpenOffice.org filter class factory object
997 //
998 //  Arguments:  cid
999 //                  [in] Class ID of class that class factory creates
1000 //              iid
1001 //                  [in] Reference IID of requested class factory interface
1002 //              ppvObj
1003 //                  [out] Address that receives requested interface pointer
1004 //
1005 //  Returns:    S_OK
1006 //                  Class factory object was created successfully
1007 //              CLASS_E_CLASSNOTAVAILABLE
1008 //                  DLL does not support the requested class
1009 //              E_INVALIDARG
1010 //                  (not implemented
1011 //              E_OUTOFMEMORY
1012 //                  Insufficient memory to create the class factory object
1013 //              E_UNEXPECTED
1014 //                  Unsuccessful due to an unexpected condition
1015 //
1016 //-------------------------------------------------------------------------
1017 extern "C" SCODE STDMETHODCALLTYPE DllGetClassObject(
1018     REFCLSID   cid,
1019     REFIID     iid,
1020     void **    ppvObj
1021 )
1022 {
1023     IUnknown *pResult = 0;
1024 
1025     if ( CLSID_COooFilter == cid )
1026         pResult = (IUnknown *) new COooFilterCF;
1027     else
1028         return CLASS_E_CLASSNOTAVAILABLE;
1029     if ( 0 != pResult )
1030     {
1031         if( SUCCEEDED( pResult->QueryInterface( iid, ppvObj ) ) )
1032             // Release extra refcount from QueryInterface
1033             pResult->Release();
1034         else
1035         {
1036             delete pResult;
1037             return E_UNEXPECTED;
1038         }
1039     }
1040     else
1041         return E_OUTOFMEMORY;
1042     return S_OK;
1043 }
1044 //F-------------------------------------------------------------------------
1045 //
1046 //  Function:   DllCanUnloadNow
1047 //
1048 //  Summary:    Indicates whether it is possible to unload DLL
1049 //
1050 //  Arguments:  void
1051 //
1052 //  Returns:    S_OK
1053 //                  DLL can be unloaded now
1054 //              S_FALSE
1055 //                  DLL must remain loaded
1056 //
1057 //--------------------------------------------------------------------------
1058 extern "C" SCODE STDMETHODCALLTYPE DllCanUnloadNow()
1059 {
1060     if ( 0 >= g_lInstances )
1061         return S_OK;
1062     else
1063         return S_FALSE;
1064 }
1065 //F-------------------------------------------------------------------------
1066 //
1067 //  Function:   DllRegisterServer
1068 //              DllUnregisterServer
1069 //
1070 //  Summary:    Registers and unregisters DLL server
1071 //
1072 //  Returns:    DllRegisterServer
1073 //                  S_OK
1074 //                      Registration was successful
1075 //                  SELFREG_E_CLASS
1076 //                      Registration was unsuccessful
1077 //                  SELFREG_E_TYPELIB
1078 //                      (not implemented)
1079 //                  E_OUTOFMEMORY
1080 //                      (not implemented)
1081 //                  E_UNEXPECTED
1082 //                      (not implemented)
1083 //              DllUnregisterServer
1084 //                  S_OK
1085 //                      Unregistration was successful
1086 //                  S_FALSE
1087 //                      Unregistration was successful, but other
1088 //                      entries still exist for the DLL's classes
1089 //                  SELFREG_E_CLASS
1090 //                      (not implemented)
1091 //                  SELFREG_E_TYPELIB
1092 //                      (not implemented)
1093 //                  E_OUTOFMEMORY
1094 //                      (not implemented)
1095 //                  E_UNEXPECTED
1096 //                      (not implemented)
1097 //
1098 //--------------------------------------------------------------------------
1099 
1100 
1101 //F-------------------------------------------------------------------------
1102 //
1103 //  helper functions to register the Indexing Service.
1104 //
1105 //--------------------------------------------------------------------------
1106 
1107 namespace /* private */
1108 {
1109     const char* GUID_PLACEHOLDER         = "{GUID}";
1110     const char* GUID_PERSIST_PLACEHOLDER = "{GUIDPERSIST}";
1111     const char* EXTENSION_PLACEHOLDER    = "{EXT}";
1112     const char* FORWARDKEY_PLACEHOLDER   = "{FWDKEY}";
1113 
1114     const char* CLSID_GUID_INPROC_ENTRY             = "CLSID\\{GUID}\\InProcServer32";
1115     const char* CLSID_GUID_ENTRY                    = "CLSID\\{GUID}";
1116     const char* CLSID_GUID_PERSIST_ADDIN_ENTRY      = "CLSID\\{GUID}\\PersistentAddinsRegistered\\{GUIDPERSIST}";
1117     const char* CLSID_PERSIST_ENTRY                 = "CLSID\\{GUID}\\PersistentHandler";
1118     const char* EXT_PERSIST_ENTRY                   = "{EXT}\\PersistentHandler";
1119 
1120     const char* INDEXING_FILTER_DLLSTOREGISTER      = "SYSTEM\\CurrentControlSet\\Control\\ContentIndex";
1121 
1122     //---------------------------
1123     // "String Placeholder" ->
1124     // "String Replacement"
1125     //---------------------------
1126 
1127     void SubstitutePlaceholder(std::string& String, const std::string& Placeholder, const std::string& Replacement)
1128     {
1129         std::string::size_type idx = String.find(Placeholder);
1130         std::string::size_type len = Placeholder.length();
1131 
1132         while (std::string::npos != idx)
1133         {
1134             String.replace(idx, len, Replacement);
1135             idx = String.find(Placeholder);
1136         }
1137     }
1138 
1139     //----------------------------------------------
1140     // Make the registry entry and set Filter Handler
1141     // HKCR\CLSID\{7BC0E710-5703-45be-A29D-5D46D8B39262} = OpenOffice.org Filter
1142     //                   InProcServer32  (Default)       = Path\ooofilt.dll
1143     //                                   ThreadingModel  = Both
1144     //----------------------------------------------
1145 
1146     HRESULT RegisterFilterHandler(const char* FilePath, const CLSID& FilterGuid)
1147     {
1148         std::string ClsidEntry = CLSID_GUID_ENTRY;
1149         SubstitutePlaceholder(ClsidEntry, GUID_PLACEHOLDER, ClsidToString(FilterGuid));
1150 
1151         if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry.c_str(), "", "OpenOffice.org Filter"))
1152             return E_FAIL;
1153 
1154         ClsidEntry = CLSID_GUID_INPROC_ENTRY;
1155         SubstitutePlaceholder(ClsidEntry, GUID_PLACEHOLDER, ClsidToString(FilterGuid));
1156 
1157         if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry.c_str(), "", FilePath))
1158             return E_FAIL;
1159 
1160         if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry.c_str(), "ThreadingModel", "Both"))
1161             return E_FAIL;
1162 
1163         return S_OK;
1164     }
1165 
1166     //----------------------------------------------
1167     // Make the registry entry and set Persistent Handler
1168     // HKCR\CLSID\{7BC0E713-5703-45be-A29D-5D46D8B39262}  = OpenOffice.org Persistent Handler
1169     //      PersistentAddinsRegistered
1170     //          {89BCB740-6119-101A-BCB7-00DD010655AF} = {7BC0E710-5703-45be-A29D-5D46D8B39262}
1171     //----------------------------------------------
1172 
1173     HRESULT RegisterPersistentHandler(const CLSID& FilterGuid, const CLSID& PersistentGuid)
1174     {
1175         std::string ClsidEntry_Persist = CLSID_GUID_ENTRY;
1176         SubstitutePlaceholder(ClsidEntry_Persist, GUID_PLACEHOLDER, ClsidToString(PersistentGuid));
1177 
1178         if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry_Persist.c_str(), "", "OpenOffice.org Persistent Handler"))
1179             return E_FAIL;
1180 
1181         std::string ClsidEntry_Persist_Addin = CLSID_GUID_PERSIST_ADDIN_ENTRY;
1182         SubstitutePlaceholder(ClsidEntry_Persist_Addin,
1183                               GUID_PLACEHOLDER,
1184                               ClsidToString(PersistentGuid));
1185         SubstitutePlaceholder(ClsidEntry_Persist_Addin,
1186                               GUID_PERSIST_PLACEHOLDER,
1187                               ClsidToString(CLSID_PERSISTENT_HANDLER_ADDIN));
1188 
1189         if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry_Persist_Addin.c_str(), "", ClsidToString(FilterGuid).c_str() ))
1190             return E_FAIL;
1191 
1192         return S_OK;
1193     }
1194 
1195     //---------------------------
1196     // Unregister Filter Handler or persistent handler
1197     //---------------------------
1198 
1199     HRESULT UnregisterHandler(const CLSID& Guid)
1200     {
1201         std::string tmp = "CLSID\\";
1202         tmp += ClsidToString(Guid);
1203         return DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str()) ? S_OK : E_FAIL;
1204     }
1205 
1206     //---------------------------
1207     // Register Indexing Service ext and class.
1208     // HKCR\{EXT}\PersistentHandler = {7BC0E713-5703-45be-A29D-5D46D8B39262}
1209     // HKCR\{GUID\PersistentHandler = {7BC0E713-5703-45be-A29D-5D46D8B39262}
1210     //---------------------------
1211 
1212     HRESULT RegisterSearchHandler(const char* ModuleFileName)
1213     {
1214         if (FAILED(RegisterFilterHandler(ModuleFileName, CLSID_FILTER_HANDLER)))
1215             return E_FAIL;
1216 
1217         if (FAILED(RegisterPersistentHandler(CLSID_FILTER_HANDLER, CLSID_PERSISTENT_HANDLER )))
1218             return E_FAIL;
1219 
1220         std::string sExtPersistEntry;
1221 
1222         for(size_t i = 0; i < OOFileExtensionTableSize; i++)
1223         {
1224             // first, register extension.
1225             sExtPersistEntry = EXT_PERSIST_ENTRY;
1226             SubstitutePlaceholder(sExtPersistEntry, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionAnsi);
1227             if (!SetRegistryKey(HKEY_CLASSES_ROOT,
1228                                 sExtPersistEntry.c_str(),
1229                                 "",
1230                                 ClsidToString(CLSID_PERSISTENT_HANDLER).c_str()))
1231                 return E_FAIL;
1232 
1233             // second, register class.
1234             char extClassName[MAX_PATH];
1235             if (QueryRegistryKey(HKEY_CLASSES_ROOT, OOFileExtensionTable[i].ExtensionAnsi, "", extClassName,MAX_PATH))
1236             {
1237                 ::std::string extCLSIDName( extClassName );
1238                 extCLSIDName += "\\CLSID";
1239                 char extCLSID[MAX_PATH];
1240 
1241                 if (QueryRegistryKey( HKEY_CLASSES_ROOT, extCLSIDName.c_str(), "", extCLSID, MAX_PATH))
1242                 {
1243                     std::string ClsidEntry_CLSID_Persist = CLSID_PERSIST_ENTRY;
1244                     SubstitutePlaceholder(ClsidEntry_CLSID_Persist,
1245                                         GUID_PLACEHOLDER,
1246                                         extCLSID);
1247 
1248                     if (!SetRegistryKey(HKEY_CLASSES_ROOT,
1249                                         ClsidEntry_CLSID_Persist.c_str(),
1250                                         "",
1251                                         ClsidToString(CLSID_PERSISTENT_HANDLER).c_str() ))
1252                         return E_FAIL;
1253                 }
1254             }
1255         }
1256 
1257         return S_OK;
1258     }
1259 
1260     // Register Indexing Service ext and class.
1261     HRESULT UnregisterSearchHandler()
1262     {
1263         std::string sExtPersistEntry;
1264 
1265         for (size_t i = 0; i < OOFileExtensionTableSize; i++)
1266         {
1267             // first, unregister extension
1268             sExtPersistEntry = EXT_PERSIST_ENTRY;
1269             SubstitutePlaceholder(sExtPersistEntry, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionAnsi);
1270             DeleteRegistryKey(HKEY_CLASSES_ROOT, sExtPersistEntry.c_str());
1271 
1272             // second, unregister class
1273             char extClassName[MAX_PATH];
1274             if (QueryRegistryKey(HKEY_CLASSES_ROOT, OOFileExtensionTable[i].ExtensionAnsi, "", extClassName,MAX_PATH))
1275             {
1276                 ::std::string extCLSIDName( extClassName );
1277                 extCLSIDName += "\\CLSID";
1278                 char extCLSID[MAX_PATH];
1279 
1280                 if (QueryRegistryKey( HKEY_CLASSES_ROOT, extCLSIDName.c_str(), "", extCLSID, MAX_PATH))
1281                 {
1282                     std::string ClsidEntry_CLSID_Persist = CLSID_PERSIST_ENTRY;
1283                     SubstitutePlaceholder(ClsidEntry_CLSID_Persist,
1284                                         GUID_PLACEHOLDER,
1285                                         extCLSID);
1286 
1287                     DeleteRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry_CLSID_Persist.c_str());
1288                 }
1289             }
1290         }
1291 
1292         return ((UnregisterHandler(CLSID_FILTER_HANDLER)==S_OK) && (UnregisterHandler(CLSID_PERSISTENT_HANDLER)==S_OK))?S_OK:E_FAIL;
1293     }
1294 
1295     //---------------------------
1296     //    add or remove an entry to DllsToRegister entry of Indexing
1297     //    Filter to let Indexing Service register our filter automatically
1298     //    each time.
1299     //---------------------------
1300     HRESULT AddOrRemoveDllsToRegisterList( const ::std::string & DllPath, bool isAdd )
1301     {
1302         char DllsToRegisterList[4096];
1303         if (QueryRegistryKey(HKEY_LOCAL_MACHINE,
1304                              INDEXING_FILTER_DLLSTOREGISTER,
1305                              "DLLsToRegister",
1306                              DllsToRegisterList,
1307                              4096))
1308         {
1309             char * pChar = DllsToRegisterList;
1310             for ( ; *pChar != '\0' || *(pChar +1) != '\0'; pChar++)
1311                 if ( *pChar == '\0')
1312                     *pChar = ';';
1313             *pChar = ';';
1314             *(pChar+1) = '\0';
1315 
1316             ::std::string DllList(DllsToRegisterList);
1317             if ( ( isAdd )&&( DllList.find( DllPath ) == ::std::string::npos ) )
1318                 DllList.append( DllPath );
1319             else if ( ( !isAdd )&&( DllList.find( DllPath ) != ::std::string::npos ) )
1320                 DllList.erase( DllList.find( DllPath )-1, DllPath.length()+1 );
1321             else
1322                 return S_OK;
1323 
1324             pChar = DllsToRegisterList;
1325             for ( size_t nChar = 0; nChar < DllList.length(); pChar++,nChar++)
1326             {
1327                 if ( DllList[nChar] == ';')
1328                     *pChar = '\0';
1329                 else
1330                     *pChar = DllList[nChar];
1331             }
1332             *pChar = *( pChar+1 ) ='\0';
1333 
1334             HKEY hSubKey;
1335             int rc = RegCreateKeyExA(HKEY_LOCAL_MACHINE,
1336                                     INDEXING_FILTER_DLLSTOREGISTER,
1337                                     0,
1338                                     "",
1339                                     REG_OPTION_NON_VOLATILE,
1340                                     KEY_WRITE,
1341                                     0,
1342                                     &hSubKey,
1343                                     0);
1344 
1345             if (ERROR_SUCCESS == rc)
1346             {
1347                 rc = RegSetValueExA( hSubKey,
1348                                     "DLLsToRegister",
1349                                     0,
1350                                     REG_MULTI_SZ,
1351                                     reinterpret_cast<const BYTE*>(DllsToRegisterList),
1352                                     DllList.length() + 2);
1353 
1354                 RegCloseKey(hSubKey);
1355             }
1356 
1357             return (ERROR_SUCCESS == rc)?S_OK:E_FAIL;
1358         }
1359 
1360         return S_OK;
1361     }
1362 
1363 } // namespace /* private */
1364 
1365 STDAPI DllRegisterServer()
1366 {
1367     TCHAR ModuleFileName[MAX_PATH];
1368 
1369     GetModuleFileName(
1370         GetModuleHandle(MODULE_NAME_FILTER),
1371         ModuleFileName,
1372         sizeof(ModuleFileName));
1373 
1374     HRESULT hr = S_OK;
1375 
1376 
1377 // register search handler
1378 #ifdef UNICODE
1379     if (FAILED(RegisterSearchHandler(WStringToString(ModuleFileName).c_str())))
1380         hr = E_FAIL;
1381     if (FAILED(AddOrRemoveDllsToRegisterList(WStringToString(ModuleFileName).c_str(), true)))
1382         hr = E_FAIL;
1383 #else
1384     if (FAILED(RegisterSearchHandler(ModuleFileName)))
1385         hr = E_FAIL;
1386     if (FAILED(AddOrRemoveDllsToRegisterList(ModuleFileName, true)))
1387         hr = E_FAIL;
1388 #endif
1389 
1390 
1391     return hr;
1392 }
1393 
1394 //---------------------------
1395 //
1396 //---------------------------
1397 
1398 STDAPI DllUnregisterServer()
1399 {
1400     TCHAR ModuleFileName[MAX_PATH];
1401 
1402     GetModuleFileName(
1403         GetModuleHandle(MODULE_NAME_FILTER),
1404         ModuleFileName,
1405         sizeof(ModuleFileName));
1406 
1407     HRESULT hr = S_OK;
1408 
1409     // unregister search handler
1410     if (FAILED(UnregisterSearchHandler()))
1411         hr = E_FAIL;
1412 
1413 #ifdef UNICODE
1414     if (FAILED(AddOrRemoveDllsToRegisterList(WStringToString(ModuleFileName).c_str(),false)))
1415         hr = E_FAIL;
1416 #else
1417     if (FAILED(AddOrRemoveDllsToRegisterList(ModuleFileName, false)))
1418         hr = E_FAIL;
1419 #endif
1420 
1421     return hr;
1422 }
1423