diff --git a/Directory.Build.props b/Directory.Build.props index 93d1e660..8b7f2bf9 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -15,7 +15,7 @@ en-US enable true - $(NoWarn);NETSDK1138;SYSLIB0003;SYSLIB0004;SYSLIB0011;IL2026;IL2050;IL2075;IL2067;IL2070;IL2072;IL2077;IL2080;IL2087;IL2090;CS0618;CA1401;CA2101;SYSLIB1054; + $(NoWarn);NETSDK1138;SYSLIB0003;SYSLIB0004;SYSLIB0011;IL2026;IL2050;IL2075;IL2067;IL2070;IL2072;IL2077;IL2080;IL2087;IL2090;CS0618;CA1041;CA1401;CA2101;SYSLIB1054;SYSLIB1096; true diff --git a/PInvoke/SearchApi/SearchApi.cs b/PInvoke/SearchApi/SearchApi.cs index 10714fd7..72d3d71f 100644 --- a/PInvoke/SearchApi/SearchApi.cs +++ b/PInvoke/SearchApi/SearchApi.cs @@ -2863,7 +2863,8 @@ public static partial class SearchApi // OnItemsChanged( DWORD dwNumberOfChanges, SEARCH_ITEM_CHANGE [] rgDataChangeEntries, DWORD [] rgdwDocIds, HRESULT [] // rghrCompletionCodes ); [PInvokeData("searchapi.h")] - void OnItemsChanged(uint dwNumberOfChanges, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] SEARCH_ITEM_CHANGE[] rgDataChangeEntries, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] uint[] rgdwDocIds, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] HRESULT[] rghrCompletionCodes); + void OnItemsChanged(uint dwNumberOfChanges, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] SEARCH_ITEM_CHANGE[] rgDataChangeEntries, + [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] uint[] rgdwDocIds, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] HRESULT[] rghrCompletionCodes); } /// Provides methods for accessing thesaurus information. @@ -2929,7 +2930,7 @@ public static partial class SearchApi // https://docs.microsoft.com/en-us/windows/desktop/api/searchapi/nf-searchapi-isearchlanguagesupport-loadwordbreaker HRESULT // LoadWordBreaker( LCID lcid, REFIID riid, void **ppWordBreaker, LCID *pLcidUsed ); [PInvokeData("searchapi.h")] - void LoadWordBreaker(uint lcid, in Guid riid, [MarshalAs(UnmanagedType.IUnknown, IidParameterIndex = 1)] out object ppWordBreaker, out uint pLcidUsed); + void LoadWordBreaker(LCID lcid, in Guid riid, [MarshalAs(UnmanagedType.IUnknown, IidParameterIndex = 1)] out object ppWordBreaker, out LCID pLcidUsed); /// Retrieves an interface to the word stemmer registered for the specified language code identifier (LCID). /// @@ -2951,7 +2952,7 @@ public static partial class SearchApi // https://docs.microsoft.com/en-us/windows/desktop/api/searchapi/nf-searchapi-isearchlanguagesupport-loadstemmer HRESULT // LoadStemmer( LCID lcid, REFIID riid, void **ppStemmer, LCID *pLcidUsed ); [PInvokeData("searchapi.h")] - void LoadStemmer(uint lcid, in Guid riid, [MarshalAs(UnmanagedType.IUnknown, IidParameterIndex = 1)] out object ppStemmer, out uint pLcidUsed); + void LoadStemmer(LCID lcid, in Guid riid, [MarshalAs(UnmanagedType.IUnknown, IidParameterIndex = 1)] out object ppStemmer, out LCID pLcidUsed); /// /// Determines whether the query token is a prefix of the document token, disregarding case, width, and (optionally) diacritics. @@ -4086,7 +4087,7 @@ public static partial class SearchApi // put_QueryContentLocale( LCID lcid ); [PInvokeData("searchapi.h")] [DispId(0x60010001)] - uint QueryContentLocale { [param: In] set; get; } + LCID QueryContentLocale { [param: In] set; get; } /// /// Gets or sets the language code identifier (LCID) for the locale to use when parsing Advanced Query Syntax (AQS) keywords. @@ -4100,7 +4101,7 @@ public static partial class SearchApi // put_QueryKeywordLocale( LCID lcid ); [PInvokeData("searchapi.h")] [DispId(0x60010003)] - uint QueryKeywordLocale { [param: In] set; get; } + LCID QueryKeywordLocale { [param: In] set; get; } /// Gets or sets a value that specifies how query terms are to be expanded. /// @@ -6065,6 +6066,26 @@ public static partial class SearchApi HRESULT LoadIFilterWithPrivateComActivation(in FILTERED_DATA_SOURCES filteredSources, [In, MarshalAs(UnmanagedType.Bool)] bool useDefault, out Guid filterClsid, [MarshalAs(UnmanagedType.Bool)] out bool isFilterPrivateComActivated, out IFilter filterObj); } + /// Gets the change notification sink interface. + /// The instance. + /// Type: ISearchNotifyInlineSite* + /// A pointer to your ISearchNotifyInlineSite interface. + /// Type: GUID* + /// Receives a pointer to the GUID representing the catalog reset. If this GUID changes, all notifications must be resent. + /// Type: GUID* + /// Receives a pointer to the GUID representing a checkpoint. + /// Type: DWORD* + /// Receives a pointer to the number indicating the last checkpoint to be saved. + /// Receives a pointer to the interface. + // https://docs.microsoft.com/en-us/windows/desktop/api/searchapi/nf-searchapi-isearchcatalogmanager-getitemschangedsink HRESULT + // GetItemsChangedSink( ISearchNotifyInlineSite *pISearchNotifyInlineSite, REFIID riid, void **ppv, GUID + // *pGUIDCatalogResetSignature, GUID *pGUIDCheckPointSignature, DWORD *pdwLastCheckPointNumber ); + public static ISearchItemsChangedSink GetItemsChangedSink(this ISearchCatalogManager mgr, ISearchNotifyInlineSite pISearchNotifyInlineSite, out Guid pGUIDCatalogResetSignature, out Guid pGUIDCheckPointSignature, out uint pdwLastCheckPointNumber) + { + mgr.GetItemsChangedSink(pISearchNotifyInlineSite, typeof(ISearchItemsChangedSink).GUID, out var ppv, out pGUIDCatalogResetSignature, out pGUIDCheckPointSignature, out pdwLastCheckPointNumber); + return (ISearchItemsChangedSink)ppv; + } + /// Describes security authentication information for content access. // https://docs.microsoft.com/en-us/windows/desktop/api/searchapi/ns-searchapi-authentication_info typedef struct // _AUTHENTICATION_INFO { DWORD dwSize; AUTH_TYPE atAuthenticationType; LPCWSTR pcwszUser; LPCWSTR pcwszPassword; } AUTHENTICATION_INFO; @@ -6307,7 +6328,7 @@ public static partial class SearchApi /// Type: LCID /// The LCID of the column. /// - public uint lcid; + public LCID lcid; } /// Specifies the changes to an indexed item. @@ -6344,7 +6365,8 @@ public static partial class SearchApi /// or SEARCH_CHANGE_MODIFY notification. In the case of a move, this member contains the new URL of the item. /// /// - [MarshalAs(UnmanagedType.LPWStr)] public string lpwszURL; + [MarshalAs(UnmanagedType.LPWStr)] + public string? lpwszURL; /// /// Type: LPWSTR @@ -6353,7 +6375,8 @@ public static partial class SearchApi /// SEARCH_CHANGE_DELETE notification. /// /// - [MarshalAs(UnmanagedType.LPWStr)] public string lpwszOldURL; + [MarshalAs(UnmanagedType.LPWStr)] + public string? lpwszOldURL; } /// Describes the status of a document to be indexed. @@ -6542,7 +6565,7 @@ public static partial class SearchApi /// word breaking of text. If the chunk is neither text-type nor a value-type with data type VT_LPWSTR, VT_LPSTR or VT_BSTR, this /// field is ignored. /// - public uint locale; + public LCID locale; /// /// The property to be applied to the chunk. See FULLPROPSPEC. If a filter requires that the same text have more than one diff --git a/UnitTests/PInvoke/SearchApi/SearchApi.csproj b/UnitTests/PInvoke/SearchApi/SearchApi.csproj new file mode 100644 index 00000000..d8a8ca21 --- /dev/null +++ b/UnitTests/PInvoke/SearchApi/SearchApi.csproj @@ -0,0 +1,8 @@ + + + UnitTest.PInvoke.SearchApi + + + + + \ No newline at end of file diff --git a/UnitTests/PInvoke/SearchApi/SearchApiTests.cs b/UnitTests/PInvoke/SearchApi/SearchApiTests.cs new file mode 100644 index 00000000..758f1563 --- /dev/null +++ b/UnitTests/PInvoke/SearchApi/SearchApiTests.cs @@ -0,0 +1,64 @@ +using NUnit.Framework; +using NUnit.Framework.Internal; +using System.IO; +using static Vanara.PInvoke.SearchApi; + +namespace Vanara.PInvoke.Tests; + +[TestFixture] +public class SearchApiTests +{ + ISearchCatalogManager? catalogManager; + + [OneTimeSetUp] + public void _Setup() + { + ISearchManager searchManager = new(); + catalogManager = searchManager.GetCatalog("SystemIndex"); + } + + [OneTimeTearDown] + public void _TearDown() + { + } + + //[Test] + public void GetItemsChangedSinkTest() + { + TestInlineSite testInlineSite = new(TestContext.Out); + ISearchItemsChangedSink itemsChangedSink = catalogManager!.GetItemsChangedSink(testInlineSite, out _, out _, out _); + + using TemporaryDirectory tempDir = new(); + string f1 = tempDir.RandomTxtFileFullPath; + File.Copy(TestCaseSources.SmallFile, f1); + Assert.That(File.Exists(f1), Is.True); + string f2 = tempDir.RandomTxtFileFullPath; + + SEARCH_ITEM_CHANGE itemChange = new() + { + Change = SEARCH_KIND_OF_CHANGE.SEARCH_CHANGE_MOVE_RENAME, + Priority = SEARCH_NOTIFICATION_PRIORITY.SEARCH_NORMAL_PRIORITY, + pUserData = default, //This is supposed to be a "Pointer to user information", but I have no idea what this means or what it wants + lpwszURL = new Uri(f2).AbsoluteUri, + lpwszOldURL = new Uri(f1).AbsoluteUri + }; + File.Move(f1, f2); + Assert.That(File.Exists(f2), Is.True); + + // I can't get this to work. I get an exception (DTS_E_OLEDBERROR) when trying to call OnItemsChanged. + SEARCH_ITEM_CHANGE[] itemsChangedArray = [itemChange]; + uint[] retInts = [0]; + HRESULT[] hresults = [0]; + itemsChangedSink.OnItemsChanged(1, itemsChangedArray, retInts, hresults); + Assert.That((int)hresults[0], Is.EqualTo(HRESULT.S_OK)); + } + + [ComVisible(true), Guid("4da1a242-8634-433a-906d-9bdba3e60b11")] + internal class TestInlineSite(TextWriter tw) : ISearchNotifyInlineSite + { + public void OnItemIndexedStatusChange([In] SEARCH_INDEXING_PHASE sipStatus, [In] uint dwNumEntries, + SEARCH_ITEM_INDEXING_STATUS[] rgItemStatusEntries) => tw.WriteLine("OnItemIndexedStatusChange"); + public void OnCatalogStatusChange(in Guid guidCatalogResetSignature, in Guid guidCheckPointSignature, uint dwLastCheckPointNumber) => + tw.WriteLine("OnCatalogStatusChange"); + } +} \ No newline at end of file diff --git a/Vanara.sln b/Vanara.sln index c9a91d75..d84e5f40 100644 --- a/Vanara.sln +++ b/Vanara.sln @@ -448,6 +448,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WUApi", "UnitTests\PInvoke\ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Vanara.WindowsUpdate", "WindowsUpdate\Vanara.WindowsUpdate.csproj", "{DCD4CDCF-F963-48B6-9B8F-1F273C38952F}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SearchApi", "UnitTests\PInvoke\SearchApi\SearchApi.csproj", "{B359422A-F804-46B1-BC79-A55F241C5DF3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -2433,7 +2435,6 @@ Global {A96CFF10-0967-429A-8700-4A86C97C5603}.Debug|x86.ActiveCfg = Debug|x86 {A96CFF10-0967-429A-8700-4A86C97C5603}.Debug|x86.Build.0 = Debug|x86 {A96CFF10-0967-429A-8700-4A86C97C5603}.DebugNoTests|Any CPU.ActiveCfg = DebugNoTests|Any CPU - {A96CFF10-0967-429A-8700-4A86C97C5603}.DebugNoTests|Any CPU.Build.0 = DebugNoTests|Any CPU {A96CFF10-0967-429A-8700-4A86C97C5603}.DebugNoTests|x64.ActiveCfg = DebugNoTests|x64 {A96CFF10-0967-429A-8700-4A86C97C5603}.DebugNoTests|x64.Build.0 = DebugNoTests|x64 {A96CFF10-0967-429A-8700-4A86C97C5603}.DebugNoTests|x86.ActiveCfg = DebugNoTests|x86 @@ -3318,7 +3319,6 @@ Global {40E5CA4E-527F-4F79-875D-2342D1136FDD}.Debug|x86.ActiveCfg = Debug|x86 {40E5CA4E-527F-4F79-875D-2342D1136FDD}.Debug|x86.Build.0 = Debug|x86 {40E5CA4E-527F-4F79-875D-2342D1136FDD}.DebugNoTests|Any CPU.ActiveCfg = DebugNoTests|Any CPU - {40E5CA4E-527F-4F79-875D-2342D1136FDD}.DebugNoTests|Any CPU.Build.0 = DebugNoTests|Any CPU {40E5CA4E-527F-4F79-875D-2342D1136FDD}.DebugNoTests|x64.ActiveCfg = DebugNoTests|x64 {40E5CA4E-527F-4F79-875D-2342D1136FDD}.DebugNoTests|x64.Build.0 = DebugNoTests|x64 {40E5CA4E-527F-4F79-875D-2342D1136FDD}.DebugNoTests|x86.ActiveCfg = DebugNoTests|x86 @@ -3929,6 +3929,22 @@ Global {DCD4CDCF-F963-48B6-9B8F-1F273C38952F}.Release|x64.Build.0 = Release|x64 {DCD4CDCF-F963-48B6-9B8F-1F273C38952F}.Release|x86.ActiveCfg = Release|x86 {DCD4CDCF-F963-48B6-9B8F-1F273C38952F}.Release|x86.Build.0 = Release|x86 + {B359422A-F804-46B1-BC79-A55F241C5DF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B359422A-F804-46B1-BC79-A55F241C5DF3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B359422A-F804-46B1-BC79-A55F241C5DF3}.Debug|x64.ActiveCfg = Debug|x64 + {B359422A-F804-46B1-BC79-A55F241C5DF3}.Debug|x64.Build.0 = Debug|x64 + {B359422A-F804-46B1-BC79-A55F241C5DF3}.Debug|x86.ActiveCfg = Debug|x86 + {B359422A-F804-46B1-BC79-A55F241C5DF3}.Debug|x86.Build.0 = Debug|x86 + {B359422A-F804-46B1-BC79-A55F241C5DF3}.DebugNoTests|Any CPU.ActiveCfg = DebugNoTests|Any CPU + {B359422A-F804-46B1-BC79-A55F241C5DF3}.DebugNoTests|x64.ActiveCfg = DebugNoTests|x64 + {B359422A-F804-46B1-BC79-A55F241C5DF3}.DebugNoTests|x64.Build.0 = DebugNoTests|x64 + {B359422A-F804-46B1-BC79-A55F241C5DF3}.DebugNoTests|x86.ActiveCfg = DebugNoTests|x86 + {B359422A-F804-46B1-BC79-A55F241C5DF3}.DebugNoTests|x86.Build.0 = DebugNoTests|x86 + {B359422A-F804-46B1-BC79-A55F241C5DF3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B359422A-F804-46B1-BC79-A55F241C5DF3}.Release|x64.ActiveCfg = Release|x64 + {B359422A-F804-46B1-BC79-A55F241C5DF3}.Release|x64.Build.0 = Release|x64 + {B359422A-F804-46B1-BC79-A55F241C5DF3}.Release|x86.ActiveCfg = Release|x86 + {B359422A-F804-46B1-BC79-A55F241C5DF3}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -4129,6 +4145,7 @@ Global {9E2D6D4B-69D0-46A0-A18A-186E3FA269BD} = {212ABBD0-B724-4CFA-9D6D-E3891547FA90} {7A2BF2BB-B565-4F0F-8EBD-5C0A57A0773B} = {212ABBD0-B724-4CFA-9D6D-E3891547FA90} {4E84A8EA-A180-4897-9542-C529A91702AC} = {385CAD2D-0A5E-4F80-927B-D5499D126B90} + {B359422A-F804-46B1-BC79-A55F241C5DF3} = {385CAD2D-0A5E-4F80-927B-D5499D126B90} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {543FAC75-2AF1-4EF1-9609-B242B63FEED4}