|
|
//+---------------------------------------------------------------------------
//
// 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 ); } }
|