Skip to content

Commit

Permalink
Merge pull request #123 from microsoft/spellchecker
Browse files Browse the repository at this point in the history
Add SpellChecker sample
  • Loading branch information
AArnott committed Feb 18, 2021
2 parents 3e0f0cd + f452916 commit 0ee8941
Show file tree
Hide file tree
Showing 9 changed files with 167 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="all" />
<PackageReference Include="Nerdbank.GitVersioning" Version="3.3.37" PrivateAssets="all" />
<PackageReference Include="Nullable" Version="1.3.0" PrivateAssets="all" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.261" PrivateAssets="all" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.321" PrivateAssets="all" />
</ItemGroup>

<ItemGroup>
Expand Down
7 changes: 7 additions & 0 deletions Microsoft.Windows.CsWin32.sln
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Win32MetaGeneration", "src\
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GenerationSandbox.Tests", "test\GenerationSandbox.Tests\GenerationSandbox.Tests.csproj", "{7E8A5179-F94C-410F-8BBE-FDAAA95A19C3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SpellChecker", "test\SpellChecker\SpellChecker.csproj", "{744BE74F-8C4A-49E8-9683-52D987224285}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -65,6 +67,10 @@ Global
{7E8A5179-F94C-410F-8BBE-FDAAA95A19C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7E8A5179-F94C-410F-8BBE-FDAAA95A19C3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7E8A5179-F94C-410F-8BBE-FDAAA95A19C3}.Release|Any CPU.Build.0 = Release|Any CPU
{744BE74F-8C4A-49E8-9683-52D987224285}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{744BE74F-8C4A-49E8-9683-52D987224285}.Debug|Any CPU.Build.0 = Debug|Any CPU
{744BE74F-8C4A-49E8-9683-52D987224285}.Release|Any CPU.ActiveCfg = Release|Any CPU
{744BE74F-8C4A-49E8-9683-52D987224285}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -75,6 +81,7 @@ Global
{EB7D0834-4236-408F-B172-64FB45FF643A} = {9E154A29-1796-4B85-BD81-B6A385D8FF71}
{6638957D-09ED-47C1-86B9-5D2DFD0FE625} = {9E154A29-1796-4B85-BD81-B6A385D8FF71}
{7E8A5179-F94C-410F-8BBE-FDAAA95A19C3} = {36CCE840-6FE5-4DB9-A8D5-8CF3CB6D342A}
{744BE74F-8C4A-49E8-9683-52D987224285} = {36CCE840-6FE5-4DB9-A8D5-8CF3CB6D342A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E3944F6A-384B-4B0F-B93F-3BD513DC57BD}
Expand Down
1 change: 0 additions & 1 deletion test/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory)../, Directory.Build.props))\Directory.Build.props" Condition=" '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory)../, Directory.Build.props))' != '' " />

<PropertyGroup>
<TargetFrameworks>net5.0;netcoreapp3.1;net472</TargetFrameworks>
<IsPackable>false</IsPackable>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<Import Project="..\..\src\Microsoft.Windows.CsWin32\build\Microsoft.Windows.CsWin32.props" />

<PropertyGroup>
<TargetFrameworks>net5.0;netcoreapp3.1;net472</TargetFrameworks>
<RootNamespace />
</PropertyGroup>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net5.0;netcoreapp3.1;net472</TargetFrameworks>
<RootNamespace />
</PropertyGroup>

Expand Down
7 changes: 7 additions & 0 deletions test/SpellChecker/NativeMethods.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CoCreateInstance
CoTaskMemFree
SpellCheckerFactory
ISpellCheckerFactory
ISpellChecker
CLSCTX
S_FALSE
31 changes: 31 additions & 0 deletions test/SpellChecker/PInvoke.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace Microsoft.Windows.Sdk
{
using System;
using System.Runtime.InteropServices;

internal partial class PInvoke
{
/// <inheritdoc cref="CoCreateInstance(System.Guid*, IUnknown*, uint, System.Guid*, void**)"/>
/// <seealso href="https://github.com/microsoft/CsWin32/issues/103" />
internal static unsafe HRESULT CoCreateInstance<T>(in System.Guid rclsid, IUnknown* pUnkOuter, uint dwClsContext, in System.Guid riid, out T* ppv)
where T : unmanaged
{
HRESULT hr = CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, out void* o);
ppv = (T*)o;
return hr;
}

/// <inheritdoc cref="Marshal.ThrowExceptionForHR(int, IntPtr)" />
/// <returns>The value from <paramref name="errorCode"/> if it does not reflect an error.</returns>
/// <seealso cref="Marshal.ThrowExceptionForHR(int, IntPtr)"/>
/// <seealso href="https://github.com/microsoft/CsWin32/issues/119" />
internal static HRESULT ThrowOnFailure(this HRESULT errorCode, IntPtr errorInfo = default)
{
Marshal.ThrowExceptionForHR(errorCode, errorInfo);
return errorCode;
}
}
}
98 changes: 98 additions & 0 deletions test/SpellChecker/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using Microsoft.Windows.Sdk;
using static Microsoft.Windows.Sdk.Constants;
using static Microsoft.Windows.Sdk.PInvoke;

