1076 lines
30 KiB
Plaintext
1076 lines
30 KiB
Plaintext
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
||
|
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
||
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
||
|
// PARTICULAR PURPOSE.
|
||
|
//
|
||
|
// Copyright (c) 1998 Microsoft Corporation. All Rights Reserved.
|
||
|
//
|
||
|
// File: smpfilt.cxx
|
||
|
//
|
||
|
// Contents: Sample filter Implementation for Indexing Service
|
||
|
//
|
||
|
// Summary: The sample filter reads unformated text files (with the
|
||
|
// extension .smp) using the current thread's ANSI code page
|
||
|
// and outputs UNICODE text for the current locale.
|
||
|
//
|
||
|
// It accepts as input only single-byte-character text files,
|
||
|
// and not multibyte-character or UNICODE text files.
|
||
|
//
|
||
|
// Platform: Windows 2000
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Include file Purpose
|
||
|
//
|
||
|
// windows.h Win32 declarations
|
||
|
// filter.h IFilter interface declarations
|
||
|
// filterr.h FACILITY_ITF error definitions for IFilter
|
||
|
// ntquery.h Indexing Service declarations
|
||
|
// filtreg.hxx DLL registration and unregistration macros
|
||
|
// smpfilt.hxx Sample filter declarations
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include <filter.h>
|
||
|
#include <filterr.h>
|
||
|
#include <ntquery.h>
|
||
|
#include "filtreg.hxx"
|
||
|
#include "smpfilt.hxx"
|
||
|
|
||
|
//C-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Class: CSmpFilter
|
||
|
//
|
||
|
// Summary: Implements sample filter class
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
//M-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CSmpFilter::CSmpFilter
|
||
|
//
|
||
|
// Summary: Class constructor
|
||
|
//
|
||
|
// Arguments: void
|
||
|
//
|
||
|
// Purpose: Manages global instance count
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
CSmpFilter::CSmpFilter() :
|
||
|
m_hFile(INVALID_HANDLE_VALUE),
|
||
|
m_lRefs(1),
|
||
|
m_pwszFileName(0),
|
||
|
m_ulBufferLen(0),
|
||
|
m_ulCharsRead(0),
|
||
|
m_ulChunkID(1),
|
||
|
m_fContents(FALSE),
|
||
|
m_fEof(FALSE)
|
||
|
{
|
||
|
InterlockedIncrement( &g_lInstances );
|
||
|
}
|
||
|
|
||
|
//M-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CSmpFilter::~CSmpFilter
|
||
|
//
|
||
|
// Summary: Class destructor
|
||
|
//
|
||
|
// Arguments: void
|
||
|
//
|
||
|
// Purpose: Manages global instance count and file handle
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
CSmpFilter::~CSmpFilter()
|
||
|
{
|
||
|
delete [] m_pwszFileName;
|
||
|
if ( INVALID_HANDLE_VALUE != m_hFile )
|
||
|
CloseHandle ( m_hFile );
|
||
|
|
||
|
InterlockedDecrement( &g_lInstances );
|
||
|
}
|
||
|
|
||
|
//M-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CSmpFilter::QueryInterface (IUnknown::QueryInterface)
|
||
|
//
|
||
|
// Summary: Queries for requested interface
|
||
|
//
|
||
|
// Arguments: riid
|
||
|
// [in] Reference IID of requested interface
|
||
|
// ppvObject
|
||
|
// [out] Address that receives requested interface pointer
|
||
|
//
|
||
|
// Returns: S_OK
|
||
|
// Interface is supported
|
||
|
// E_NOINTERFACE
|
||
|
// Interface is not supported
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
SCODE STDMETHODCALLTYPE CSmpFilter::QueryInterface(
|
||
|
REFIID riid,
|
||
|
void ** ppvObject
|
||
|
)
|
||
|
{
|
||
|
IUnknown *pUnkTemp = 0;
|
||
|
|
||
|
if ( IID_IFilter == riid )
|
||
|
pUnkTemp = (IUnknown *)(IFilter *)this;
|
||
|
else if ( IID_IPersistFile == riid )
|
||
|
pUnkTemp = (IUnknown *)(IPersistFile *)this;
|
||
|
else if ( IID_IPersist == riid )
|
||
|
pUnkTemp = (IUnknown *)(IPersist *)(IPersistFile *)this;
|
||
|
else if ( IID_IUnknown == riid )
|
||
|
pUnkTemp = (IUnknown *)(IPersist *)(IPersistFile *)this;
|
||
|
else
|
||
|
{
|
||
|
*ppvObject = NULL;
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
|
||
|
*ppvObject = (void *)pUnkTemp;
|
||
|
pUnkTemp->AddRef();
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//M-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CSmpFilter::AddRef (IUnknown::AddRef)
|
||
|
//
|
||
|
// Summary: Increments interface refcount
|
||
|
//
|
||
|
// Arguments: void
|
||
|
//
|
||
|
// Returns: Value of incremented interface refcount
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
ULONG STDMETHODCALLTYPE CSmpFilter::AddRef()
|
||
|
{
|
||
|
return InterlockedIncrement( &m_lRefs );
|
||
|
}
|
||
|
|
||
|
//M-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CSmpFilter::Release (IUnknown::Release)
|
||
|
//
|
||
|
// Summary: Decrements interface refcount, deleting if unreferenced
|
||
|
//
|
||
|
// Arguments: void
|
||
|
//
|
||
|
// Returns: Value of decremented interface refcount
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
ULONG STDMETHODCALLTYPE CSmpFilter::Release()
|
||
|
{
|
||
|
ULONG ulTmp = InterlockedDecrement( &m_lRefs );
|
||
|
|
||
|
if ( 0 == ulTmp )
|
||
|
delete this;
|
||
|
|
||
|
return ulTmp;
|
||
|
}
|
||
|
|
||
|
//M-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CSmpFilter::Init (IFilter::Init)
|
||
|
//
|
||
|
// Summary: Initializes sample filter instance
|
||
|
//
|
||
|
// Arguments: grfFlags
|
||
|
// [in] Flags for filter behavior
|
||
|
// cAttributes
|
||
|
// [in] Number attributes in array aAttributes
|
||
|
// aAttributes
|
||
|
// [in] Array of requested attribute strings
|
||
|
// pFlags
|
||
|
// [out] Pointer to return flags for additional properties
|
||
|
//
|
||
|
// Returns: S_OK
|
||
|
// Initialization succeeded
|
||
|
// E_FAIL
|
||
|
// File not previously loaded
|
||
|
// E_INVALIDARG
|
||
|
// Count and contents of attributes do not agree
|
||
|
// FILTER_E_ACCESS
|
||
|
// Unable to access file to be filtered
|
||
|
// FILTER_E_PASSWORD
|
||
|
// (not implemented)
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
SCODE STDMETHODCALLTYPE CSmpFilter::Init(
|
||
|
ULONG grfFlags,
|
||
|
ULONG cAttributes,
|
||
|
FULLPROPSPEC const * aAttributes,
|
||
|
ULONG * pFlags
|
||
|
)
|
||
|
{
|
||
|
// Ignore flags for text canonicalization (text is unformatted)
|
||
|
// Check for proper attributes request and recognize only "contents"
|
||
|
|
||
|
if( 0 < cAttributes )
|
||
|
{
|
||
|
ULONG ulNumAttr;
|
||
|
|
||
|
if ( 0 == aAttributes )
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
for ( ulNumAttr = 0 ; ulNumAttr < cAttributes; ulNumAttr++ )
|
||
|
{
|
||
|
if ( guidStorage == aAttributes[ulNumAttr].guidPropSet &&
|
||
|
PID_STG_CONTENTS == aAttributes[ulNumAttr].psProperty.propid )
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ( ulNumAttr < cAttributes )
|
||
|
m_fContents = TRUE;
|
||
|
else
|
||
|
m_fContents = FALSE;
|
||
|
}
|
||
|
else if ( 0 == grfFlags ||
|
||
|
(grfFlags & IFILTER_INIT_APPLY_INDEX_ATTRIBUTES) )
|
||
|
m_fContents = TRUE;
|
||
|
else
|
||
|
m_fContents = FALSE;
|
||
|
|
||
|
m_fEof = FALSE;
|
||
|
|
||
|
// Open the file previously specified in call to IPersistFile::Load
|
||
|
|
||
|
if ( 0 != m_pwszFileName )
|
||
|
{
|
||
|
if ( INVALID_HANDLE_VALUE != m_hFile )
|
||
|
{
|
||
|
CloseHandle ( m_hFile );
|
||
|
m_hFile = INVALID_HANDLE_VALUE;
|
||
|
}
|
||
|
|
||
|
m_hFile = CreateFile (
|
||
|
m_pwszFileName,
|
||
|
GENERIC_READ,
|
||
|
FILE_SHARE_READ | FILE_SHARE_DELETE,
|
||
|
0,
|
||
|
OPEN_EXISTING,
|
||
|
FILE_ATTRIBUTE_NORMAL,
|
||
|
0
|
||
|
);
|
||
|
|
||
|
if ( INVALID_HANDLE_VALUE == m_hFile )
|
||
|
return FILTER_E_ACCESS;
|
||
|
}
|
||
|
else
|
||
|
return E_FAIL;
|
||
|
|
||
|
// Enumerate OLE properties, since any NTFS file can have them
|
||
|
|
||
|
*pFlags = IFILTER_FLAGS_OLE_PROPERTIES;
|
||
|
|
||
|
// Re-initialize
|
||
|
|
||
|
m_ulChunkID = 1;
|
||
|
m_ulCharsRead = 0;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//M-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CSmpFilter::GetChunk (IFilter::GetChunk)
|
||
|
//
|
||
|
// Summary: Gets the next chunk (text only)
|
||
|
//
|
||
|
// Note: GetChunk accepts as input only single-byte-character text
|
||
|
// files, and not multibyte-character or UNICODE text files.
|
||
|
//
|
||
|
// Arguments: ppStat
|
||
|
// [out] Pointer to description of current chunk
|
||
|
// Returns: S_OK
|
||
|
// Chunk was successfully retrieved
|
||
|
// E_FAIL
|
||
|
// Character conversion failed
|
||
|
// FILTER_E_ACCESS
|
||
|
// General access failure occurred
|
||
|
// FILTER_E_END_OF_CHUNKS
|
||
|
// Previous chunk was the last chunk
|
||
|
// FILTER_E_EMBEDDING_UNAVAILABLE
|
||
|
// (not implemented)
|
||
|
// FILTER_E_LINK_UNAVAILABLE
|
||
|
// (not implemented)
|
||
|
// FILTER_E_PASSWORD
|
||
|
// (not implemented)
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
SCODE STDMETHODCALLTYPE CSmpFilter::GetChunk(
|
||
|
STAT_CHUNK * pStat
|
||
|
)
|
||
|
{
|
||
|
if ( INVALID_HANDLE_VALUE == m_hFile )
|
||
|
return FILTER_E_ACCESS;
|
||
|
|
||
|
// Read characters from single-byte file
|
||
|
|
||
|
char cszBuffer[TEXT_FILTER_CHUNK_SIZE];
|
||
|
|
||
|
if ( !ReadFile(
|
||
|
m_hFile,
|
||
|
cszBuffer,
|
||
|
TEXT_FILTER_CHUNK_SIZE,
|
||
|
&m_ulBufferLen,
|
||
|
NULL
|
||
|
) )
|
||
|
return FILTER_E_ACCESS;
|
||
|
else if( 0 == m_ulBufferLen )
|
||
|
m_fEof = TRUE;
|
||
|
|
||
|
if ( !m_fContents || m_fEof )
|
||
|
return FILTER_E_END_OF_CHUNKS;
|
||
|
|
||
|
// Convert single-byte characters to UNICODE
|
||
|
//
|
||
|
// This conversion assumes a one-to-one conversion:
|
||
|
// one input single-byte character to
|
||
|
// one output multibyte (UNICODE) character
|
||
|
//
|
||
|
// This is typically not the general case with multibyte
|
||
|
// characters, and a general case needs to handle the possible
|
||
|
// difference of pre- and post-conversion buffer lengths
|
||
|
|
||
|
if ( !MultiByteToWideChar(
|
||
|
CP_THREAD_ACP,
|
||
|
MB_COMPOSITE,
|
||
|
cszBuffer,
|
||
|
m_ulBufferLen,
|
||
|
m_wcsBuffer,
|
||
|
TEXT_FILTER_CHUNK_SIZE
|
||
|
) )
|
||
|
return E_FAIL;
|
||
|
|
||
|
// Set chunk description
|
||
|
|
||
|
pStat->idChunk = m_ulChunkID;
|
||
|
pStat->breakType = CHUNK_NO_BREAK;
|
||
|
pStat->flags = CHUNK_TEXT;
|
||
|
pStat->locale = GetSystemDefaultLCID();
|
||
|
pStat->attribute.guidPropSet = guidStorage;
|
||
|
pStat->attribute.psProperty.ulKind = PRSPEC_PROPID;
|
||
|
pStat->attribute.psProperty.propid = PID_STG_CONTENTS;
|
||
|
pStat->idChunkSource = m_ulChunkID;
|
||
|
pStat->cwcStartSource = 0;
|
||
|
pStat->cwcLenSource = 0;
|
||
|
|
||
|
m_ulCharsRead = 0;
|
||
|
m_ulChunkID++;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//M-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CSmpFilter::GetText (IFilter::GetText)
|
||
|
//
|
||
|
// Summary: Retrieves UNICODE text for index
|
||
|
//
|
||
|
// Arguments: pcwcBuffer
|
||
|
// [in] Pointer to size of UNICODE buffer
|
||
|
// [out] Pointer to count of UNICODE characters returned
|
||
|
// awcBuffer
|
||
|
// [out] Pointer to buffer to receive UNICODE text
|
||
|
//
|
||
|
// Returns: S_OK
|
||
|
// Text successfully retrieved, but text remains in chunk
|
||
|
// FILTER_E_NO_MORE_TEXT
|
||
|
// All of the text in the current chunk has been returned
|
||
|
// FILTER_S_LAST_TEXT
|
||
|
// Next call to GetText will return FILTER_E_NO_MORE_TEXT
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
SCODE STDMETHODCALLTYPE CSmpFilter::GetText(
|
||
|
ULONG * pcwcBuffer,
|
||
|
WCHAR * awcBuffer
|
||
|
)
|
||
|
{
|
||
|
if ( !m_fContents || 0 == m_ulBufferLen )
|
||
|
{
|
||
|
*pcwcBuffer = 0;
|
||
|
return FILTER_E_NO_MORE_TEXT;
|
||
|
}
|
||
|
|
||
|
// Copy characters in chunk buffer to output UNICODE buffer
|
||
|
//
|
||
|
// This copy assumes a one-to-one conversion in GetChunk
|
||
|
// of input single-byte characters (each 1 byte long)
|
||
|
// to output UNICODE characters (each 2 bytes long)
|
||
|
|
||
|
ULONG ulToCopy = min( *pcwcBuffer, m_ulBufferLen - m_ulCharsRead );
|
||
|
|
||
|
memcpy( awcBuffer, m_wcsBuffer + m_ulCharsRead, 2*ulToCopy );
|
||
|
m_ulCharsRead += ulToCopy;
|
||
|
*pcwcBuffer = ulToCopy;
|
||
|
|
||
|
if ( m_ulBufferLen == m_ulCharsRead )
|
||
|
{
|
||
|
m_ulCharsRead = 0;
|
||
|
m_ulBufferLen = 0;
|
||
|
return FILTER_S_LAST_TEXT;
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//M-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CSmpFilter::GetValue (IFilter::GetValue)
|
||
|
//
|
||
|
// Summary: Retrieves properites for index
|
||
|
//
|
||
|
// Arguments: ppPropValue
|
||
|
// [out] Address that receives pointer to property value
|
||
|
//
|
||
|
// Returns: FILTER_E_NO_VALUES
|
||
|
// Always
|
||
|
// FILTER_E_NO_MORE_VALUES
|
||
|
// (not implemented)
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
SCODE STDMETHODCALLTYPE CSmpFilter::GetValue(
|
||
|
PROPVARIANT ** ppPropValue
|
||
|
)
|
||
|
{
|
||
|
// Sample filter does not retieve any properties
|
||
|
|
||
|
return FILTER_E_NO_VALUES;
|
||
|
}
|
||
|
|
||
|
//M-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CSmpFilter::BindRegion (IFilter::BindRegion)
|
||
|
//
|
||
|
// Summary: Creates moniker or other interface for indicated text
|
||
|
//
|
||
|
// Arguments: origPos
|
||
|
// [in] Description of text location and extent
|
||
|
// riid
|
||
|
// [in] Reference IID of specified interface
|
||
|
// ppunk
|
||
|
// [out] Address that receives requested interface pointer
|
||
|
//
|
||
|
// Returns: E_NOTIMPL
|
||
|
// Always
|
||
|
// FILTER_W_REGION_CLIPPED
|
||
|
// (not implemented)
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
SCODE STDMETHODCALLTYPE CSmpFilter::BindRegion(
|
||
|
FILTERREGION origPos,
|
||
|
REFIID riid,
|
||
|
void ** ppunk
|
||
|
)
|
||
|
{
|
||
|
// BindRegion is currently reserved for future use
|
||
|
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
//M-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CSmpFilter::GetClassID (IPersist::GetClassID)
|
||
|
//
|
||
|
// Summary: Retrieves the class id of the filter class
|
||
|
//
|
||
|
// Arguments: pClassID
|
||
|
// [out] Pointer to the class ID of the filter
|
||
|
//
|
||
|
// Returns: S_OK
|
||
|
// Always
|
||
|
// E_FAIL
|
||
|
// (not implemented)
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
SCODE STDMETHODCALLTYPE CSmpFilter::GetClassID(
|
||
|
CLSID * pClassID
|
||
|
)
|
||
|
{
|
||
|
*pClassID = CLSID_CSmpFilter;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//M-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CSmpFilter::IsDirty (IPersistFile::IsDirty)
|
||
|
//
|
||
|
// Summary: Checks whether file has changed since last save
|
||
|
//
|
||
|
// Arguments: void
|
||
|
//
|
||
|
// Returns: S_FALSE
|
||
|
// Always
|
||
|
// S_OK
|
||
|
// (not implemented)
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
SCODE STDMETHODCALLTYPE CSmpFilter::IsDirty()
|
||
|
{
|
||
|
// File is opened read-only and never changes
|
||
|
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
|
||
|
//M-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CSmpFilter::Load (IPersistFile::Load)
|
||
|
//
|
||
|
// Summary: Opens and initializes the specified file
|
||
|
//
|
||
|
// Arguments: pszFileName
|
||
|
// [in] Pointer to zero-terminated string
|
||
|
// of absolute path of file to open
|
||
|
// dwMode
|
||
|
// [in] Access mode to open the file
|
||
|
//
|
||
|
// Returns: S_OK
|
||
|
// File was successfully loaded
|
||
|
// E_OUTOFMEMORY
|
||
|
// File could not be loaded due to insufficient memory
|
||
|
// E_FAIL
|
||
|
// (not implemented)
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
SCODE STDMETHODCALLTYPE CSmpFilter::Load(
|
||
|
LPCWSTR pszFileName,
|
||
|
DWORD dwMode
|
||
|
)
|
||
|
{
|
||
|
// Load just sets the filename for GetChunk to read and ignores the mode
|
||
|
|
||
|
ULONG ulChars = wcslen( pszFileName ) + 1;
|
||
|
delete [] m_pwszFileName;
|
||
|
|
||
|
m_pwszFileName = new WCHAR [ulChars];
|
||
|
|
||
|
if ( 0 != m_pwszFileName )
|
||
|
wcscpy( m_pwszFileName, pszFileName );
|
||
|
else
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//M-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CSmpFilter::Save (IPersistFile::Save)
|
||
|
//
|
||
|
// Summary: Saves a copy of the current file being filtered
|
||
|
//
|
||
|
// Arguments: pszFileName
|
||
|
// [in] Pointer to zero-terminated string of
|
||
|
// absolute path of where to save file
|
||
|
// fRemember
|
||
|
// [in] Whether the saved copy is made the current file
|
||
|
//
|
||
|
// Returns: E_FAIL
|
||
|
// Always
|
||
|
// S_OK
|
||
|
// (not implemented)
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
SCODE STDMETHODCALLTYPE CSmpFilter::Save(
|
||
|
LPCWSTR pszFileName,
|
||
|
BOOL fRemember
|
||
|
)
|
||
|
{
|
||
|
// File is opened read-only; saving it is an error
|
||
|
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
//M-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CSmpFilter::SaveCompleted (IPersistFile::SaveCompleted)
|
||
|
//
|
||
|
// Summary: Determines whether a file save is completed
|
||
|
//
|
||
|
// Arguments: pszFileName
|
||
|
// [in] Pointer to zero-terminated string of
|
||
|
// absolute path where file was previously saved
|
||
|
//
|
||
|
// Returns: S_OK
|
||
|
// Always
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
SCODE STDMETHODCALLTYPE CSmpFilter::SaveCompleted(
|
||
|
LPCWSTR pszFileName
|
||
|
)
|
||
|
{
|
||
|
// File is opened read-only, so "save" is always finished
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//M-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CSmpFilter::GetCurFile (IPersistFile::GetCurFile)
|
||
|
//
|
||
|
// Summary: Returns a copy of the current file name
|
||
|
//
|
||
|
// Arguments: ppszFileName
|
||
|
// [out] Address to receive pointer to zero-terminated
|
||
|
// string for absolute path to current file
|
||
|
//
|
||
|
// Returns: S_OK
|
||
|
// A valid absolute path was successfully returned
|
||
|
// S_FALSE
|
||
|
// (not implemented)
|
||
|
// E_OUTOFMEMORY
|
||
|
// Operation failed due to insufficient memory
|
||
|
// E_FAIL
|
||
|
// Operation failed due to some reason
|
||
|
// other than insufficient memory
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
SCODE STDMETHODCALLTYPE CSmpFilter::GetCurFile(
|
||
|
LPWSTR * ppszFileName
|
||
|
)
|
||
|
{
|
||
|
if ( 0 == m_pwszFileName )
|
||
|
return E_FAIL;
|
||
|
|
||
|
ULONG ulChars = wcslen( m_pwszFileName ) + 1;
|
||
|
*ppszFileName = (WCHAR *)CoTaskMemAlloc(ulChars*sizeof(WCHAR));
|
||
|
|
||
|
if ( 0 != *ppszFileName )
|
||
|
wcscpy( *ppszFileName, m_pwszFileName );
|
||
|
else
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//C-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Class: CSmpFilterCF
|
||
|
//
|
||
|
// Summary: Implements class factory for sample filter
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
//M-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CSmpFilterCF::CSmpFilterCF
|
||
|
//
|
||
|
// Summary: Class factory constructor
|
||
|
//
|
||
|
// Arguments: void
|
||
|
//
|
||
|
// Purpose: Manages global instance count
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
CSmpFilterCF::CSmpFilterCF() :
|
||
|
m_lRefs(1)
|
||
|
{
|
||
|
InterlockedIncrement( &g_lInstances );
|
||
|
}
|
||
|
|
||
|
//M-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CSmpFilterCF::~CSmpFilterCF
|
||
|
//
|
||
|
// Summary: Class factory destructor
|
||
|
//
|
||
|
// Arguments: void
|
||
|
//
|
||
|
// Purpose: Manages global instance count
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
CSmpFilterCF::~CSmpFilterCF()
|
||
|
{
|
||
|
InterlockedDecrement( &g_lInstances );
|
||
|
}
|
||
|
|
||
|
//M-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CSmpFilterCF::QueryInterface (IUnknown::QueryInterface)
|
||
|
//
|
||
|
// Summary: Queries for requested interface
|
||
|
//
|
||
|
// Arguments: riid
|
||
|
// [in] Reference IID of requested interface
|
||
|
// ppvObject
|
||
|
// [out] Address that receives requested interface pointer
|
||
|
//
|
||
|
// Returns: S_OK
|
||
|
// Interface is supported
|
||
|
// E_NOINTERFACE
|
||
|
// Interface is not supported
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
SCODE STDMETHODCALLTYPE CSmpFilterCF::QueryInterface(
|
||
|
REFIID riid,
|
||
|
void ** ppvObject
|
||
|
)
|
||
|
{
|
||
|
IUnknown *pUnkTemp;
|
||
|
|
||
|
if ( IID_IClassFactory == riid )
|
||
|
pUnkTemp = (IUnknown *)(IClassFactory *)this;
|
||
|
else if ( IID_IUnknown == riid )
|
||
|
pUnkTemp = (IUnknown *)this;
|
||
|
else
|
||
|
{
|
||
|
*ppvObject = NULL;
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
|
||
|
*ppvObject = (void *)pUnkTemp;
|
||
|
pUnkTemp->AddRef();
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//M-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CSmpFilterCF::AddRef (IUknown::AddRef)
|
||
|
//
|
||
|
// Summary: Increments interface refcount
|
||
|
//
|
||
|
// Arguments: void
|
||
|
//
|
||
|
// Returns: Value of incremented interface refcount
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
ULONG STDMETHODCALLTYPE CSmpFilterCF::AddRef()
|
||
|
{
|
||
|
return InterlockedIncrement( &m_lRefs );
|
||
|
}
|
||
|
|
||
|
//M-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CSmpFilterCF::Release (IUnknown::Release)
|
||
|
//
|
||
|
// Summary: Decrements interface refcount, deleting if unreferenced
|
||
|
//
|
||
|
// Arguments: void
|
||
|
//
|
||
|
// Returns: Value of decremented refcount
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
ULONG STDMETHODCALLTYPE CSmpFilterCF::Release()
|
||
|
{
|
||
|
ULONG ulTmp = InterlockedDecrement( &m_lRefs );
|
||
|
|
||
|
if ( 0 == ulTmp )
|
||
|
delete this;
|
||
|
|
||
|
return ulTmp;
|
||
|
}
|
||
|
|
||
|
//M-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CSmpFilterCF::CreateInstance (IClassFactory::CreateInstance)
|
||
|
//
|
||
|
// Summary: Creates new sample filter object
|
||
|
//
|
||
|
// Arguments: pUnkOuter
|
||
|
// [in] Pointer to IUnknown interface of aggregating object
|
||
|
// riid
|
||
|
// [in] Reference IID of requested interface
|
||
|
// ppvObject
|
||
|
// [out] Address that receives requested interface pointer
|
||
|
//
|
||
|
// Returns: S_OK
|
||
|
// Sample filter object was successfully created
|
||
|
// CLASS_E_NOAGGREGATION
|
||
|
// pUnkOuter parameter was non-NULL
|
||
|
// E_NOINTERFACE
|
||
|
// (not implemented)
|
||
|
// E_OUTOFMEMORY
|
||
|
// Sample filter object could not be created
|
||
|
// due to insufficient memory
|
||
|
// E_UNEXPECTED
|
||
|
// Unsuccessful due to an unexpected condition
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
SCODE STDMETHODCALLTYPE CSmpFilterCF::CreateInstance(
|
||
|
IUnknown * pUnkOuter,
|
||
|
REFIID riid,
|
||
|
void * * ppvObject
|
||
|
)
|
||
|
{
|
||
|
CSmpFilter *pIUnk = 0;
|
||
|
|
||
|
if ( 0 != pUnkOuter )
|
||
|
return CLASS_E_NOAGGREGATION;
|
||
|
|
||
|
pIUnk = new CSmpFilter();
|
||
|
|
||
|
if ( 0 != pIUnk )
|
||
|
{
|
||
|
if ( SUCCEEDED( pIUnk->QueryInterface( riid , ppvObject ) ) )
|
||
|
// Release extra refcount from QueryInterface
|
||
|
pIUnk->Release();
|
||
|
else
|
||
|
{
|
||
|
delete pIUnk;
|
||
|
return E_UNEXPECTED;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//M-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CSmpFilterCF::LockServer (IClassFactory::LockServer)
|
||
|
//
|
||
|
// Summary: Forces/allows filter class to remain loaded/be unloaded
|
||
|
//
|
||
|
// Arguments: fLock
|
||
|
// [in] TRUE to lock, FALSE to unlock
|
||
|
//
|
||
|
// Returns: S_OK
|
||
|
// Always
|
||
|
// E_FAIL
|
||
|
// (not implemented)
|
||
|
// E_OUTOFMEMORY
|
||
|
// (not implemented)
|
||
|
// E_UNEXPECTED
|
||
|
// (not implemented)
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
SCODE STDMETHODCALLTYPE CSmpFilterCF::LockServer(
|
||
|
BOOL fLock
|
||
|
)
|
||
|
{
|
||
|
if( fLock )
|
||
|
InterlockedIncrement( &g_lInstances );
|
||
|
else
|
||
|
InterlockedDecrement( &g_lInstances );
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// DLL: SmpFilt.dll
|
||
|
//
|
||
|
// Summary: Implements Dynamic Link Library functions for sample filter
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
//F-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DllMain
|
||
|
//
|
||
|
// Summary: Called from C-Runtime on process/thread attach/detach
|
||
|
//
|
||
|
// Arguments: hInstance
|
||
|
// [in] Handle to the DLL
|
||
|
// fdwReason
|
||
|
// [in] Reason for calling DLL entry point
|
||
|
// lpReserved
|
||
|
// [in] Details of DLL initialization and cleanup
|
||
|
//
|
||
|
// Returns: TRUE
|
||
|
// Always
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
extern "C" BOOL WINAPI DllMain(
|
||
|
HINSTANCE hInstance,
|
||
|
DWORD fdwReason,
|
||
|
LPVOID lpvReserved
|
||
|
)
|
||
|
{
|
||
|
if ( DLL_PROCESS_ATTACH == fdwReason )
|
||
|
DisableThreadLibraryCalls( (HINSTANCE)hInstance );
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//F-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DllGetClassObject
|
||
|
//
|
||
|
// Summary: Create sample filter class factory object
|
||
|
//
|
||
|
// Arguments: cid
|
||
|
// [in] Class ID of class that class factory creates
|
||
|
// iid
|
||
|
// [in] Reference IID of requested class factory interface
|
||
|
// ppvObj
|
||
|
// [out] Address that receives requested interface pointer
|
||
|
//
|
||
|
// Returns: S_OK
|
||
|
// Class factory object was created successfully
|
||
|
// CLASS_E_CLASSNOTAVAILABLE
|
||
|
// DLL does not support the requested class
|
||
|
// E_INVALIDARG
|
||
|
// (not implemented)
|
||
|
// E_OUTOFMEMORY
|
||
|
// Insufficient memory to create the class factory object
|
||
|
// E_UNEXPECTED
|
||
|
// Unsuccessful due to an unexpected condition
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
extern "C" SCODE STDMETHODCALLTYPE DllGetClassObject(
|
||
|
REFCLSID cid,
|
||
|
REFIID iid,
|
||
|
void ** ppvObj
|
||
|
)
|
||
|
{
|
||
|
IUnknown *pResult = 0;
|
||
|
|
||
|
if ( CLSID_CSmpFilter == cid )
|
||
|
pResult = (IUnknown *) new CSmpFilterCF;
|
||
|
else
|
||
|
return CLASS_E_CLASSNOTAVAILABLE;
|
||
|
|
||
|
if ( 0 != pResult )
|
||
|
{
|
||
|
if( SUCCEEDED( pResult->QueryInterface( iid, ppvObj ) ) )
|
||
|
// Release extra refcount from QueryInterface
|
||
|
pResult->Release();
|
||
|
else
|
||
|
{
|
||
|
delete pResult;
|
||
|
return E_UNEXPECTED;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//F-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DllCanUnloadNow
|
||
|
//
|
||
|
// Summary: Indicates whether it is possible to unload DLL
|
||
|
//
|
||
|
// Arguments: void
|
||
|
//
|
||
|
// Returns: S_OK
|
||
|
// DLL can be unloaded now
|
||
|
// S_FALSE
|
||
|
// DLL must remain loaded
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
extern "C" SCODE STDMETHODCALLTYPE DllCanUnloadNow(
|
||
|
void
|
||
|
)
|
||
|
{
|
||
|
if ( 0 >= g_lInstances )
|
||
|
return S_OK;
|
||
|
else
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
|
||
|
//F-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DllRegisterServer
|
||
|
// DllUnregisterServer
|
||
|
//
|
||
|
// Summary: Registers and unregisters DLL server
|
||
|
//
|
||
|
// The registration procedure uses a set of macros
|
||
|
// developed for use within the Indexing Service code.
|
||
|
// The macros are in the included filtreg.hxx.
|
||
|
//
|
||
|
// Returns: DllRegisterServer
|
||
|
// S_OK
|
||
|
// Registration was successful
|
||
|
// SELFREG_E_CLASS
|
||
|
// Registration was unsuccessful
|
||
|
// SELFREG_E_TYPELIB
|
||
|
// (not implemented)
|
||
|
// E_OUTOFMEMORY
|
||
|
// (not implemented)
|
||
|
// E_UNEXPECTED
|
||
|
// (not implemented)
|
||
|
// DllUnregisterServer
|
||
|
// S_OK
|
||
|
// Unregistration was successful
|
||
|
// S_FALSE
|
||
|
// Unregistration was successful, but other
|
||
|
// entries still exist for the DLL's classes
|
||
|
// SELFREG_E_CLASS
|
||
|
// (not implemented)
|
||
|
// SELFREG_E_TYPELIB
|
||
|
// (not implemented)
|
||
|
// E_OUTOFMEMORY
|
||
|
// (not implemented)
|
||
|
// E_UNEXPECTED
|
||
|
// (not implemented)
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// These structures define the registry keys for the registration process.
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
SClassEntry const asmpClasses[] =
|
||
|
{
|
||
|
{ L".smp",
|
||
|
L"SmpFilt.Document",
|
||
|
L"Sample Filter Document",
|
||
|
L"{8B0E5E72-3C30-11d1-8C0D-00AA00C26CD4}",
|
||
|
L"Sample Filter Document"
|
||
|
}
|
||
|
};
|
||
|
|
||
|
SHandlerEntry const smpHandler =
|
||
|
{
|
||
|
L"{8B0E5E73-3C30-11d1-8C0D-00AA00C26CD4}",
|
||
|
L"SmpFilt Persistent Handler",
|
||
|
L"{8B0E5E70-3C30-11d1-8C0D-00AA00C26CD4}"
|
||
|
};
|
||
|
|
||
|
SFilterEntry const smpFilter =
|
||
|
{
|
||
|
L"{8B0E5E70-3C30-11d1-8C0D-00AA00C26CD4}",
|
||
|
L"Sample Filter",
|
||
|
L"smpfilt.dll",
|
||
|
L"Both"
|
||
|
};
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// This macro defines the registration/unregistration routines for the DLL.
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
DEFINE_DLLREGISTERFILTER( smpHandler, smpFilter, asmpClasses )
|