structuredquery is required to support AQS filters in Windows.Devices.Enumeration's `FindAllAsync` methods, this adds a basic set of stubs to get the ball rolling.
-- v9: dlls/structuredquery: Add stubs for IQueryParserManager. dlls/structuredquery/tests: Add conformance tests for IQueryParserManager.
From: Vibhav Pant vibhavp@gmail.com
--- include/Makefile.in | 1 + include/structuredquery.idl | 293 +++++++++++++++++++++++++++ include/structuredquerycondition.idl | 43 ++++ 3 files changed, 337 insertions(+) create mode 100644 include/structuredquery.idl
diff --git a/include/Makefile.in b/include/Makefile.in index ab4957969d3..e5272a647f5 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -761,6 +761,7 @@ SOURCES = \ strmif.idl \ strongname.h \ strsafe.h \ + structuredquery.idl \ structuredquerycondition.idl \ svrapi.h \ synchapi.h \ diff --git a/include/structuredquery.idl b/include/structuredquery.idl new file mode 100644 index 00000000000..3f28f4f63a7 --- /dev/null +++ b/include/structuredquery.idl @@ -0,0 +1,293 @@ +/* + * Structured Query support + * + * Copyright 2024 Vibhav Pant + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +import "structuredquerycondition.idl"; +import "objectarray.idl"; + +cpp_quote("#if 0") +typedef PROPERTYKEY *REFPROPERTYKEY; +cpp_quote("#endif") +cpp_quote("#include <propkeydef.h>") + +typedef [v1_enum] enum tagSTRUCTURED_QUERY_SINGLE_OPTION +{ + SQSO_SCHEMA, + SQSO_LOCALE_WORD_BREAKING, + SQSO_WORD_BREAKER, + SQSO_NATURAL_SYNTAX, + SQSO_AUTOMATIC_WILDCARD, + SQSO_TRACE_LEVEL, + SQSO_LANGUAGE_KEYWORDS, + SQSO_SYNTAX, + SQSO_TIME_ZONE, + SQSO_IMPLICIT_CONNECTOR, + SQSO_CONNECTOR_CASE, +} STRUCTURED_QUERY_SINGLE_OPTION; + +typedef [v1_enum] enum tagSTRUCTURED_QUERY_MULTIOPTION +{ + SQMO_VIRTUAL_PROPERTY, + SQMO_DEFAULT_PROPERTY, + SQMO_GENERATOR_FOR_TYPE, + SQMO_MAP_PROPERTY, +} STRUCTURED_QUERY_MULTIOPTION; + +typedef [v1_enum] enum STRUCTURED_QUERY_RESOLVE_OPTION +{ + SQRO_DEFAULT = 0, + SQRO_DONT_RESOLVE_DATETIME = 0x0001, + SQRO_ALWAYS_ONE_INTERVAL = 0x0002, + SQRO_DONT_SIMPLIFY_CONDITION_TREES = 0x0004, + SQRO_DONT_MAP_RELATIONS = 0x0008, + SQRO_DONT_RESOLVE_RANGES = 0x0010, + SQRO_DONT_REMOVE_UNRESTRICTED_KEYWORDS = 0x0020, + SQRO_DONT_SPLIT_WORDS = 0x0040, + SQRO_IGNORE_PHRASE_ORDER = 0x0080, + SQRO_ADD_VALUE_TYPE_FOR_PLAIN_VALUES = 0x0100, + SQRO_ADD_ROBUST_ITEM_NAME = 0x0200, +} STRUCTURED_QUERY_RESOLVE_OPTION; +cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(STRUCTURED_QUERY_RESOLVE_OPTION);") + +interface IQueryParser; +interface IQuerySolution; +interface IConditionFactory; +interface IConditionFactory2; +interface ITokenCollection; +interface IRelationship; +interface IEntity; +interface INamedEntity; +interface ISchemaLocalizerSupport; +interface ISchemaProvider; + +[ + object, + pointer_default(unique), + uuid(2ebdee67-3505-43f8-9946-ea44abc8e5b0) +] +interface IQueryParser : IUnknown +{ + HRESULT Parse([in] LPCWSTR input, [in] IEnumUnknown *custom_props, [out, retval] IQuerySolution **solution); + HRESULT SetOption([in] STRUCTURED_QUERY_SINGLE_OPTION option, [in] const PROPVARIANT *val); + HRESULT GetOption([in] STRUCTURED_QUERY_SINGLE_OPTION option, [out, retval] PROPVARIANT *val); + HRESULT SetMultiOption([in] STRUCTURED_QUERY_MULTIOPTION option, [in] LPCWSTR key, [in] const PROPVARIANT *val); + HRESULT GetSchemaProvider([out, retval] ISchemaProvider **provider); + HRESULT RestateToString([in] ICondition *cond, [in] BOOL english, [out] LPWSTR *query); + HRESULT ParsePropertyValue([in] LPCWSTR property, [in] LPCWSTR input, [out, retval] IQuerySolution **solution); + HRESULT RestatePropertyValueToString([in] ICondition* cond, [in] BOOL english, [out] LPWSTR *name, + [out] LPWSTR *query); + +} + +typedef [v1_enum] enum tagQUERY_PARSER_MANAGER_OPTION +{ + QPMO_SCHEMA_BINARY_NAME, + QPMO_PRELOCALIZED_SCHEMA_BINARY_PATH, + QPMO_UNLOCALIZED_SCHEMA_BINARY_PATH, + QPMO_LOCALIZED_SCHEMA_BINARY_PATH, + QPMO_APPEND_LCID_TO_LOCALIZED_PATH, + QPMO_LOCALIZER_SUPPORT, +} QUERY_PARSER_MANAGER_OPTION; + +[ + object, + uuid(D6EBC66B-8921-4193-AFDD-A1789FB7FF57), + pointer_default(unique) +] +interface IQuerySolution : IConditionFactory +{ + [local] + HRESULT GetQuery([out] ICondition **cond, [out] IEntity **main); + /* ID can be IID_IEnumUnknown and IID_IEnumVARIANT */ + HRESULT GetErrors([in] REFIID riid, [out, retval, iid_is(riid)] void **out); + [local] + HRESULT GetLexicalData([out] LPWSTR *input, [out] ITokenCollection **tokens, [out] LCID *lcid, + [out] IUnknown **breaker); +} + +[ + object, + pointer_default(unique), + uuid(A5EFE073-B16F-474f-9F3E-9f8b497a3e08) +] +interface IConditionFactory : IUnknown +{ + HRESULT MakeNot([in] ICondition *cond, [in] BOOL simplify, [out, retval] ICondition **result); + HRESULT MakeAndOr([in] CONDITION_TYPE type, [in] IEnumUnknown *conditions, [in] BOOL simplify, + [out, retval] ICondition **result); + HRESULT MakeLeaf([in, unique] LPCWSTR prop, [in] CONDITION_OPERATION cop, [in, unique] LPCWSTR val_type, + [in] const PROPVARIANT *prop_var, [in] IRichChunk *prop_term, [in] IRichChunk *op_term, + [in] IRichChunk *value_term, [in] BOOL expand, [out, retval] ICondition **result); + [local] + HRESULT Resolve([in] ICondition *cond, [in] STRUCTURED_QUERY_RESOLVE_OPTION opt, [in, ref] const SYSTEMTIME *time, + [out, retval] ICondition **result); +} + +typedef [v1_enum] enum CONDITION_CREATION_OPTIONS +{ + CONDITION_CREATION_DEFAULT = 0, + CONDITION_CREATION_NONE = 0, + CONDITION_CREATION_SIMPLIFY = 0x01, + CONDITION_CREATION_VECTOR_AND = 0x02, + CONDITION_CREATION_VECTOR_OR = 0x04, + CONDITION_CREATION_VECTOR_LEAF = 0x08, + CONDITION_CREATION_USE_CONTENT_LOCALE = 0x10, +} CONDITION_CREATION_OPTIONS; +cpp_quote("DEFINE_ENUM_FLAG_OPERATORS( CONDITION_CREATION_OPTIONS );") + + +[ + object, + pointer_default(unique), + uuid(71d222e1-432f-429e-8c13-b6dafde5077a), + local +] +interface IConditionFactory2 : IConditionFactory +{ + HRESULT CreateTrueFalse([in] BOOL val, [in] CONDITION_CREATION_OPTIONS opts, [in] REFIID riid, + [out, iid_is(riid)] void **out); + HRESULT CreateNegation([in] ICondition *cond, [in] CONDITION_CREATION_OPTIONS opts, [in] REFIID riid, + [out, iid_is(riid)] void **out); + HRESULT CreateCompoundFromObjectArray([in] CONDITION_TYPE type, [in] IObjectArray *conditions, + [in] CONDITION_CREATION_OPTIONS opts, [in] REFIID riid, + [out, iid_is(riid)] void **out); + HRESULT CreateCompoundFromArray([in] CONDITION_TYPE type, [in, size_is(cond_count)] ICondition **conditions, + [in] ULONG cond_count, [in] CONDITION_CREATION_OPTIONS opts, [in] REFIID riid, + [out, iid_is(riid)] void **out); + HRESULT CreateStringLeaf([in] REFPROPERTYKEY propkey, [in] CONDITION_OPERATION op, [in] LPCWSTR val, + [in] LPCWSTR locale, [in] CONDITION_CREATION_OPTIONS opts, [in] REFIID riid, + [out, iid_is(riid)] void **out); + HRESULT CreateIntegerLeaf([in] REFPROPERTYKEY propkey, [in] CONDITION_OPERATION op, [in] INT32 val, + [in] CONDITION_CREATION_OPTIONS opts, [in] REFIID riid, [out, iid_is(riid)] void **out); + HRESULT CreateBooleanLeaf([in] REFPROPERTYKEY propkey, [in] CONDITION_OPERATION op, [in] BOOL val, + [in] CONDITION_CREATION_OPTIONS opts, [in] REFIID riid, [out, iid_is(riid)] void **out); + HRESULT CreateLeaf([in] REFPROPERTYKEY propkey, [in] CONDITION_OPERATION op, [in] REFPROPVARIANT prop_var, + [in] LPCWSTR type, [in] LPCWSTR locale, [in] IRichChunk *prop_name_term, [in] IRichChunk *op_term, + [in] IRichChunk *val_term, [in] CONDITION_CREATION_OPTIONS cco, [in] REFIID riid, + [out, iid_is(riid)] void **out); + HRESULT ResolveCondition([in] ICondition *cond, [in] STRUCTURED_QUERY_RESOLVE_OPTION opt, [in] const SYSTEMTIME *time, + [in] REFIID riid, [out, iid_is(riid)] void **out); +} + +[ + object, + pointer_default(unique), + uuid(22d8b4f2-f577-4adb-a335-c2ae88416fab), +] +interface ITokenCollection : IUnknown +{ + HRESULT NumberOfTokens([out] ULONG *num); + [local] + HRESULT GetToken([in] ULONG i, [out] ULONG *begin, [out] ULONG *len, [out] LPWSTR *token_str); +}; + +[ + object, + pointer_default(unique), + uuid(2769280b-5108-498c-9c7f-a51239b63147), +] +interface IRelationship : IUnknown +{ + [local] + HRESULT Name([out, retval] LPWSTR *name); + HRESULT IsReal([out, retval] BOOL *real); + HRESULT Destination([out, retval] IEntity **dest); + /* ID can be be IID_IEnumUnknown or IID_IEnumVARIANT */ + HRESULT MetaData([in] REFIID riid, [out, retval, iid_is(riid)] void **out); + [local] + HRESULT DefaultPhrase([out, retval] LPWSTR *phrase); +}; + +[ + object, + pointer_default(unique), + uuid(24264891-e80b-4fd3-b7ce-4ff2fae8931f), +] +interface IEntity : IUnknown +{ + [local] + HRESULT Name([out, retval] LPWSTR *name); + HRESULT Base([out, retval] IEntity **base); + /* ID can be IID_IEnumUnknown or IID_IEnumVARIANT. */ + HRESULT Relationships([in] REFIID riid, [out, retval, iid_is(riid)] void **out); + HRESULT GetRelationship([in] LPCWSTR name, [out, retval] IRelationship **relation); + HRESULT MetaData([in] REFIID riid, [out, retval, iid_is(riid)] void **out); + /* ID can be IID_IEnumUnknown or IID_IEnumVARIANT. */ + HRESULT NamedEntities([in] REFIID riid, [out, retval, iid_is(riid)] void **out); + HRESULT GetNamedEntity([in] LPCWSTR name, [out, retval] INamedEntity **entity); + [local] + HRESULT DefaultPhrase([out, retval] LPWSTR *phrase); +}; + +[ + object, + pointer_default(unique), + uuid(abdbd0b1-7d54-49fb-ab5c-bff4130004cd), +] +interface INamedEntity : IUnknown +{ + HRESULT GetValue([out, retval] LPWSTR *value); + [local] + HRESULT DefaultPhrase([out, retval] LPWSTR *phrase); +} + +[ + object, + pointer_default(unique), + uuid(ca3fdca2-bfbe-4eed-90d7-0caef0a1bda1), +] +interface ISchemaLocalizerSupport : IUnknown +{ + HRESULT Localize([in] LPCWSTR str, [out, retval] LPWSTR *str_out); +} + +[ + object, + pointer_default(unique), + uuid(8cf89bcb-394c-49b2-ae28-a59dd4ed7f68), +] +interface ISchemaProvider : IUnknown +{ + /* ID can be be IID_IEnumUnknown or IID_IEnumVARIANT */ + HRESULT Entities([in] REFIID riid, [out, retval, iid_is(riid)] void** out); + HRESULT RootEntity([out, retval] IEntity **root); + HRESULT GetEntity([in] LPCWSTR name, [out, retval] IEntity **entity); + /* ID can be be IID_IEnumUnknown or IID_IEnumVARIANT */ + HRESULT MetaData([in] REFIID riid, [out, retval, iid_is(riid)] void** out); + HRESULT Localize([in] LCID lcid, [in] ISchemaLocalizerSupport *support); + HRESULT SaveBinary([in] LPCWSTR path); + HRESULT LookupAuthoredNamedEntity([in] IEntity *entity, [in] LPCWSTR input, [in] ITokenCollection *tokens, + [in] ULONG begin, [out] ULONG *len, [out] LPWSTR *val); +}; + +[ + uuid(1352fa67-2022-41df-9d6f-943a5ee97c9f), + version(1.0) +] +library StructuredQuery1 +{ + [ + uuid(b72f8fd8-0fab-4dd9-bdbf-245a6ce1485b) + ] + coclass QueryParser + { + interface IQueryParser; + }; +} diff --git a/include/structuredquerycondition.idl b/include/structuredquerycondition.idl index 8eb4d51ce87..9cc3b12e147 100644 --- a/include/structuredquerycondition.idl +++ b/include/structuredquerycondition.idl @@ -51,3 +51,46 @@ typedef [v1_enum] enum tagCONDITION_OPERATION COP_WORD_STARTSWITH, COP_APPLICATION_SPECIFIC } CONDITION_OPERATION; + +[ + object, + pointer_default(unique), + uuid(4fdef69c-dbc9-454e-9910-b34f3c64b510), +] +interface IRichChunk : IUnknown +{ + [local] + HRESULT GetData([out, unique] ULONG *first_pos, [out, unique] ULONG *len, + [out, unique] LPWSTR *str, [out, unique] PROPVARIANT *val); + [call_as(GetData)] + HRESULT RemoteGetData([out, unique] ULONG *first_pos, [out, unique] ULONG *len, + [out, unique] LPWSTR *str, [out, unique] PROPVARIANT *val); +}; + +[ + object, + uuid(0FC988D4-C935-4b97-A973-46282EA175C8), + pointer_default(unique), +] +interface ICondition : IPersistStream +{ + HRESULT GetConditionType([out, retval] CONDITION_TYPE *type); + /* ID can be ID IID_IEnumUnknown, IID_IEnumVARIANT IID_IObjectArray, or IID_ICondition. */ + HRESULT GetSubConditions([in] REFIID riid, [out, retval, iid_is(riid)] void** ppv); + [local] + HRESULT GetComparisonInfo([out, unique] LPWSTR *prop_name, [out, unique] CONDITION_OPERATION *op, + [out, unique] PROPVARIANT *prop_var); + [call_as(GetComparisonInfo)] + HRESULT RemoteGetComparisonInfo([out, unique] LPWSTR *prop_name, [out, unique] CONDITION_OPERATION *op, + [out, unique] PROPVARIANT *prop_var); + HRESULT GetValueType([out, retval] LPWSTR *name); + HRESULT GetValueNormalization([out, retval] LPWSTR *normalized); + [local] + HRESULT GetInputTerms([out, unique] IRichChunk **prop_Term, [out, unique] IRichChunk **op_term, + [out, unique] IRichChunk **val_term); + + [call_as(GetInputTerms)] + HRESULT RemoteGetInputTerms([out, unique] IRichChunk **prop_Term, [out, unique] IRichChunk **op_term, + [out, unique] IRichChunk **val_term); + HRESULT Clone([out, retval] ICondition **out); +};
From: Vibhav Pant vibhavp@gmail.com
--- configure | 3 + configure.ac | 2 + dlls/structuredquery/Makefile.in | 8 ++ dlls/structuredquery/classes.idl | 28 +++++ dlls/structuredquery/main.c | 130 ++++++++++++++++++++++ dlls/structuredquery/structuredquery.spec | 4 + 6 files changed, 175 insertions(+) create mode 100644 dlls/structuredquery/Makefile.in create mode 100644 dlls/structuredquery/classes.idl create mode 100644 dlls/structuredquery/main.c create mode 100644 dlls/structuredquery/structuredquery.spec
diff --git a/configure b/configure index 8b5b40f3789..3a5c189cde4 100755 --- a/configure +++ b/configure @@ -1442,6 +1442,7 @@ enable_stdole2_tlb enable_stdole32_tlb enable_sti enable_strmdll +enable_structuredquery enable_svrapi enable_sxs enable_t2embed @@ -22882,6 +22883,8 @@ wine_fn_config_makefile dlls/sti/tests enable_tests wine_fn_config_makefile dlls/storage.dll16 enable_win16 wine_fn_config_makefile dlls/stress.dll16 enable_win16 wine_fn_config_makefile dlls/strmdll enable_strmdll +wine_fn_config_makefile dlls/structuredquery enable_structuredquery +wine_fn_config_makefile dlls/structuredquery/tests enable_tests wine_fn_config_makefile dlls/svrapi enable_svrapi wine_fn_config_makefile dlls/sxs enable_sxs wine_fn_config_makefile dlls/sxs/tests enable_tests diff --git a/configure.ac b/configure.ac index b373c47cfbb..d2c43ffd4ae 100644 --- a/configure.ac +++ b/configure.ac @@ -3170,6 +3170,8 @@ WINE_CONFIG_MAKEFILE(dlls/sti/tests) WINE_CONFIG_MAKEFILE(dlls/storage.dll16) WINE_CONFIG_MAKEFILE(dlls/stress.dll16) WINE_CONFIG_MAKEFILE(dlls/strmdll) +WINE_CONFIG_MAKEFILE(dlls/structuredquery) +WINE_CONFIG_MAKEFILE(dlls/structuredquery/tests) WINE_CONFIG_MAKEFILE(dlls/svrapi) WINE_CONFIG_MAKEFILE(dlls/sxs) WINE_CONFIG_MAKEFILE(dlls/sxs/tests) diff --git a/dlls/structuredquery/Makefile.in b/dlls/structuredquery/Makefile.in new file mode 100644 index 00000000000..747309707a3 --- /dev/null +++ b/dlls/structuredquery/Makefile.in @@ -0,0 +1,8 @@ +MODULE = structuredquery.dll +IMPORTLIB = structuredquery +IMPORTS = ole32 oleaut32 uuid + +EXTRADLLFLAGS = -Wb,--prefer-native +SOURCES = \ + classes.idl \ + main.c \ diff --git a/dlls/structuredquery/classes.idl b/dlls/structuredquery/classes.idl new file mode 100644 index 00000000000..d5cf17fd37c --- /dev/null +++ b/dlls/structuredquery/classes.idl @@ -0,0 +1,28 @@ +/* + * Copyright 2024 Vibhav Pant + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma makedep register + +[ + uuid(b72f8fd8-0fab-4dd9-bdbf-245a6ce1485b), + threading(both) +] +coclass QueryParser +{ + interface IQueryParser; +} diff --git a/dlls/structuredquery/main.c b/dlls/structuredquery/main.c new file mode 100644 index 00000000000..81b24c3873d --- /dev/null +++ b/dlls/structuredquery/main.c @@ -0,0 +1,130 @@ +/* + * Copyright 2024 Vibhav Pant + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS +#include <initguid.h> +#include <structuredquery.h> + +#include <wine/debug.h> + +WINE_DEFAULT_DEBUG_CHANNEL( structquery ); + +struct class_factory +{ + IClassFactory iface; + LONG ref; +}; + +static inline struct class_factory *impl_from_IClassFactory( IClassFactory *iface ) +{ + return CONTAINING_RECORD( iface, struct class_factory, iface ); +} + +static HRESULT WINAPI factory_QueryInterface( IClassFactory *iface, REFIID iid, void **out ) +{ + TRACE( "(%p, %s, %p)\n", iface, debugstr_guid( iid ), out ); + *out = NULL; + + if (IsEqualGUID( &IID_IUnknown, iid ) || + IsEqualGUID( &IID_IClassFactory, iid )) + { + *out = iface; + IClassFactory_AddRef( iface ); + return S_OK; + } + + FIXME( "Interface not implemented, returning E_NOINTERFACE.\n" ); + return E_NOINTERFACE; +} + +static ULONG WINAPI factory_AddRef( IClassFactory *iface ) +{ + struct class_factory *impl = impl_from_IClassFactory( iface ); + TRACE( "(%p)\n", iface ); + return InterlockedIncrement( &impl->ref ); +} + +static ULONG WINAPI factory_Release( IClassFactory *iface ) +{ + struct class_factory *impl = impl_from_IClassFactory( iface ); + ULONG ref; + + TRACE( "(%p)\n", iface ); + ref = InterlockedDecrement( &impl->ref ); + if (!ref) + free( impl ); + return ref; +} + +static HRESULT WINAPI factory_CreateInstance( IClassFactory *iface, IUnknown *outer, REFIID iid, + void **out ) +{ + FIXME( "(%p, %p, %s, %p) stub!\n", iface, outer, debugstr_guid( iid ), out ); + return E_NOTIMPL; +} + +static HRESULT WINAPI factory_LockServer( IClassFactory *iface, BOOL lock ) +{ + TRACE( "(%p, %d\n)", iface, lock ); + return S_OK; +} + +const static IClassFactoryVtbl factory_vtbl = +{ + /* IUnknown */ + factory_QueryInterface, + factory_AddRef, + factory_Release, + /* IClassFactory */ + factory_CreateInstance, + factory_LockServer +}; + +static HRESULT factory_create( REFIID iid, void **obj ) +{ + HRESULT hr; + struct class_factory *impl; + + + impl = calloc( 1, sizeof( *impl ) ); + if (!impl) + return E_OUTOFMEMORY; + impl->iface.lpVtbl = &factory_vtbl; + impl->ref = 1; + + hr = IClassFactory_QueryInterface( &impl->iface, iid, obj ); + IClassFactory_Release( &impl->iface ); + + return hr; +} + +HRESULT WINAPI DllGetClassObject( REFCLSID clsid, REFIID iid, void **out ) +{ + TRACE( "(%s, %s, %p)\n", debugstr_guid( clsid ), debugstr_guid( iid ), out ); + + if (!clsid || !iid || !out) + return E_INVALIDARG; + + *out = NULL; + + if (IsEqualCLSID( clsid, &CLSID_QueryParser )) + return factory_create( iid, out ); + + FIXME("Class not implemented, returning CLASS_E_CLASSNOTAVAILABLE.\n"); + return CLASS_E_CLASSNOTAVAILABLE; +} diff --git a/dlls/structuredquery/structuredquery.spec b/dlls/structuredquery/structuredquery.spec new file mode 100644 index 00000000000..b16365d0c9f --- /dev/null +++ b/dlls/structuredquery/structuredquery.spec @@ -0,0 +1,4 @@ +@ stdcall -private DllCanUnloadNow() +@ stdcall -private DllGetClassObject(ptr ptr ptr) +@ stdcall -private DllRegisterServer() +@ stdcall -private DllUnregisterServer()
From: Vibhav Pant vibhavp@gmail.com
--- dlls/structuredquery/tests/Makefile.in | 5 +++ dlls/structuredquery/tests/query.c | 48 ++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 dlls/structuredquery/tests/Makefile.in create mode 100644 dlls/structuredquery/tests/query.c
diff --git a/dlls/structuredquery/tests/Makefile.in b/dlls/structuredquery/tests/Makefile.in new file mode 100644 index 00000000000..5bf2fc317b7 --- /dev/null +++ b/dlls/structuredquery/tests/Makefile.in @@ -0,0 +1,5 @@ +TESTDLL = structuredquery.dll +IMPORTS = ole32 oleaut32 + +SOURCES = \ + query.c diff --git a/dlls/structuredquery/tests/query.c b/dlls/structuredquery/tests/query.c new file mode 100644 index 00000000000..88b7d02f265 --- /dev/null +++ b/dlls/structuredquery/tests/query.c @@ -0,0 +1,48 @@ +/* + * Copyright 2024 Vibhav Pant + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS +#include <initguid.h> +#include <structuredquery.h> + +#include <wine/test.h> + +void test_IQueryParser( void ) +{ + HRESULT hr; + IQueryParser *parser = NULL; + + hr = CoCreateInstance( &CLSID_QueryParser, NULL, CLSCTX_INPROC, &IID_IQueryParser, + (void **)&parser ); + todo_wine ok( hr == S_OK, "got %#lx\n", hr ); + if (!parser) + { + skip( "Could not create IQueryParser instance.\n" ); + return; + } + IQueryParser_Release( parser ); +} + +START_TEST(query) +{ + CoInitializeEx( NULL, COINIT_MULTITHREADED ); + + test_IQueryParser(); + + CoUninitialize(); +}
From: Vibhav Pant vibhavp@gmail.com
--- dlls/structuredquery/Makefile.in | 1 + dlls/structuredquery/main.c | 38 +++++-- dlls/structuredquery/private.h | 24 +++++ dlls/structuredquery/queryparser.c | 167 +++++++++++++++++++++++++++++ dlls/structuredquery/tests/query.c | 2 +- 5 files changed, 224 insertions(+), 8 deletions(-) create mode 100644 dlls/structuredquery/private.h create mode 100644 dlls/structuredquery/queryparser.c
diff --git a/dlls/structuredquery/Makefile.in b/dlls/structuredquery/Makefile.in index 747309707a3..673ab666aa1 100644 --- a/dlls/structuredquery/Makefile.in +++ b/dlls/structuredquery/Makefile.in @@ -6,3 +6,4 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ classes.idl \ main.c \ + queryparser.c diff --git a/dlls/structuredquery/main.c b/dlls/structuredquery/main.c index 81b24c3873d..939b5da251f 100644 --- a/dlls/structuredquery/main.c +++ b/dlls/structuredquery/main.c @@ -18,16 +18,25 @@
#define COBJMACROS #include <initguid.h> -#include <structuredquery.h> +#include "private.h"
#include <wine/debug.h>
WINE_DEFAULT_DEBUG_CHANNEL( structquery );
+static const struct class_info +{ + const CLSID *clsid; + HRESULT (*constructor)(REFIID, void **); +} class_info[] = { + { &CLSID_QueryParser, queryparser_create }, +}; + struct class_factory { IClassFactory iface; LONG ref; + const struct class_info *info; };
static inline struct class_factory *impl_from_IClassFactory( IClassFactory *iface ) @@ -74,8 +83,18 @@ static ULONG WINAPI factory_Release( IClassFactory *iface ) static HRESULT WINAPI factory_CreateInstance( IClassFactory *iface, IUnknown *outer, REFIID iid, void **out ) { - FIXME( "(%p, %p, %s, %p) stub!\n", iface, outer, debugstr_guid( iid ), out ); - return E_NOTIMPL; + struct class_factory *impl; + + TRACE( "(%p, %p, %s, %p)\n", iface, outer, debugstr_guid( iid ), out ); + impl = impl_from_IClassFactory( iface ); + + if (!iid || !out) + return E_INVALIDARG; + if (outer) + return CLASS_E_NOAGGREGATION; + + *out = NULL; + return impl->info->constructor( iid, out ); }
static HRESULT WINAPI factory_LockServer( IClassFactory *iface, BOOL lock ) @@ -95,16 +114,16 @@ const static IClassFactoryVtbl factory_vtbl = factory_LockServer };
-static HRESULT factory_create( REFIID iid, void **obj ) +static HRESULT factory_create( const struct class_info *info, REFIID iid, void **obj ) { HRESULT hr; struct class_factory *impl;
- impl = calloc( 1, sizeof( *impl ) ); if (!impl) return E_OUTOFMEMORY; impl->iface.lpVtbl = &factory_vtbl; + impl->info = info; impl->ref = 1;
hr = IClassFactory_QueryInterface( &impl->iface, iid, obj ); @@ -115,6 +134,8 @@ static HRESULT factory_create( REFIID iid, void **obj )
HRESULT WINAPI DllGetClassObject( REFCLSID clsid, REFIID iid, void **out ) { + SIZE_T i; + TRACE( "(%s, %s, %p)\n", debugstr_guid( clsid ), debugstr_guid( iid ), out );
if (!clsid || !iid || !out) @@ -122,8 +143,11 @@ HRESULT WINAPI DllGetClassObject( REFCLSID clsid, REFIID iid, void **out )
*out = NULL;
- if (IsEqualCLSID( clsid, &CLSID_QueryParser )) - return factory_create( iid, out ); + for (i = 0; i < ARRAY_SIZE( class_info ); i++) + { + if (IsEqualCLSID( class_info[i].clsid, clsid )) + return factory_create( &class_info[i], iid, out ); + }
FIXME("Class not implemented, returning CLASS_E_CLASSNOTAVAILABLE.\n"); return CLASS_E_CLASSNOTAVAILABLE; diff --git a/dlls/structuredquery/private.h b/dlls/structuredquery/private.h new file mode 100644 index 00000000000..52c968b9a89 --- /dev/null +++ b/dlls/structuredquery/private.h @@ -0,0 +1,24 @@ +/* + * Copyright 2024 Vibhav Pant + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_STRUCTUREDQUERY_PRIVATE_H__ +#define __WINE_STRUCTUREDQUERY_PRIVATE_H__ +#include <structuredquery.h> + +extern HRESULT queryparser_create( REFIID iid, void **out ); +#endif diff --git a/dlls/structuredquery/queryparser.c b/dlls/structuredquery/queryparser.c new file mode 100644 index 00000000000..ffb153be197 --- /dev/null +++ b/dlls/structuredquery/queryparser.c @@ -0,0 +1,167 @@ +/* + * Copyright 2024 Vibhav Pant + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS +#include "private.h" + +#include <wine/debug.h> + +WINE_DEFAULT_DEBUG_CHANNEL( structquery ); + +struct queryparser +{ + IQueryParser iface; + PROPVARIANT options[SQSO_CONNECTOR_CASE]; + LONG ref; +}; + +static inline struct queryparser *impl_from_IQueryParser( IQueryParser *iface ) +{ + return CONTAINING_RECORD( iface, struct queryparser, iface ); +} + +static HRESULT WINAPI queryparser_QueryInterface( IQueryParser *iface, REFIID iid, void **out ) +{ + TRACE( "(%p, %s, %p)\n", iface, debugstr_guid( iid ), out ); + + *out = NULL; + if (IsEqualGUID( &IID_IUnknown, iid ) || + IsEqualGUID( &IID_IQueryParser, iid )) + { + *out = iface; + IUnknown_AddRef( iface ); + return S_OK; + } + + FIXME( "interface not implemented, returning E_NOINTERFACE\n" ); + return E_NOINTERFACE; +} + +static ULONG WINAPI queryparser_AddRef( IQueryParser *iface ) +{ + struct queryparser *impl; + TRACE( "(%p)\n", iface ); + + impl = impl_from_IQueryParser( iface ); + return InterlockedIncrement( &impl->ref ); +} + +static ULONG WINAPI queryparser_Release( IQueryParser *iface ) +{ + struct queryparser *impl; + ULONG ref; + + TRACE( "(%p)\n", iface ); + + impl = impl_from_IQueryParser( iface ); + ref = InterlockedDecrement( &impl->ref ); + if (!ref) + free( impl ); + return ref; +} + +static HRESULT WINAPI queryparser_Parse( IQueryParser *iface, LPCWSTR input, + IEnumUnknown *custom_props, IQuerySolution **solution ) +{ + FIXME( "(%p, %s, %p, %p) stub!\n", iface, debugstr_w( input ), custom_props, solution ); + return E_NOTIMPL; +} + +static HRESULT WINAPI queryparser_SetOption( IQueryParser *iface, + STRUCTURED_QUERY_SINGLE_OPTION option, + const PROPVARIANT *val ) +{ + FIXME( "(%p, %d, %p) stub!\n", iface, option, val ); + return E_NOTIMPL; +} + +static HRESULT WINAPI queryparser_GetOption( IQueryParser *iface, + STRUCTURED_QUERY_SINGLE_OPTION option, + PROPVARIANT *val ) +{ + FIXME( "(%p, %d, %p) stub!\n", iface, option, val ); + return E_NOTIMPL; +} + +static HRESULT WINAPI queryparser_SetMultiOption( IQueryParser *iface, + STRUCTURED_QUERY_MULTIOPTION opt, LPCWSTR key, + const PROPVARIANT *val ) +{ + FIXME( "(%p, %d, %s, %p) stub!\n", iface, opt, debugstr_w( key ), val ); + return E_NOTIMPL; +} + +static HRESULT WINAPI queryparser_GetSchemaProvider( IQueryParser *iface, + ISchemaProvider **provider ) +{ + FIXME( "(%p, %p) stub!\n", iface, provider ); + return E_NOTIMPL; +} + +static HRESULT WINAPI queryparser_RestateToString( IQueryParser *iface, ICondition *cond, + BOOL english, LPWSTR *query ) +{ + FIXME( "(%p, %p, %d, %p) stub!\n", iface, cond, english, query ); + return E_NOTIMPL; +} + +static HRESULT WINAPI queryparser_ParsePropertyValue( IQueryParser *iface, LPCWSTR property, + LPCWSTR input, IQuerySolution **solution ) +{ + FIXME( "(%p, %s, %s, %p) stub!\n", iface, debugstr_w( property ), debugstr_w( input ), + solution ); + return E_NOTIMPL; +} + +static HRESULT WINAPI queryparser_RestatePropertyValueToString( IQueryParser *iface, + ICondition *cond, BOOL english, + LPWSTR *name, LPWSTR *query ) +{ + FIXME( "(%p, %p, %d, %p, %p) stub!\n", iface, cond, english, name, query ); + return E_NOTIMPL; +} + +const static IQueryParserVtbl queryparser_vtbl = +{ + /* IUnknown */ + queryparser_QueryInterface, + queryparser_AddRef, + queryparser_Release, + /* IQueryParser */ + queryparser_Parse, + queryparser_SetOption, + queryparser_GetOption, + queryparser_SetMultiOption, + queryparser_GetSchemaProvider, + queryparser_RestateToString, + queryparser_ParsePropertyValue, + queryparser_RestatePropertyValueToString, +}; + +HRESULT queryparser_create( REFIID iid, void **out ) +{ + struct queryparser *impl; + + impl = calloc( 1, sizeof( *impl ) ); + if (!impl) + return E_OUTOFMEMORY; + impl->iface.lpVtbl = &queryparser_vtbl; + impl->ref = 1; + *out = &impl->iface; + return S_OK; +} diff --git a/dlls/structuredquery/tests/query.c b/dlls/structuredquery/tests/query.c index 88b7d02f265..27d374331e6 100644 --- a/dlls/structuredquery/tests/query.c +++ b/dlls/structuredquery/tests/query.c @@ -29,7 +29,7 @@ void test_IQueryParser( void )
hr = CoCreateInstance( &CLSID_QueryParser, NULL, CLSCTX_INPROC, &IID_IQueryParser, (void **)&parser ); - todo_wine ok( hr == S_OK, "got %#lx\n", hr ); + ok( hr == S_OK, "got %#lx\n", hr ); if (!parser) { skip( "Could not create IQueryParser instance.\n" );
From: Vibhav Pant vibhavp@gmail.com
--- include/structuredquery.idl | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
diff --git a/include/structuredquery.idl b/include/structuredquery.idl index 3f28f4f63a7..2188fc0227b 100644 --- a/include/structuredquery.idl +++ b/include/structuredquery.idl @@ -106,6 +106,20 @@ typedef [v1_enum] enum tagQUERY_PARSER_MANAGER_OPTION QPMO_LOCALIZER_SUPPORT, } QUERY_PARSER_MANAGER_OPTION;
+[ + object, + pointer_default(unique), + uuid(a879e3c4-af77-44fb-8f37-ebd1487cf920), +] +interface IQueryParserManager : IUnknown +{ + /* ID should be IID_IQueryParser */ + HRESULT CreateLoadedParser([in] LPCWSTR catalog, [in] LANGID langid, [in] REFIID riid, + [out, retval, iid_is(riid)] void **out); + HRESULT InitializeOptions([in] BOOL nqs, [in] BOOL auto_wild_card, [in] IQueryParser *parser); + HRESULT SetOption([in] QUERY_PARSER_MANAGER_OPTION opt, [in] const PROPVARIANT *val); +} + [ object, uuid(D6EBC66B-8921-4193-AFDD-A1789FB7FF57), @@ -290,4 +304,12 @@ library StructuredQuery1 { interface IQueryParser; }; + + [ + uuid(5088b39a-29b4-4d9d-8245-4ee289222f66) + ] + coclass QueryParserManager + { + interface IQueryParserManager; + }; }
From: Vibhav Pant vibhavp@gmail.com
--- dlls/structuredquery/tests/Makefile.in | 2 +- dlls/structuredquery/tests/query.c | 306 ++++++++++++++++++++++++- 2 files changed, 306 insertions(+), 2 deletions(-)
diff --git a/dlls/structuredquery/tests/Makefile.in b/dlls/structuredquery/tests/Makefile.in index 5bf2fc317b7..993410856b4 100644 --- a/dlls/structuredquery/tests/Makefile.in +++ b/dlls/structuredquery/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = structuredquery.dll -IMPORTS = ole32 oleaut32 +IMPORTS = ole32 oleaut32 propsys
SOURCES = \ query.c diff --git a/dlls/structuredquery/tests/query.c b/dlls/structuredquery/tests/query.c index 27d374331e6..b09f887703e 100644 --- a/dlls/structuredquery/tests/query.c +++ b/dlls/structuredquery/tests/query.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 Vibhav Pant + * Copyright 2024-2025 Vibhav Pant * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,9 +19,44 @@ #define COBJMACROS #include <initguid.h> #include <structuredquery.h> +#include <propvarutil.h>
#include <wine/test.h>
+static const char *debugstr_propvar( const PROPVARIANT *v ) +{ + if (!v) + return "(null)"; + + switch (v->vt) + { + case VT_EMPTY: + return wine_dbg_sprintf( "%p {VT_EMPTY}", v ); + case VT_NULL: + return wine_dbg_sprintf( "%p {VT_NULL}", v ); + case VT_UI4: + return wine_dbg_sprintf( "%p {VT_UI4: %ld}", v, v->ulVal ); + case VT_UI8: + return wine_dbg_sprintf( "%p {VT_UI8: %s}", v, wine_dbgstr_longlong( v->uhVal.QuadPart ) ); + case VT_I8: + return wine_dbg_sprintf( "%p {VT_I8: %s}", v, wine_dbgstr_longlong( v->hVal.QuadPart ) ); + case VT_R4: + return wine_dbg_sprintf( "%p {VT_R4: %.8e}", v, v->fltVal ); + case VT_R8: + return wine_dbg_sprintf( "%p {VT_R8: %lf}", v, v->dblVal ); + case VT_CLSID: + return wine_dbg_sprintf( "%p {VT_CLSID: %s}", v, wine_dbgstr_guid( v->puuid ) ); + case VT_LPWSTR: + return wine_dbg_sprintf( "%p {VT_LPWSTR: %s}", v, wine_dbgstr_w( v->pwszVal ) ); + case VT_BOOL: + return wine_dbg_sprintf( "%p {VT_BOOL: %d}", v, v->bVal ); + case VT_FILETIME: + return wine_dbg_sprintf( "%p {VT_FILETIME: %s}", v, wine_dbgstr_longlong( v->uhVal.QuadPart ) ); + default: + return wine_dbg_sprintf( "%p {vt %#x}", v, v->vt ); + } +} + void test_IQueryParser( void ) { HRESULT hr; @@ -38,11 +73,280 @@ void test_IQueryParser( void ) IQueryParser_Release( parser ); }
+void test_parser( IQueryParser *parser ) +{ + WCHAR *guid = wcsdup( L"{92383B0E-F90E-4AC9-8D44-8C2D0D0EBDA2}" ); + struct test_case + { + const WCHAR *query_str; + struct + { + const WCHAR *prop_name; + CONDITION_OPERATION op; + PROPVARIANT propvar; + } leaf_conds[2]; + CONDITION_TYPE cond_type; + DWORD subconditions; + } test_cases[] = { + { + L"System.Devices.InterfaceEnabled:=System.StructuredQueryType.Boolean#True", + {{L"System.Devices.InterfaceEnabled", COP_EQUAL, {.vt = VT_BOOL, .boolVal = VARIANT_TRUE}}}, + CT_LEAF_CONDITION, + 1 + }, + { + L"System.Devices.InterfaceEnabled:=System.StructuredQueryType.Boolean#False", + {{L"System.Devices.InterfaceEnabled", COP_EQUAL, {.vt = VT_BOOL, .boolVal = VARIANT_FALSE}}}, + CT_LEAF_CONDITION, + 1 + }, + { + L"System.Devices.InterfaceEnabled:-System.StructuredQueryType.Boolean#True", + {{L"System.Devices.InterfaceEnabled", COP_NOTEQUAL, {.vt = VT_BOOL, .boolVal = VARIANT_TRUE}}}, + CT_LEAF_CONDITION, + 1 + }, + { + L"System.Devices.InterfaceEnabled:≠System.StructuredQueryType.Boolean#True", + {{L"System.Devices.InterfaceEnabled", COP_NOTEQUAL, {.vt = VT_BOOL, .boolVal = VARIANT_TRUE}}}, + CT_LEAF_CONDITION, + 1 + }, + { + L"System.Devices.InterfaceEnabled:NOT System.StructuredQueryType.Boolean#True", + {{L"System.Devices.InterfaceEnabled", COP_NOTEQUAL, {.vt = VT_BOOL, .boolVal = VARIANT_TRUE}}}, + CT_LEAF_CONDITION, + 1 + }, + { + L"System.Devices.CompatibleIds:~={92383B0E-F90E-4AC9-8D44-8C2D0D0EBDA2}", + {{L"System.Devices.CompatibleIds", COP_VALUE_CONTAINS, {.vt = VT_LPWSTR, .pwszVal = guid}}}, + CT_LEAF_CONDITION, + 1 + }, + { + L"System.Devices.CompatibleIds:~!{92383B0E-F90E-4AC9-8D44-8C2D0D0EBDA2}", + {{L"System.Devices.CompatibleIds", COP_VALUE_NOTCONTAINS, {.vt = VT_LPWSTR, .pwszVal = guid}}}, + CT_LEAF_CONDITION, + 1 + }, + { + L"System.Devices.InterfaceClassGuid:="{92383B0E-F90E-4AC9-8D44-8C2D0D0EBDA2}" OR " + L"System.Devices.InterfaceEnabled:=System.StructuredQueryType.Boolean#True", + { + {L"System.Devices.InterfaceClassGuid", COP_EQUAL, {.vt = VT_LPWSTR, .pwszVal = guid}}, + {L"System.Devices.InterfaceEnabled", COP_EQUAL, {.vt = VT_BOOL, .boolVal = VARIANT_TRUE}}, + }, + CT_OR_CONDITION, + 2 + }, + { + L"System.Devices.InterfaceClassGuid:="{92383B0E-F90E-4AC9-8D44-8C2D0D0EBDA2}" AND " + L"System.Devices.InterfaceEnabled:=System.StructuredQueryType.Boolean#True", + { + {L"System.Devices.InterfaceClassGuid", COP_EQUAL, {.vt = VT_LPWSTR, .pwszVal = guid}}, + {L"System.Devices.InterfaceEnabled", COP_EQUAL, {.vt = VT_BOOL, .boolVal = VARIANT_TRUE}}, + }, + CT_AND_CONDITION, + 2 + }, + { + L"System.Devices.InterfaceClassGuid:="{92383B0E-F90E-4AC9-8D44-8C2D0D0EBDA2}" AND " + L"System.Devices.InterfaceEnabled:=System.StructuredQueryType.Boolean#False", + { + {L"System.Devices.InterfaceClassGuid", COP_EQUAL, {.vt = VT_LPWSTR, .pwszVal = guid}}, + {L"System.Devices.InterfaceEnabled", COP_EQUAL, {.vt = VT_BOOL, .boolVal = VARIANT_FALSE}}, + }, + CT_AND_CONDITION, + 2 + }, + }; + DWORD i; + + for (i = 0; i < ARRAY_SIZE( test_cases ); i++ ) + { + const WCHAR *query = test_cases[i].query_str; + IEnumUnknown *conditions; + IQuerySolution *solution; + IConditionFactory *factory; + CONDITION_TYPE cond_type; + ICondition *cond, *cond2; + + IEntity *entity; + HRESULT hr; + DWORD j; + + winetest_push_context( "test_cases[%lu]", i ); + hr = IQueryParser_Parse( parser, query, NULL, &solution ); + ok( hr == S_OK, "got %#lx\n", hr ); + if (FAILED( hr )) + { + skip( "Parse failed.\n" ); + winetest_pop_context(); + continue; + } + + hr = IQuerySolution_GetQuery( solution, &cond, &entity ); + ok( hr == S_OK, "got %#lx\n", hr ); + if (FAILED( hr )) + { + skip( "GetQuery failed.\n" ); + winetest_pop_context(); + IQuerySolution_Release( solution ); + continue; + } + hr = IQuerySolution_QueryInterface( solution, &IID_IConditionFactory, (void *)&factory ); + IQuerySolution_Release( solution ); + ok( hr == S_OK, "got %#lx\n", hr ); + if (FAILED( hr )) + { + skip( "QueryInterface failed.\n" ); + winetest_pop_context(); + continue; + } + + hr = IConditionFactory_Resolve( factory, cond, SQRO_DONT_RESOLVE_DATETIME | SQRO_ADD_VALUE_TYPE_FOR_PLAIN_VALUES, + NULL, &cond2 ); + ICondition_Release( cond ); + ok( hr == S_OK, "got %#lx\n", hr ); + if (FAILED( hr )) + { + skip("Resolve failed.\n"); + winetest_pop_context(); + continue; + } + + hr = ICondition_GetConditionType( cond2, &cond_type ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( cond_type == test_cases[i].cond_type, "%d != %d\n", cond_type, test_cases[i].cond_type ); + + if (cond_type == CT_LEAF_CONDITION) + { + LPWSTR prop_name; + CONDITION_OPERATION op; + PROPVARIANT propvar; + + PropVariantInit( &propvar ); + hr = ICondition_GetComparisonInfo( cond2, &prop_name, &op, &propvar ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( !wcsicmp( prop_name, test_cases[i].leaf_conds[0].prop_name ), "%s != %s\n", debugstr_w( prop_name ), + debugstr_w( test_cases[i].leaf_conds[0].prop_name ) ); + ok( op == test_cases[i].leaf_conds[0].op, "%d != %d\n", op, test_cases[i].leaf_conds[0].op ); + + ok( !PropVariantCompareEx( &propvar, &test_cases[i].leaf_conds[0].propvar, PVCU_DEFAULT, PVCF_DEFAULT ), + "%s != %s\n", debugstr_propvar( &propvar ), debugstr_propvar( &test_cases[i].leaf_conds[0].propvar ) ); + PropVariantClear( &propvar ); + CoTaskMemFree( prop_name ); + winetest_pop_context(); + ICondition_Release( cond2 ); + IEntity_Release( entity ); + continue; + } + + hr = ICondition_GetSubConditions( cond2, &IID_IEnumUnknown, (void *)&conditions ); + ok( hr == S_OK, "got %#lx\n", hr ); + if (FAILED( hr )) + { + skip( "GetSubConditions failed.\n" ); + ICondition_Release( cond2 ); + IEntity_Release( entity ); + winetest_pop_context(); + continue; + } + + for (j = 0; j < test_cases[i].subconditions; j++) + { + IUnknown *out; + ICondition *leaf; + ULONG fetched; + LPWSTR prop_name; + CONDITION_OPERATION op; + PROPVARIANT propvar; + + winetest_push_context( "leaf_conds[%lu]", j ); + hr = IEnumUnknown_Next( conditions, 1, &out, &fetched ); + ok( hr == S_OK, "got %#lx\n", hr ); + if (hr != S_OK) + { + skip( "Next failed.\n" ); + winetest_pop_context(); + break; + } + + hr = IUnknown_QueryInterface( out, &IID_ICondition, (void *)&leaf ); + ok( hr == S_OK, "got %#lx\n", hr ); + IUnknown_Release( out ); + if (FAILED( hr )) + { + skip( "QueryInterface failed.\n" ); + winetest_pop_context(); + break; + } + + hr = ICondition_GetConditionType( leaf, &cond_type ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( cond_type == CT_LEAF_CONDITION, "%d != %d\n", cond_type, CT_LEAF_CONDITION ); + + PropVariantInit( &propvar ); + hr = ICondition_GetComparisonInfo( leaf, &prop_name, &op, &propvar ); + ok( hr == S_OK, "got %#lx\n", hr ); + ok( !wcsicmp( prop_name, test_cases[i].leaf_conds[j].prop_name ), "%s != %s\n", debugstr_w( prop_name ), + debugstr_w( test_cases[i].leaf_conds[j].prop_name ) ); + ok( op == test_cases[i].leaf_conds[j].op, "%d != %d\n", op, test_cases[i].leaf_conds[j].op ); + + ok( !PropVariantCompareEx( &propvar, &test_cases[i].leaf_conds[j].propvar, PVCU_DEFAULT, PVCF_DEFAULT ), + "%s != %s\n", debugstr_propvar( &propvar ), debugstr_propvar( &test_cases[i].leaf_conds[j].propvar ) ); + winetest_pop_context(); + PropVariantClear( &propvar ); + ICondition_Release( leaf ); + CoTaskMemFree( prop_name ); + } + + winetest_pop_context(); + IEnumUnknown_Release( conditions ); + ICondition_Release( cond2 ); + IEntity_Release( entity ); + } + + free( guid ); +} + +void test_IQueryParserManager( void ) +{ + HRESULT hr; + IQueryParserManager *manager = NULL; + IQueryParser *parser; + + hr = CoCreateInstance( &CLSID_QueryParserManager, NULL, CLSCTX_INPROC, &IID_IQueryParserManager, + (void **)&manager ); + todo_wine ok( hr == S_OK, "got %#lx\n", hr ); + if (!manager) + { + skip( "Could not create IQueryParserManager instance.\n" ); + return; + } + + hr = IQueryParserManager_CreateLoadedParser( manager, L"SystemIndex", LANG_SYSTEM_DEFAULT, &IID_IQueryParser, + (void *)&parser ); + todo_wine ok( hr == S_OK, "got %#lx\n", hr ); + if (FAILED( hr )) + { + skip( "CreateLoadedParser failed.\n" ); + goto done; + } + + todo_wine test_parser( parser ); + IQueryParser_Release( parser ); +done: + IQueryParserManager_Release( manager ); +} + START_TEST(query) { CoInitializeEx( NULL, COINIT_MULTITHREADED );
test_IQueryParser(); + test_IQueryParserManager();
CoUninitialize(); }
From: Vibhav Pant vibhavp@gmail.com
--- dlls/structuredquery/Makefile.in | 3 +- dlls/structuredquery/classes.idl | 9 ++ dlls/structuredquery/main.c | 1 + dlls/structuredquery/private.h | 1 + dlls/structuredquery/queryparsermanager.c | 126 ++++++++++++++++++++++ 5 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 dlls/structuredquery/queryparsermanager.c
diff --git a/dlls/structuredquery/Makefile.in b/dlls/structuredquery/Makefile.in index 673ab666aa1..7caa33a3a21 100644 --- a/dlls/structuredquery/Makefile.in +++ b/dlls/structuredquery/Makefile.in @@ -6,4 +6,5 @@ EXTRADLLFLAGS = -Wb,--prefer-native SOURCES = \ classes.idl \ main.c \ - queryparser.c + queryparser.c \ + queryparsermanager.c diff --git a/dlls/structuredquery/classes.idl b/dlls/structuredquery/classes.idl index d5cf17fd37c..666393f0d01 100644 --- a/dlls/structuredquery/classes.idl +++ b/dlls/structuredquery/classes.idl @@ -26,3 +26,12 @@ coclass QueryParser { interface IQueryParser; } + +[ + uuid(5088b39a-29b4-4d9d-8245-4ee289222f66), + threading(both) +] +coclass QueryParserManager +{ + interface IQueryParserManager; +}; diff --git a/dlls/structuredquery/main.c b/dlls/structuredquery/main.c index 939b5da251f..2e7221c8a30 100644 --- a/dlls/structuredquery/main.c +++ b/dlls/structuredquery/main.c @@ -30,6 +30,7 @@ static const struct class_info HRESULT (*constructor)(REFIID, void **); } class_info[] = { { &CLSID_QueryParser, queryparser_create }, + { &CLSID_QueryParserManager, queryparsermanager_create }, };
struct class_factory diff --git a/dlls/structuredquery/private.h b/dlls/structuredquery/private.h index 52c968b9a89..5221888a839 100644 --- a/dlls/structuredquery/private.h +++ b/dlls/structuredquery/private.h @@ -21,4 +21,5 @@ #include <structuredquery.h>
extern HRESULT queryparser_create( REFIID iid, void **out ); +extern HRESULT queryparsermanager_create( REFIID iid, void **out ); #endif diff --git a/dlls/structuredquery/queryparsermanager.c b/dlls/structuredquery/queryparsermanager.c new file mode 100644 index 00000000000..50f6582f93b --- /dev/null +++ b/dlls/structuredquery/queryparsermanager.c @@ -0,0 +1,126 @@ +/* + * Copyright 2024 Vibhav Pant + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS +#include "private.h" + +#include <wine/debug.h> + +WINE_DEFAULT_DEBUG_CHANNEL( structquery ); + +struct queryparsermanager +{ + IQueryParserManager iface; + LONG ref; +}; + +static inline struct queryparsermanager *impl_from_IQueryParserManager( IQueryParserManager *iface ) +{ + return CONTAINING_RECORD( iface, struct queryparsermanager, iface ); +} + +static HRESULT WINAPI queryparsermanager_QueryInterface( IQueryParserManager *iface, REFIID iid, void **out ) +{ + TRACE( "(%p, %s, %p)\n", iface, debugstr_guid( iid ), out ); + + *out = NULL; + if (IsEqualGUID( &IID_IUnknown, iid ) || + IsEqualGUID( &IID_IQueryParserManager, iid )) + { + *out = iface; + IUnknown_AddRef( iface ); + return S_OK; + } + + FIXME( "interface not implemented, returning E_NOINTERFACE\n" ); + return E_NOINTERFACE; +} + +static ULONG WINAPI queryparsermanager_AddRef( IQueryParserManager *iface ) +{ + struct queryparsermanager *impl; + TRACE( "(%p)\n", iface ); + + impl = impl_from_IQueryParserManager( iface ); + return InterlockedIncrement( &impl->ref ); +} + +static ULONG WINAPI queryparsermanager_Release( IQueryParserManager *iface ) +{ + struct queryparsermanager *impl; + ULONG ref; + + TRACE( "(%p)\n", iface ); + + impl = impl_from_IQueryParserManager( iface ); + ref = InterlockedDecrement( &impl->ref ); + if (!ref) + free( impl ); + return ref; +} + + +static HRESULT WINAPI queryparsermanager_CreateLoadedParser( IQueryParserManager *iface, + LPCWSTR catalog, LANGID langid, + REFIID iid, void **out ) +{ + FIXME( "(%p, %s, %d, %s, %p) stub!\n", iface, debugstr_w( catalog ), langid, + debugstr_guid( iid ), out ); + return E_NOTIMPL; +} + +static HRESULT WINAPI queryparsermanager_InitializeOptions( IQueryParserManager *iface, BOOL nqs, + BOOL auto_wildcard, + IQueryParser *parser ) +{ + FIXME( "(%p, %d, %d, %p) stub!\n", iface, nqs, auto_wildcard, parser ); + return E_NOTIMPL; +} + +static HRESULT WINAPI queryparsermanager_SetOption( IQueryParserManager *iface, + QUERY_PARSER_MANAGER_OPTION opt, + const PROPVARIANT *val ) +{ + FIXME("(%p, %d, %p) stub!\n", iface, opt, val); + return E_NOTIMPL; +} + +const static IQueryParserManagerVtbl queryparsermanager_vtbl = +{ + /* IUnknown */ + queryparsermanager_QueryInterface, + queryparsermanager_AddRef, + queryparsermanager_Release, + /* IQueryParserManager */ + queryparsermanager_CreateLoadedParser, + queryparsermanager_InitializeOptions, + queryparsermanager_SetOption, +}; + +HRESULT queryparsermanager_create( REFIID iid, void **out ) +{ + struct queryparsermanager *impl; + + impl = calloc( 1, sizeof( *impl ) ); + if (!impl) + return E_OUTOFMEMORY; + impl->iface.lpVtbl = &queryparsermanager_vtbl; + impl->ref = 1; + *out = &impl->iface; + return S_OK; +}