unsafe
{
CoCreateInstance(
typeof(SpellCheckerFactory).GUID,
null,
(uint)CLSCTX.CLSCTX_INPROC_SERVER, // https://github.com/microsoft/win32metadata/issues/185
typeof(ISpellCheckerFactory).GUID,
out ISpellCheckerFactory* spellCheckerFactory).ThrowOnFailure();

spellCheckerFactory->IsSupported(
"en-US",
out bool supported).ThrowOnFailure();

if (!supported)
{
return;
}

spellCheckerFactory->CreateSpellChecker(
"en-US",
out ISpellChecker* spellChecker).ThrowOnFailure();

var text = @"""Cann I I haev some?""";

Console.WriteLine(@"Check {0}", text);

spellChecker->Check(
text,
out IEnumSpellingError* errors).ThrowOnFailure();

while (true)
{
if (errors->Next(out ISpellingError* error).ThrowOnFailure() == S_FALSE)
{
break;
}

error->get_StartIndex(out uint startIndex).ThrowOnFailure();
error->get_Length(out uint length).ThrowOnFailure();

var word = text.Substring((int)startIndex, (int)length);

error->get_CorrectiveAction(out CORRECTIVE_ACTION action).ThrowOnFailure();

switch (action)
{
case CORRECTIVE_ACTION.CORRECTIVE_ACTION_DELETE:
Console.WriteLine(@"Delete ""{0}""", word);
break;
case CORRECTIVE_ACTION.CORRECTIVE_ACTION_REPLACE:
// KNOWN ISSUE: ushort will be changed to string (https://github.com/microsoft/CsWin32/issues/121)
error->get_Replacement(out ushort* replacement).ThrowOnFailure();
Console.WriteLine(@"Replace ""{0}"" with ""{1}""", word, new string((char*)replacement));
CoTaskMemFree(replacement);
break;
case CORRECTIVE_ACTION.CORRECTIVE_ACTION_GET_SUGGESTIONS:
var l = new List<string>();
spellChecker->Suggest(word, out IEnumString* suggestions).ThrowOnFailure();
while (true)
{
// KNOWN ISSUE: ushort will be changed to string (https://github.com/microsoft/CsWin32/issues/121)
ushort* suggestion;
if (suggestions->Next(1, &suggestion, null).ThrowOnFailure() != 0)
{
break;
}

l.Add(new string((char*)suggestion));
CoTaskMemFree(suggestion);
}

suggestions->Release();
Console.WriteLine(@"Suggest replacing ""{0}"" with:", word);
foreach (var s in l)
{
Console.WriteLine("\t{0}", s);
}

break;
default:
break;
}

error->Release();
}

errors->Release();
spellChecker->Release();
}
21 changes: 21 additions & 0 deletions test/SpellChecker/SpellChecker.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\src\Microsoft.Windows.CsWin32\build\Microsoft.Windows.CsWin32.props" />

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.Windows.CsWin32\Microsoft.Windows.CsWin32.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<Analyzer Include="$(RepoRootPath)\bin\Microsoft.Windows.CsWin32\$(Configuration)\netstandard2.0\System.Text.Json.dll" />
<Analyzer Include="$(RepoRootPath)\bin\Microsoft.Windows.CsWin32\$(Configuration)\netstandard2.0\Microsoft.Bcl.AsyncInterfaces.dll" />
<Analyzer Include="$(RepoRootPath)\bin\Microsoft.Windows.CsWin32\$(Configuration)\netstandard2.0\System.Text.Encodings.Web.dll" />
<Analyzer Include="$(RepoRootPath)\bin\Microsoft.Windows.CsWin32\$(Configuration)\netstandard2.0\YamlDotNet.dll" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Windows.SDK.Win32Metadata" Version="$(MetadataVersion)" GeneratePathProperty="true" PrivateAssets="none" />
<PackageReference Include="System.Memory" Version="4.5.4" />
</ItemGroup>

</Project>

0 comments on commit 0ee8941

Please sign in to comment.