887 lines
32 KiB
C++
887 lines
32 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Copyright (C) 1997, Microsoft Corporation.
|
|
//
|
|
// File: SlickDLL.cpp
|
|
//
|
|
// Contents: Visual Slick 3.0 extension to call Index Server
|
|
//
|
|
// History: 15-Oct-97 KyleP Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stddef.h>
|
|
|
|
// VSAPI includes windows.h. The define keeps windowsx.h out.
|
|
#define _INC_WINDOWSX 1
|
|
#include <vsapi.h>
|
|
|
|
// #define OLEDBVER 0x0250 // enable ICommandTree interface
|
|
#define DBINITCONSTANTS
|
|
|
|
#include <oledberr.h>
|
|
#include <oledb.h>
|
|
#include <cmdtree.h>
|
|
#include <oledbdep.h>
|
|
#include <ntquery.h>
|
|
#include <cierror.h>
|
|
|
|
// This is the *only* thing needed from nt.h by the command tree helpers.
|
|
typedef LONG NTSTATUS;
|
|
|
|
#include <dbcmdtre.hxx>
|
|
|
|
#define Win4Assert(x)
|
|
#include <tgrow.hxx>
|
|
|
|
//
|
|
// Local prototypes and structures
|
|
//
|
|
|
|
HRESULT SetCommandProperties( ICommand * pICommand );
|
|
HRESULT SetScope( ICommand * pICommand, WCHAR const * pwcQueryScope );
|
|
void ErrorMessagePopup( SCODE sc );
|
|
|
|
struct SResultItem
|
|
{
|
|
LONGLONG llSize;
|
|
FILETIME ftWrite;
|
|
ULONG ulAttrib;
|
|
WCHAR * pwcsPath;
|
|
};
|
|
|
|
//
|
|
// Local constants
|
|
//
|
|
|
|
CIPROPERTYDEF aProperties[] = { { L"FUNC",
|
|
DBTYPE_WSTR | DBTYPE_BYREF,
|
|
{ { 0x8dee0300, 0x16c2, 0x101b, 0xb1, 0x21, 0x08, 0x00, 0x2b, 0x2e, 0xcd, 0xa9 },
|
|
DBKIND_GUID_NAME,
|
|
L"func"
|
|
}
|
|
},
|
|
{ L"CLASS",
|
|
DBTYPE_WSTR | DBTYPE_BYREF,
|
|
{ { 0x8dee0300, 0x16c2, 0x101b, 0xb1, 0x21, 0x08, 0x00, 0x2b, 0x2e, 0xcd, 0xa9 },
|
|
DBKIND_GUID_NAME,
|
|
L"class"
|
|
}
|
|
}
|
|
};
|
|
|
|
//
|
|
// Static command tree (sans select node) to fetch required columns and sort by Rank.
|
|
//
|
|
// NOTE: There are some funny casts below, because of the requirement to
|
|
// statically initialize a union.
|
|
//
|
|
|
|
const DBID dbcolSize = { { 0xb725f130, 0x47ef, 0x101a, 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac },
|
|
DBKIND_GUID_PROPID,
|
|
(LPWSTR)12 };
|
|
|
|
const DBID dbcolWrite = { { 0xb725f130, 0x47ef, 0x101a, 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac },
|
|
DBKIND_GUID_PROPID,
|
|
(LPWSTR)14 };
|
|
|
|
const DBID dbcolAttrib = { { 0xb725f130, 0x47ef, 0x101a, 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac },
|
|
DBKIND_GUID_PROPID,
|
|
(LPWSTR)13 };
|
|
|
|
const DBID dbcolPath = { { 0xb725f130, 0x47ef, 0x101a, 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac },
|
|
DBKIND_GUID_PROPID,
|
|
(LPWSTR)11 };
|
|
|
|
const DBID dbcolRank = { { 0x49691c90, 0x7e17, 0x101a, 0xa9, 0x1c, 0x08, 0x00, 0x2b, 0x2e, 0xcd, 0xa9 },
|
|
DBKIND_GUID_PROPID,
|
|
(LPWSTR)3 };
|
|
|
|
//
|
|
// Columns
|
|
//
|
|
|
|
DBCOMMANDTREE dbcmdColumnSize = { DBOP_column_name, DBVALUEKIND_ID, 0, 0, (ULONG_PTR)&dbcolSize, S_OK };
|
|
DBCOMMANDTREE dbcmdColumnWrite = { DBOP_column_name, DBVALUEKIND_ID, 0, 0, (ULONG_PTR)&dbcolWrite, S_OK };
|
|
DBCOMMANDTREE dbcmdColumnAttrib = { DBOP_column_name, DBVALUEKIND_ID, 0, 0, (ULONG_PTR)&dbcolAttrib, S_OK };
|
|
DBCOMMANDTREE dbcmdColumnPath = { DBOP_column_name, DBVALUEKIND_ID, 0, 0, (ULONG_PTR)&dbcolPath, S_OK };
|
|
DBCOMMANDTREE dbcmdColumnRank = { DBOP_column_name, DBVALUEKIND_ID, 0, 0, (ULONG_PTR)&dbcolRank, S_OK };
|
|
|
|
//
|
|
// Forward declare a few nodes to make linking easy
|
|
//
|
|
|
|
extern DBCOMMANDTREE dbcmdSortListAnchor;
|
|
extern DBCOMMANDTREE dbcmdProjectListAnchor;
|
|
|
|
//
|
|
// The Select node. The actual Select expression will be plugged in to the dbcmdTable node.
|
|
//
|
|
|
|
WCHAR wszTable[] = L"Table";
|
|
|
|
DBCOMMANDTREE dbcmdTable = { DBOP_table_name,
|
|
DBVALUEKIND_WSTR,
|
|
0,
|
|
0, // CITextToSelectTree goes here...
|
|
(ULONG_PTR)&wszTable[0],
|
|
S_OK };
|
|
|
|
DBCOMMANDTREE dbcmdSelect = { DBOP_select,
|
|
DBVALUEKIND_EMPTY,
|
|
&dbcmdTable,
|
|
&dbcmdProjectListAnchor,
|
|
0,
|
|
S_OK };
|
|
|
|
//
|
|
// Project (Path, GUID, ...)
|
|
//
|
|
// NOTE: The order here defines the ordinals of columns.
|
|
//
|
|
|
|
DBCOMMANDTREE dbcmdProjectPath = { DBOP_project_list_element,
|
|
DBVALUEKIND_EMPTY,
|
|
&dbcmdColumnPath,
|
|
0,
|
|
0,
|
|
S_OK };
|
|
|
|
DBCOMMANDTREE dbcmdProjectAttrib = { DBOP_project_list_element,
|
|
DBVALUEKIND_EMPTY,
|
|
&dbcmdColumnAttrib,
|
|
&dbcmdProjectPath,
|
|
0,
|
|
S_OK };
|
|
|
|
DBCOMMANDTREE dbcmdProjectWrite = { DBOP_project_list_element,
|
|
DBVALUEKIND_EMPTY,
|
|
&dbcmdColumnWrite,
|
|
&dbcmdProjectAttrib,
|
|
0,
|
|
S_OK };
|
|
|
|
DBCOMMANDTREE dbcmdProjectSize = { DBOP_project_list_element,
|
|
DBVALUEKIND_EMPTY,
|
|
&dbcmdColumnSize,
|
|
&dbcmdProjectWrite,
|
|
0,
|
|
S_OK };
|
|
|
|
DBCOMMANDTREE dbcmdProjectListAnchor = { DBOP_project_list_anchor,
|
|
DBVALUEKIND_EMPTY,
|
|
&dbcmdProjectSize,
|
|
0,
|
|
0,
|
|
S_OK };
|
|
|
|
DBCOMMANDTREE dbcmdProject = { DBOP_project,
|
|
DBVALUEKIND_EMPTY,
|
|
&dbcmdSelect,
|
|
&dbcmdSortListAnchor,
|
|
0,
|
|
S_OK };
|
|
|
|
//
|
|
// Sort (Descending by Rank)
|
|
//
|
|
|
|
DBSORTINFO dbsortDescending = { TRUE, LOCALE_NEUTRAL };
|
|
|
|
DBCOMMANDTREE dbcmdSortByRank = { DBOP_sort_list_element,
|
|
DBVALUEKIND_SORTINFO,
|
|
&dbcmdColumnRank,
|
|
0,
|
|
(ULONG_PTR)&dbsortDescending,
|
|
S_OK };
|
|
|
|
DBCOMMANDTREE dbcmdSortListAnchor = { DBOP_sort_list_anchor,
|
|
DBVALUEKIND_EMPTY,
|
|
&dbcmdSortByRank,
|
|
0,
|
|
0,
|
|
S_OK };
|
|
|
|
DBCOMMANDTREE dbcmdSort = { DBOP_sort,
|
|
DBVALUEKIND_EMPTY,
|
|
&dbcmdProject,
|
|
0,
|
|
0,
|
|
S_OK };
|
|
|
|
//
|
|
// Bindings
|
|
//
|
|
|
|
DBBINDING aColumns[] = { { 1, // Column 1 -- Size
|
|
offsetof(SResultItem,llSize), // obValue
|
|
0, // obLength
|
|
0, // obStatus
|
|
0, // pTypeInfo
|
|
0, // pObject
|
|
0, // pBindExt
|
|
DBPART_VALUE, // retrieve only value
|
|
0, // dwMemOwner
|
|
0, // eParamIO
|
|
0, // cbMaxLen doesn't apply to fixed types
|
|
0, // dwFlags
|
|
DBTYPE_I8, // dwType
|
|
0, // dwPrecision
|
|
0 // dwScale
|
|
},
|
|
{ 2, // Column 2 -- Write time
|
|
offsetof(SResultItem,ftWrite), // obValue
|
|
0, // obLength
|
|
0, // obStatus
|
|
0, // pTypeInfo
|
|
0, // pObject
|
|
0, // pBindExt
|
|
DBPART_VALUE, // retrieve only value
|
|
0, // dwMemOwner
|
|
0, // eParamIO
|
|
0, // cbMaxLen doesn't apply to fixed types
|
|
0, // dwFlags
|
|
VT_FILETIME, // dwType
|
|
0, // dwPrecision
|
|
0 // dwScale
|
|
},
|
|
{ 3, // Column 3 -- Attributes
|
|
offsetof(SResultItem,ulAttrib),// obValue
|
|
0, // obLength
|
|
0, // obStatus
|
|
0, // pTypeInfo
|
|
0, // pObject
|
|
0, // pBindExt
|
|
DBPART_VALUE, // retrieve only value
|
|
0, // dwMemOwner
|
|
0, // eParamIO
|
|
0, // cbMaxLen doesn't apply to fixed types
|
|
0, // dwFlags
|
|
VT_UI4, // dwType
|
|
0, // dwPrecision
|
|
0 // dwScale
|
|
},
|
|
{ 4, // Column 4 -- Path
|
|
offsetof(SResultItem,pwcsPath), // obValue
|
|
0, // obLength
|
|
0, // obStatus
|
|
0, // pTypeInfo
|
|
0, // pObject
|
|
0, // pBindExt
|
|
DBPART_VALUE, // retrieve only value
|
|
DBMEMOWNER_PROVIDEROWNED, // Index Server owned
|
|
0, // eParamIO
|
|
0, // cbMaxLen doesn't apply to fixed types
|
|
0, // dwFlags
|
|
DBTYPE_WSTR|DBTYPE_BYREF, // dwType
|
|
0, // dwPrecision
|
|
0 // dwScale
|
|
}
|
|
};
|
|
|
|
//
|
|
// C++ Helpers
|
|
//
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Template: XInterface
|
|
//
|
|
// Synopsis: Template for managing ownership of interfaces
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
template<class T> class XInterface
|
|
{
|
|
public:
|
|
XInterface( T * p = 0 ) : _p( p ) {}
|
|
~XInterface() { if ( 0 != _p ) _p->Release(); }
|
|
T * operator->() { return _p; }
|
|
T * GetPointer() const { return _p; }
|
|
IUnknown ** GetIUPointer() { return (IUnknown **) &_p; }
|
|
T ** GetPPointer() { return &_p; }
|
|
void ** GetQIPointer() { return (void **) &_p; }
|
|
T * Acquire() { T * p = _p; _p = 0; return p; }
|
|
|
|
private:
|
|
T * _p;
|
|
};
|
|
|
|
extern "C" {
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: vsDllInit, public
|
|
//
|
|
// Synopsis: Always called by VSlick
|
|
//
|
|
// History: 15-Oct-97 KyleP Stole from VSlick sample (simple.c)
|
|
//
|
|
// Notes: Called from VSlick's dllmain.obj
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void VSAPI vsDllInit()
|
|
{
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: vsDllRegisterExports, public
|
|
//
|
|
// Synopsis: Called by VSlick to register new commands
|
|
//
|
|
// History: 15-Oct-97 KyleP Stole from VSlick sample (simple.c)
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void VSAPI vsDllRegisterExports()
|
|
{
|
|
//
|
|
// This call says CISearch takes two parameters. The first is a filename
|
|
// and the second is just a string. The *_ARG2 mean the command can
|
|
// be called from many different places in VSlick.
|
|
//
|
|
|
|
vsDllExport( "_command void CISearch(VSPSZ,VSPSZ)",
|
|
VSFILE_ARG,
|
|
VSNCW_ARG2|VSICON_ARG2|VSCMDLINE_ARG2|VSREAD_ONLY_ARG2 );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: vsDllExit, public
|
|
//
|
|
// Synopsis: Always called by VSlick
|
|
//
|
|
// History: 15-Oct-97 KyleP Stole from VSlick sample (simple.c)
|
|
//
|
|
// Notes: Called from VSlick's dllmain.obj
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void VSAPI vsDllExit()
|
|
{
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CISearch, public
|
|
//
|
|
// Synopsis: Execute an Index Server search
|
|
//
|
|
// Arguments: [pszScope] -- Scope to search. Also used to locate catalog.
|
|
// [pszQuery] -- Query, in Tripolish
|
|
//
|
|
// History: 15-Oct-97 KyleP Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void VSAPI CISearch(VSPSZ pszScope, VSPSZ pszQuery)
|
|
{
|
|
long status;
|
|
|
|
// Current object/window is mdi child
|
|
status=vsExecute(0,"edit .SearchResults","");
|
|
if ( status && status!=NEW_FILE_RC )
|
|
{
|
|
MessageBox(HWND_DESKTOP,
|
|
L"VSNTQ: Error loading file",
|
|
L"DLL Error",
|
|
0);
|
|
return;
|
|
}
|
|
|
|
if ( status==NEW_FILE_RC )
|
|
// Delete the blank line in the new file created
|
|
vsDeleteLine(0);
|
|
else
|
|
vsExecute( 0, "bottom_of_buffer", "" );
|
|
|
|
vsExecute( 0, "fileman-mode", "" );
|
|
|
|
//
|
|
// Convert arguments to WCHAR
|
|
//
|
|
|
|
unsigned ccQuery = strlen( pszQuery );
|
|
XGrowable<WCHAR> xwcsQuery( ccQuery + ccQuery/2 + 1 );
|
|
mbstowcs( xwcsQuery.Get(), pszQuery, xwcsQuery.Count() );
|
|
|
|
unsigned ccScope = strlen( pszScope );
|
|
XGrowable<WCHAR> xwcsScope( ccScope + ccScope/2 + 1 );
|
|
mbstowcs( xwcsScope.Get(), pszScope, xwcsScope.Count() );
|
|
|
|
//
|
|
// Find catalog
|
|
//
|
|
|
|
XGrowable<WCHAR> xwcsMachine;
|
|
ULONG ccMachine = xwcsMachine.Count();
|
|
XGrowable<WCHAR> xwcsCat;
|
|
ULONG ccCat = xwcsCat.Count();
|
|
|
|
SCODE sc = LocateCatalogs( xwcsScope.Get(), // Scope
|
|
0, // Bookmark
|
|
xwcsMachine.Get(), // Machine
|
|
&ccMachine, // Size
|
|
xwcsCat.Get(), // Catalog
|
|
&ccCat ); // Size
|
|
|
|
if ( S_OK == sc )
|
|
{
|
|
//
|
|
// Execute query
|
|
//
|
|
|
|
SCODE hr = S_OK;
|
|
|
|
do
|
|
{
|
|
//
|
|
// Create an ICommand object. The default scope for the query is the
|
|
// entire catalog. CICreateCommand is a shortcut for making an
|
|
// ICommand. The ADVQUERY sample shows the OLE DB equivalent.
|
|
//
|
|
|
|
XInterface<ICommand> xICommand;
|
|
hr = CICreateCommand( xICommand.GetIUPointer(), // result
|
|
0, // controlling unknown
|
|
IID_ICommand, // IID requested
|
|
xwcsCat.Get(), // catalog name
|
|
xwcsMachine.Get() ); // machine name
|
|
|
|
if ( FAILED( hr ) )
|
|
break;
|
|
|
|
// Set required properties on the ICommand
|
|
|
|
hr = SetCommandProperties( xICommand.GetPointer() );
|
|
|
|
if ( FAILED( hr ) )
|
|
break;
|
|
|
|
hr = SetScope( xICommand.GetPointer(), xwcsScope.Get() );
|
|
|
|
if ( FAILED( hr ) )
|
|
break;
|
|
|
|
//
|
|
// Create an OLE DB query tree from a text restriction, column
|
|
// set, and sort order.
|
|
//
|
|
|
|
DBCOMMANDTREE * pTree;
|
|
hr = CITextToSelectTree( xwcsQuery.Get(), // the query itself
|
|
&pTree, // resulting tree
|
|
sizeof(aProperties)/sizeof(aProperties[0]), // custom properties
|
|
aProperties, // custom properties
|
|
0 ); // neutral locale
|
|
|
|
if ( QPLIST_E_DUPLICATE == hr )
|
|
hr = CITextToSelectTree( xwcsQuery.Get(), // the query itself
|
|
&pTree, // resulting tree
|
|
0, // custom properties
|
|
0, // custom properties
|
|
0 ); // neutral locale
|
|
|
|
if ( FAILED( hr ) )
|
|
break; // Worth a special message?
|
|
|
|
//
|
|
// Set the Select node.
|
|
//
|
|
// Since this code uses a global command tree it is not
|
|
// thread-safe. I don't think this is a problem for VSlick.
|
|
//
|
|
|
|
dbcmdTable.pctNextSibling = pTree;
|
|
pTree = &dbcmdSort;
|
|
|
|
// Set the tree in the ICommandTree
|
|
|
|
XInterface<ICommandTree> xICommandTree;
|
|
hr = xICommand->QueryInterface( IID_ICommandTree,
|
|
xICommandTree.GetQIPointer() );
|
|
if ( FAILED( hr ) )
|
|
break;
|
|
|
|
hr = xICommandTree->SetCommandTree( &pTree,
|
|
DBCOMMANDREUSE_NONE,
|
|
TRUE );
|
|
if ( FAILED( hr ) )
|
|
break;
|
|
|
|
// Execute the query. The query is complete when Execute() returns
|
|
|
|
XInterface<IRowset> xIRowset;
|
|
hr = xICommand->Execute( 0, // no aggregating IUnknown
|
|
IID_IRowset, // IID for interface to return
|
|
0, // no DBPARAMs
|
|
0, // no rows affected
|
|
xIRowset.GetIUPointer() ); // result
|
|
if ( FAILED( hr ) )
|
|
break; // Worth a special message?
|
|
|
|
// Create an accessor, so data can be retrieved from the rowset
|
|
|
|
XInterface<IAccessor> xIAccessor;
|
|
hr = xIRowset->QueryInterface( IID_IAccessor,
|
|
xIAccessor.GetQIPointer() );
|
|
if ( FAILED( hr ) )
|
|
break;
|
|
|
|
//
|
|
// Column iOrdinals are parallel with those passed to CiTextToFullTree,
|
|
// so MapColumnIDs isn't necessary. These binding values for dwPart,
|
|
// dwMemOwner, and wType are the most optimal bindings for Index Server.
|
|
//
|
|
|
|
HACCESSOR hAccessor;
|
|
hr = xIAccessor->CreateAccessor( DBACCESSOR_ROWDATA, // rowdata accessor
|
|
sizeof(aColumns)/sizeof(aColumns[0]), // # of columns
|
|
aColumns, // columns
|
|
0, // ignored
|
|
&hAccessor, // result
|
|
0 ); // no status
|
|
if ( FAILED( hr ) )
|
|
break;
|
|
|
|
//
|
|
// Display the results of the query. Print in 'fileman mode' format.
|
|
//
|
|
|
|
static char const szQueryCaption[] = "Query: ";
|
|
|
|
XGrowable<char> xszLine1( ccQuery + sizeof(szQueryCaption) );
|
|
|
|
strcpy( xszLine1.Get(), szQueryCaption );
|
|
strcat( xszLine1.Get(), pszQuery );
|
|
|
|
vsInsertLine(0,"",-1);
|
|
vsInsertLine(0,xszLine1.Get(),-1);
|
|
vsInsertLine(0,"",-1);
|
|
|
|
DBCOUNTITEM cRowsSoFar = 0;
|
|
|
|
do
|
|
{
|
|
DBCOUNTITEM cRowsReturned = 0;
|
|
const ULONG cRowsAtATime = 10;
|
|
HROW aHRow[cRowsAtATime];
|
|
HROW * pgrHRows = aHRow;
|
|
hr = xIRowset->GetNextRows( 0, // no chapter
|
|
0, // no rows to skip
|
|
cRowsAtATime, // # rows to get
|
|
&cRowsReturned, // # rows returned
|
|
&pgrHRows); // resulting hrows
|
|
|
|
if ( FAILED( hr ) )
|
|
break;
|
|
|
|
for ( ULONG iRow = 0; iRow < cRowsReturned; iRow++ )
|
|
{
|
|
SResultItem result;
|
|
hr = xIRowset->GetData( aHRow[iRow], // hrow being accessed
|
|
hAccessor, // accessor to use
|
|
&result ); // resulting data
|
|
if ( FAILED( hr ) )
|
|
break;
|
|
|
|
//
|
|
// Note: there is no Data type error checking. But our
|
|
// schema here is fixed so it's safe.
|
|
//
|
|
|
|
unsigned ccPath = wcslen( result.pwcsPath );
|
|
|
|
XGrowable<char> xszResult( ccPath + ccPath/2 + 40 );
|
|
|
|
//
|
|
// Size (or <DIR>)
|
|
//
|
|
|
|
if ( result.ulAttrib & FILE_ATTRIBUTE_DIRECTORY )
|
|
strcpy( xszResult.Get(), " <DIR> " );
|
|
else
|
|
sprintf( xszResult.Get(), "%11I64u ", result.llSize );
|
|
|
|
//
|
|
// Date and time
|
|
//
|
|
|
|
FILETIME ftLocal;
|
|
FileTimeToLocalFileTime( &result.ftWrite, &ftLocal );
|
|
|
|
SYSTEMTIME systime;
|
|
FileTimeToSystemTime( &ftLocal, &systime );
|
|
|
|
sprintf( xszResult.Get() + 13, "%2u-%02u-%4u %2u:%02u%c ",
|
|
systime.wMonth, systime.wDay, systime.wYear,
|
|
systime.wHour % 12, systime.wMinute, (systime.wHour >= 12) ? 'p' : 'a' );
|
|
|
|
//
|
|
// Attributes
|
|
//
|
|
|
|
char szAttrib[] = "RSHDA ";
|
|
|
|
szAttrib[0] = ( result.ulAttrib & FILE_ATTRIBUTE_READONLY ) ? 'R' : '-';
|
|
szAttrib[1] = ( result.ulAttrib & FILE_ATTRIBUTE_SYSTEM ) ? 'S' : '-';
|
|
szAttrib[2] = ( result.ulAttrib & FILE_ATTRIBUTE_HIDDEN ) ? 'H' : '-';
|
|
szAttrib[3] = ( result.ulAttrib & FILE_ATTRIBUTE_DIRECTORY ) ? 'D' : '-';
|
|
szAttrib[4] = ( result.ulAttrib & FILE_ATTRIBUTE_ARCHIVE ) ? 'A' : '-';
|
|
|
|
strcat( xszResult.Get(), szAttrib );
|
|
|
|
//
|
|
// Path
|
|
//
|
|
|
|
wcstombs( xszResult.Get() + 39, result.pwcsPath, ccPath + ccPath/2 );
|
|
|
|
//
|
|
// Write out to the VSlick buffer
|
|
//
|
|
|
|
vsInsertLine(0, xszResult.Get(), -1);
|
|
}
|
|
|
|
if ( 0 != cRowsReturned )
|
|
xIRowset->ReleaseRows( cRowsReturned, // # of rows to release
|
|
aHRow, // rows to release
|
|
0, // no options
|
|
0, // no refcounts
|
|
0 ); // no status
|
|
|
|
if ( DB_S_ENDOFROWSET == hr )
|
|
{
|
|
hr = S_OK; // succeeded, return S_OK from DoQuery
|
|
break;
|
|
}
|
|
|
|
if ( FAILED( hr ) )
|
|
break;
|
|
|
|
cRowsSoFar += cRowsReturned;
|
|
} while ( TRUE );
|
|
|
|
if ( FAILED(hr) )
|
|
break;
|
|
|
|
xIAccessor->ReleaseAccessor( hAccessor, 0 );
|
|
|
|
} while ( FALSE );
|
|
|
|
//
|
|
// Clean up Select node.
|
|
//
|
|
|
|
if ( 0 != dbcmdTable.pctNextSibling )
|
|
{
|
|
CDbCmdTreeNode * pSelect = (CDbCmdTreeNode *)(ULONG_PTR)dbcmdTable.pctNextSibling;
|
|
delete pSelect;
|
|
dbcmdTable.pctNextSibling = 0;
|
|
}
|
|
|
|
if ( FAILED(hr) )
|
|
ErrorMessagePopup( hr );
|
|
}
|
|
else
|
|
{
|
|
MessageBox( HWND_DESKTOP,
|
|
L"Unable to find catalog covering specified scope.",
|
|
L"Error",
|
|
MB_OK | MB_ICONERROR );
|
|
}
|
|
}
|
|
|
|
} // "C"
|
|
|
|
//
|
|
// Non-VSlick stuff
|
|
//
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: SetCommandProperties
|
|
//
|
|
// Synopsis: Sets the DBPROP_USEEXTENDEDDBTYPES property to TRUE, so
|
|
// data is returned in PROPVARIANTs, as opposed to the
|
|
// default, which is OLE automation VARIANTs. PROPVARIANTS
|
|
// allow a superset of VARIANT data types. Use of these
|
|
// types avoids costly coercions.
|
|
//
|
|
// Also sets the DBPROP_USECONTENTINDEX property to TRUE, so
|
|
// the index will always be used to resolve the query (as
|
|
// opposed to enumerating all the files on the disk), even
|
|
// if the index is out of date.
|
|
//
|
|
// Both of these properties are unique to Index Server's OLE DB
|
|
// implementation.
|
|
//
|
|
// Arguments: [pICommand] - The ICommand used to set the property
|
|
//
|
|
// Returns: HRESULT result of setting the properties
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
HRESULT SetCommandProperties( ICommand * pICommand )
|
|
{
|
|
static const DBID dbcolNull = { { 0,0,0, { 0,0,0,0,0,0,0,0 } },
|
|
DBKIND_GUID_PROPID, 0 };
|
|
static const GUID guidQueryExt = DBPROPSET_QUERYEXT;
|
|
|
|
DBPROP aProp[2];
|
|
|
|
aProp[0].dwPropertyID = DBPROP_USEEXTENDEDDBTYPES;
|
|
aProp[0].dwOptions = DBPROPOPTIONS_OPTIONAL;
|
|
aProp[0].dwStatus = 0;
|
|
aProp[0].colid = dbcolNull;
|
|
aProp[0].vValue.vt = VT_BOOL;
|
|
aProp[0].vValue.boolVal = VARIANT_TRUE;
|
|
|
|
aProp[1] = aProp[0];
|
|
aProp[1].dwPropertyID = DBPROP_USECONTENTINDEX;
|
|
|
|
DBPROPSET aPropSet[1];
|
|
|
|
aPropSet[0].rgProperties = &aProp[0];
|
|
aPropSet[0].cProperties = 2;
|
|
aPropSet[0].guidPropertySet = guidQueryExt;
|
|
|
|
XInterface<ICommandProperties> xICommandProperties;
|
|
HRESULT hr = pICommand->QueryInterface( IID_ICommandProperties,
|
|
xICommandProperties.GetQIPointer() );
|
|
if ( FAILED( hr ) )
|
|
return hr;
|
|
|
|
return xICommandProperties->SetProperties( 1, // 1 property set
|
|
aPropSet ); // the properties
|
|
} //SetCommandProperties
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: SetScope
|
|
//
|
|
// Synopsis: Sets the catalog and machine properties in the ICommand.
|
|
// Also sets a default scope.
|
|
//
|
|
// Arguments: [pICommand] - ICommand to set props on
|
|
// [pwcQueryScope] - Scope for the query
|
|
//
|
|
// Returns: HRESULT result of the operation
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
HRESULT SetScope( ICommand * pICommand, WCHAR const * pwcQueryScope )
|
|
{
|
|
// Get an ICommandProperties so we can set the properties
|
|
|
|
XInterface<ICommandProperties> xICommandProperties;
|
|
HRESULT hr = pICommand->QueryInterface( IID_ICommandProperties,
|
|
xICommandProperties.GetQIPointer() );
|
|
if ( FAILED( hr ) )
|
|
return hr;
|
|
|
|
// note: SysAllocString, SafeArrayCreate, and SafeArrayPutElement can
|
|
// fail, but this isn't checked here for brevity.
|
|
|
|
SAFEARRAYBOUND rgBound[1];
|
|
rgBound[0].lLbound = 0;
|
|
rgBound[0].cElements = 1;
|
|
long i = 0;
|
|
|
|
SAFEARRAY * pScopes = SafeArrayCreate( VT_BSTR, 1, rgBound );
|
|
hr = SafeArrayPutElement( pScopes, &i, SysAllocString( pwcQueryScope ) );
|
|
if ( FAILED( hr ) )
|
|
return hr;
|
|
|
|
LONG lFlags = QUERY_DEEP;
|
|
SAFEARRAY * pFlags = SafeArrayCreate( VT_I4, 1, rgBound );
|
|
hr = SafeArrayPutElement( pFlags, &i, &lFlags );
|
|
if ( FAILED( hr ) )
|
|
return hr;
|
|
|
|
DBPROP aScopeProperties[2];
|
|
memset( aScopeProperties, 0, sizeof aScopeProperties );
|
|
aScopeProperties[0].dwPropertyID = DBPROP_CI_INCLUDE_SCOPES;
|
|
aScopeProperties[0].vValue.vt = VT_BSTR | VT_ARRAY;
|
|
aScopeProperties[0].vValue.parray = pScopes;
|
|
|
|
aScopeProperties[1].dwPropertyID = DBPROP_CI_SCOPE_FLAGS;
|
|
aScopeProperties[1].vValue.vt = VT_I4 | VT_ARRAY;
|
|
aScopeProperties[1].vValue.parray = pFlags;
|
|
|
|
const GUID guidFSCI = DBPROPSET_FSCIFRMWRK_EXT;
|
|
DBPROPSET aAllPropsets[1];
|
|
aAllPropsets[0].rgProperties = aScopeProperties;
|
|
aAllPropsets[0].cProperties = 2;
|
|
aAllPropsets[0].guidPropertySet = guidFSCI;
|
|
|
|
const ULONG cPropertySets = sizeof aAllPropsets / sizeof aAllPropsets[0];
|
|
|
|
hr = xICommandProperties->SetProperties( cPropertySets, // # of propsets
|
|
aAllPropsets ); // the propsets
|
|
|
|
SafeArrayDestroy( pScopes );
|
|
SafeArrayDestroy( pFlags );
|
|
|
|
return hr;
|
|
} //SetScopeCatalogAndMachine
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: ErrorMessagePopup
|
|
//
|
|
// Synopsis: Popup error dialog.
|
|
//
|
|
// Arguments: [sc] -- Error code
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
void ErrorMessagePopup( SCODE sc )
|
|
{
|
|
WCHAR * pBuf = 0;
|
|
|
|
if ( !FormatMessage( FORMAT_MESSAGE_FROM_HMODULE |
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
|
GetModuleHandle(L"query.dll"),
|
|
sc,
|
|
GetSystemDefaultLCID(),
|
|
(WCHAR *)&pBuf,
|
|
0,
|
|
0 ) &&
|
|
!FormatMessage( FORMAT_MESSAGE_FROM_HMODULE |
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
|
GetModuleHandle(L"kernel32.dll"),
|
|
sc,
|
|
GetSystemDefaultLCID(),
|
|
(WCHAR *)&pBuf,
|
|
0,
|
|
0 ) )
|
|
{
|
|
XGrowable<WCHAR> xawcText(100);
|
|
|
|
wsprintf( xawcText.Get(), L"Query error: 0x%x", sc );
|
|
|
|
MessageBox( HWND_DESKTOP,
|
|
xawcText.Get(),
|
|
L"Error",
|
|
MB_OK | MB_ICONERROR );
|
|
}
|
|
else
|
|
{
|
|
MessageBox( HWND_DESKTOP,
|
|
pBuf,
|
|
L"Error",
|
|
MB_OK | MB_ICONERROR );
|
|
|
|
LocalFree( pBuf );
|
|
}
|
|
}
|