add speech2 stuff

This commit is contained in:
Lily Tsuru 2024-07-17 21:38:27 -04:00
parent fe9a8af8c2
commit 20f59c5663
51 changed files with 55999 additions and 436 deletions

44
.clang-format Executable file
View file

@ -0,0 +1,44 @@
BasedOnStyle: Google
# force T* or T&
DerivePointerAlignment: false
PointerAlignment: Left
TabWidth: 4
IndentWidth: 4
UseTab: Always
IndentPPDirectives: BeforeHash
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortFunctionsOnASingleLine: InlineOnly
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: true
BinPackArguments: true
BinPackParameters: true
BreakConstructorInitializers: BeforeColon
BreakStringLiterals: false
ColumnLimit: 150
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ContinuationIndentWidth: 0
# turning this on causes major issues with initializer lists
Cpp11BracedListStyle: false
SpaceBeforeCpp11BracedList: true
FixNamespaceComments: true
NamespaceIndentation: All
ReflowComments: true
SortIncludes: CaseInsensitive
SortUsingDeclarations: true
SpacesInSquareBrackets: false
SpaceBeforeParens: Never
SpacesBeforeTrailingComments: 1

11
.editorconfig Normal file
View file

@ -0,0 +1,11 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
indent_style = tab
indent_size = 4
# specifically for YAML
[{yml, yaml}]
indent_style = space

368
.gitignore vendored
View file

@ -1,363 +1,7 @@
## Ignore Visual Studio temporary files, build results, and # ccls/clangd
## files generated by popular Visual Studio add-ons. .cache/
## **/bin/
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore **/obj/
# User-specific files # on your own machine, please.
*.rsuser /speech2/compile_commands.json
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Oo]ut/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd

7
Justfile Normal file
View file

@ -0,0 +1,7 @@
build:
dotnet build
make -C speech2 -j$(nproc)
clean:
rm -rf SAPIServer/bin SAPIServer/obj
make -C speech2 clean

View file

@ -2,6 +2,14 @@
Simple HTTP frontend API for Microsoft Speech API Simple HTTP frontend API for Microsoft Speech API
## Building
Requirements
- .NET SDK
- mingw-w64 toolchain built with `win32` thread model (`pthread` won't work)
`just` should do the trick.
## Running ## Running
``` ```
@ -27,4 +35,4 @@ Content-Type: application/json
{"text":"Lorem ipsum doler sit amet...","voice":"Microsoft Sam"} {"text":"Lorem ipsum doler sit amet...","voice":"Microsoft Sam"}
``` ```
Returns synthesized TTS audio as a wave-form file. Returns synthesized TTS audio as a wave-form file.

View file

@ -1,58 +1,15 @@
<?xml version="1.0" encoding="utf-8"?> <Project Sdk="Microsoft.NET.Sdk">
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <!-- Older VS generated one for us; we're just using that one.
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> Unless we wanna use the generated one?? -->
<ProjectGuid>{BF824074-4C4E-4DE1-8DCA-F022682B00E1}</ProjectGuid> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<RootNamespace>SAPIServer</RootNamespace> <TargetFrameworks>net40</TargetFrameworks>
<AssemblyName>SAPIServer</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget> <ItemGroup>
<DebugSymbols>true</DebugSymbols> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net40\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Speech" /> <Reference Include="System.Speech" />
@ -62,23 +19,5 @@
<Reference Include="System.Data" /> <Reference Include="System.Data" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Compile Include="HTTPServer.cs" /> </Project>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SynthesizePayload.cs" />
<Compile Include="VoicesResponse.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.manifest" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View file

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{BF824074-4C4E-4DE1-8DCA-F022682B00E1}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>SAPIServer</RootNamespace>
<AssemblyName>SAPIServer</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net40\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Speech" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="HTTPServer.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SynthesizePayload.cs" />
<Compile Include="VoicesResponse.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.manifest" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

36
speech2/Makefile Normal file
View file

@ -0,0 +1,36 @@
include build/arch.mk
include build/configs.mk
NAME = sapiserver
BINDIR = bin/$(ARCH)/$(CONFIG)
OBJDIR = obj/$(ARCH)/$(CONFIG)
# Any C++ file in src/ is automatically picked up.
CXXSRCS = $(wildcard src/*.cpp) $(wildcard src/*/*.cpp)
VPATH = $(dir $(CXXSRCS))
OBJS = $(addprefix $(OBJDIR)/,$(notdir $(CXXSRCS:.cpp=.o)))
.PHONY: all dumpinfo clean matrix
all: $(BINDIR)/$(NAME).exe
# dir rules
$(BINDIR)/:
echo -e "\e[95mMKDIR $@\e[0m"
mkdir -p $(BINDIR)
$(OBJDIR)/:
echo -e "\e[95mMKDIR $@\e[0m"
mkdir -p $(OBJDIR)
include build/rules.mk
clean:
echo -e "\e[91mCleaning... \e[0m"
rm -rf $(BINDIR)/ $(OBJS)
$V.SILENT:
# Include dependency files.
-include $(OBJS:.o=.d)

3
speech2/README.md Normal file
View file

@ -0,0 +1,3 @@
# speech2
speech dll thing

19
speech2/build/arch.mk Normal file
View file

@ -0,0 +1,19 @@
x86_Valid=yes
x86_TRIPLET=i686-w64-mingw32
#x64_Valid=yes
#x64_TRIPLET=x86_64-w64-mingw32
ifeq ($(ARCH),)
ARCH = x86
endif
ifneq ($($(ARCH)_Valid),yes)
$(error Please select a valid target)
endif
# if we really need C
CC = $($(ARCH)_TRIPLET)-gcc
CXX = $($(ARCH)_TRIPLET)-g++
WINDRES = $($(ARCH)_TRIPLET)-windres

23
speech2/build/configs.mk Normal file
View file

@ -0,0 +1,23 @@
# Base compiler flags. Only change if you *explicitly* know what you're doing.
BASE_CCFLAGS = -MMD -std=gnu17 -fpermissive -fno-pic -fno-pie -msse -Iinclude -Isrc -D_UCRT -D_WIN32_WINNT=0x0501
BASE_CXXFLAGS = -MMD -std=c++20 -fpermissive -fno-pic -fno-pie -fno-rtti -msse -Iinclude -Isrc -Ithird_party -D_UCRT -D_WIN32_WINNT=0x0501
BASE_LDFLAGS = -mwindows -static -static-libgcc -lkernel32 -lshell32 -luser32 -luuid -lole32
Release_Valid = yes
Release_CCFLAGS = -O3 -ffast-math -fomit-frame-pointer -DNDEBUG
Release_CXXFLAGS = -O3 -ffast-math -fomit-frame-pointer -DNDEBUG
Release_LDFLAGS = -s
Debug_Valid = yes
Debug_CCFLAGS = -O0 -g -DDEBUG
Debug_CXXFLAGS = -O0 -g -DDEBUG
Debug_LDFLAGS =
# select a default configuration or validate configuration
ifeq ($(CONFIG),)
CONFIG = Release
endif
ifneq ($($(CONFIG)_Valid),yes)
$(error Please select a valid configuration)
endif

20
speech2/build/rules.mk Normal file
View file

@ -0,0 +1,20 @@
# TODO: Link DLL
$(BINDIR)/$(NAME).exe: $(BINDIR)/ $(OBJDIR)/ $(OBJS)
echo -e "\e[92mLinking binary $@\e[0m"
$(CXX) $(OBJS) $(BASE_LDFLAGS) $($(CONFIG)_LDFLAGS) -o $@
$(OBJDIR)/%.o: %.c
echo -e "\e[94mCompiling C source file $< ($@)\e[0m"
$(CC) -c $(BASE_CCFLAGS) $($(CONFIG)_CCFLAGS) $< -o $@
$(OBJDIR)/%.o: %.cpp
echo -e "\e[94mCompiling C++ source file $< ($@)\e[0m"
$(CC) -c $(BASE_CXXFLAGS) $($(CONFIG)_CXXFLAGS) $< -o $@
$(OBJDIR)/%.o: %.S
echo -e "\e[94mAssembling $< ($@)\e[0m"
$(CC) -xassembler-with-cpp -c $(BASE_CCFLAGS) $($(CONFIG)_CCFLAGS) $< -o $@
$(OBJDIR)/%.o: %.rc
echo -e "\e[94mCompiling Windows resource script $<\e[0m"
$(WINDRES) -Iinclude $< -o $@

2
speech2/compdb.sh Executable file
View file

@ -0,0 +1,2 @@
make clean
bear -- make

View file

@ -0,0 +1,156 @@
#include <handleapi.h>
#include <synchapi.h>
#include <windows.h>
#include <base/BThread.hpp>
namespace base::osdep {
enum class MemoryOrder {
Relaxed = __ATOMIC_RELAXED,
Consume = __ATOMIC_CONSUME,
Acquire = __ATOMIC_ACQUIRE,
Release = __ATOMIC_RELEASE,
AcqRel = __ATOMIC_ACQ_REL,
SeqCst = __ATOMIC_SEQ_CST
};
// TODO: public!
template<class T, MemoryOrder DefaultOrder = MemoryOrder::SeqCst>
struct BAtomic {
BAtomic() = default;
BAtomic(const T value) :
value(value) {
}
inline T fetch_add(T val, MemoryOrder order = DefaultOrder) volatile noexcept {
return __atomic_fetch_add(&value, val, static_cast<int>(order));
}
inline T fetch_sub(T val, MemoryOrder order = DefaultOrder) volatile noexcept {
volatile T* ptr = &value;
return __atomic_fetch_sub(ptr, val, static_cast<int>(order));
}
void store(T desiredValue, MemoryOrder order = DefaultOrder) volatile noexcept {
__atomic_store_n(&value, desiredValue, order);
}
T operator++() volatile noexcept {
return fetch_add(1) + 1;
}
T operator++(int) volatile noexcept {
return fetch_add(1);
}
T operator--() volatile noexcept {
return fetch_sub(1) - 1;
}
T operator--(int) volatile noexcept {
return fetch_sub(1);
}
T operator-=(T val) volatile noexcept {
return fetch_sub(val) - val;
}
T operator+=(T val) volatile noexcept{
return fetch_add(val) + val;
}
private:
T value;
};
struct BCondVar {
BCondVar() {
hNotifyAllEvent = CreateEventA(nullptr, TRUE, FALSE, nullptr);
hNotifyOneEvent = CreateEventA(nullptr, FALSE, FALSE, nullptr);
waiterMutex = BMutex_Create(true);
}
~BCondVar() {
if(hNotifyAllEvent != INVALID_HANDLE_VALUE)
CloseHandle(hNotifyAllEvent);
if(hNotifyOneEvent != INVALID_HANDLE_VALUE)
CloseHandle(hNotifyOneEvent);
BMutex_Destroy(waiterMutex);
}
void SignalOne() {
SetEvent(hNotifyOneEvent);
}
void SignalAll() {
SetEvent(hNotifyAllEvent);
}
void Wait(bool(*predicate)(void* ctx), void* ctx) {
HANDLE handles[2] = { hNotifyAllEvent, hNotifyOneEvent };
BMutex_Lock(waiterMutex);
waiterSemaphore++;
BMutex_Unlock(waiterMutex);
while(!predicate(ctx)) {
switch(WaitForMultipleObjects(2, &handles[0], FALSE, INFINITE)) {
case WAIT_OBJECT_0: // hNotifyAllEvent
BMutex_Lock(waiterMutex);
if(waiterSemaphore-- == 0) {
ResetEvent(hNotifyAllEvent);
}
BMutex_Unlock(waiterMutex);
break;
case WAIT_OBJECT_0 + 1: // hNotifyOneEvent
continue;
break;
case WAIT_FAILED:
return;
break;
default:
return;
break;
}
}
}
HANDLE hNotifyAllEvent{};
HANDLE hNotifyOneEvent{};
// Semaphore for SignalAll().
BMutex* waiterMutex;
BAtomic<int> waiterSemaphore{0};
};
BCondVar* BCondVar_Create() {
return new BCondVar();
}
/// Signals one thread.
void BCondVar_SignalOne(BCondVar* cond) {
cond->SignalOne();
}
// Signals all threads.
void BCondVar_SignalAll(BCondVar* cond) {
cond->SignalAll();
}
// Waits. Call this on all threads.
void BCondVar_Wait(BCondVar* condvar, bool(*predicate)(void* ctx), void* ctx) {
condvar->Wait(predicate, ctx);
}
void BCondVar_Destroy(BCondVar* condvar) {
delete condvar;
}
}

View file

@ -0,0 +1,53 @@
#include <base/BThread.hpp>
#include <cassert>
namespace base::osdep {
struct BMutex {
CRITICAL_SECTION critSec {};
bool recursive{};
BMutex(bool recursive = false) : recursive(recursive) { InitializeCriticalSection(&critSec); }
~BMutex() {
if(critSec.LockCount != 0)
Unlock();
DeleteCriticalSection(&critSec);
}
inline void Lock() {
// recursive lock check
if(!recursive) {
if(critSec.LockCount + 1 > 1) {
ExitProcess(0x69420);
return;
}
}
EnterCriticalSection(&critSec);
}
inline void Unlock() { LeaveCriticalSection(&critSec); }
};
BMutex* BMutex_Create(bool recursive) {
return new BMutex(recursive);
}
void BMutex_Destroy(BMutex* mutex) {
delete mutex;
}
void BMutex_Lock(BMutex* mutex) {
if(mutex)
mutex->Lock();
}
void BMutex_Unlock(BMutex* mutex) {
if(mutex)
mutex->Unlock();
}
} // namespace base::osdep

View file

@ -0,0 +1,38 @@
#include <process.h>
#include <base/BThread.hpp>
namespace base::osdep {
struct BThread {
HANDLE hThread;
unsigned dwId;
};
BThreadHandle BThread_Spawn(BThreadFunc ep, void* arg, unsigned stackSize) {
unsigned dwID{};
auto res = _beginthreadex(nullptr, stackSize, static_cast<_beginthreadex_proc_type>(ep), arg, 0, &dwID);
if(res == -1)
return nullptr;
auto handle = new BThread();
handle->hThread = reinterpret_cast<HANDLE>(res);
handle->dwId = dwID;
return handle;
}
unsigned BThread_GetID(BThreadHandle handle) {
if(handle)
return handle->dwId;
return -1;
}
void BThread_Join(BThreadHandle handle) {
if(handle) {
auto res = WaitForSingleObject(handle->hThread, INFINITE);
return;
}
}
} // namespace base::osdep

View file

@ -0,0 +1,64 @@
// BThread - it's like GThread, but mentally sane!
// (and without __, pthreads, and other smells.)
#pragma once
#ifdef _WIN32
#include <base/SaneWin.hpp>
#else
#error BThread only supports Windows.
#endif
namespace base::osdep {
// Threads
struct BThread;
using BThreadHandle = BThread*;
#ifdef _WIN32
using BThreadNativeHandle = HANDLE;
#endif
using BThreadFunc =
unsigned WINAPI (*)(void* argp);
// Spawns a new thread, with the given entry point, argument, and stack size.
BThreadHandle BThread_Spawn(BThreadFunc ep, void* arg = nullptr, unsigned stackSize = 0);
// TODO BThread_Native(BThreadHandle handle)
unsigned BThread_GetID(BThreadHandle handle);
// Joins (waits for this thread to terminate) this thread.
void BThread_Join(BThreadHandle handle);
// Mutexes
struct BMutex;
// if recursive is true, this BMutex will be a recursive mutex,
// and multiple threads are allowed to lock it.
BMutex* BMutex_Create(bool recursive);
void BMutex_Lock(BMutex* mutex);
void BMutex_Unlock(BMutex* mutex);
void BMutex_Destroy(BMutex* mutex);
struct BCondVar;
BCondVar* BCondVar_Create();
/// Signals one thread.
void BCondVar_SignalOne(BCondVar* cond);
// Signals all threads.
void BCondVar_SignalAll(BCondVar* cond);
// Waits. Call this on all threads.
void BCondVar_Wait(BCondVar* condvar, bool(*predicate)(void* ctx), void* ctx);
void BCondVar_Destroy(BCondVar* condvar);
}

View file

@ -0,0 +1,21 @@
#include <base/Mutex.hpp>
namespace base {
Mutex::Mutex() {
mutex = osdep::BMutex_Create(false);
}
Mutex::~Mutex() {
osdep::BMutex_Destroy(mutex);
}
void Mutex::Lock() {
osdep::BMutex_Lock(mutex);
}
void Mutex::Unlock() {
osdep::BMutex_Unlock(mutex);
}
} // namespace base

View file

@ -0,0 +1,47 @@
#pragma once
#include <base/BThread.hpp>
namespace base {
/**
* A mutex.
*/
struct Mutex {
Mutex();
~Mutex();
Mutex(const Mutex&) = delete;
Mutex(Mutex&&) = default;
void Lock();
void Unlock();
// impl data.
private:
osdep::BMutex* mutex;
};
template <typename T>
concept Lockable = requires(T t) {
{ t.Lock() };
{ t.Unlock() };
};
/**
* Scoped lock guard.
*/
template<Lockable Mut>
struct LockGuard {
LockGuard(Mut& mtx)
: mutex(mtx) {
mutex.Lock();
}
~LockGuard() {
mutex.Unlock();
}
private:
Mut& mutex;
};
}

View file

@ -0,0 +1,10 @@
# base/
This basically contains replacements of stuff from the standard library that we can't use on Windows XP because mingw sucks:
- Mutex
- Thread
- ManualResetEvent
- AutoResetEvent
Oh and some stuff for dealing with COM

View file

@ -0,0 +1,6 @@
// Sane windows.h
#pragma once
#define _WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <commctrl.h>
#undef _WIN32_LEAN_AND_MEAN

View file

@ -0,0 +1,53 @@
#include <base/Thread.hpp>
namespace base {
/*static*/ unsigned Thread::EntryFunc(void* argp) {
auto invocable = static_cast<ThreadInvocable*>(argp);
(*invocable)();
// Usually cross thread frees are a no-no, but the thread effectively
// owns the invocable once it has been passed to it, so /shrug.
delete invocable;
return 0;
}
Thread::~Thread() {
// Join thread on destruction, unless
// it has already been detached.
if(Joinable())
Join();
}
unsigned Thread::Id() const {
return osdep::BThread_GetID(threadHandle);
}
bool Thread::Joinable() const {
if(!threadHandle)
return false;
return joinable;
}
void Thread::Detach() {
threadHandle = nullptr;
joinable = false;
}
void Thread::Join() {
if(Joinable())
osdep::BThread_Join(threadHandle);
}
void Thread::SpawnImpl(ThreadInvocable* pInvocable) {
threadHandle = osdep::BThread_Spawn(&Thread::EntryFunc, static_cast<void*>(pInvocable), 0);
if(threadHandle != nullptr)
joinable = true;
else {
// Thread failed to create, delete the invocable so we don't leak memory.
delete pInvocable;
}
}
}

View file

@ -0,0 +1,70 @@
#pragma once
#include <base/BThread.hpp>
#include <base/SaneWin.hpp>
#include <tuple>
namespace base {
// TODO: Put this in a bits header.
#define __BASE_FWD(T) static_cast<T&&>
/// A thread.
struct Thread {
using NativeHandle = osdep::BThreadHandle;
Thread() = default;
template <class Func, class... Args>
explicit Thread(Func&& func, Args&&... args) {
struct FuncInvocable final : ThreadInvocable {
Func&& func;
std::tuple<Args&&...> args;
constexpr FuncInvocable(Func&& func, Args&&... args) : func(__BASE_FWD(Func)(func)), args({ __BASE_FWD(Args)(args)... }) {}
constexpr void operator()() override {
std::apply([&](auto&&... argt) { func(__BASE_FWD(Args)(argt)...); }, args);
}
};
SpawnImpl(new FuncInvocable(__BASE_FWD(Func)(func), __BASE_FWD(Args)(args)...));
}
Thread(const Thread&) = delete;
Thread(Thread&&) = default;
~Thread();
// TODO: Actually return a OS native thread handle, instead of a BThreads handle.
NativeHandle Native() const { return threadHandle; }
unsigned Id() const;
bool Joinable() const;
// Detaches the native thread.
// Once this function is called the thread
// will no longer be joinable.
void Detach();
void Join();
private:
// For type erasure. I know it's bad or whatever, but generally,
// it shouldn't be a big enough deal.
struct ThreadInvocable {
virtual ~ThreadInvocable() = default;
virtual void operator()() = 0;
};
// Takes the invocable and spawns le epic heckin thread.
void SpawnImpl(ThreadInvocable* pInvocable);
// Actually recieves a pointer to a [ThreadInvocable] on the heap,
// synthesized from a given function.
static unsigned WINAPI EntryFunc(void* args);
NativeHandle threadHandle {};
bool joinable { false }; // implicitly false if there's no thread.
};
} // namespace base

View file

@ -0,0 +1,71 @@
#pragma once
#include <base/SaneWin.hpp>
#include <stdio.h>
namespace base {
// A relatively sane (non-intrinsic) COM smart pointer
// TODO: Allow downcasting to ComPtr<IUnknown, IID_IUnknown> (all COM objects implement this anyways)
//
template <class T = IUnknown, const IID* iid = &IID_IUnknown>
struct ComPtr {
//constexpr ComPtr() = default;
//explicit ComPtr(T* t) : interface_ptr(t) {}
constexpr ComPtr() : interface_ptr(nullptr) {}
// Assignment won't require AddRef() because most COM interfaces
// will automatically AddRef() upon querying them.
ComPtr& operator=(T* interface_) {
// Release an existing interface.
if(interface_ptr) {
printf("ComPtr<T>::operator= releasing %p (guid %08x)\n", interface_ptr, *iid);
interface_ptr->Release();
}
interface_ptr = interface_;
return *this;
}
ComPtr(const ComPtr& copy) {
if(interface_ptr) {
interface_ptr->AddRef();
interface_ptr = copy.interface_ptr;
}
}
~ComPtr() {
if(interface_ptr) {
printf("ComPtr<T>::~ComPtr releasing %p (guid %08x)\n", interface_ptr, *iid);
interface_ptr->Release();
}
}
// Helper to CoCreateInstance() on this pointer
HRESULT CreateInstance(REFCLSID clsid, DWORD ctx) {
return CoCreateInstance(clsid, nullptr, CLSCTX_ALL, *iid, reinterpret_cast<void**>(&interface_ptr));
}
// smart pointer overrides
constexpr T** operator&() { return &interface_ptr; }
constexpr T* operator->() { return interface_ptr; }
constexpr operator T*() const { return interface_ptr; }
T* Get() { return interface_ptr; }
const T* Get() const { return interface_ptr; }
// release pointer - you need to manage it yourself or put it
// into another ComSmartPtr then
T* ReleasePtr() {
auto old = interface_ptr;
interface_ptr = nullptr;
return old;
}
private:
T* interface_ptr { nullptr };
};
} // namespace base

View file

@ -0,0 +1,17 @@
#pragma once
#include <variant>
#include <windows.h>
template<class T>
struct ComResult {
private:
using VariantType = std::variant<
HRESULT,
T
>;
VariantType storage;
};

120
speech2/src/main.cpp Normal file
View file

@ -0,0 +1,120 @@
#include <stdio.h>
#include <winscard.h>
#include <base/BThread.hpp>
#include <base/Mutex.hpp>
#include <base/Thread.hpp>
#include "speechapi.hpp"
// args
// -v <voice> (voice to use)
// -s 4|5 (what SAPI version to use)
// -p 0..100 (pitch)
// -s 0..100
// [message]
int main(int argc, char** argv) {
#if 1
if(FAILED(CoInitialize(nullptr))) {
printf("Couldn't initalize COM\n");
return 1;
}
auto api = ISpeechAPI::CreateSapi4();
if(!api) {
printf("Couldn't allocate memory for speech API\n");
return 1;
}
if(auto hRes = api->Initialize(); FAILED(hRes)) {
printf("Couldn't initalize SAPI 4 (hr: %08x)\n", hRes);
return 1;
}
#if 1
auto voices = api->GetVoices();
printf("Available voices:\n");
for(auto& voice : voices) {
auto& guid = voice.guid;
printf("%s (GUID {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X})\n", voice.voiceName.c_str(), guid.Data1, guid.Data2, guid.Data3,
guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
}
#endif
if(auto hRes = api->SelectVoice("Sam"); FAILED(hRes)) {
printf("Test: Couldn't select Microsoft Sam\n");
return 1;
} else {
printf("Test: Selected Microsoft Sam\n");
}
#if 1
if(auto hRes = api->SelectVoice("Mike"); FAILED(hRes)) {
printf("Test: Couldn't select Microsoft Mike\n");
return 1;
} else {
printf("Test: Seleced Microsoft Mike\n");
}
#endif
printf("Test: Selected voices successfully\n");
printf("Test: Destroying voice\n");
delete api;
CoUninitialize();
#endif
// condvar/threading tests
#if 0
static auto cv = base::osdep::BCondVar_Create();
static auto PrintMutex = base::Mutex{};
static auto n = 0;
//auto n = 0;
Sleep(100);
base::Thread t([]() {
base::osdep::BCondVar_Wait(cv, [](void* ctx) {
base::LockGuard lk(PrintMutex);
printf("t: wait predicate called %d\n", *static_cast<int*>(ctx));
return *static_cast<int*>(ctx) == 4;
}, static_cast<void*>(&n));
{
base::LockGuard lk(PrintMutex);
printf("t: condvar exited wait!\n");
}
});
base::Thread t2([]() {
base::osdep::BCondVar_Wait(cv, [](void* ctx) {
base::LockGuard lk(PrintMutex);
printf("t2: wait predicate called %d\n", *static_cast<int*>(ctx));
return *static_cast<int*>(ctx) == 4;
}, static_cast<void*>(&n));
{
base::LockGuard lk(PrintMutex);
printf("t2: condvar exited wait!\n");
}
});
for(auto i = 0; i < 4; ++i) {
base::osdep::BCondVar_SignalOne(cv);
n++;
Sleep(100);
}
t2.Join();
t.Join();
base::osdep::BCondVar_Destroy(cv);
#endif
return 0;
}

View file

@ -0,0 +1,84 @@
#include <stdio.h>
#include <base/comptr.hpp>
#include "sapi4/audio_buffer.hpp"
#include "sapi4/include/speech.h"
#include "speechapi.hpp"
struct SpeechAPI_SAPI4 : public ISpeechAPI {
virtual ~SpeechAPI_SAPI4() {
printf("~SpeechAPI_SAPI4\n");
// if(pAudioOut)
// pAudioOut->AddRef();
if(pCentral)
pCentral->Release();
};
HRESULT Initialize() override {
HRESULT hRes;
hRes = pEnum.CreateInstance(CLSID_TTSEnumerator, CLSCTX_INPROC);
if(FAILED(hRes))
return hRes;
return S_OK;
}
std::vector<VoiceInfo> GetVoices() override {
TTSMODEINFO found {};
std::vector<VoiceInfo> ret;
while(!pEnum->Next(1, &found, nullptr)) {
ret.push_back({ .guid = found.gModeID, .voiceName = found.szModeName });
}
pEnum->Reset();
return ret;
}
HRESULT SelectVoiceImpl(const GUID& guid) {
pAudioOut = new AudioOutBuffer();
if(pCentral)
pCentral->Release();
ITTSCentral* central;
if(auto hr = pEnum->Select(guid, &central, static_cast<IUnknown*>(pAudioOut)); FAILED(hr))
return hr;
pCentral = central;
// From Microsoft Speech SDK 4.0 documentation:
// The engine will AddRef the interface, and release the interface when the engine is destroyed.
// Because of this the application will need to call Release on the audio object after the select call or audio objects will be leaked.
pAudioOut->Release();
return S_OK;
}
HRESULT SelectVoice(std::string_view voiceName) override {
TTSMODEINFO found {};
while(!pEnum->Next(1, &found, nullptr)) {
if(voiceName == found.szModeName) {
return SelectVoiceImpl(found.gModeID);
}
}
pEnum->Reset();
return S_OK;
}
private:
base::ComPtr<ITTSEnum, &IID_ITTSEnum> pEnum;
ITTSCentral* pCentral { nullptr };
// The above comment is also why this isn't a ComPtr.
AudioOutBuffer* pAudioOut { nullptr };
};
ISpeechAPI* ISpeechAPI::CreateSapi4() {
return new SpeechAPI_SAPI4();
}

View file

@ -0,0 +1,185 @@
#include "audio_buffer.hpp"
#include <stdio.h>
#include <winerror.h>
// Implements IAudioDest.
struct AudioOutBuffer::Dest : public IAudioDest {
Dest(AudioOutBuffer* pOut) : pOut(pOut) {}
~Dest() = default;
// IUnknown
STDMETHODIMP QueryInterface(const IID& riid, LPVOID* ppvObj) noexcept override { return pOut->QueryInterface(riid, ppvObj); }
STDMETHODIMP_(ULONG) AddRef() noexcept override {
m_iRefCount++;
return pOut->AddRef();
}
STDMETHODIMP_(ULONG) Release() noexcept override {
m_iRefCount--;
return pOut->Release();
}
// IAudioDest
STDMETHODIMP FreeSpace(DWORD* pFree, BOOL* pEOF) noexcept override { return E_NOTIMPL; }
STDMETHODIMP DataSet(PVOID pBuffer, DWORD dwSize) noexcept override {
// TODO
printf("AudioOutBuffer::Dest::DataSet()\n");
return E_NOTIMPL;
}
STDMETHODIMP BookMark(DWORD pos) noexcept override {
// Ignored
return S_OK;
}
private:
AudioOutBuffer* pOut;
ULONG m_iRefCount{};
};
// Implements IAudio.
struct AudioOutBuffer::Audio : public IAudio {
Audio(AudioOutBuffer* pOut) : pOut(pOut) {}
~Audio() {
};
// IUnknown
STDMETHODIMP QueryInterface(const IID& riid, LPVOID* ppvObj) noexcept override { return pOut->QueryInterface(riid, ppvObj); }
STDMETHODIMP_(ULONG) AddRef() noexcept override {
m_iRefCount++;
return pOut->AddRef();
}
STDMETHODIMP_(ULONG) Release() noexcept override {
m_iRefCount--;
return pOut->Release();
}
// IAudio
STDMETHODIMP Flush() noexcept override { return S_OK; }
STDMETHODIMP LevelGet(DWORD* pLevel) noexcept override { return E_NOTIMPL; }
STDMETHODIMP LevelSet(DWORD level) noexcept override { return E_NOTIMPL; }
STDMETHODIMP PassNotify(PVOID pSink, IID iid) noexcept override {
printf("AudioOutBuffer::Audio::PassNotify() %p\n", pSink);
if(pSink == nullptr) {
return E_INVALIDARG;
}
if(iid != IID_IAudioDestNotifySink)
return AUDERR_INVALIDNOTIFYSINK;
pOut->m_pDestNotifySink = static_cast<IAudioDestNotifySink*>(pSink);
return S_OK;
}
STDMETHODIMP PosnGet(PQWORD pos) noexcept override {
if(!pos)
return E_POINTER;
*pos = pOut->m_BufferWritten;
return S_OK;
}
STDMETHODIMP Claim() noexcept override { return S_OK; }
STDMETHODIMP UnClaim() noexcept override { return S_OK; }
STDMETHODIMP Start() noexcept override {
// TODO
return S_OK;
}
STDMETHODIMP Stop() noexcept override {
// TODO
return S_OK;
}
STDMETHODIMP TotalGet(PQWORD total) noexcept override { return PosnGet(total); }
STDMETHODIMP ToFileTime(PQWORD time, FILETIME* out) noexcept override { return E_NOTIMPL; }
STDMETHODIMP WaveFormatGet(SDATA* pOut) noexcept override {
// TODO
//IMalloc* pMalloc { nullptr };
//if(auto hr = CoGetMalloc(1, &pMalloc); FAILED(hr))
// return hr;
return S_OK;
}
STDMETHODIMP WaveFormatSet(SDATA data) noexcept override {
if(!data.pData)
return E_INVALIDARG;
return S_OK;
}
private:
AudioOutBuffer* pOut;
ULONG m_iRefCount{};
};
AudioOutBuffer::AudioOutBuffer() {
printf("AudioOutBuffer() %p\n", this);
m_Audio = new AudioOutBuffer::Audio(this);
m_AudioDestBuffer = new AudioOutBuffer::Dest(this);
}
AudioOutBuffer::~AudioOutBuffer() {
printf("~AudioOutBuffer() %p\n", this);
if(m_AudioDestBuffer)
delete m_AudioDestBuffer;
if(m_Audio)
delete m_Audio;
}
// IUnknown
STDMETHODIMP AudioOutBuffer::QueryInterface(const IID& riid, LPVOID* ppvObj) noexcept {
if(!ppvObj)
return E_NOINTERFACE;
*ppvObj = nullptr;
// This object only directly implements IUnknown, and proxies
// to other implementation objects for other interfaces.
if(riid == IID_IUnknown) {
*ppvObj = static_cast<void*>(this);
AddRef();
return S_OK;
}
// Return implementations
if(riid == IID_IAudio) {
*ppvObj = static_cast<void*>(m_Audio);
//m_Audio->AddRef();
return S_OK;
} else if(riid == IID_IAudioDest) {
*ppvObj = static_cast<void*>(m_AudioDestBuffer);
//m_AudioDestBuffer->AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) AudioOutBuffer::AddRef() {
return InterlockedIncrement(&m_iRefCount);
}
STDMETHODIMP_(ULONG) AudioOutBuffer::Release() {
auto ulRefCount = InterlockedDecrement(&m_iRefCount);
if(ulRefCount == 0) {
printf("Deleting release AudioOutBuffer\n");
delete this;
}
return ulRefCount;
}

View file

@ -0,0 +1,43 @@
#pragma once
#include <windows.h>
#include "base/comptr.hpp"
#include "sapi4/include/speech.h"
// Implementation of SAPI 4 IAudio(Dest) to spit out wave format data to a buffer
// TODO: out-line definition so other components can call methods they need
struct AudioOutBuffer : public IUnknown {
// Implements IAudioDest.
struct Dest;
struct Audio;
AudioOutBuffer();
virtual ~AudioOutBuffer();
AudioOutBuffer(const AudioOutBuffer&) = delete;
AudioOutBuffer(AudioOutBuffer&&) = delete;
// IUnknown
STDMETHODIMP QueryInterface(const IID& riid, LPVOID* ppvObj) noexcept override;
STDMETHODIMP_(ULONG) AddRef() override;
STDMETHODIMP_(ULONG) Release() override;
private:
ULONG m_iRefCount{};
Dest* m_AudioDestBuffer{};
Audio* m_Audio{};
enum class State {
Clear,
WroteHeader,
WritingWaveData,
Done
};
//base::ComPtr<IAudioDestNotifySink, &IID_IAudioDestNotifySink> m_pDestNotifySink{};
IAudioDestNotifySink* m_pDestNotifySink{nullptr};
QWORD m_BufferWritten{};
};

View file

@ -0,0 +1,6 @@
// This file declares all the SAPI 4.0 GUID's.
#include <windows.h>
#include <initguid.h>
#include "sapi4/include/speech.h"

29
speech2/src/speechapi.hpp Normal file
View file

@ -0,0 +1,29 @@
#include <windows.h>
#include <string>
#include <vector>
/// base class for access to text-to-speech APIs.
struct ISpeechAPI {
struct VoiceInfo {
GUID guid{}; // Optional. May not be filled out if th e
std::string voiceName;
};
virtual ~ISpeechAPI() = default;
/// Creates a implementation of SpeechAPI for SAPI 4.
/// COM must be initalized before calling this function.
static ISpeechAPI* CreateSapi4();
/// Performs the bare level of initalization required to use the speech API
virtual HRESULT Initialize() = 0;
virtual std::vector<VoiceInfo> GetVoices() = 0;
/// Selects a voice.
virtual HRESULT SelectVoice(std::string_view voiceName) = 0;
//virtual HRESULT Speak(LPCSTR text, char** pOutputBuffer, size_t* pOutSize) = 0;
};

4
speech2/third_party/README.md vendored Normal file
View file

@ -0,0 +1,4 @@
Files in this directory are the intellectual property of:
- sapi4: Microsoft Speech SDK 4.0.4.2512
- sapi5: Microsoft Speech SDK 5.1

View file

@ -0,0 +1,63 @@
/* buildnum.h*/
#ifndef BUILDNUM_H
#define BUILDNUM_H
/* NOTE: To change build number, change the definitions
* of both BN_BN and BUILD_NUMBER. The rest will use
* the BN_BN definition.
*
* Change log:
*/
#define BN_BN 2512
#define BN_MAJOR 4
#define BN_STR "2512"
#ifndef BUILD_NUMBER
#define BUILD_NUMBER "4.0.4." BN_STR "\0"
#endif
#ifndef JUSTDEFINES
char gszBuildNumber[] = "@(#) Microsoft Speech Build " BUILD_NUMBER;
#endif
#ifndef BN_PRODUCT_VERSION
#define BN_PRODUCT_VERSION 4,0,4,BN_BN
#endif
#ifndef BN_FILE_VER
#define BN_FILE_VERSION BN_PRODUCT_VERSION
#else
#define BN_FILE_VERSION BN_FILE_VER,BN_BN
#endif//BN_FILE_VER
#ifndef BN_FILE_STR
#define BN_FILE_VERSION_STR BUILD_NUMBER
#else
#define BN_FILE_VERSION_STR BN_FILE_STR " " BN_STR "\0"
#endif
#ifndef BN_FLAGS
#ifdef _DEBUG
#define BN_FLAGS VS_FF_DEBUG
#else
#ifdef TEST
#define BN_FLAGS VS_FF_PRERELEASE
#else
#define BN_FLAGS 0
#endif
#endif
#endif
#ifndef BN_FLAGSMASK
#define BN_FLAGSMASK VS_FF_PRERELEASE | VS_FF_DEBUG
#endif//BN_FLAGSMASK
#ifndef BN_PRODUCTNAME
#define BN_PRODUCTNAME "Microsoft Speech\0"
#endif//BN_PRODUCTNAME
#ifndef BN_COPYRIGHT
#define BN_COPYRIGHT "Copyright © 1991-1998 Microsoft Corporation\0"
#endif//BN_COPYRIGHT
#endif // BUILDNUM_H

View file

@ -0,0 +1,69 @@
/* Each RC file that includes this file for version
* stamping, must define the following items:
*
* #define VER_FILE_TYPE VFT_ // VFT_APP, VFT_DLL, VFT_DRV, VFT_VXD
* #define VER_FILE_DESC "Your app name\0" // don't forget the explicit null.
* #define VER_FILE_SUBTYPE 0 // All but driver should be 0
* #define VER_FILE_INTNAME "<module-name>\0" //don't forget the null.
*
* Change Log:
* 8/31/93 - benm - Tweaked to handle internal name correctly.
*/
#ifndef BUILDNUM_RC
#define BUILDNUM_RC
#include <buildnum.h>
#ifndef VS_FF_DEBUG
#include <ver.h>
#endif
// Default internal name to be same as file desc.
#ifndef VER_INTERNAL_NAME
#define VER_INTERNAL_NAME VER_FILE_DESC
#endif
VS_VERSION_INFO VERSIONINFO
FILEVERSION BN_FILE_VERSION
PRODUCTVERSION BN_PRODUCT_VERSION
FILEFLAGSMASK BN_FLAGSMASK
FILEFLAGS BN_FLAGS
FILEOS VOS_NT_WINDOWS32
FILETYPE VER_FILE_TYPE
FILESUBTYPE VER_FILE_SUBTYPE
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
VALUE "CompanyName", "Microsoft Corporation\0"
VALUE "FileDescription", VER_FILE_DESC
VALUE "FileVersion", BN_FILE_VERSION_STR
VALUE "InternalName", VER_INTERNAL_NAME
VALUE "LegalCopyright", BN_COPYRIGHT
VALUE "ProductName", BN_PRODUCTNAME
VALUE "ProductVersion", BUILD_NUMBER
VALUE "OriginalFilename", VER_ORIGINAL_FILENAME
END
BLOCK "040904B0"
BEGIN
VALUE "CompanyName", "Microsoft Corporation\0"
VALUE "FileDescription", VER_FILE_DESC
VALUE "FileVersion", BN_FILE_VERSION_STR
VALUE "InternalName", VER_INTERNAL_NAME
VALUE "LegalCopyright", BN_COPYRIGHT
VALUE "ProductName", BN_PRODUCTNAME
VALUE "ProductVersion", BUILD_NUMBER
VALUE "OriginalFilename", VER_ORIGINAL_FILENAME
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1252
END
END
#endif // BUILDNUM_RC

View file

@ -0,0 +1,313 @@
/*****************************************************************
Spchtel.H - Header file to use the Microsoft Speech telephony controls.
Copyright 1998 by Microsoft corporation.All rights reserved.
*/
#ifndef _SPCHTEL_H_
#define _SPCHTEL_H_
// Flag values for the ITelControl::TypeSet call
#define INFOTYPE_PC 0x00000001
#define INFOTYPE_TAPI20 0x00000002
#define INFOTYPE_TAPI30 0x00000004
// Common return codes from controls
// not usually handled, often returned
#define TCR_ABORT ((DWORD)-1L) // the user has hung up
#define TCR_NORESPONSE ((DWORD)-2L) // the user hasn't repsonded to the questions
#define TCR_ASKOPERATOR ((DWORD)-3L) // the user has asked for an operator (often control just auto replies)
#define TCR_ASKHANGUP ((DWORD)-4L) // the user has asked to hang up. App must handle
#define TCR_ASKBACK ((DWORD)-5L) // the user has asked to go back and redo the previous thing
// usually handled by control, unless overrided
#define TCR_ASKWHERE ((DWORD)-10L) // the user has asked where he/she is (usualy handled by control)
#define TCR_ASKHELP ((DWORD)-11L) // the user has asked for help (usually handled by control)
#define TCR_ASKREPEAT ((DWORD)-12L) // the user has asked for the question to be repeated (usually handled by the control)
#define TCR_ASKSPEAKFASTER ((DWORD)-13L) // the user has asked to speak faster. usually handled by the control
#define TCR_ASKSPEAKSLOWER ((DWORD)-14L) // the user has asked to speak slower. Usually handled by the control
// {F9D18BF8-E0ED-11d0-AB8B-08002BE4E3B7}
DEFINE_GUID (CLSID_TelInfo,
0xf9d18bf8, 0xe0ed, 0x11d0, 0xab, 0x8b, 0x8, 0x0, 0x2b, 0xe4, 0xe3, 0xb7);
/*
* ITelNotifySink
*/
#undef INTERFACE
#define INTERFACE ITelNotifySink
// {CD0C7D7C-E1CD-11d0-AB8B-08002BE4E3B7}
DEFINE_GUID(IID_ITelNotifySink,
0xcd0c7d7c, 0xe1cd, 0x11d0, 0xab, 0x8b, 0x8, 0x0, 0x2b, 0xe4, 0xe3, 0xb7);
DECLARE_INTERFACE_ (ITelNotifySink, IUnknown) {
// IUnkown members
STDMETHOD (QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
STDMETHOD_(ULONG,AddRef) (THIS) PURE;
STDMETHOD_(ULONG,Release) (THIS) PURE;
// ITelNotifySink members
STDMETHOD (DTMF) (THIS_ WCHAR) PURE;
STDMETHOD (Abort) (THIS_ DWORD) PURE;
};
typedef ITelNotifySink FAR *PITELNOTIFYSINK;
/*
* ITelControlNotifySink
*/
#undef INTERFACE
#define INTERFACE ITelControlNotifySink
// {A55E2436-E297-11d0-AB8B-08002BE4E3B7}
DEFINE_GUID(IID_ITelControlNotifySink,
0xa55e2436, 0xe297, 0x11d0, 0xab, 0x8b, 0x8, 0x0, 0x2b, 0xe4, 0xe3, 0xb7);
DECLARE_INTERFACE_ (ITelControlNotifySink, IUnknown) {
// IUnkown members
STDMETHOD (QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
STDMETHOD_(ULONG,AddRef) (THIS) PURE;
STDMETHOD_(ULONG,Release) (THIS) PURE;
// ITelControlNotifySink members
STDMETHOD (Finish) (THIS_ DWORD, PVOID, DWORD) PURE;
STDMETHOD (Info) (THIS_ DWORD, PVOID, DWORD) PURE;
};
typedef ITelControlNotifySink FAR *PITELCONTROLNOTIFYSINK;
/*
* ITelInfo
*/
#undef INTERFACE
#define INTERFACE ITelInfo
// {250F0433-E0EB-11d0-AB8B-08002BE4E3B7}
DEFINE_GUID(IID_ITelInfo,
0x250f0433, 0xe0eb, 0x11d0, 0xab, 0x8b, 0x8, 0x0, 0x2b, 0xe4, 0xe3, 0xb7);
DECLARE_INTERFACE_ (ITelInfo, IUnknown) {
// IUnkown members
STDMETHOD (QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
STDMETHOD_(ULONG,AddRef) (THIS) PURE;
STDMETHOD_(ULONG,Release) (THIS) PURE;
// ITelInfo members
STDMETHOD (ObjectGet) (THIS_ GUID, LPUNKNOWN *) PURE;
STDMETHOD (ObjectSet) (THIS_ GUID, LPUNKNOWN) PURE;
STDMETHOD (DWORDGet) (THIS_ GUID, DWORD *) PURE;
STDMETHOD (DWORDSet) (THIS_ GUID, DWORD) PURE;
STDMETHOD (MemoryGet) (THIS_ GUID, PVOID *, DWORD *) PURE;
STDMETHOD (MemorySet) (THIS_ GUID, PVOID, DWORD) PURE;
STDMETHOD (SendDTMF) (THIS_ WCHAR) PURE;
STDMETHOD (SendAbort) (THIS_ DWORD) PURE;
STDMETHOD (TypeSet) (THIS_ DWORD) PURE;
STDMETHOD (WaveDeviceSet) (THIS_ DWORD, DWORD) PURE;
STDMETHOD (AudioSourceCreate) (THIS_ LPUNKNOWN *) PURE;
STDMETHOD (AudioDestCreate) (THIS_ LPUNKNOWN *) PURE;
STDMETHOD (QuickCreate) (THIS_ HMODULE, PSRMODEINFOW, PTTSMODEINFOW,
PCWSTR, BOOL) PURE;
};
typedef ITelInfo FAR *PITELINFO;
/*
* ITelControl
*/
#undef INTERFACE
#define INTERFACE ITelControl
// {17674DEB-E298-11d0-AB8B-08002BE4E3B7}
DEFINE_GUID(IID_ITelControl,
0x17674deb, 0xe298, 0x11d0, 0xab, 0x8b, 0x8, 0x0, 0x2b, 0xe4, 0xe3, 0xb7);
DECLARE_INTERFACE_ (ITelControl, IUnknown) {
// IUnkown members
STDMETHOD (QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE;
STDMETHOD_(ULONG,AddRef) (THIS) PURE;
STDMETHOD_(ULONG,Release) (THIS) PURE;
// ITelControl members
STDMETHOD (FromMemory) (THIS_ PVOID, DWORD) PURE;
STDMETHOD (FromStream) (THIS_ IStream *) PURE;
#ifdef STRICT
STDMETHOD (FromResource) (THIS_ PVOID, DWORD) PURE;
#else
STDMETHOD (FromResource) (THIS_ HINSTANCE, DWORD) PURE;
#endif
STDMETHOD (FromFile) (THIS_ PCWSTR) PURE;
STDMETHOD (Compile) (THIS_ LPWSTR*, DWORD*) PURE;
STDMETHOD (IsCompiled) (THIS_ BOOL*) PURE;
STDMETHOD (LanguageGet) (THIS_ LANGUAGEW*) PURE;
STDMETHOD (ToMemory) (THIS_ PVOID*, DWORD*) PURE;
STDMETHOD (ToStream) (THIS_ IStream *) PURE;
STDMETHOD (ToFile) (THIS_ PCWSTR) PURE;
STDMETHOD (TextGet) (THIS_ LPWSTR*, DWORD*) PURE;
STDMETHOD (TextDefaultGet) (THIS_ LPWSTR*, DWORD*) PURE;
STDMETHOD (ObjectSet) (THIS_ PITELINFO) PURE;
STDMETHOD (Start) (THIS_ PITELCONTROLNOTIFYSINK) PURE;
STDMETHOD (Abort) (THIS) PURE;
};
typedef ITelControl FAR *PITELCONTROL;
//
// GUID identifiers for objects
//
// {44DB6739-E10E-11d0-AB8B-08002BE4E3B7}
DEFINE_GUID(TELOBJ_SPEECHRECOG,
0x44db6739, 0xe10e, 0x11d0, 0xab, 0x8b, 0x8, 0x0, 0x2b, 0xe4, 0xe3, 0xb7);
// {44DB673B-E10E-11d0-AB8B-08002BE4E3B7}
DEFINE_GUID(TELOBJ_TTSQUEUE,
0x44db673b, 0xe10e, 0x11d0, 0xab, 0x8b, 0x8, 0x0, 0x2b, 0xe4, 0xe3, 0xb7);
// {44DB673C-E10E-11d0-AB8B-08002BE4E3B7}
DEFINE_GUID(TELOBJ_LOGGING,
0x44db673c, 0xe10e, 0x11d0, 0xab, 0x8b, 0x8, 0x0, 0x2b, 0xe4, 0xe3, 0xb7);
// {44DB673D-E10E-11d0-AB8B-08002BE4E3B7}
DEFINE_GUID(TELOBJ_TAPI30,
0x44db673d, 0xe10e, 0x11d0, 0xab, 0x8b, 0x8, 0x0, 0x2b, 0xe4, 0xe3, 0xb7);
// {44DB673E-E10E-11d0-AB8B-08002BE4E3B7}
DEFINE_GUID(TELOBJ_NOTIFYSINK,
0x44db673e, 0xe10e, 0x11d0, 0xab, 0x8b, 0x8, 0x0, 0x2b, 0xe4, 0xe3, 0xb7);
// hcall for TAPI
// {F40CC4C0-0D0A-11d2-BEF0-006008317CE8}
DEFINE_GUID(TELDWORD_HCALL,
0xf40cc4c0, 0xd0a, 0x11d2, 0xbe, 0xf0, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8);
// hline for tapi
// {F40CC4C1-0D0A-11d2-BEF0-006008317CE8}
DEFINE_GUID(TELDWORD_HLINE,
0xf40cc4c1, 0xd0a, 0x11d2, 0xbe, 0xf0, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8);
// If this is set to TRUE, then beeps on a recognition are enabled.
// Disabling speeds up the response time of the system, but some people
// will speak before the beep. It's a tradeoff.
// {DB7F6130-0D2D-11d2-BEF1-006008317CE8}
DEFINE_GUID(TELDWORD_EnableRecognizeBeeps,
0xdb7f6130, 0xd2d, 0x11d2, 0xbe, 0xf1, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8);
// if set to true, and we're using tapi, then we should use tapi
// beeps rather than recordings for recognition acknowledgement
// beeps. This doesn't work properly on most telephony cards, and there's no
// way to tell, so be careful about using it
// {F40CC4C2-0D0A-11d2-BEF0-006008317CE8}
DEFINE_GUID(TELDWORD_UseTAPIBeep,
0xf40cc4c2, 0xd0a, 0x11d2, 0xbe, 0xf0, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8);
// disable the ability for a user to change the speed
// {59596FBE-F936-11d0-8FAD-08002BE4E62A}
DEFINE_GUID(TELDWORD_DisableSpeedChange,
0x59596fbe, 0xf936, 0x11d0, 0x8f, 0xad, 0x8, 0x0, 0x2b, 0xe4, 0xe6, 0x2a);
// enable the ability for the user to ask for an operator
// {59596FBF-F936-11d0-8FAD-08002BE4E62A}
DEFINE_GUID(TELDWORD_EnableOperator,
0x59596fbf, 0xf936, 0x11d0, 0x8f, 0xad, 0x8, 0x0, 0x2b, 0xe4, 0xe6, 0x2a);
// eanble the user to ask to hang up. If TRUE application must handle
// {59596FC0-F936-11d0-8FAD-08002BE4E62A}
DEFINE_GUID(TELDWORD_EnableAskHangUp,
0x59596fc0, 0xf936, 0x11d0, 0x8f, 0xad, 0x8, 0x0, 0x2b, 0xe4, 0xe6, 0x2a);
// if TRUE, then the system supports full duplex
// both full duplex and echo cancelling must be TRUE for telephony controls to have barge in
// {10FEF992-343F-11d1-BE71-006008317CE8}
DEFINE_GUID(TELDWORD_FullDuplex,
0x10fef992, 0x343f, 0x11d1, 0xbe, 0x71, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8);
// if TRUE, then the system has echo cancelling built in.
// both full duplex and echo cancelling must be TRUE for telephony controls to have barge in
// {10FEF991-343F-11d1-BE71-006008317CE8}
DEFINE_GUID(TELDWORD_EchoCancel,
0x10fef991, 0x343f, 0x11d1, 0xbe, 0x71, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8);
/**************************************************************************
Telephon controls in spchtel.dll. */
// {53961A01-459B-11d1-BE77-006008317CE8}
DEFINE_GUID(CLSID_YesNoControl,
0x53961a01, 0x459b, 0x11d1, 0xbe, 0x77, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8);
// {53961A02-459B-11d1-BE77-006008317CE8}
DEFINE_GUID(CLSID_ExtensionControl,
0x53961a02, 0x459b, 0x11d1, 0xbe, 0x77, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8);
// {53961A03-459B-11d1-BE77-006008317CE8}
DEFINE_GUID(CLSID_PhoneNumControl,
0x53961a03, 0x459b, 0x11d1, 0xbe, 0x77, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8);
// {53961A04-459B-11d1-BE77-006008317CE8}
DEFINE_GUID(CLSID_GrammarControl,
0x53961a04, 0x459b, 0x11d1, 0xbe, 0x77, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8);
// {53961A05-459B-11d1-BE77-006008317CE8}
DEFINE_GUID(CLSID_DateControl,
0x53961a05, 0x459b, 0x11d1, 0xbe, 0x77, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8);
// {53961A06-459B-11d1-BE77-006008317CE8}
DEFINE_GUID(CLSID_TimeControl,
0x53961a06, 0x459b, 0x11d1, 0xbe, 0x77, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8);
// {53961A07-459B-11d1-BE77-006008317CE8}
DEFINE_GUID(CLSID_RecordControl,
0x53961a07, 0x459b, 0x11d1, 0xbe, 0x77, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8);
// {53961A08-459B-11d1-BE77-006008317CE8}
DEFINE_GUID(CLSID_SpellingControl,
0x53961a08, 0x459b, 0x11d1, 0xbe, 0x77, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8);
// {53961A09-459B-11d1-BE77-006008317CE8}
DEFINE_GUID(CLSID_NameControl,
0x53961a09, 0x459b, 0x11d1, 0xbe, 0x77, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8);
/**************************************************************************
Sample telephony controls GUIDs. These samples appear in the SDK. */
// {C869F0DE-EF29-11d0-8FAD-08002BE4E62A}
DEFINE_GUID(CLSID_SampleYesNoControl,
0xc869f0de, 0xef29, 0x11d0, 0x8f, 0xad, 0x8, 0x0, 0x2b, 0xe4, 0xe6, 0x2a);
// {9DE44BA9-F94A-11d0-8FAD-08002BE4E62A}
DEFINE_GUID(CLSID_SampleExtensionControl,
0x9de44ba9, 0xf94a, 0x11d0, 0x8f, 0xad, 0x8, 0x0, 0x2b, 0xe4, 0xe6, 0x2a);
// {9DE44BAA-F94A-11d0-8FAD-08002BE4E62A}
DEFINE_GUID(CLSID_SamplePhoneNumControl,
0x9de44baa, 0xf94a, 0x11d0, 0x8f, 0xad, 0x8, 0x0, 0x2b, 0xe4, 0xe6, 0x2a);
// {9DE44BAB-F94A-11d0-8FAD-08002BE4E62A}
DEFINE_GUID(CLSID_SampleGrammarControl,
0x9de44bab, 0xf94a, 0x11d0, 0x8f, 0xad, 0x8, 0x0, 0x2b, 0xe4, 0xe6, 0x2a);
// {9DE44BAC-F94A-11d0-8FAD-08002BE4E62A}
DEFINE_GUID(CLSID_SampleDateControl,
0x9de44bac, 0xf94a, 0x11d0, 0x8f, 0xad, 0x8, 0x0, 0x2b, 0xe4, 0xe6, 0x2a);
// {9DE44BAD-F94A-11d0-8FAD-08002BE4E62A}
DEFINE_GUID(CLSID_SampleTimeControl,
0x9de44bad, 0xf94a, 0x11d0, 0x8f, 0xad, 0x8, 0x0, 0x2b, 0xe4, 0xe6, 0x2a);
// {275931C6-FD27-11d0-8FAE-08002BE4E62A}
DEFINE_GUID(CLSID_SampleRecordControl,
0x275931c6, 0xfd27, 0x11d0, 0x8f, 0xae, 0x8, 0x0, 0x2b, 0xe4, 0xe6, 0x2a);
// {9DE44BAE-F94A-11d0-8FAD-08002BE4E62A}
DEFINE_GUID(CLSID_SampleSpellingControl,
0x9de44bae, 0xf94a, 0x11d0, 0x8f, 0xad, 0x8, 0x0, 0x2b, 0xe4, 0xe6, 0x2a);
// {9DE44BAF-F94A-11d0-8FAD-08002BE4E62A}
DEFINE_GUID(CLSID_SampleNameControl,
0x9de44baf, 0xf94a, 0x11d0, 0x8f, 0xad, 0x8, 0x0, 0x2b, 0xe4, 0xe6, 0x2a);
#endif // _SPCHTEL_H_

File diff suppressed because it is too large Load diff

6635
speech2/third_party/sapi4/include/speech.h vendored Normal file

File diff suppressed because it is too large Load diff

Binary file not shown.

2197
speech2/third_party/sapi5/idl/sapi.idl vendored Normal file

File diff suppressed because it is too large Load diff

4847
speech2/third_party/sapi5/idl/sapiaut.idl vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,818 @@
/****************************************************************************
* sapiddk.idl
*
* This is the interface definition file for the Microsoft Speech API DLL's
* Version 5.0.
*
* It contains definitions for the DDI layer between SAPI.DLL and both
* TTS and SR engines.
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*****************************************************************************/
//--- Includes --------------------------------------------------------------
import "oaidl.idl";
import "ocidl.idl";
import "sapi.idl";
//--- Locally scoped define for LANGID
#ifndef LANGID
#define LANGID WORD
#endif
//--- ITN Processor
interface ISpITNProcessor;
//--- Grammar compiler and dynamic manipulation
interface ISpErrorLog;
interface ISpGrammarCompiler;
interface ISpGramCompBackend;
//--- Phrase builder
interface ISpPhraseBuilder;
//--- Token String Key Names
cpp_quote("#define SPRECOEXTENSION L\"RecoExtension\"")
cpp_quote("#define SPALTERNATESCLSID L\"AlternatesCLSID\"")
//--- ISpTokenUI -----------------------------------------------------------
[
object,
uuid(F8E690F0-39CB-4843-B8D7-C84696E1119D),
helpstring("ISpTokenUI Interface"),
pointer_default(unique),
restricted
]
interface ISpTokenUI : IUnknown
{
[local] HRESULT IsUISupported(
[in] const WCHAR * pszTypeOfUI,
[in] void * pvExtraData,
[in] ULONG cbExtraData,
[in] IUnknown * punkObject,
[out] BOOL *pfSupported);
[local] HRESULT DisplayUI(
[in] HWND hwndParent,
[in] const WCHAR * pszTitle,
[in] const WCHAR * pszTypeOfUI,
[in] void * pvExtraData,
[in] ULONG cbExtraData,
[in] ISpObjectToken * pToken,
[in] IUnknown * punkObject);
};
//--- ISpObjectTokenEnumBuilder ---------------------------------------------
[
object,
uuid(06B64F9F-7FDA-11d2-B4F2-00C04F797396),
helpstring("ISpObjectTokensEnumBuilder Interface"),
pointer_default(unique),
restricted
]
interface ISpObjectTokenEnumBuilder : IEnumSpObjectTokens
{
HRESULT SetAttribs(const WCHAR * pszReqAttribs, const WCHAR * pszOptAttribs);
HRESULT AddTokens(ULONG cTokens, ISpObjectToken ** pToken);
HRESULT AddTokensFromDataKey(ISpDataKey * pDataKey, const WCHAR * pszSubKey, const WCHAR * pszCategoryId);
HRESULT AddTokensFromTokenEnum(IEnumSpObjectTokens * pTokenEnum);
HRESULT Sort(const WCHAR * pszTokenIdToListFirst);
};
//--- Handles for SR grammars and results
cpp_quote("#if 0")
typedef void * SPWORDHANDLE;
typedef void * SPRULEHANDLE;
typedef void * SPGRAMMARHANDLE;
typedef void * SPRECOCONTEXTHANDLE;
typedef void * SPPHRASERULEHANDLE;
typedef void * SPPHRASEPROPERTYHANDLE;
typedef void * SPTRANSITIONID;
cpp_quote("#else")
cpp_quote("DECLARE_HANDLE(SPWORDHANDLE);")
cpp_quote("DECLARE_HANDLE(SPRULEHANDLE);")
cpp_quote("DECLARE_HANDLE(SPGRAMMARHANDLE);")
cpp_quote("DECLARE_HANDLE(SPRECOCONTEXTHANDLE);")
cpp_quote("DECLARE_HANDLE(SPPHRASERULEHANDLE);")
cpp_quote("DECLARE_HANDLE(SPPHRASEPROPERTYHANDLE);")
cpp_quote("DECLARE_HANDLE(SPTRANSITIONID);")
cpp_quote("#endif")
//--- ISpErrorLog -----------------------------------------------------------
// This interface is used to log error information.
[
object,
uuid(F4711347-E608-11d2-A086-00C04F8EF9B5),
helpstring("ISpErrorLog Interface"),
pointer_default(unique),
restricted
]
interface ISpErrorLog : IUnknown
{
HRESULT AddError(
const long lLineNumber,
HRESULT hr,
const WCHAR * pszDescription,
const WCHAR * pszHelpFile,
DWORD dwHelpContext);
};
//--- ISpGrammarCompiler ----------------------------------------------------
[
object,
uuid(B1E29D58-A675-11D2-8302-00C04F8EE6C0),
helpstring("ISpGrammarCompiler Interface"),
pointer_default(unique),
restricted
]
interface ISpGrammarCompiler : IUnknown
{
HRESULT CompileStream(
IStream * pSource,
IStream * pDest,
IStream * pHeader,
IUnknown * pReserved,
ISpErrorLog * pErrorLog,
[in] DWORD dwFlags);
};
[
object,
uuid(3DDCA27C-665C-4786-9F97-8C90C3488B61),
helpstring("ISpGramCompBackend Interface"),
pointer_default(unique),
restricted
]
interface ISpGramCompBackend : ISpGrammarBuilder
{
HRESULT SetSaveObjects(IStream * pStream, ISpErrorLog * pErrorLog);
HRESULT InitFromBinaryGrammar(const SPBINARYGRAMMAR * pBinaryData);
};
//--- ISpITNProcessor ----------------------------------------------------------
[
object,
uuid(12D7360F-A1C9-11d3-BC90-00C04F72DF9F),
helpstring("ISpITNProcessor Interface"),
pointer_default(unique),
local,
restricted
]
interface ISpITNProcessor : IUnknown
{
HRESULT LoadITNGrammar(WCHAR *pszCLSID);
HRESULT ITNPhrase(ISpPhraseBuilder *pPhrase);
};
[
object,
uuid(88A3342A-0BED-4834-922B-88D43173162F),
local,
helpstring("ISpPhraseBuilder Interface"),
pointer_default(unique),
restricted
]
interface ISpPhraseBuilder : ISpPhrase
{
HRESULT InitFromPhrase(const SPPHRASE * pPhrase);
HRESULT InitFromSerializedPhrase(const SPSERIALIZEDPHRASE * pPhrase);
HRESULT AddElements(ULONG cElements, const SPPHRASEELEMENT *pElement);
HRESULT AddRules(const SPPHRASERULEHANDLE hParent, const SPPHRASERULE * pRule, SPPHRASERULEHANDLE * phNewRule);
HRESULT AddProperties(const SPPHRASEPROPERTYHANDLE hParent, const SPPHRASEPROPERTY * pProperty, SPPHRASEPROPERTYHANDLE * phNewProperty);
HRESULT AddReplacements(ULONG cReplacements, const SPPHRASEREPLACEMENT * pReplacements);
};
//--- ISpTask ---------------------------------------------------------------
cpp_quote("#if defined(__cplusplus)")
cpp_quote("interface ISpTask")
cpp_quote("{")
cpp_quote("virtual HRESULT STDMETHODCALLTYPE Execute(")
cpp_quote(" void *pvTaskData,")
cpp_quote(" volatile const BOOL* pfContinueProcessing) = 0;")
cpp_quote("};")
cpp_quote("#else")
typedef void * ISpTask;
cpp_quote("#endif")
//--- ISpThreadTask ---------------------------------------------------------
cpp_quote("#if defined(__cplusplus)")
cpp_quote("interface ISpThreadTask")
cpp_quote("{")
cpp_quote("virtual HRESULT STDMETHODCALLTYPE InitThread(")
cpp_quote(" void * pvTaskData,")
cpp_quote(" HWND hwnd) = 0;")
cpp_quote("virtual HRESULT STDMETHODCALLTYPE ThreadProc(")
cpp_quote(" void *pvTaskData,")
cpp_quote(" HANDLE hExitThreadEvent,")
cpp_quote(" HANDLE hNotifyEvent,")
cpp_quote(" HWND hwndWorker,")
cpp_quote(" volatile const BOOL * pfContinueProcessing) = 0;")
cpp_quote("virtual LRESULT STDMETHODCALLTYPE WindowMessage(")
cpp_quote(" void *pvTaskData,")
cpp_quote(" HWND hWnd,")
cpp_quote(" UINT Msg,")
cpp_quote(" WPARAM wParam,")
cpp_quote(" LPARAM lParam) = 0;")
cpp_quote("};")
cpp_quote("#else")
typedef void * ISpThreadTask;
cpp_quote("#endif")
//--- ISpThreadControl ------------------------------------------------------
[
object,
uuid(A6BE4D73-4403-4358-B22D-0346E23B1764),
helpstring("ISpThreadControl Interface"),
pointer_default(unique),
local,
restricted
]
interface ISpThreadControl : ISpNotifySink
{
HRESULT StartThread(DWORD dwFlags, HWND * phwnd);
HRESULT WaitForThreadDone(
BOOL fForceStop,
HRESULT * phrThreadResult,
ULONG msTimeOut);
HRESULT TerminateThread(void);
HANDLE ThreadHandle(void);
DWORD ThreadId(void);
HANDLE NotifyEvent(void);
HWND WindowHandle(void);
HANDLE ThreadCompleteEvent(void);
HANDLE ExitThreadEvent(void);
};
//--- ISpTaskManager --------------------------------------------------------
// This interface is used to implement a task managment service provider
// to optimize thread usage.
typedef [restricted] struct SPTMTHREADINFO
{
long lPoolSize; // Number of threads in pool (-1 default)
long lPriority; // Priority of threads in pool
ULONG ulConcurrencyLimit; // Number of threads allowed to concurrently execute (0 default)
ULONG ulMaxQuickAllocThreads; // Maximum number of dedicated threads retained
} SPTMTHREADINFO;
[
local,
uuid(2BAEEF81-2CA3-4331-98F3-26EC5ABEFB03),
helpstring("ISpTaskManager Interface"),
pointer_default(unique),
restricted
]
interface ISpTaskManager : IUnknown
{
HRESULT SetThreadPoolInfo([in] const SPTMTHREADINFO* pPoolInfo);
HRESULT GetThreadPoolInfo([out] SPTMTHREADINFO* pPoolInfo);
HRESULT QueueTask(
[in] ISpTask* pTask,
[in] void* pvTaskData,
[in] HANDLE hCompEvent,
[in, out] DWORD* pdwGroupId,
[out] DWORD* pTaskID);
HRESULT CreateReoccurringTask(
[in] ISpTask* pTask,
[in] void* pvTaskData,
[in] HANDLE hCompEvent,
[out] ISpNotifySink** ppTaskCtrl);
HRESULT CreateThreadControl(
[in] ISpThreadTask* pTask,
[in] void* pvTaskData,
[in] long nPriority,
[out] ISpThreadControl** ppTaskCtrl);
HRESULT TerminateTask([in] DWORD dwTaskId, [in] ULONG ulWaitPeriod);
HRESULT TerminateTaskGroup([in] DWORD dwGroupId, [in] ULONG ulWaitPeriod);
};
//--- ISpTTSEngineSite ------------------------------------------------------
typedef enum SPVSKIPTYPE
{
SPVST_SENTENCE = (1L << 0) // Skip sentences
} SPVSKIPTYPE;
typedef enum SPVESACTIONS
{
SPVES_CONTINUE = 0,
SPVES_ABORT = ( 1L << 0 ),
SPVES_SKIP = ( 1L << 1 ),
SPVES_RATE = ( 1L << 2 ),
SPVES_VOLUME = ( 1L << 3 )
} SPVESACTIONS;
[
object,
local,
uuid(9880499B-CCE9-11d2-B503-00C04F797396),
helpstring("ISpTTSEngineSite Interface"),
pointer_default(unique)
]
interface ISpTTSEngineSite : ISpEventSink
{
DWORD GetActions( void );
HRESULT Write( [in]const void* pBuff, [in]ULONG cb, [out]ULONG *pcbWritten );
HRESULT GetRate( [out]long* pRateAdjust );
HRESULT GetVolume( [out]USHORT* pusVolume );
HRESULT GetSkipInfo( [out]SPVSKIPTYPE* peType, [out]long* plNumItems );
HRESULT CompleteSkip( [in]long ulNumSkipped );
};
//--- ISpTTSEngine ----------------------------------------------------------
typedef struct SPVTEXTFRAG
{
struct SPVTEXTFRAG* pNext; // Next text fragment in list, NULL == end of list
SPVSTATE State; // Current XML attribute state
LPCWSTR pTextStart;
ULONG ulTextLen;
ULONG ulTextSrcOffset; // Original source position of the fragment text
} SPVTEXTFRAG;
[
object,
local,
uuid(A74D7C8E-4CC5-4f2f-A6EB-804DEE18500E),
helpstring("ISpTTSEngine Interface"),
pointer_default(unique)
]
interface ISpTTSEngine : IUnknown
{
HRESULT Speak( [in]DWORD dwSpeakFlags,
[in]REFGUID rguidFormatId, [in]const WAVEFORMATEX * pWaveFormatEx,
[in]const SPVTEXTFRAG* pTextFragList, [in]ISpTTSEngineSite* pOutputSite );
HRESULT GetOutputFormat( [in] const GUID * pTargetFmtId, [in] const WAVEFORMATEX * pTargetWaveFormatEx,
[out] GUID * pOutputFormatId, [out] WAVEFORMATEX ** ppCoMemOutputWaveFormatEx);
};
//--- SR Engine data structures ----------------------------------------
typedef [restricted] struct SPWORDENTRY
{
SPWORDHANDLE hWord;
LANGID LangID;
WCHAR * pszDisplayText;
WCHAR * pszLexicalForm;
SPPHONEID * aPhoneId;
void * pvClientContext;
} SPWORDENTRY;
typedef [restricted] struct SPRULEENTRY
{
SPRULEHANDLE hRule;
SPSTATEHANDLE hInitialState;
DWORD Attributes; // SPCFGRULEATTRIBUTES
void * pvClientRuleContext;
void * pvClientGrammarContext;
} SPRULEENTRY;
typedef enum SPTRANSITIONTYPE
{
SPTRANSEPSILON,
SPTRANSWORD,
SPTRANSRULE,
SPTRANSTEXTBUF,
SPTRANSWILDCARD,
SPTRANSDICTATION
} SPTRANSITIONTYPE;
typedef [restricted] struct SPTRANSITIONENTRY
{
SPTRANSITIONID ID;
SPSTATEHANDLE hNextState;
BYTE Type; // SPTRANSITIONTYPE
char RequiredConfidence;
struct
{
DWORD fHasProperty; // Boolean type
};
float Weight;
union
{
struct
{
SPSTATEHANDLE hRuleInitialState; // Only if Type == SPTRANSRULE
SPRULEHANDLE hRule;
void * pvClientRuleContext;
};
struct
{
SPWORDHANDLE hWord; // Only if Type == SPTRANSWORD
void * pvClientWordContext;
};
struct
{
void * pvGrammarCookie; // Only if Type == SPTRANSTEXTBUF or SPTRANSWILDCARD or SPTRANSDICTATION
};
};
} SPTRANSITIONENTRY;
typedef [restricted] struct SPTRANSITIONPROPERTY
{
const WCHAR * pszName;
ULONG ulId;
const WCHAR * pszValue;
VARIANT vValue; // Will be VT_BOOL, VT_I4, VT_R4, VT_R8, or VT_BYREF (only for dynamic grammars)
} SPTRANSITIONPROPERTY;
typedef [restricted] struct SPSTATEINFO
{
ULONG cAllocatedEntries;
SPTRANSITIONENTRY * pTransitions;
ULONG cEpsilons;
ULONG cRules;
ULONG cWords;
ULONG cSpecialTransitions;
} SPSTATEINFO;
typedef [restricted] struct SPPATHENTRY
{
SPTRANSITIONID hTransition;
SPPHRASEELEMENT elem;
} SPPATHENTRY;
//--- ISpCFGInterpreterSite -------------------------------------------------
[
object,
uuid(6A6FFAD8-78B6-473d-B844-98152E4FB16B),
helpstring("ISpCFGInterpreterSite Interface"),
pointer_default(unique),
local,
restricted
]
interface ISpCFGInterpreterSite : IUnknown
{
HRESULT AddTextReplacement([in] SPPHRASEREPLACEMENT * pReplace);
HRESULT AddProperty([in] const SPPHRASEPROPERTY *pProperty);
HRESULT GetResourceValue(
[in] const WCHAR *pszResourceName,
[out] WCHAR ** ppCoMemResource);
};
//--- ISpCFGInterpreter -----------------------------------------------------
[
object,
uuid(F3D3F926-11FC-11d3-BB97-00C04F8EE6C0),
helpstring("ISpCFGInterpreter Interface"),
pointer_default(unique),
local,
restricted
]
interface ISpCFGInterpreter : IUnknown
{
HRESULT InitGrammar(
[in] const WCHAR * pszGrammarName,
[in] const void ** pvGrammarData);
HRESULT Interpret(
[in] ISpPhraseBuilder * pPhrase,
[in] const ULONG ulFirstElement,
[in] const ULONG ulCountOfElements,
[in] ISpCFGInterpreterSite * pSite);
};
typedef enum SPCFGNOTIFY
{
SPCFGN_ADD,
SPCFGN_REMOVE,
SPCFGN_INVALIDATE,
SPCFGN_ACTIVATE,
SPCFGN_DEACTIVATE
} SPCFGNOTIFY;
//--- ISpSREngineSite -------------------------------------------------------
typedef enum SPRESULTTYPE
{
SPRT_CFG = 0,
SPRT_SLM = 1,
SPRT_PROPRIETARY = 2,
SPRT_FALSE_RECOGNITION = ( 1L << 2 ) // Flag used to indicate a false recognition
} SPRESULTTYPE;
typedef struct tagSPPHRASEALT
{
ISpPhraseBuilder * pPhrase;
ULONG ulStartElementInParent;
ULONG cElementsInParent;
ULONG cElementsInAlternate;
void * pvAltExtra;
ULONG cbAltExtra;
} SPPHRASEALT;
// Result structure passed from engine to SAPI
typedef struct SPRECORESULTINFO
{
ULONG cbSize; // Total size of this structure
SPRESULTTYPE eResultType; // Type of result object (CFG, SLM, or Proprietary)
BOOL fHypothesis; // If true then this recognition is a hypothesis
BOOL fProprietaryAutoPause;// This field is only used for SPERT_PROPRIETARY grammars. If true, recognition will pause.
ULONGLONG ullStreamPosStart; // Start and end stream positions of recognition
ULONGLONG ullStreamPosEnd;
SPGRAMMARHANDLE hGrammar; // Required for SPERT_SLM and SPERT_PROPRIETARY else NULL
ULONG ulSizeEngineData; // Size of pvEngineData
void * pvEngineData; // Extra engine specific data
ISpPhraseBuilder* pPhrase; // Pointer to phrase object
SPPHRASEALT* aPhraseAlts; // Alternates array
ULONG ulNumAlts; // Number of alternates in the array
} SPRECORESULTINFO;
typedef enum SPWORDINFOOPT
{
SPWIO_NONE = 0,
SPWIO_WANT_TEXT = 1
} SPWORDINFOOPT;
typedef enum SPRULEINFOOPT
{
SPRIO_NONE = 0,
} SPRULEINFOOPT;
typedef struct SPPARSEINFO
{
ULONG cbSize;
SPRULEHANDLE hRule;
ULONGLONG ullAudioStreamPosition;
ULONG ulAudioSize;
ULONG cTransitions;
SPPATHENTRY * pPath;
GUID SREngineID;
ULONG ulSREnginePrivateDataSize;
const BYTE * pSREnginePrivateData;
BOOL fHypothesis;
} SPPARSEINFO;
[
object,
uuid(3B414AEC-720C-4883-B9EF-178CD394FB3A),
helpstring("ISpSREngineSite Interface"),
pointer_default(unique),
local
]
interface ISpSREngineSite : IUnknown
{
HRESULT Read([in] void * pv, [in] ULONG cb, [out] ULONG * pcbRead);
HRESULT DataAvailable(ULONG * pcb);
HRESULT SetBufferNotifySize([in] ULONG cbSize);
HRESULT ParseFromTransitions([in] const SPPARSEINFO * pParseInfo,
[out] ISpPhraseBuilder ** ppNewPhrase);
HRESULT Recognition([in] const SPRECORESULTINFO * pResultInfo);
HRESULT AddEvent([in] const SPEVENT* pEvent, [in] SPRECOCONTEXTHANDLE hSAPIRecoContext);
HRESULT Synchronize([in] ULONGLONG ullProcessedThruPos);
HRESULT GetWordInfo([in, out] SPWORDENTRY * pWordEntry, [in] SPWORDINFOOPT Options); // Caller must fill in hWord. if fWantWordText then caller must CoTaskMemFree the pszWord.
HRESULT SetWordClientContext(SPWORDHANDLE hWord, void * pvClientContext);
HRESULT GetRuleInfo([in, out] SPRULEENTRY * pRuleEntry, [in] SPRULEINFOOPT Options); // Caller must fill in hRule.SPRULEHANDLE hRule, BOOL * pfActive, BOOL *pfAutoPause, SPSTATEHANDLE * phInitialState, void ** ppvClientContext);
HRESULT SetRuleClientContext(SPRULEHANDLE hRule, void * pvClientContext);
HRESULT GetStateInfo(SPSTATEHANDLE hState, SPSTATEINFO * pStateInfo);
HRESULT GetResource( [in] SPRULEHANDLE hRule, [in] const WCHAR *pszResourceName, [out] WCHAR ** ppCoMemResource );
HRESULT GetTransitionProperty([in] SPTRANSITIONID ID, [out] SPTRANSITIONPROPERTY **ppCoMemProperty);
HRESULT IsAlternate( [in]SPRULEHANDLE hRule, [in]SPRULEHANDLE hAltRule );
HRESULT GetMaxAlternates( [in]SPRULEHANDLE hRule, [out]ULONG* pulNumAlts );
HRESULT GetContextMaxAlternates( [in] SPRECOCONTEXTHANDLE hContext, [out] ULONG * pulNumAlts);
HRESULT UpdateRecoPos([in] ULONGLONG ullCurrentRecoPos);
};
//--- ISpSREngine -----------------------------------------------------------
typedef enum SPPROPSRC
{
SPPROPSRC_RECO_INST,
SPPROPSRC_RECO_CTX,
SPPROPSRC_RECO_GRAMMAR
} SPPROPSRC;
[
object,
uuid(2F472991-854B-4465-B613-FBAFB3AD8ED8),
helpstring("ISpSREngine Interface"),
pointer_default(unique),
local
]
interface ISpSREngine : IUnknown
{
HRESULT SetSite([in] ISpSREngineSite *pSite);
HRESULT GetInputAudioFormat(
[in] const GUID * pguidSourceFormatId,
[in] const WAVEFORMATEX * pSourceWaveFormatEx,
[out] GUID * pguidDesiredFormatId,
[out] WAVEFORMATEX ** ppCoMemDesiredWaveFormatEx);
HRESULT RecognizeStream([in] REFGUID rguidFmtId, [in] const WAVEFORMATEX * pWaveFormatEx,
[in] HANDLE hRequestSync, [in] HANDLE hDataAvailable,
[in] HANDLE hExit, [in] BOOL fNewAudioStream, [in] BOOL fRealTimeAudio,
[in] ISpObjectToken * pAudioObjectToken);
HRESULT SetRecoProfile(ISpObjectToken * pProfile);
HRESULT OnCreateGrammar([in] void * pvEngineRecoContext,
[in] SPGRAMMARHANDLE hSAPIGrammar,
[out] void ** ppvEngineGrammarContext);
HRESULT OnDeleteGrammar([in] void * pvEngineGrammar);
HRESULT LoadProprietaryGrammar(
[in] void * pvEngineGrammar,
[in] REFGUID rguidParam,
[in, string] const WCHAR * pszStringParam,
[in] const void * pvDataParam,
[in] ULONG ulDataSize,
[in] SPLOADOPTIONS Options); // Note for SAPI 5.0 this is always SPLO_NONE
HRESULT UnloadProprietaryGrammar([in] void * pvEngineGrammar);
HRESULT SetProprietaryRuleState([in] void * pvEngineGrammar,
[in, string] const WCHAR * pszName,
[in] void * pReserved,
[in] SPRULESTATE NewState,
[out] ULONG * pcRulesChanged);
HRESULT SetProprietaryRuleIdState([in] void * pvEngineGrammar,
[in] DWORD dwRuleId,
[in] SPRULESTATE NewState);
HRESULT LoadSLM([in] void * pvEngineGrammar, [in, string] const WCHAR * pszTopicName);
HRESULT UnloadSLM([in] void * pvEngineGrammar);
HRESULT SetSLMState([in] void * pvEngineGrammar, [in] SPRULESTATE NewState);
HRESULT SetWordSequenceData([in] void * pvEngineGrammar, [in] const WCHAR * pText, [in] ULONG cchText, [in] const SPTEXTSELECTIONINFO * pInfo);
HRESULT SetTextSelection([in] void * pvEngineGrammar, [in] const SPTEXTSELECTIONINFO * pInfo);
HRESULT IsPronounceable([in] void * pvEngineGrammar, [in, string] const WCHAR * pszWord, [out] SPWORDPRONOUNCEABLE *pWordPronounceable);
HRESULT OnCreateRecoContext(
[in] SPRECOCONTEXTHANDLE hSAPIRecoContext,
[out] void ** ppvEngineContext);
HRESULT OnDeleteRecoContext([in] void * pvEngineContext);
HRESULT PrivateCall([in] void * pvEngineContext, [in, out] PVOID pCallFrame, [in] ULONG ulCallFrameSize);
HRESULT SetAdaptationData([in] void * pvEngineContext, const WCHAR *pAdaptationData, const ULONG cch);
HRESULT SetPropertyNum( [in]SPPROPSRC eSrc, [in]void* pvSrcObj,
[in]const WCHAR* pName, [in]LONG lValue );
HRESULT GetPropertyNum( [in]SPPROPSRC eSrc, [in]void* pvSrcObj,
[in]const WCHAR* pName, [out]LONG* lValue );
HRESULT SetPropertyString( [in]SPPROPSRC eSrc, [in]void* pvSrcObj,
[in]const WCHAR* pName, [in]const WCHAR* pValue );
HRESULT GetPropertyString( [in]SPPROPSRC eSrc, [in]void* pvSrcObj,
[in]const WCHAR* pName, [out]WCHAR** ppCoMemValue );
HRESULT SetGrammarState([in] void * pvEngineGrammar, [in] SPGRAMMARSTATE eGrammarState);
HRESULT WordNotify(SPCFGNOTIFY Action, ULONG cWords, const SPWORDENTRY * pWords);
HRESULT RuleNotify(SPCFGNOTIFY Action, ULONG cRules, const SPRULEENTRY * pRules);
HRESULT PrivateCallEx([in] void * pvEngineContext, [in] const void * pInCallFrame, [in] ULONG ulInCallFrameSize,
[out] void ** ppvCoMemResponse, [out] ULONG * pulResponseSize);
HRESULT SetContextState([in] void * pvEngineContext, [in] SPCONTEXTSTATE eContextState);
};
//--- ISpSRAlternates
typedef struct tagSPPHRASEALTREQUEST
{
ULONG ulStartElement;
ULONG cElements;
ULONG ulRequestAltCount;
void * pvResultExtra;
ULONG cbResultExtra;
ISpPhrase * pPhrase;
ISpRecoContext * pRecoContext;
} SPPHRASEALTREQUEST;
[
object,
uuid(FECE8294-2BE1-408f-8E68-2DE377092F0E),
helpstring("ISpSRAlternates Interface"),
pointer_default(unique),
local
]
interface ISpSRAlternates : IUnknown
{
HRESULT GetAlternates([in] SPPHRASEALTREQUEST * pAltRequest,
[out] SPPHRASEALT **ppAlts,
[out] ULONG *pcAlts);
HRESULT Commit([in] SPPHRASEALTREQUEST * pAltRequest,
[in] SPPHRASEALT * pAlt,
[out] void **ppvResultExtra,
[out] ULONG *pcbResultExtra);
}
// Interface used by engine specific recoctxt extension object to call into engine
[
object,
uuid(8E7C791E-4467-11d3-9723-00C04F72DB08),
helpstring("_ISpPrivateEngineCall Interface"),
pointer_default(unique),
local
]
interface _ISpPrivateEngineCall : IUnknown
{
HRESULT CallEngine([in, out] void * pCallFrame, [in] ULONG ulCallFrameSize);
HRESULT CallEngineEx([in] const void * pInFrame, [in] ULONG ulInFrameSize,
[out] void ** ppCoMemOutFrame, [out] ULONG * pulOutFrameSize);
}
//
//--- CoClass definitions ---------------------------------------------------
//
[
helpstring("Microsoft Speech Object DDK Library"),
uuid(9903F14C-12CE-4c99-9986-2EE3D7D588A8),
version(5.0)
]
library SpeechDDKLib
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");
//--- SpDataKey ---------------------------------------------------------
[
uuid(D9F6EE60-58C9-458b-88E1-2F908FD7F87C),
helpstring("Data Key")
]
coclass SpDataKey
{
interface ISpRegDataKey;
[default] interface ISpDataKey;
}
//--- SpObjectTokenEnum --------------------------------------------------
[
uuid(3918D75F-0ACB-41f2-B733-92AA15BCECF6),
helpstring("Object Token Enumerator")
]
coclass SpObjectTokenEnum
{
interface ISpObjectTokenEnumBuilder;
[default] interface IEnumSpObjectTokens;
}
//--- SpPhraseBuilder ---------------------------------------------------
[
uuid(777B6BBD-2FF2-11d3-88FE-00C04F8EF9B5),
helpstring("Phrase Builder Class")
]
coclass SpPhraseBuilder
{
[default] interface ISpPhraseBuilder;
}
//--- SpITNProcessor ----------------------------------------------------
[
uuid(12D73610-A1C9-11d3-BC90-00C04F72DF9F),
helpstring("SpITNProcessor Class"),
restricted
]
coclass SpITNProcessor
{
[default] interface ISpITNProcessor;
};
//--- SpGrammarCompiler ---------------------------------------------
[
uuid(B1E29D59-A675-11D2-8302-00C04F8EE6C0),
helpstring("Microsoft Speech Grammar Compiler")
]
coclass SpGrammarCompiler
{
[default] interface ISpGrammarCompiler;
};
//--- SpGramCompBackend ---------------------------------------------
[
uuid(DA93E903-C843-11D2-A084-00C04F8EF9B5),
helpstring("Grammar Class"),
restricted
]
coclass SpGramCompBackend
{
[default] interface ISpGramCompBackend;
};
}

View file

@ -0,0 +1,854 @@
/*******************************************************************************
* SPDDKHLP.h *
*------------*
* Description:
* This is the header file for core helper functions implementation.
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*******************************************************************************/
#ifndef SPDDKHLP_h
#define SPDDKHLP_h
#ifndef SPHelper_h
#include <sphelper.h>
#endif
#include <sapiddk.h>
#ifndef SPError_h
#include <SPError.h>
#endif
#ifndef SPDebug_h
#include <SPDebug.h>
#endif
#ifndef _INC_LIMITS
#include <limits.h>
#endif
#ifndef _INC_CRTDBG
#include <crtdbg.h>
#endif
#ifndef _INC_MALLOC
#include <malloc.h>
#endif
#ifndef _INC_MMSYSTEM
#include <mmsystem.h>
#endif
#ifndef __comcat_h__
#include <comcat.h>
#endif
//=== Constants ==============================================================
#define sp_countof(x) ((sizeof(x) / sizeof(*(x))))
#define SP_IS_BAD_WRITE_PTR(p) ( SPIsBadWritePtr( p, sizeof(*(p)) ))
#define SP_IS_BAD_READ_PTR(p) ( SPIsBadReadPtr( p, sizeof(*(p)) ))
#define SP_IS_BAD_CODE_PTR(p) ( ::IsBadCodePtr((FARPROC)(p) )
#define SP_IS_BAD_INTERFACE_PTR(p) ( SPIsBadInterfacePtr( (p) ) )
#define SP_IS_BAD_VARIANT_PTR(p) ( SPIsBadVARIANTPtr( (p) ) )
#define SP_IS_BAD_STRING_PTR(p) ( SPIsBadStringPtr( (p) ) )
#define SP_IS_BAD_OPTIONAL_WRITE_PTR(p) ((p) && SPIsBadWritePtr( p, sizeof(*(p)) ))
#define SP_IS_BAD_OPTIONAL_READ_PTR(p) ((p) && SPIsBadReadPtr( p, sizeof(*(p)) ))
#define SP_IS_BAD_OPTIONAL_INTERFACE_PTR(p) ((p) && SPIsBadInterfacePtr(p))
#define SP_IS_BAD_OPTIONAL_STRING_PTR(p) ((p) && SPIsBadStringPtr(p))
//=== Class, Enum, Struct, Template, and Union Declarations ==================
//=== Inlines ================================================================
/*** Pointer validation functions
*/
// TODO: Add decent debug output for bad parameters
inline BOOL SPIsBadStringPtr( const WCHAR * psz, ULONG cMaxChars = 0xFFFF )
{
BOOL IsBad = false;
__try
{
do
{
if( *psz++ == 0 ) return IsBad;
}
while( --cMaxChars );
}
__except( GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION )
{
IsBad = true;
}
return IsBad;
}
inline BOOL SPIsBadReadPtr( const void* pMem, UINT Size )
{
#ifdef _DEBUG
BOOL bIsBad = ::IsBadReadPtr( pMem, Size );
SPDBG_ASSERT(!bIsBad);
return bIsBad;
#else
return ::IsBadReadPtr( pMem, Size );
#endif
}
inline BOOL SPIsBadWritePtr( void* pMem, UINT Size )
{
#ifdef _DEBUG
BOOL bIsBad = ::IsBadWritePtr( pMem, Size );
SPDBG_ASSERT(!bIsBad);
return bIsBad;
#else
return ::IsBadWritePtr( pMem, Size );
#endif
}
inline BOOL SPIsBadInterfacePtr( const IUnknown* pUnknown )
{
#ifdef _DEBUG
BOOL bIsBad = ( ::IsBadReadPtr( pUnknown, sizeof( *pUnknown ) ) ||
::IsBadCodePtr( (FARPROC)((void**)pUnknown)[0] ))?
(true):(false);
SPDBG_ASSERT(!bIsBad);
return bIsBad;
#else
return ( ::IsBadReadPtr( pUnknown, sizeof( *pUnknown ) ) ||
::IsBadCodePtr( (FARPROC)((void**)pUnknown)[0] ))?
(true):(false);
#endif
}
inline BOOL SPIsBadVARIANTPtr( const VARIANT* pVar )
{
#ifdef _DEBUG
BOOL bIsBad = ::IsBadReadPtr( pVar, sizeof( *pVar ) );
SPDBG_ASSERT(!bIsBad);
return bIsBad;
#else
return ::IsBadReadPtr( pVar, sizeof( *pVar ) );
#endif
}
#ifdef __ATLCOM_H__ //--- Only enable these if ATL is being used
//
// Helper functions can be used to implement GetObjectToken/SetObjectToken for objects that
// support ISpObjectWithToken
//
inline HRESULT SpGenericSetObjectToken(ISpObjectToken * pCallersToken, CComPtr<ISpObjectToken> & cpObjToken)
{
HRESULT hr = S_OK;
if (SP_IS_BAD_INTERFACE_PTR(pCallersToken))
{
hr = E_INVALIDARG;
}
else
{
if (cpObjToken)
{
hr = SPERR_ALREADY_INITIALIZED;
}
else
{
cpObjToken = pCallersToken;
}
}
return hr;
}
inline HRESULT SpGenericGetObjectToken(ISpObjectToken ** ppCallersToken, CComPtr<ISpObjectToken> & cpObjToken)
{
HRESULT hr = S_OK;
if (SP_IS_BAD_WRITE_PTR(ppCallersToken))
{
hr = E_POINTER;
}
else
{
*ppCallersToken = cpObjToken;
if (*ppCallersToken)
{
(*ppCallersToken)->AddRef();
}
else
{
hr = S_FALSE;
}
}
return hr;
}
#endif // __ATLCOM_H__
//
// Helper class for SPSTATEINFO sturcture automatically initializes and cleans up
// the structure + provides a few helper functions.
//
class CSpStateInfo : public SPSTATEINFO
{
public:
CSpStateInfo()
{
cAllocatedEntries = NULL;
pTransitions = NULL;
}
~CSpStateInfo()
{
::CoTaskMemFree(pTransitions);
}
SPTRANSITIONENTRY * FirstEpsilon()
{
return pTransitions;
}
SPTRANSITIONENTRY * FirstRule()
{
return pTransitions + cEpsilons;
}
SPTRANSITIONENTRY * FirstWord()
{
return pTransitions + cEpsilons + cRules;
}
SPTRANSITIONENTRY * FirstSpecialTransition()
{
return pTransitions + cEpsilons + cRules + cWords;
}
};
//
// This basic queue implementation can be used to maintin linked lists of classes. The class T
// must contain the member m_pNext which is used by this template to point to the next element.
// If the bPurgeWhenDeleted is TRUE then all of the elements in the queue will be deleted
// when the queue is deleted, otherwise they will not.
// If bMaintainCount is TRUE then a running count will be maintained, and GetCount() will be
// efficent. If it is FALSE then a running count will not be maintained, and GetCount() will
// be an order N operation. If you do not require a count, then
//
template <class T, BOOL bPurgeWhenDeleted> class CSpBasicList;
template <class T, BOOL bPurgeWhenDeleted = TRUE, BOOL bMaintainCount = FALSE>
class CSpBasicQueue
{
public:
T * m_pHead;
T * m_pTail;
ULONG m_cElements; // Warning! Use GetCount() -- Not maintained if bMaintainCount is FALSE.
CSpBasicQueue()
{
m_pHead = NULL;
if (bMaintainCount)
{
m_cElements = 0;
}
}
~CSpBasicQueue()
{
if (bPurgeWhenDeleted)
{
Purge();
}
}
HRESULT CreateNode(T ** ppNode)
{
*ppNode = new T;
if (*ppNode)
{
return S_OK;
}
else
{
return E_OUTOFMEMORY;
}
}
T * GetNext(const T * pNode)
{
return pNode->m_pNext;
}
T * Item(ULONG i)
{
T * pNode = m_pHead;
while (pNode && i)
{
i--;
pNode = pNode->m_pNext;
}
return pNode;
}
void InsertAfter(T * pPrev, T * pNewNode)
{
if (pPrev)
{
pNewNode->m_pNext = pPrev->m_pNext;
pPrev->m_pNext = pNewNode;
if (pNewNode->m_pNext == NULL)
{
m_pTail = pNewNode;
}
if (bMaintainCount) ++m_cElements;
}
else
{
InsertHead(pNewNode);
}
}
void InsertTail(T * pNode)
{
pNode->m_pNext = NULL;
if (m_pHead)
{
m_pTail->m_pNext = pNode;
}
else
{
m_pHead = pNode;
}
m_pTail = pNode;
if (bMaintainCount) ++m_cElements;
}
void InsertHead(T * pNode)
{
pNode->m_pNext = m_pHead;
if (m_pHead == NULL)
{
m_pTail = pNode;
}
m_pHead = pNode;
if (bMaintainCount) ++m_cElements;
}
T * RemoveHead()
{
T * pNode = m_pHead;
if (pNode)
{
m_pHead = pNode->m_pNext;
if (bMaintainCount) --m_cElements;
}
return pNode;
}
T * RemoveTail()
{
T * pNode = m_pHead;
if (pNode)
{
if (pNode == m_pTail)
{
m_pHead = NULL;
}
else
{
T * pPrev;
do
{
pPrev = pNode;
pNode = pNode->m_pNext;
} while ( pNode != m_pTail );
pPrev->m_pNext = NULL;
m_pTail = pPrev;
}
if (bMaintainCount) --m_cElements;
}
return pNode;
}
void Purge()
{
while (m_pHead)
{
T * pDie = m_pHead;
m_pHead = pDie->m_pNext;
delete pDie;
}
if (bMaintainCount) m_cElements = 0;
}
void ExplicitPurge()
{
T * pDie;
BYTE * pb;
while (m_pHead)
{
pDie = m_pHead;
m_pHead = pDie->m_pNext;
pDie->~T();
pb = reinterpret_cast<BYTE *>(pDie);
delete [] pb;
}
if (bMaintainCount) m_cElements = 0;
}
T * GetTail() const
{
if (m_pHead)
{
return m_pTail;
}
return NULL;
}
T * GetHead() const
{
return m_pHead;
}
BOOL IsEmpty() const
{
return m_pHead == NULL;
}
BOOL Remove(T * pNode)
{
if (m_pHead == pNode)
{
m_pHead = pNode->m_pNext;
if (bMaintainCount) --m_cElements;
return TRUE;
}
else
{
T * pCur = m_pHead;
while (pCur)
{
T * pNext = pCur->m_pNext;
if (pNext == pNode)
{
if ((pCur->m_pNext = pNode->m_pNext) == NULL)
{
m_pTail = pCur;
}
if (bMaintainCount) --m_cElements;
return TRUE;
}
pCur = pNext;
}
}
return FALSE;
}
void MoveAllToHeadOf(CSpBasicQueue & DestQueue)
{
if (m_pHead)
{
m_pTail->m_pNext = DestQueue.m_pHead;
if (DestQueue.m_pHead == NULL)
{
DestQueue.m_pTail = m_pTail;
}
DestQueue.m_pHead = m_pHead;
m_pHead = NULL;
if (bMaintainCount)
{
DestQueue.m_cElements += m_cElements;
m_cElements = 0;
}
}
}
void MoveAllToList(CSpBasicList<T, bPurgeWhenDeleted> & List)
{
if (m_pHead)
{
m_pTail->m_pNext = List.m_pFirst;
List.m_pFirst = m_pHead;
m_pHead = NULL;
}
if (bMaintainCount)
{
m_cElements = 0;
}
}
BOOL MoveToList(T * pNode, CSpBasicList<T, bPurgeWhenDeleted> & List)
{
BOOL bFound = Remove(pNode);
if (bFound)
{
List.AddNode(pNode);
}
return bFound;
}
ULONG GetCount() const
{
if (bMaintainCount)
{
return m_cElements;
}
else
{
ULONG c = 0;
for (T * pNode = m_pHead;
pNode;
pNode = pNode->m_pNext, c++) {}
return c;
}
}
//
// The following functions require the class T to implement a static function:
//
// LONG Compare(const T * pElem1, const T * pElem2)
//
// which returns < 0 if pElem1 is less than pElem2, 0 if they are equal, and > 0 if
// pElem1 is greater than pElem2.
//
void InsertSorted(T * pNode)
{
if (m_pHead)
{
if (T::Compare(pNode, m_pTail) >= 0)
{
pNode->m_pNext = NULL;
m_pTail->m_pNext = pNode;
m_pTail = pNode;
}
else
{
//
// We don't have to worry about walking off of the end of the list here since
// we have already checked the tail.
//
T ** ppNext = &m_pHead;
while (T::Compare(pNode, *ppNext) >= 0)
{
ppNext = &((*ppNext)->m_pNext);
}
pNode->m_pNext = *ppNext;
*ppNext = pNode;
}
}
else
{
pNode->m_pNext = NULL;
m_pHead = m_pTail = pNode;
}
if (bMaintainCount) ++m_cElements;
}
HRESULT InsertSortedUnique(T * pNode)
{
HRESULT hr = S_OK;
if (m_pHead)
{
if (T::Compare(pNode, m_pTail) > 0)
{
pNode->m_pNext = NULL;
m_pTail->m_pNext = pNode;
m_pTail = pNode;
}
else
{
//
// We don't have to worry about walking off of the end of the list here since
// we have already checked the tail.
//
T ** ppNext = &m_pHead;
while (T::Compare(pNode, *ppNext) > 0)
{
ppNext = &((*ppNext)->m_pNext);
}
if (T::Compare(pNode, *ppNext) != 0)
{
pNode->m_pNext = *ppNext;
*ppNext = pNode;
}
else
{
delete pNode;
hr = S_FALSE;
}
}
}
else
{
pNode->m_pNext = NULL;
m_pHead = m_pTail = pNode;
}
if (bMaintainCount) ++m_cElements;
return hr;
}
//
// These functions must support the "==" operator for the TFIND type.
//
template <class TFIND>
T * Find(TFIND & FindVal) const
{
for (T * pNode = m_pHead; pNode && (!(*pNode == FindVal)); pNode = pNode->m_pNext)
{}
return pNode;
}
template <class TFIND>
T * FindNext(const T * pCurNode, TFIND & FindVal) const
{
for (T * pNode = pCurNode->m_pNext; pNode && (!(*pNode == FindVal)); pNode = pNode->m_pNext)
{}
return pNode;
}
//
// Searches for and removes a single list element
//
template <class TFIND>
T * FindAndRemove(TFIND & FindVal)
{
T * pNode = m_pHead;
if (pNode)
{
if (*pNode == FindVal)
{
m_pHead = pNode->m_pNext;
if (bMaintainCount) --m_cElements;
}
else
{
T * pPrev = pNode;
for (pNode = pNode->m_pNext;
pNode;
pPrev = pNode, pNode = pNode->m_pNext)
{
if (*pNode == FindVal)
{
pPrev->m_pNext = pNode->m_pNext;
if (pNode->m_pNext == NULL)
{
m_pTail = pPrev;
}
if (bMaintainCount) --m_cElements;
break;
}
}
}
}
return pNode;
}
//
// Searches for and deletes all list elements that match
//
template <class TFIND>
void FindAndDeleteAll(TFIND & FindVal)
{
T * pNode = m_pHead;
while (pNode && *pNode == FindVal)
{
m_pHead = pNode->m_pNext;
delete pNode;
if (bMaintainCount) --m_cElements;
pNode = m_pHead;
}
T * pPrev = pNode;
while (pNode)
{
T * pNext = pNode->m_pNext;
if (*pNode == FindVal)
{
pPrev->m_pNext = pNext;
delete pNode;
if (bMaintainCount) --m_cElements;
}
else
{
pPrev = pNode;
}
pNode = pNext;
}
m_pTail = pPrev; // Just always set it in case we removed the tail.
}
};
template <class T, BOOL bPurgeWhenDeleted = TRUE>
class CSpBasicList
{
public:
T * m_pFirst;
CSpBasicList() : m_pFirst(NULL) {}
~CSpBasicList()
{
if (bPurgeWhenDeleted)
{
Purge();
}
}
void Purge()
{
while (m_pFirst)
{
T * pNext = m_pFirst->m_pNext;
delete m_pFirst;
m_pFirst = pNext;
}
}
void ExplicitPurge()
{
T * pDie;
BYTE * pb;
while (m_pFirst)
{
pDie = m_pFirst;
m_pFirst = pDie->m_pNext;
pDie->~T();
pb = reinterpret_cast<BYTE *>(pDie);
delete [] pb;
}
}
HRESULT RemoveFirstOrAllocateNew(T ** ppNode)
{
if (m_pFirst)
{
*ppNode = m_pFirst;
m_pFirst = m_pFirst->m_pNext;
}
else
{
*ppNode = new T;
if (*ppNode == NULL)
{
return E_OUTOFMEMORY;
}
}
return S_OK;
}
void AddNode(T * pNode)
{
pNode->m_pNext = m_pFirst;
m_pFirst = pNode;
}
T * GetFirst()
{
return m_pFirst;
}
T * RemoveFirst()
{
T * pNode = m_pFirst;
if (pNode)
{
m_pFirst = pNode->m_pNext;
}
return pNode;
}
};
#define STACK_ALLOC(TYPE, COUNT) (TYPE *)_alloca(sizeof(TYPE) * (COUNT))
#define STACK_ALLOC_AND_ZERO(TYPE, COUNT) (TYPE *)memset(_alloca(sizeof(TYPE) * (COUNT)), 0, (sizeof(TYPE) * (COUNT)))
#define STACK_ALLOC_AND_COPY(TYPE, COUNT, SOURCE) (TYPE *)memcpy(_alloca(sizeof(TYPE) * (COUNT)), (SOURCE), (sizeof(TYPE) * (COUNT)))
inline HRESULT SpGetSubTokenFromToken(
ISpObjectToken * pToken,
const WCHAR * pszSubKeyName,
ISpObjectToken ** ppToken,
BOOL fCreateIfNotExist = FALSE)
{
SPDBG_FUNC("SpGetTokenFromDataKey");
HRESULT hr = S_OK;
if (SP_IS_BAD_INTERFACE_PTR(pToken) ||
SP_IS_BAD_STRING_PTR(pszSubKeyName) ||
SP_IS_BAD_WRITE_PTR(ppToken))
{
hr = E_POINTER;
}
// First, either create or open the datakey for the new token
CComPtr<ISpDataKey> cpDataKeyForNewToken;
if (SUCCEEDED(hr))
{
if (fCreateIfNotExist)
{
hr = pToken->CreateKey(pszSubKeyName, &cpDataKeyForNewToken);
}
else
{
hr = pToken->OpenKey(pszSubKeyName, &cpDataKeyForNewToken);
}
}
// The sub token's category will be the token id of it's parent token
CSpDynamicString dstrCategoryId;
if (SUCCEEDED(hr))
{
hr = pToken->GetId(&dstrCategoryId);
}
// The sub token's token id will be it's category id + "\\" the key name
CSpDynamicString dstrTokenId;
if (SUCCEEDED(hr))
{
dstrTokenId = dstrCategoryId;
dstrTokenId.Append2(L"\\", pszSubKeyName);
}
// Now create the token and initalize it
CComPtr<ISpObjectTokenInit> cpTokenInit;
if (SUCCEEDED(hr))
{
hr = cpTokenInit.CoCreateInstance(CLSID_SpObjectToken);
}
if (SUCCEEDED(hr))
{
hr = cpTokenInit->InitFromDataKey(dstrCategoryId, dstrTokenId, cpDataKeyForNewToken);
}
if (SUCCEEDED(hr))
{
*ppToken = cpTokenInit.Detach();
}
SPDBG_REPORT_ON_FAIL(hr);
return hr;
}
template<class T>
HRESULT SpCreateObjectFromSubToken(ISpObjectToken * pToken, const WCHAR * pszSubKeyName, T ** ppObject,
IUnknown * pUnkOuter = NULL, DWORD dwClsCtxt = CLSCTX_ALL)
{
SPDBG_FUNC("SpCreateObjectFromSubToken");
HRESULT hr;
CComPtr<ISpObjectToken> cpSubToken;
hr = SpGetSubTokenFromToken(pToken, pszSubKeyName, &cpSubToken);
if (SUCCEEDED(hr))
{
hr = SpCreateObjectFromToken(cpSubToken, ppObject, pUnkOuter, dwClsCtxt);
}
SPDBG_REPORT_ON_FAIL(hr);
return hr;
}
#endif /* This must be the last line in the file */

25599
speech2/third_party/sapi5/include/sapi.h vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,636 @@
/*******************************************************************************
* SPDebug.h *
*-----------*
* Description:
* This header file contains debug output services for SAPI5
*-------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
*******************************************************************************/
#pragma once
#include <TCHAR.h>
#include <crtdbg.h>
#ifdef ASSERT_WITH_STACK
#include "AssertWithStack.h"
#endif
const TCHAR g_szSpDebugKey[] = _T("SPDebug");
const TCHAR g_szSpDebugFuncTraceReportMode[] = _T("FuncTraceMode");
const TCHAR g_szSpDebugFuncTraceReportFile[] = _T("FuncTraceFile");
const TCHAR g_szSpDebugParamInfoReportMode[] = _T("ParamInfoMode");
const TCHAR g_szSpDebugParamInfoReportFile[] = _T("ParamInfoFile");
const TCHAR g_szSpDebugDumpInfoReportMode[] = _T("DumpInfoMode");
const TCHAR g_szSpDebugDumpInfoReportFile[] = _T("DumpInfoFile");
const TCHAR g_szSpDebugAssertReportMode[] = _T("AssertMode");
const TCHAR g_szSpDebugAssertReportFile[] = _T("AssertFile");
const TCHAR g_szSpDebugHRFailReportMode[] = _T("HRFailMode");
const TCHAR g_szSpDebugHRFailReportFile[] = _T("HRFailFile");
const TCHAR g_szSpDebugAssertSettingsReReadEachTime[] = _T("AssertSettingsReReadEachTime");
const TCHAR g_szSpDebugServerOnStart[] = _T("DebugServerOnStart");
const TCHAR g_szSpDebugClientOnStart[] = _T("DebugClientOnStart");
const TCHAR g_szSpDebugLog[] = _T("c:\\spdebug.log");
#ifdef _DEBUG
class CSpDebug
{
public:
CSpDebug()
{
m_mutex = NULL;
m_reportModePrev = -1;
m_hfilePrev = NULL;
Read();
}
~CSpDebug()
{
if (m_mutex != NULL)
{
CloseHandle(m_mutex);
}
}
BOOL FuncTrace(BOOL fEnter = TRUE)
{
return fEnter
? Enter(_CRT_WARN, m_FuncTraceMode, m_szFuncTraceFile)
: Leave();
}
BOOL ParamInfo(BOOL fEnter = TRUE)
{
return fEnter
? Enter(_CRT_WARN, m_ParamInfoMode, m_szParamInfoFile)
: Leave();
}
BOOL DumpInfo(BOOL fEnter = TRUE)
{
return fEnter
? Enter(_CRT_WARN, m_DumpInfoMode, m_szDumpInfoFile)
: Leave();
}
BOOL Assert(BOOL fEnter = TRUE)
{
if (m_fAssertSettingsReReadEachTime)
Read();
return fEnter
? Enter(_CRT_ASSERT, m_AssertMode, m_szAssertFile)
: Leave();
}
BOOL HRFail(BOOL fEnter = TRUE)
{
return fEnter
? Enter(_CRT_WARN, m_HRFailMode, m_szHRFailFile)
: Leave();
}
BOOL DebugServerOnStart()
{
return m_fDebugServerOnStart;
}
BOOL DebugClientOnStart()
{
return m_fDebugClientOnStart;
}
private:
void Read()
{
HKEY hkeyDebug;
RegCreateKeyEx(
HKEY_CLASSES_ROOT,
g_szSpDebugKey,
0,
NULL,
0,
KEY_READ | KEY_WRITE,
NULL,
&hkeyDebug,
NULL);
if (hkeyDebug == NULL)
{
RegCreateKeyEx(
HKEY_CLASSES_ROOT,
g_szSpDebugKey,
0,
NULL,
0,
KEY_READ,
NULL,
&hkeyDebug,
NULL);
}
DWORD dw = sizeof(m_fAssertSettingsReReadEachTime);
if (RegQueryValueEx(
hkeyDebug,
g_szSpDebugAssertSettingsReReadEachTime,
NULL,
NULL,
LPBYTE(&m_fAssertSettingsReReadEachTime),
&dw) != ERROR_SUCCESS)
{
m_fAssertSettingsReReadEachTime = FALSE;
RegSetValueEx(
hkeyDebug,
g_szSpDebugAssertSettingsReReadEachTime,
NULL,
REG_DWORD,
LPBYTE(&m_fAssertSettingsReReadEachTime),
sizeof(m_fAssertSettingsReReadEachTime));
}
ReadFor(
hkeyDebug,
g_szSpDebugFuncTraceReportMode,
g_szSpDebugFuncTraceReportFile,
&m_FuncTraceMode,
m_szFuncTraceFile,
0,
g_szSpDebugLog);
ReadFor(
hkeyDebug,
g_szSpDebugParamInfoReportMode,
g_szSpDebugParamInfoReportFile,
&m_ParamInfoMode,
m_szParamInfoFile,
0,
g_szSpDebugLog);
ReadFor(
hkeyDebug,
g_szSpDebugDumpInfoReportMode,
g_szSpDebugDumpInfoReportFile,
&m_DumpInfoMode,
m_szDumpInfoFile,
_CRTDBG_MODE_DEBUG,
g_szSpDebugLog);
ReadFor(
hkeyDebug,
g_szSpDebugAssertReportMode,
g_szSpDebugAssertReportFile,
&m_AssertMode,
m_szAssertFile,
_CRTDBG_MODE_WNDW,
g_szSpDebugLog);
ReadFor(
hkeyDebug,
g_szSpDebugHRFailReportMode,
g_szSpDebugHRFailReportFile,
&m_HRFailMode,
m_szHRFailFile,
_CRTDBG_MODE_DEBUG,
g_szSpDebugLog);
dw = sizeof(m_fDebugServerOnStart);
if (RegQueryValueEx(
hkeyDebug,
g_szSpDebugServerOnStart,
NULL,
NULL,
LPBYTE(&m_fDebugServerOnStart),
&dw) != ERROR_SUCCESS)
{
m_fDebugServerOnStart = FALSE;
RegSetValueEx(
hkeyDebug,
g_szSpDebugServerOnStart,
NULL,
REG_DWORD,
LPBYTE(&m_fDebugServerOnStart),
sizeof(m_fDebugServerOnStart));
}
dw = sizeof(m_fDebugClientOnStart);
if (RegQueryValueEx(
hkeyDebug,
g_szSpDebugClientOnStart,
NULL,
NULL,
LPBYTE(&m_fDebugClientOnStart),
&dw) != ERROR_SUCCESS)
{
m_fDebugClientOnStart = FALSE;
RegSetValueEx(
hkeyDebug,
g_szSpDebugClientOnStart,
NULL,
REG_DWORD,
LPBYTE(&m_fDebugClientOnStart),
sizeof(m_fDebugClientOnStart));
}
RegCloseKey(hkeyDebug);
}
void ReadFor(
HKEY hkey,
const TCHAR * pszModeValueName,
const TCHAR * pszFileValueName,
DWORD * pdwModeValue,
TCHAR * pszFileValue,
DWORD dwDefaultModeValue,
const TCHAR * pszDefaultFileValue)
{
DWORD dw = sizeof(*pdwModeValue);
if (RegQueryValueEx(
hkey,
pszModeValueName,
NULL,
NULL,
LPBYTE(pdwModeValue),
&dw) != ERROR_SUCCESS)
{
*pdwModeValue = dwDefaultModeValue;
RegSetValueEx(
hkey,
pszModeValueName,
NULL,
REG_DWORD,
LPBYTE(pdwModeValue),
sizeof(*pdwModeValue));
}
dw = MAX_PATH;
if (RegQueryValueEx(
hkey,
pszFileValueName,
NULL,
NULL,
LPBYTE(pszFileValue),
&dw) != ERROR_SUCCESS)
{
_tcscpy(pszFileValue, pszDefaultFileValue);
RegSetValueEx(
hkey,
pszFileValueName,
NULL,
REG_SZ,
LPBYTE(pszFileValue),
MAX_PATH);
}
}
BOOL Enter(int reportType, DWORD &reportMode, TCHAR * pszFile)
{
if (reportMode != 0)
{
// We'll hold the mutex, until the caller also calls Leave
if (m_mutex == NULL)
{
m_mutex = CreateMutex(NULL, FALSE, _T("SpDebug"));
}
WaitForSingleObject(m_mutex, INFINITE);
m_reportType = reportType;
m_reportModePrev = _CrtSetReportMode(reportType, reportMode);
if (reportMode & _CRTDBG_MODE_FILE)
{
HANDLE hfile = CreateFile(
pszFile,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
0,
NULL);
SetFilePointer(hfile, 0, NULL, FILE_END);
m_hfilePrev = (_HFILE)_CrtSetReportFile(reportType, (_HFILE)hfile);
}
return TRUE;
}
return FALSE;
}
BOOL Leave()
{
int reportMode = _CrtSetReportMode(m_reportType, m_reportModePrev);
if (reportMode & _CRTDBG_MODE_FILE)
{
CloseHandle((_HFILE)_CrtSetReportFile(m_reportType, (_HFILE)m_hfilePrev));
}
ReleaseMutex(m_mutex);
return TRUE;
}
private:
HANDLE m_mutex;
int m_reportType;
int m_reportModePrev;
_HFILE m_hfilePrev;
BOOL m_fAssertSettingsReReadEachTime;
DWORD m_FuncTraceMode;
TCHAR m_szFuncTraceFile[MAX_PATH + 1];
DWORD m_ParamInfoMode;
TCHAR m_szParamInfoFile[MAX_PATH + 1];
DWORD m_DumpInfoMode;
TCHAR m_szDumpInfoFile[MAX_PATH + 1];
DWORD m_AssertMode;
TCHAR m_szAssertFile[MAX_PATH + 1];
DWORD m_HRFailMode;
TCHAR m_szHRFailFile[MAX_PATH + 1];
BOOL m_fDebugServerOnStart;
BOOL m_fDebugClientOnStart;
};
inline CSpDebug *PSpDebug()
{
static CSpDebug debug;
return &debug;
}
class CSpFuncTrace
{
public:
CSpFuncTrace(PCHAR pFuncName)
{
m_pFuncName = pFuncName;
if (PSpDebug()->FuncTrace())
{
_RPT1( _CRT_WARN, "\nEntering Function: %s\n", m_pFuncName );
PSpDebug()->FuncTrace(FALSE);
}
}
~CSpFuncTrace()
{
if (PSpDebug()->FuncTrace())
{
_RPT1( _CRT_WARN, "Leaving Function: %s\n", m_pFuncName );
PSpDebug()->FuncTrace(FALSE);
}
}
private:
PCHAR m_pFuncName;
};
#endif // _DEBUG
//=== User macros ==============================================================
#ifdef _DEBUG
#define SPDBG_FUNC(name) \
CSpFuncTrace functrace(name)
#if defined(ASSERT_WITH_STACK) && !defined(_WIN64)
#define SPDBG_REPORT_ON_FAIL(hr) \
do \
{ \
HRESULT _hr = (hr); \
if (FAILED(_hr) && PSpDebug()->HRFail()) \
{ \
SYSTEMTIME sysTime; \
GetLocalTime(&sysTime); \
CHAR pszHrWithTime[100]; \
sprintf(pszHrWithTime, "%lX\n\n%d.%d.%d %02d:%02d:%02d", \
_hr, \
sysTime.wMonth,sysTime.wDay,sysTime.wYear, \
sysTime.wHour,sysTime.wMinute,sysTime.wSecond); \
PCHAR pszStack = \
(PCHAR)_alloca( \
cchMaxAssertStackLevelStringLen * \
cfrMaxAssertStackLevels + 1); \
GetStringFromStackLevels(0, 10, pszStack); \
_RPT4(_CRT_WARN, \
"%s(%d): Failed HR = %s\n\n%s\n", \
__FILE__, \
__LINE__, \
pszHrWithTime, \
pszStack); \
PSpDebug()->HRFail(FALSE); \
} \
} while (0)
#else // ASSERT_WITH_STACK & !_WIN64
#define SPDBG_REPORT_ON_FAIL(hr) \
do \
{ \
HRESULT _hr = (hr); \
if (FAILED(_hr) && PSpDebug()->HRFail()) \
{ \
_RPT3(_CRT_WARN, "%s(%d): Failed HR = %lX\n", __FILE__, __LINE__, (_hr) );\
PSpDebug()->HRFail(FALSE); \
} \
} while (0)
#endif // ASSERT_WITH_STACK
#define SPDBG_ASSERT(expr) \
do \
{ \
if (!(expr)) \
{ \
if (PSpDebug()->Assert()) \
{ \
_ASSERTE( expr ); \
PSpDebug()->Assert(FALSE); \
} \
} \
} \
while (0)
#define SPDBG_VERIFY(expr) \
SPDBG_ASSERT(expr)
#define SPDBG_PMSG0(format) \
do \
{ \
if (PSpDebug()->ParamInfo()) \
{ \
_RPT0(_CRT_WARN, format); \
PSpDebug()->ParamInfo(FALSE); \
} \
} while (0)
#define SPDBG_PMSG1(format, arg1) \
do \
{ \
if (PSpDebug()->ParamInfo()) \
{ \
_RPT1(_CRT_WARN, format, arg1); \
PSpDebug()->ParamInfo(FALSE); \
} \
} while (0)
#define SPDBG_PMSG2(format, arg1, arg2) \
do \
{ \
if (PSpDebug()->ParamInfo()) \
{ \
_RPT2(_CRT_WARN, format, arg1, arg2); \
PSpDebug()->ParamInfo(FALSE); \
} \
} while (0)
#define SPDBG_PMSG3(format, arg1, arg2, arg3) \
do \
{ \
if (PSpDebug()->ParamInfo()) \
{ \
_RPT3(_CRT_WARN, format, arg1, arg2, arg3); \
PSpDebug()->ParamInfo(FALSE); \
} \
} while (0)
#define SPDBG_PMSG4(format, arg1, arg2, arg3, arg4) \
do \
{ \
if (PSpDebug()->ParamInfo()) \
{ \
_RPT4(_CRT_WARN, format, arg1, arg2, arg3, arg4); \
PSpDebug()->ParamInfo(FALSE); \
} \
} while (0)
#define SPDBG_DMSG0(format) \
do \
{ \
if (PSpDebug()->DumpInfo()) \
{ \
_RPT0(_CRT_WARN, format); \
PSpDebug()->DumpInfo(FALSE); \
} \
} while (0)
#define SPDBG_DMSG1(format, arg1) \
do \
{ \
if (PSpDebug()->DumpInfo()) \
{ \
_RPT1(_CRT_WARN, format, arg1); \
PSpDebug()->DumpInfo(FALSE); \
} \
} while (0)
#define SPDBG_DMSG2(format, arg1, arg2) \
do \
{ \
if (PSpDebug()->DumpInfo()) \
{ \
_RPT2(_CRT_WARN, format, arg1, arg2); \
PSpDebug()->DumpInfo(FALSE); \
} \
} while (0)
#define SPDBG_DMSG3(format, arg1, arg2, arg3) \
do \
{ \
if (PSpDebug()->DumpInfo()) \
{ \
_RPT3(_CRT_WARN, format, arg1, arg2, arg3); \
PSpDebug()->DumpInfo(FALSE); \
} \
} while (0)
#define SPDBG_DMSG4(format, arg1, arg2, arg3, arg4) \
do \
{ \
if (PSpDebug()->DumpInfo()) \
{ \
_RPT4(_CRT_WARN, format, arg1, arg2, arg3, arg4); \
PSpDebug()->DumpInfo(FALSE); \
} \
} while (0)
#define SPDBG_RETURN(hr) \
{ \
HRESULT __hr = (hr); \
if (FAILED(__hr)) \
{ \
SPDBG_REPORT_ON_FAIL(__hr); \
} \
return __hr; \
}
#define SPDBG_DEBUG_SERVER_ON_START() \
{ \
if (PSpDebug()->DebugServerOnStart()) \
{ \
if (MessageBox( \
GetDesktopWindow(), \
_T("Attach Debugger to the SAPI Server process?"), \
_T("SAPI"), \
MB_YESNO) == IDYES) \
{ \
USES_CONVERSION; \
TCHAR szCommand[MAX_PATH + 1]; \
wsprintf( \
szCommand, \
_T("msdev -p %d"), \
GetCurrentProcessId()); \
system(T2A(szCommand)); \
} \
} \
}
#define SPDBG_DEBUG_CLIENT_ON_START() \
{ \
if (PSpDebug()->DebugClientOnStart()) \
{ \
TCHAR szModule[MAX_PATH + 1]; \
szModule[0] = '\0'; \
TCHAR * pszSapiServer = \
_T("sapisvr.exe"); \
GetModuleFileName( \
NULL, \
szModule, \
MAX_PATH); \
if ((_tcslen(szModule) <= \
_tcslen(pszSapiServer) || \
_tcsicmp( \
szModule + \
_tcslen(szModule) - \
_tcslen(pszSapiServer), \
pszSapiServer) != 0) && \
MessageBox( \
GetDesktopWindow(), \
_T("Attach Debugger to the SAPI Client process?"), \
_T("SAPI"), \
MB_YESNO) == IDYES) \
{ \
USES_CONVERSION; \
TCHAR szCommand[MAX_PATH + 1]; \
wsprintf( \
szCommand, \
_T("msdev -p %d"), \
GetCurrentProcessId()); \
system(T2A(szCommand)); \
} \
} \
}
#else // _DEBUG
#define SPDBG_FUNC(name)
#define SPDBG_REPORT_ON_FAIL(hr)
#define SPDBG_ASSERT(expr)
#define SPDBG_VERIFY(expr) (expr)
#define SPDBG_PMSG0(format)
#define SPDBG_PMSG1(format, arg1)
#define SPDBG_PMSG2(format, arg1, arg2)
#define SPDBG_PMSG3(format, arg1, arg2, arg3)
#define SPDBG_PMSG4(format, arg1, arg2, arg3, arg4)
#define SPDBG_DMSG0(format)
#define SPDBG_DMSG1(format, arg1)
#define SPDBG_DMSG2(format, arg1, arg2)
#define SPDBG_DMSG3(format, arg1, arg2, arg3)
#define SPDBG_DMSG4(format, arg1, arg2, arg3, arg4)
#define SPDBG_RETURN(hr) return (hr)
#define SPDBG_DEBUG_SERVER_ON_START()
#define SPDBG_DEBUG_CLIENT_ON_START()
#endif // _DEBUG

View file

@ -0,0 +1,559 @@
/*******************************************************************************
* SPError.h *
*-----------*
* Description:
* This header file contains the custom error codes specific to SAPI5
*-------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
*******************************************************************************/
#ifndef SPError_h
#define SPError_h
#ifndef _WINERROR_
#include <winerror.h>
#endif
#define FACILITY_SAPI FACILITY_ITF
#define SAPI_ERROR_BASE 0x5000
#define MAKE_SAPI_HRESULT(sev, err) MAKE_HRESULT(sev, FACILITY_SAPI, err)
#define MAKE_SAPI_ERROR(err) MAKE_SAPI_HRESULT(SEVERITY_ERROR, err + SAPI_ERROR_BASE)
#define MAKE_SAPI_SCODE(scode) MAKE_SAPI_HRESULT(SEVERITY_SUCCESS, scode + SAPI_ERROR_BASE)
/*** SPERR_UNINITIALIZED 0x80045001 -2147201023
* The object has not been properly initialized.
*/
#define SPERR_UNINITIALIZED MAKE_SAPI_ERROR(0x001)
/*** SPERR_ALREADY_INITIALIZED 0x80045002 -2147201022
* The object has already been initialized.
*/
#define SPERR_ALREADY_INITIALIZED MAKE_SAPI_ERROR(0x002)
/*** SPERR_UNSUPPORTED_FORMAT 0x80045003 -2147201021
* The caller has specified an unsupported format.
*/
#define SPERR_UNSUPPORTED_FORMAT MAKE_SAPI_ERROR(0x003)
/*** SPERR_INVALID_FLAGS 0x80045004 -2147201020
* The caller has specified invalid flags for this operation.
*/
#define SPERR_INVALID_FLAGS MAKE_SAPI_ERROR(0x004)
/*** SP_END_OF_STREAM 0x00045005 282629
* The operation has reached the end of stream.
*/
#define SP_END_OF_STREAM MAKE_SAPI_SCODE(0x005)
/*** SPERR_DEVICE_BUSY 0x80045006 -2147201018
* The wave device is busy.
*/
#define SPERR_DEVICE_BUSY MAKE_SAPI_ERROR(0x006)
/*** SPERR_DEVICE_NOT_SUPPORTED 0x80045007 -2147201017
* The wave device is not supported.
*/
#define SPERR_DEVICE_NOT_SUPPORTED MAKE_SAPI_ERROR(0x007)
/*** SPERR_DEVICE_NOT_ENABLED 0x80045008 -2147201016
* The wave device is not enabled.
*/
#define SPERR_DEVICE_NOT_ENABLED MAKE_SAPI_ERROR(0x008)
/*** SPERR_NO_DRIVER 0x80045009 -2147201015
* There is no wave driver installed.
*/
#define SPERR_NO_DRIVER MAKE_SAPI_ERROR(0x009)
/*** SPERR_FILEMUSTBEUNICODE 0x8004500a -2147201014
* The file must be Unicode.
*/
#define SPERR_FILE_MUST_BE_UNICODE MAKE_SAPI_ERROR(0x00a)
/*** SP_INSUFFICIENTDATA 0x0004500b 282635
*
*/
#define SP_INSUFFICIENT_DATA MAKE_SAPI_SCODE(0x00b)
/*** SPERR_INVALID_PHRASE_ID 0x8004500c -2147201012
* The phrase ID specified does not exist or is out of range.
*/
#define SPERR_INVALID_PHRASE_ID MAKE_SAPI_ERROR(0x00c)
/*** SPERR_BUFFER_TOO_SMALL 0x8004500d -2147201011
* The caller provided a buffer too small to return a result.
*/
#define SPERR_BUFFER_TOO_SMALL MAKE_SAPI_ERROR(0x00d)
/*** SPERR_FORMAT_NOT_SPECIFIED 0x8004500e -2147201010
* Caller did not specify a format prior to opening a stream.
*/
#define SPERR_FORMAT_NOT_SPECIFIED MAKE_SAPI_ERROR(0x00e)
/*** SPERR_AUDIO_STOPPED 0x8004500f -2147201009
* This method is deprecated. Use SP_AUDIO_STOPPED instead.
*/
#define SPERR_AUDIO_STOPPED MAKE_SAPI_ERROR(0x00f)
/*** SP_AUDIO_PAUSED 0x00045010 282640
* This will be returned only on input (read) streams when the stream is paused. Reads on
* paused streams will not block, and this return code indicates that all of the data has been
* removed from the stream.
*/
#define SP_AUDIO_PAUSED MAKE_SAPI_SCODE(0x010)
/*** SPERR_RULE_NOT_FOUND 0x80045011 -2147201007
* Invalid rule name passed to ActivateGrammar.
*/
#define SPERR_RULE_NOT_FOUND MAKE_SAPI_ERROR(0x011)
/*** SPERR_TTS_ENGINE_EXCEPTION 0x80045012 -2147201006
* An exception was raised during a call to the current TTS driver.
*/
#define SPERR_TTS_ENGINE_EXCEPTION MAKE_SAPI_ERROR(0x012)
/*** SPERR_TTS_NLP_EXCEPTION 0x80045013 -2147201005
* An exception was raised during a call to an application sentence filter.
*/
#define SPERR_TTS_NLP_EXCEPTION MAKE_SAPI_ERROR(0x013)
/*** SPERR_ENGINE_BUSY 0x80045014 -2147201004
* In speech recognition, the current method can not be performed while
* a grammar rule is active.
*/
#define SPERR_ENGINE_BUSY MAKE_SAPI_ERROR(0x014)
/*** SP_AUDIO_CONVERSION_ENABLED 0x00045015 282645
* The operation was successful, but only with automatic stream format conversion.
*/
#define SP_AUDIO_CONVERSION_ENABLED MAKE_SAPI_SCODE(0x015)
/*** SP_NO_HYPOTHESIS_AVAILABLE 0x00045016 282646
* There is currently no hypothesis recognition available.
*/
#define SP_NO_HYPOTHESIS_AVAILABLE MAKE_SAPI_SCODE(0x016)
/*** SPERR_CANT_CREATE 0x80045017 -2147201001
* Can not create a new object instance for the specified object category.
*/
#define SPERR_CANT_CREATE MAKE_SAPI_ERROR(0x017)
/*** SP_ALREADY_IN_LEX 0x00045018 282648
* The word, pronunciation, or POS pair being added is already in lexicon.
*/
#define SP_ALREADY_IN_LEX MAKE_SAPI_SCODE(0x018)
/*** SPERR_NOT_IN_LEX 0x80045019 -2147200999
* The word does not exist in the lexicon.
*/
#define SPERR_NOT_IN_LEX MAKE_SAPI_ERROR(0x019)
/*** SP_LEX_NOTHING_TO_SYNC 0x0004501a 282650
* The client is currently synced with the lexicon.
*/
#define SP_LEX_NOTHING_TO_SYNC MAKE_SAPI_SCODE(0x01a)
/*** SPERR_LEX_VERY_OUT_OF_SYNC 0x8004501b -2147200997
* The client is excessively out of sync with the lexicon. Mismatches may not be incrementally sync'd.
*/
#define SPERR_LEX_VERY_OUT_OF_SYNC MAKE_SAPI_ERROR(0x01b)
/*** SPERR_UNDEFINED_FORWARD_RULE_REF 0x8004501c -2147200996
* A rule reference in a grammar was made to a named rule that was never defined.
*/
#define SPERR_UNDEFINED_FORWARD_RULE_REF MAKE_SAPI_ERROR(0x01c)
/*** SPERR_EMPTY_RULE 0x8004501d -2147200995
* A non-dynamic grammar rule that has no body.
*/
#define SPERR_EMPTY_RULE MAKE_SAPI_ERROR(0x01d)
/*** SPERR_GRAMMAR_COMPILER_INTERNAL_ERROR 0x8004501e -2147200994
* The grammar compiler failed due to an internal state error.
*/
#define SPERR_GRAMMAR_COMPILER_INTERNAL_ERROR MAKE_SAPI_ERROR(0x01e)
/*** SPERR_RULE_NOT_DYNAMIC 0x8004501f -2147200993
* An attempt was made to modify a non-dynamic rule.
*/
#define SPERR_RULE_NOT_DYNAMIC MAKE_SAPI_ERROR(0x01f)
/*** SPERR_DUPLICATE_RULE_NAME 0x80045020 -2147200992
* A rule name was duplicated.
*/
#define SPERR_DUPLICATE_RULE_NAME MAKE_SAPI_ERROR(0x020)
/*** SPERR_DUPLICATE_RESOURCE_NAME 0x80045021 -2147200991
* A resource name was duplicated for a given rule.
*/
#define SPERR_DUPLICATE_RESOURCE_NAME MAKE_SAPI_ERROR(0x021)
/*** SPERR_TOO_MANY_GRAMMARS 0x80045022 -2147200990
* Too many grammars have been loaded.
*/
#define SPERR_TOO_MANY_GRAMMARS MAKE_SAPI_ERROR(0x022)
/*** SPERR_CIRCULAR_REFERENCE 0x80045023 -2147200989
* Circular reference in import rules of grammars.
*/
#define SPERR_CIRCULAR_REFERENCE MAKE_SAPI_ERROR(0x023)
/*** SPERR_INVALID_IMPORT 0x80045024 -2147200988
* A rule reference to an imported grammar that could not be resolved.
*/
#define SPERR_INVALID_IMPORT MAKE_SAPI_ERROR(0x024)
/*** SPERR_INVALID_WAV_FILE 0x80045025 -2147200987
* The format of the WAV file is not supported.
*/
#define SPERR_INVALID_WAV_FILE MAKE_SAPI_ERROR(0x025)
/*** SP_REQUEST_PENDING 0x00045026 282662
* This success code indicates that an SR method called with the SPRIF_ASYNC flag is
* being processed. When it has finished processing, an SPFEI_ASYNC_COMPLETED event will be generated.
*/
#define SP_REQUEST_PENDING MAKE_SAPI_SCODE(0x026)
/*** SPERR_ALL_WORDS_OPTIONAL 0x80045027 -2147200985
* A grammar rule was defined with a null path through the rule. That is, it is possible
* to satisfy the rule conditions with no words.
*/
#define SPERR_ALL_WORDS_OPTIONAL MAKE_SAPI_ERROR(0x027)
/*** SPERR_INSTANCE_CHANGE_INVALID 0x80045028 -2147200984
* It is not possible to change the current engine or input. This occurs in the
* following cases:
*
* 1) SelectEngine called while a recognition context exists, or
* 2) SetInput called in the shared instance case.
*/
#define SPERR_INSTANCE_CHANGE_INVALID MAKE_SAPI_ERROR(0x028)
/*** SPERR_RULE_NAME_ID_CONFLICT 0x80045029 -2147200983
* A rule exists with matching IDs (names) but different names (IDs).
*/
#define SPERR_RULE_NAME_ID_CONFLICT MAKE_SAPI_ERROR(0x029)
/*** SPERR_NO_RULES 0x8004502a -2147200982
* A grammar contains no top-level, dynamic, or exported rules. There is no possible
* way to activate or otherwise use any rule in this grammar.
*/
#define SPERR_NO_RULES MAKE_SAPI_ERROR(0x02a)
/*** SPERR_CIRCULAR_RULE_REF 0x8004502b -2147200981
* Rule 'A' refers to a second rule 'B' which, in turn, refers to rule 'A'.
*/
#define SPERR_CIRCULAR_RULE_REF MAKE_SAPI_ERROR(0x02b)
/*** SP_NO_PARSE_FOUND 0x0004502c 282668
* Parse path cannot be parsed given the currently active rules.
*/
#define SP_NO_PARSE_FOUND MAKE_SAPI_SCODE(0x02c)
/*** SPERR_NO_PARSE_FOUND 0x8004502d -2147200979
* Parse path cannot be parsed given the currently active rules.
*/
#define SPERR_INVALID_HANDLE MAKE_SAPI_ERROR(0x02d)
/*** SPERR_REMOTE_CALL_TIMED_OUT 0x8004502e -2147200978
* A marshaled remote call failed to respond.
*/
#define SPERR_REMOTE_CALL_TIMED_OUT MAKE_SAPI_ERROR(0x02e)
/*** SPERR_AUDIO_BUFFER_OVERFLOW 0x8004502f -2147200977
* This will only be returned on input (read) streams when the stream is paused because
* the SR driver has not retrieved data recently.
*/
#define SPERR_AUDIO_BUFFER_OVERFLOW MAKE_SAPI_ERROR(0x02f)
/*** SPERR_NO_AUDIO_DATA 0x80045030 -2147200976
* The result does not contain any audio, nor does the portion of the element chain of the result
* contain any audio.
*/
#define SPERR_NO_AUDIO_DATA MAKE_SAPI_ERROR(0x030)
/*** SPERR_DEAD_ALTERNATE 0x80045031 -2147200975
* This alternate is no longer a valid alternate to the result it was obtained from.
* Returned from ISpPhraseAlt methods.
*/
#define SPERR_DEAD_ALTERNATE MAKE_SAPI_ERROR(0x031)
/*** SPERR_HIGH_LOW_CONFIDENCE 0x80045032 -2147200974
* The result does not contain any audio, nor does the portion of the element chain of the result
* contain any audio. Returned from ISpResult::GetAudio and ISpResult::SpeakAudio.
*/
#define SPERR_HIGH_LOW_CONFIDENCE MAKE_SAPI_ERROR(0x032)
/*** SPERR_INVALID_FORMAT_STRING 0x80045033 -2147200973
* The XML format string for this RULEREF is invalid, e.g. not a GUID or REFCLSID.
*/
#define SPERR_INVALID_FORMAT_STRING MAKE_SAPI_ERROR(0x033)
/*** SP_UNSUPPORTED_ON_STREAM_INPUT 0x00045034 282676
* The operation is not supported for stream input.
*/
#define SP_UNSUPPORTED_ON_STREAM_INPUT MAKE_SAPI_SCODE(0x034)
/*** SPERR_APPLEX_READ_ONLY 0x80045035 -2147200971
* The operation is invalid for all but newly created application lexicons.
*/
#define SPERR_APPLEX_READ_ONLY MAKE_SAPI_ERROR(0x035)
/*** SPERR_NO_TERMINATING_RULE_PATH 0x80045036 -2147200970
*
*/
#define SPERR_NO_TERMINATING_RULE_PATH MAKE_SAPI_ERROR(0x036)
/*** SP_WORD_EXISTS_WITHOUT_PRONUNCIATION 0x00045037 282679
* The word exists but without pronunciation.
*/
#define SP_WORD_EXISTS_WITHOUT_PRONUNCIATION MAKE_SAPI_SCODE(0x037)
/*** SPERR_STREAM_CLOSED 0x80045038 -2147200968
* An operation was attempted on a stream object that has been closed.
*/
#define SPERR_STREAM_CLOSED MAKE_SAPI_ERROR(0x038)
// --- The following error codes are taken directly from WIN32 ---
/*** SPERR_NO_MORE_ITEMS 0x80045039 -2147200967
* When enumerating items, the requested index is greater than the count of items.
*/
#define SPERR_NO_MORE_ITEMS MAKE_SAPI_ERROR(0x039)
/*** SPERR_NOT_FOUND 0x8004503a -2147200966
* The requested data item (data key, value, etc.) was not found.
*/
#define SPERR_NOT_FOUND MAKE_SAPI_ERROR(0x03a)
/*** SPERR_INVALID_AUDIO_STATE 0x8004503b -2147200965
* Audio state passed to SetState() is invalid.
*/
#define SPERR_INVALID_AUDIO_STATE MAKE_SAPI_ERROR(0x03b)
/*** SPERR_GENERIC_MMSYS_ERROR 0x8004503c -2147200964
* A generic MMSYS error not caught by _MMRESULT_TO_HRESULT.
*/
#define SPERR_GENERIC_MMSYS_ERROR MAKE_SAPI_ERROR(0x03c)
/*** SPERR_MARSHALER_EXCEPTION 0x8004503d -2147200963
* An exception was raised during a call to the marshaling code.
*/
#define SPERR_MARSHALER_EXCEPTION MAKE_SAPI_ERROR(0x03d)
/*** SPERR_NOT_DYNAMIC_GRAMMAR 0x8004503e -2147200962
* Attempt was made to manipulate a non-dynamic grammar.
*/
#define SPERR_NOT_DYNAMIC_GRAMMAR MAKE_SAPI_ERROR(0x03e)
/*** SPERR_AMBIGUOUS_PROPERTY 0x8004503f -2147200961
* Cannot add ambiguous property.
*/
#define SPERR_AMBIGUOUS_PROPERTY MAKE_SAPI_ERROR(0x03f)
/*** SPERR_INVALID_REGISTRY_KEY 0x80045040 -2147200960
* The key specified is invalid.
*/
#define SPERR_INVALID_REGISTRY_KEY MAKE_SAPI_ERROR(0x040)
/*** SPERR_INVALID_TOKEN_ID 0x80045041 -2147200959
* The token specified is invalid.
*/
#define SPERR_INVALID_TOKEN_ID MAKE_SAPI_ERROR(0x041)
/*** SPERR_XML_BAD_SYNTAX 0x80045042 -2147200958
* The xml parser failed due to bad syntax.
*/
#define SPERR_XML_BAD_SYNTAX MAKE_SAPI_ERROR(0x042)
/*** SPERR_XML_RESOURCE_NOT_FOUND 0x80045043 -2147200957
* The xml parser failed to load a required resource (e.g., voice, phoneconverter, etc.).
*/
#define SPERR_XML_RESOURCE_NOT_FOUND MAKE_SAPI_ERROR(0x043)
/*** SPERR_TOKEN_IN_USE 0x80045044 -2147200956
* Attempted to remove registry data from a token that is already in use elsewhere.
*/
#define SPERR_TOKEN_IN_USE MAKE_SAPI_ERROR(0x044)
/*** SPERR_TOKEN_DELETED 0x80045045 -2147200955
* Attempted to perform an action on an object token that has had associated registry key deleted.
*/
#define SPERR_TOKEN_DELETED MAKE_SAPI_ERROR(0x045)
/*** SPERR_MULTI_LINGUAL_NOT_SUPPORTED 0x80045046 -2147200954
* The selected voice was registered as multi-lingual. SAPI does not support multi-lingual registration.
*/
#define SPERR_MULTI_LINGUAL_NOT_SUPPORTED MAKE_SAPI_ERROR(0x046)
/*** SPERR_EXPORT_DYNAMIC_RULE 0x80045047 -2147200953
* Exported rules cannot refer directly or indirectly to a dynamic rule.
*/
#define SPERR_EXPORT_DYNAMIC_RULE MAKE_SAPI_ERROR(0x047)
/*** SPERR_STGF_ERROR 0x80045048 -2147200952
* Error parsing the SAPI Text Grammar Format (XML grammar).
*/
#define SPERR_STGF_ERROR MAKE_SAPI_ERROR(0x048)
/*** SPERR_WORDFORMAT_ERROR 0x80045049 -2147200951
* Incorrect word format, probably due to incorrect pronunciation string.
*/
#define SPERR_WORDFORMAT_ERROR MAKE_SAPI_ERROR(0x049)
/*** SPERR_STREAM_NOT_ACTIVE 0x8004504a -2147200950
* Methods associated with active audio stream cannot be called unless stream is active.
*/
#define SPERR_STREAM_NOT_ACTIVE MAKE_SAPI_ERROR(0x04a)
/*** SPERR_ENGINE_RESPONSE_INVALID 0x8004504b -2147200949
* Arguments or data supplied by the engine are in an invalid format or are inconsistent.
*/
#define SPERR_ENGINE_RESPONSE_INVALID MAKE_SAPI_ERROR(0x04b)
/*** SPERR_SR_ENGINE_EXCEPTION 0x8004504c -2147200948
* An exception was raised during a call to the current SR engine.
*/
#define SPERR_SR_ENGINE_EXCEPTION MAKE_SAPI_ERROR(0x04c)
/*** SPERR_STREAM_POS_INVALID 0x8004504d -2147200947
* Stream position information supplied from engine is inconsistent.
*/
#define SPERR_STREAM_POS_INVALID MAKE_SAPI_ERROR(0x04d)
/*** SP_RECOGNIZER_INACTIVE 0x0004504e 282702
* Operation could not be completed because the recognizer is inactive. It is inactive either
* because the recognition state is currently inactive or because no rules are active .
*/
#define SP_RECOGNIZER_INACTIVE MAKE_SAPI_SCODE(0x04e)
/*** SPERR_REMOTE_CALL_ON_WRONG_THREAD 0x8004504f -2147200945
* When making a remote call to the server, the call was made on the wrong thread.
*/
#define SPERR_REMOTE_CALL_ON_WRONG_THREAD MAKE_SAPI_ERROR(0x04f)
/*** SPERR_REMOTE_PROCESS_TERMINATED 0x80045050 -2147200944
* The remote process terminated unexpectedly.
*/
#define SPERR_REMOTE_PROCESS_TERMINATED MAKE_SAPI_ERROR(0x050)
/*** SPERR_REMOTE_PROCESS_ALREADY_RUNNING 0x80045051 -2147200943
* The remote process is already running; it cannot be started a second time.
*/
#define SPERR_REMOTE_PROCESS_ALREADY_RUNNING MAKE_SAPI_ERROR(0x051)
/*** SPERR_LANGID_MISMATCH 0x80045052 -2147200942
* An attempt to load a CFG grammar with a LANGID different than other loaded grammars.
*/
#define SPERR_LANGID_MISMATCH MAKE_SAPI_ERROR(0x052)
/*** SP_PARTIAL_PARSE_FOUND 0x00045053 282707
* A grammar-ending parse has been found that does not use all available words.
*/
#define SP_PARTIAL_PARSE_FOUND MAKE_SAPI_SCODE(0x053)
/*** SPERR_NOT_TOPLEVEL_RULE 0x80045054 -2147200940
* An attempt to deactivate or activate a non-toplevel rule.
*/
#define SPERR_NOT_TOPLEVEL_RULE MAKE_SAPI_ERROR(0x054)
/*** SP_NO_RULE_ACTIVE 0x00045055 282709
* An attempt to parse when no rule was active.
*/
#define SP_NO_RULE_ACTIVE MAKE_SAPI_SCODE(0x055)
/*** SPERR_LEX_REQUIRES_COOKIE 0x80045056 -2147200938
* An attempt to ask a container lexicon for all words at once.
*/
#define SPERR_LEX_REQUIRES_COOKIE MAKE_SAPI_ERROR(0x056)
/*** SP_STREAM_UNINITIALIZED 0x00045057 282711
* An attempt to activate a rule/dictation/etc without calling SetInput
* first in the inproc case.
*/
#define SP_STREAM_UNINITIALIZED MAKE_SAPI_SCODE(0x057)
// Error x058 is not used in SAPI 5.0
/*** SPERR_UNSUPPORTED_LANG 0x80045059 -2147200935
* The requested language is not supported.
*/
#define SPERR_UNSUPPORTED_LANG MAKE_SAPI_ERROR(0x059)
/*** SPERR_VOICE_PAUSED 0x8004505a -2147200934
* The operation cannot be performed because the voice is currently paused.
*/
#define SPERR_VOICE_PAUSED MAKE_SAPI_ERROR(0x05a)
/*** SPERR_AUDIO_BUFFER_UNDERFLOW 0x8004505b -2147200933
* This will only be returned on input (read) streams when the real time audio device
* stops returning data for a long period of time.
*/
#define SPERR_AUDIO_BUFFER_UNDERFLOW MAKE_SAPI_ERROR(0x05b)
/*** SPERR_AUDIO_STOPPED_UNEXPECTEDLY 0x8004505c -2147200932
* An audio device stopped returning data from the Read() method even though it was in
* the run state. This error is only returned in the END_SR_STREAM event.
*/
#define SPERR_AUDIO_STOPPED_UNEXPECTEDLY MAKE_SAPI_ERROR(0x05c)
/*** SPERR_NO_WORD_PRONUNCIATION 0x8004505d -2147200931
* The SR engine is unable to add this word to a grammar. The application may need to supply
* an explicit pronunciation for this word.
*/
#define SPERR_NO_WORD_PRONUNCIATION MAKE_SAPI_ERROR(0x05d)
/*** SPERR_ALTERNATES_WOULD_BE_INCONSISTENT 0x8004505e -2147200930
* An attempt to call ScaleAudio on a recognition result having previously
* called GetAlternates. Allowing the call to succeed would result in
* the previously created alternates located in incorrect audio stream positions.
*/
#define SPERR_ALTERNATES_WOULD_BE_INCONSISTENT MAKE_SAPI_ERROR(0x05e)
/*** SPERR_NOT_SUPPORTED_FOR_SHARED_RECOGNIZER 0x8004505f -2147200929
* The method called is not supported for the shared recognizer.
* For example, ISpRecognizer::GetInputStream().
*/
#define SPERR_NOT_SUPPORTED_FOR_SHARED_RECOGNIZER MAKE_SAPI_ERROR(0x05f)
/*** SPERR_TIMEOUT 0x80045060 -2147200928
* A task could not complete because the SR engine had timed out.
*/
#define SPERR_TIMEOUT MAKE_SAPI_ERROR(0x060)
/*** SPERR_REENTER_SYNCHRONIZE 0x80045061 -2147200927
* A SR engine called synchronize while inside of a synchronize call.
*/
#define SPERR_REENTER_SYNCHRONIZE MAKE_SAPI_ERROR(0x061)
/*** SPERR_STATE_WITH_NO_ARCS 0x80045062 -2147200926
* The grammar contains a node no arcs.
*/
#define SPERR_STATE_WITH_NO_ARCS MAKE_SAPI_ERROR(0x062)
/*** SPERR_NOT_ACTIVE_SESSION 0x80045063 -2147200925
* Neither audio output and input is supported for non-active console sessions.
*/
#define SPERR_NOT_ACTIVE_SESSION MAKE_SAPI_ERROR(0x063)
/*** SPERR_ALREADY_DELETED 0x80045064 -2147200924
* The object is a stale reference and is invalid to use.
* For example having a ISpeechGrammarRule object reference and then calling
* ISpeechRecoGrammar::Reset() will cause the rule object to be invalidated.
* Calling any methods after this will result in this error.
*/
#define SPERR_ALREADY_DELETED MAKE_SAPI_ERROR(0x064)
/*** SP_AUDIO_STOPPED 0x00045065 282725
* This can be returned from Read or Write calls audio streams when the stream is stopped.
*/
#define SP_AUDIO_STOPPED MAKE_SAPI_SCODE(0x065)
#endif //--- This must be the last line in the file

View file

@ -0,0 +1,605 @@
/*******************************************************************************
* SPEventQ.h *
*------------*
* Description:
* This is the header file for the SAPI5 event queue implementation.
*-------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
*******************************************************************************/
#ifndef SPEventQ_h
#define SPEventQ_h
#ifndef SPHelper_h
#include <SPHelper.h>
#endif
#ifndef SPCollec_h
#include <SPCollec.h>
#endif
//=== Inline helpers for copying and deleting events ============================
//=== Class definition ==========================================================
class CSpEventNode : public CSpEvent
{
public:
CSpEventNode * m_pNext;
static LONG Compare(const CSpEventNode * p1, const CSpEventNode *p2)
{
// Assumes offsets DO or DO NOT reset when stream number changes
if (p1->ulStreamNum < p2->ulStreamNum)
{
return -1;
}
else if (p1->ulStreamNum > p2->ulStreamNum)
{
return 1;
}
else if (p1->ullAudioStreamOffset < p2->ullAudioStreamOffset)
{
return -1;
}
else if (p1->ullAudioStreamOffset > p2->ullAudioStreamOffset)
{
return 1;
}
return 0;
}
};
typedef CSpBasicQueue<CSpEventNode, TRUE, TRUE> CSpEventList;
#define DECLARE_SPNOTIFYSOURCE_METHODS(T) \
STDMETHODIMP SetNotifySink(ISpNotifySink * pNotifySink) \
{ return T._SetNotifySink(pNotifySink); } \
STDMETHODIMP SetNotifyWindowMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) \
{ return T._SetNotifyWindowMessage(hWnd, Msg, wParam, lParam); } \
STDMETHODIMP SetNotifyCallbackFunction(SPNOTIFYCALLBACK * pfnCallback, WPARAM wParam, LPARAM lParam) \
{ return T._SetNotifyCallbackFunction(pfnCallback, wParam, lParam); } \
STDMETHODIMP SetNotifyCallbackInterface(ISpNotifyCallback * pSpCallback, WPARAM wParam, LPARAM lParam) \
{ return T._SetNotifyCallbackInterface(pSpCallback, wParam, lParam); } \
STDMETHODIMP SetNotifyWin32Event() \
{ return T._SetNotifyWin32Event(); } \
STDMETHODIMP WaitForNotifyEvent(DWORD dwMilliseconds) \
{ return T._WaitForNotifyEvent(dwMilliseconds); } \
STDMETHODIMP_(HANDLE) GetNotifyEventHandle() \
{ return T._GetNotifyEventHandle(); }
#define DECLARE_SPEVENTSOURCE_METHODS(T) \
DECLARE_SPNOTIFYSOURCE_METHODS(T) \
STDMETHODIMP SetInterest(ULONGLONG ullEventInterest, ULONGLONG ullQueuedInterest) \
{ return T._SetInterest(ullEventInterest, ullQueuedInterest); } \
STDMETHODIMP GetEvents(ULONG ulCount, SPEVENT* pEventArray, ULONG * pulFetched) \
{ return T._GetEvents(ulCount, pEventArray, pulFetched); } \
STDMETHODIMP GetInfo(SPEVENTSOURCEINFO *pInfo) \
{ return T._GetInfo(pInfo); }
class CSpEventSource
{
public:
CSpEventSource(CComObjectRootEx<CComMultiThreadModel> * pParent) :
m_pParent(pParent)
{
m_ullEventInterest = 0; m_ullQueuedInterest = 0;
m_ulStreamNum = 0;
}
HRESULT _SetNotifySink(ISpNotifySink * pNotifySink);
HRESULT _SetNotifyWindowMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
HRESULT _SetNotifyCallbackFunction(SPNOTIFYCALLBACK * pfnCallback, WPARAM wParam, LPARAM lParam);
HRESULT _SetNotifyCallbackInterface(ISpNotifyCallback * pSpCallback, WPARAM wParam, LPARAM lParam);
HRESULT _SetNotifyWin32Event();
HRESULT _WaitForNotifyEvent(DWORD dwMilliseconds);
HANDLE _GetNotifyEventHandle();
HRESULT _SetInterest(ULONGLONG ullEventInterest , ULONGLONG ullQueuedInterest);
HRESULT _GetEvents( ULONG ulCount, SPEVENT* pEventArray, ULONG * pulFetched );
HRESULT _GetInfo(SPEVENTSOURCEINFO *pInfo );
/*--- Non interface methods ---*/
HRESULT _CompleteEvents( ULONGLONG ullPos = 0xFFFFFFFFFFFFFFFF );
inline void _MoveAllToFreeList(CSpEventList * pList);
inline void _RemoveAllEvents();
inline HRESULT _AddEvent(const SPEVENT & Event);
inline HRESULT _AddEvents(const SPEVENT* pEventArray, ULONG ulCount);
inline HRESULT _DeserializeAndAddEvent(const BYTE * pBuffer, ULONG * pcbUsed);
inline HRESULT _GetStreamNumber(const ULONGLONG ullAudioOffset, ULONG *pulStreamNum);
//=== Data members ==============================
public:
ULONGLONG m_ullEventInterest;
ULONGLONG m_ullQueuedInterest;
ULONG m_ulStreamNum;
CSpEventList m_PendingList;
CSpEventList m_CompletedList;
CSpEventList m_FreeList;
CComPtr<ISpNotifySink> m_cpNotifySink;
CComPtr<ISpNotifyTranslator> m_cpEventTranslator; // If non-NULL then Win32 events being used
CComObjectRootEx<CComMultiThreadModel> * m_pParent;
CComAutoCriticalSection m_NotifyObjChangeCrit; // Critical section used to make sure that
// the notify object (m_cpNotifySink) not changed
// while waiting on it.
};
//
//=== Inlines =========================================================
//
//
// WARNING: If this logic changes, you will need to change the logic in SetNotifyWin32Event also.
//
inline HRESULT CSpEventSource::_SetNotifySink(ISpNotifySink * pNotifySink)
{
if (SP_IS_BAD_OPTIONAL_INTERFACE_PTR(pNotifySink))
{
return E_INVALIDARG;
}
else
{
m_pParent->Lock();
m_NotifyObjChangeCrit.Lock();
m_cpEventTranslator.Release();
m_cpNotifySink = pNotifySink;
if (m_cpNotifySink && m_CompletedList.GetHead())
{
m_cpNotifySink->Notify();
}
m_NotifyObjChangeCrit.Unlock();
m_pParent->Unlock();
return S_OK;
}
}
/****************************************************************************
* CSpEventSource::_SetNotifyWindowMessage *
*-----------------------------------------*
* Description:
*
* Returns:
*
********************************************************************* RAL ***/
inline HRESULT CSpEventSource::_SetNotifyWindowMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
SPDBG_FUNC("CSpEventSource::_SetNotifyWindowMessage");
HRESULT hr = S_OK;
CComPtr<ISpNotifyTranslator> cpTranslator;
hr = cpTranslator.CoCreateInstance(CLSID_SpNotifyTranslator);
if (SUCCEEDED(hr))
{
hr = cpTranslator->InitWindowMessage(hWnd, Msg, wParam, lParam);
}
if (SUCCEEDED(hr))
{
hr = _SetNotifySink(cpTranslator);
}
return hr;
}
/****************************************************************************
* CSpEventSource::_SetNotifyCallbackFunction *
*--------------------------------------------*
* Description:
*
* Returns:
*
********************************************************************* RAL ***/
inline HRESULT CSpEventSource::_SetNotifyCallbackFunction(SPNOTIFYCALLBACK * pfnCallback, WPARAM wParam, LPARAM lParam)
{
SPDBG_FUNC("CSpEventSource::_SetNotifyCallbackFunction");
HRESULT hr = S_OK;
CComPtr<ISpNotifyTranslator> cpTranslator;
hr = cpTranslator.CoCreateInstance(CLSID_SpNotifyTranslator);
if (SUCCEEDED(hr))
{
hr = cpTranslator->InitCallback(pfnCallback, wParam, lParam);
}
if (SUCCEEDED(hr))
{
hr = _SetNotifySink(cpTranslator);
}
return hr;
}
/****************************************************************************
* CSpEventSource::_SetNotifyCallbackInterface *
*---------------------------------------------*
* Description:
*
* Returns:
*
********************************************************************* RAL ***/
inline HRESULT CSpEventSource::_SetNotifyCallbackInterface(ISpNotifyCallback * pSpCallback, WPARAM wParam, LPARAM lParam)
{
SPDBG_FUNC("CSpEventSource::_SetNotifyCallbackInterface");
HRESULT hr = S_OK;
CComPtr<ISpNotifyTranslator> cpTranslator;
hr = cpTranslator.CoCreateInstance(CLSID_SpNotifyTranslator);
if (SUCCEEDED(hr))
{
hr = cpTranslator->InitSpNotifyCallback(pSpCallback, wParam, lParam);
}
if (SUCCEEDED(hr))
{
hr = _SetNotifySink(cpTranslator);
}
return hr;
}
/****************************************************************************
* CSpEventSource::_SetNotifyWin32Event *
*--------------------------------------*
* Description:
*
* Returns:
*
********************************************************************* RAL ***/
inline HRESULT CSpEventSource::_SetNotifyWin32Event(void)
{
SPDBG_FUNC("CSpEventSource::_SetNotifyWin32Event");
HRESULT hr = S_OK;
CComPtr<ISpNotifyTranslator> cpTranslator;
hr = cpTranslator.CoCreateInstance(CLSID_SpNotifyTranslator);
if (SUCCEEDED(hr))
{
hr = cpTranslator->InitWin32Event(NULL, TRUE);
}
if (SUCCEEDED(hr))
{
//
// In this case we do NOT call _SetNotify sink since we want to set the cpEventTranslator
//
m_pParent->Lock();
m_NotifyObjChangeCrit.Lock();
m_cpEventTranslator = cpTranslator;
m_cpNotifySink = cpTranslator;
if (m_cpNotifySink && m_CompletedList.GetHead())
{
m_cpNotifySink->Notify();
}
m_NotifyObjChangeCrit.Unlock();
m_pParent->Unlock();
}
return hr;
}
/****************************************************************************
* CSpEventSource::_WaitForNotifyEvent *
*-------------------------------------*
* Description:
*
* Returns:
*
********************************************************************* RAL ***/
inline HRESULT CSpEventSource::_WaitForNotifyEvent(DWORD dwMilliseconds)
{
SPDBG_FUNC("CSpEventSource::_WaitForNotifyEvent");
HRESULT hr = S_OK;
m_NotifyObjChangeCrit.Lock();
if (m_cpEventTranslator)
{
hr = m_cpEventTranslator->Wait(dwMilliseconds);
}
else
{
if (m_cpNotifySink)
{
hr = SPERR_ALREADY_INITIALIZED;
}
else
{
hr = _SetNotifyWin32Event();
if (SUCCEEDED(hr))
{
hr = m_cpEventTranslator->Wait(dwMilliseconds);
}
}
}
m_NotifyObjChangeCrit.Unlock();
return hr;
}
/****************************************************************************
* CSpEventSource::_GetNotifyEventHandle *
*---------------------------------------*
* Description:
*
* Returns:
*
********************************************************************* RAL ***/
inline HANDLE CSpEventSource::_GetNotifyEventHandle()
{
HANDLE h = NULL;
SPDBG_FUNC("CSpEventSource::_GetNotifyEventHandle");
m_NotifyObjChangeCrit.Lock();
if (!m_cpNotifySink)
{
_SetNotifyWin32Event();
}
if (m_cpEventTranslator)
{
h = m_cpEventTranslator->GetEventHandle();
}
m_NotifyObjChangeCrit.Unlock();
return h;
}
inline HRESULT CSpEventSource::_SetInterest( ULONGLONG ullEventInterest, ULONGLONG ullQueuedInterest )
{
HRESULT hr = S_OK;
m_pParent->Lock();
if(ullEventInterest && SPFEI_FLAGCHECK != (ullEventInterest & SPFEI_FLAGCHECK))
{
hr = E_INVALIDARG;
}
else if(ullQueuedInterest && SPFEI_FLAGCHECK != (ullQueuedInterest & SPFEI_FLAGCHECK))
{
hr = E_INVALIDARG;
}
else if ((ullQueuedInterest | ullEventInterest) != ullEventInterest)
{
hr = E_INVALIDARG;
}
else
{
m_ullEventInterest = ullEventInterest;
m_ullQueuedInterest = ullQueuedInterest;
}
m_pParent->Unlock();
return hr;
}
//
// Same as AddEvents except: No param validation, and caller must take the critical section
// prior to calling.
//
inline HRESULT CSpEventSource::_AddEvents( const SPEVENT* pEventArray, ULONG ulCount )
{
HRESULT hr = S_OK;
for( ULONG i = 0; i < ulCount && SUCCEEDED(hr = _AddEvent(pEventArray[i])); ++i ) {}
return hr;
}
inline HRESULT CSpEventSource::_AddEvent(const SPEVENT & Event)
{
SPDBG_ASSERT(Event.eEventId < 64);
SPDBG_ASSERT(Event.elParamType == SPET_LPARAM_IS_UNDEFINED ||
Event.elParamType == SPET_LPARAM_IS_TOKEN ||
Event.elParamType == SPET_LPARAM_IS_OBJECT ||
Event.elParamType == SPET_LPARAM_IS_POINTER ||
Event.elParamType == SPET_LPARAM_IS_STRING);
#ifdef _DEBUG
if (Event.eEventId == SPEI_VOICE_CHANGE)
{
SPDBG_ASSERT(Event.elParamType == SPET_LPARAM_IS_TOKEN);
}
else if (Event.eEventId == SPEI_RECOGNITION || Event.eEventId == SPEI_FALSE_RECOGNITION || Event.eEventId == SPEI_HYPOTHESIS)
{
SPDBG_ASSERT(Event.elParamType == SPET_LPARAM_IS_OBJECT);
}
else if (Event.eEventId ==SPEI_REQUEST_UI || Event.eEventId == SPEI_TTS_BOOKMARK)
{
SPDBG_ASSERT(Event.elParamType == SPET_LPARAM_IS_STRING);
}
#endif
if ( (1i64 << Event.eEventId) & m_ullEventInterest )
{
CSpEventNode *pNode = m_FreeList.RemoveHead();
if (pNode == NULL)
{
pNode = new CSpEventNode();
if (pNode == NULL)
{
return E_OUTOFMEMORY;
}
}
pNode->CopyFrom(&Event);
m_PendingList.InsertSorted(pNode);
}
return S_OK;
}
inline HRESULT CSpEventSource::
_DeserializeAndAddEvent(const BYTE *pBuffer, ULONG * pcbUsed)
{
HRESULT hr = S_OK;
const SPEVENT * pSrcEvent = (const SPEVENT *)pBuffer;
SPDBG_ASSERT(pSrcEvent->eEventId < 64);
if ( (1i64 << pSrcEvent->eEventId) & m_ullEventInterest )
{
CSpEventNode *pNode = m_FreeList.RemoveHead();
if (pNode == NULL)
{
pNode = new CSpEventNode();
if (pNode == NULL)
{
hr = E_OUTOFMEMORY;
}
}
if (SUCCEEDED(hr))
{
hr = pNode->Deserialize(((const SPSERIALIZEDEVENT64 *)(pBuffer)), pcbUsed);
if (SUCCEEDED(hr))
{
m_PendingList.InsertSorted(pNode);
}
else
{
m_FreeList.InsertHead(pNode);
}
}
}
else
{
// WCE compiler does not work propertly with template
#ifndef _WIN32_WCE
*pcbUsed = SpEventSerializeSize<SPSERIALIZEDEVENT64>(pSrcEvent);
#else
*pcbUsed = SpEventSerializeSize(pSrcEvent, sizeof(SPSERIALIZEDEVENT64));
#endif
}
return hr;
}
inline HRESULT CSpEventSource::_GetEvents( ULONG ulCount, SPEVENT* pEventArray, ULONG *pulFetched )
{
HRESULT hr = S_OK;
m_pParent->Lock();
if( SPIsBadWritePtr( pEventArray, sizeof( SPEVENT ) * ulCount ) ||
SP_IS_BAD_OPTIONAL_WRITE_PTR(pulFetched) )
{
hr = E_INVALIDARG;
}
else
{
ULONG ulCopied = 0;
ULONG ulRemaining = ulCount;
CSpEventNode * pCur = m_CompletedList.m_pHead;
CSpEventNode * pLastCopied = NULL;
while (ulRemaining && pCur)
{
pCur->Detach(pEventArray + ulCopied);
pLastCopied = pCur;
ulCopied++;
pCur = pCur->m_pNext;
ulRemaining--;
}
if (ulCopied)
{
if (m_FreeList.m_pHead == NULL)
{
m_FreeList.m_pTail = pLastCopied;
}
pLastCopied->m_pNext = m_FreeList.m_pHead;
m_FreeList.m_pHead = m_CompletedList.m_pHead;
m_CompletedList.m_pHead = pCur;
m_CompletedList.m_cElements -= ulCopied;
m_FreeList.m_cElements += ulCopied;
}
if (ulCopied < ulCount)
{
hr = S_FALSE;
}
if (pulFetched)
{
*pulFetched = ulCopied;
}
}
m_pParent->Unlock();
return hr;
}
inline HRESULT CSpEventSource::_GetInfo( SPEVENTSOURCEINFO * pInfo )
{
HRESULT hr = S_OK;
m_pParent->Lock();
if( SP_IS_BAD_WRITE_PTR( pInfo ) )
{
hr = E_POINTER;
}
else
{
pInfo->ulCount = m_CompletedList.GetCount();
pInfo->ullEventInterest = m_ullEventInterest;
pInfo->ullQueuedInterest= m_ullQueuedInterest;
}
m_pParent->Unlock();
return hr;
}
//
// The caller must call this function with the critical section owned
//
inline HRESULT CSpEventSource::_CompleteEvents( ULONGLONG ullPos )
{
HRESULT hr = S_OK;
if (m_PendingList.m_pHead && m_PendingList.m_pHead->ullAudioStreamOffset <= ullPos)
{
BOOL bNotify = FALSE;
while (m_PendingList.m_pHead &&
m_PendingList.m_pHead->ullAudioStreamOffset <= ullPos)
{
CSpEventNode *pNode = m_PendingList.RemoveHead();
if(pNode->ulStreamNum != m_ulStreamNum)
{
m_ulStreamNum = pNode->ulStreamNum;
}
if ( (1i64 << pNode->eEventId) & m_ullEventInterest )
{
bNotify = TRUE;
//
// NOTE: If we're forwarding events to an event sink then we'll only
// pay attention to the Interest flags. If we're going to notify, then
// we'll only queue completed events that the user has explicitly asked
// us to store as completed events.
//
if ( (1i64 << pNode->eEventId) & m_ullQueuedInterest )
{
m_CompletedList.InsertSorted(pNode);
}
else
{
pNode->Clear();
m_FreeList.InsertHead(pNode);
}
}
else
{
pNode->Clear();
m_FreeList.InsertHead(pNode);
}
}
if (bNotify && m_cpNotifySink)
{
hr = m_cpNotifySink->Notify();
}
}
return hr;
};
inline void CSpEventSource::_MoveAllToFreeList(CSpEventList * pList)
{
CSpEventNode * pNode;
while ((pNode = pList->RemoveHead()) != NULL)
{
pNode->Clear();
m_FreeList.InsertHead(pNode);
}
}
inline void CSpEventSource::_RemoveAllEvents( )
{
m_pParent->Lock();
_MoveAllToFreeList(&m_CompletedList);
_MoveAllToFreeList(&m_PendingList);
m_pParent->Unlock();
}
inline HRESULT CSpEventSource::_GetStreamNumber(const ULONGLONG ullAudioOffset, ULONG *pulStreamNum)
{
CSpEventNode *pNode = m_PendingList.m_pHead;
*pulStreamNum = m_ulStreamNum;
for(;pNode && pNode->ullAudioStreamOffset <= ullAudioOffset; pNode = pNode->m_pNext)
{
*pulStreamNum = pNode->ulStreamNum;
}
return S_OK;
}
#endif //--- This must be the last line in this file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,253 @@
/*******************************************************************************
* SPUIHelp.h *
*------------*
* Description:
* This is the header file for user-interface helper functions. Note that
* unlike SpHelper.H, this file requires the use of ATL.
*-------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
*******************************************************************************/
#ifndef SPUIHelp_h
#define SPUIHelp_h
#ifndef __sapi_h__
#include <sapi.h>
#endif
#ifndef SPError_h
#include <SPError.h>
#endif
#ifndef SPDebug_h
#include <SPDebug.h>
#endif
#ifndef SPHelper_h
#include <SPHelper.h>
#endif
#ifndef __ATLBASE_H__
#include <ATLBASE.h>
#endif
#ifndef __ATLCONV_H__
#include <ATLCONV.H>
#endif
/****************************************************************************
*
*
*
********************************************************************* RAL ***/
//
// Dont call this function directly. Use SpInitTokenComboBox or SpInitTokenListBox.
//
inline HRESULT SpInitTokenList(UINT MsgAddString, UINT MsgSetItemData, UINT MsgSetCurSel,
HWND hwnd, const WCHAR * pszCatName,
const WCHAR * pszRequiredAttrib, const WCHAR * pszOptionalAttrib)
{
HRESULT hr;
ISpObjectToken * pToken; // NOTE: Not a CComPtr! Be Careful.
CComPtr<IEnumSpObjectTokens> cpEnum;
hr = SpEnumTokens(pszCatName, pszRequiredAttrib, pszOptionalAttrib, &cpEnum);
if (hr == S_OK)
{
bool fSetDefault = false;
while (cpEnum->Next(1, &pToken, NULL) == S_OK)
{
CSpDynamicString dstrDesc;
hr = SpGetDescription(pToken, &dstrDesc);
if (SUCCEEDED(hr))
{
USES_CONVERSION;
LRESULT i = ::SendMessage(hwnd, MsgAddString, 0, (LPARAM)W2T(dstrDesc));
if (i == CB_ERR || i == CB_ERRSPACE) // Note: CB_ and LB_ errors are identical values...
{
hr = E_OUTOFMEMORY;
}
else
{
::SendMessage(hwnd, MsgSetItemData, i, (LPARAM)pToken);
if (!fSetDefault)
{
::SendMessage(hwnd, MsgSetCurSel, i, 0);
fSetDefault = true;
}
}
}
if (FAILED(hr))
{
pToken->Release();
}
}
}
else
{
hr = SPERR_NO_MORE_ITEMS;
}
return hr;
}
inline HRESULT SpInitTokenComboBox(HWND hwnd, const WCHAR * pszCatName,
const WCHAR * pszRequiredAttrib = NULL, const WCHAR * pszOptionalAttrib = NULL)
{
return SpInitTokenList(CB_ADDSTRING, CB_SETITEMDATA, CB_SETCURSEL, hwnd, pszCatName, pszRequiredAttrib, pszOptionalAttrib);
}
inline HRESULT SpInitTokenListBox(HWND hwnd, const WCHAR * pszCatName,
const WCHAR * pszRequiredAttrib = NULL, const WCHAR * pszOptionalAttrib = NULL)
{
return SpInitTokenList(LB_ADDSTRING, LB_SETITEMDATA, LB_SETCURSEL, hwnd, pszCatName, pszRequiredAttrib, pszOptionalAttrib);
}
//
// Dont call this function directly. Use SpDestoyTokenComboBox or SpDestroyTokenListBox.
//
inline void SpDestroyTokenList(UINT MsgGetCount, UINT MsgGetItemData, HWND hwnd)
{
LRESULT c = ::SendMessage(hwnd, MsgGetCount, 0, 0);
for (LRESULT i = 0; i < c; i++)
{
IUnknown * pUnkObj = (IUnknown *)::SendMessage(hwnd, MsgGetItemData, i, 0);
if (pUnkObj)
{
pUnkObj->Release();
}
}
}
inline void SpDestroyTokenComboBox(HWND hwnd)
{
SpDestroyTokenList(CB_GETCOUNT, CB_GETITEMDATA, hwnd);
}
inline void SpDestroyTokenListBox(HWND hwnd)
{
SpDestroyTokenList(LB_GETCOUNT, LB_GETITEMDATA, hwnd);
}
inline ISpObjectToken * SpGetComboBoxToken(HWND hwnd, WPARAM Index)
{
return (ISpObjectToken *)::SendMessage(hwnd, CB_GETITEMDATA, Index, 0);
}
inline ISpObjectToken * SpGetListBoxToken(HWND hwnd, WPARAM Index)
{
return (ISpObjectToken *)::SendMessage(hwnd, LB_GETITEMDATA, Index, 0);
}
inline ISpObjectToken * SpGetCurSelComboBoxToken(HWND hwnd)
{
LRESULT i = ::SendMessage(hwnd, CB_GETCURSEL, 0, 0);
return (i == CB_ERR) ? NULL : SpGetComboBoxToken(hwnd, i);
}
inline ISpObjectToken * SpGetCurSelListBoxToken(HWND hwnd)
{
LRESULT i = ::SendMessage(hwnd, LB_GETCURSEL, 0, 0);
return (i == LB_ERR) ? NULL : SpGetListBoxToken(hwnd, i);
}
//
// Don't call this directly. Use SpUpdateCurSelComboBoxToken or SpUpdateCurSelListBoxToken
//
inline HRESULT SpUpdateCurSelToken(UINT MsgDelString, UINT MsgInsertString, UINT MsgGetItemData, UINT MsgSetItemData, UINT MsgGetCurSel, UINT MsgSetCurSel,
HWND hwnd)
{
HRESULT hr = S_OK;
LRESULT i = ::SendMessage(hwnd, MsgGetCurSel, 0, 0);
if (i != CB_ERR)
{
ISpObjectToken * pToken = (ISpObjectToken *)::SendMessage(hwnd, MsgGetItemData, i, 0);
CSpDynamicString dstrDesc;
hr = SpGetDescription(pToken, &dstrDesc);
if (SUCCEEDED(hr))
{
USES_CONVERSION;
::SendMessage(hwnd, MsgDelString, i, 0);
::SendMessage(hwnd, MsgInsertString, i, (LPARAM)W2T(dstrDesc));
::SendMessage(hwnd, MsgSetItemData, i, (LPARAM)pToken);
::SendMessage(hwnd, MsgSetCurSel, i, 0);
}
}
return hr;
}
inline HRESULT SpUpdateCurSelComboBoxToken(HWND hwnd)
{
return SpUpdateCurSelToken(CB_DELETESTRING, CB_INSERTSTRING, CB_GETITEMDATA, CB_SETITEMDATA, CB_GETCURSEL, CB_SETCURSEL, hwnd);
}
inline HRESULT SpUpdateCurSelListBoxToken(HWND hwnd)
{
return SpUpdateCurSelToken(LB_DELETESTRING, LB_INSERTSTRING, LB_GETITEMDATA, LB_SETITEMDATA, LB_GETCURSEL, LB_SETCURSEL, hwnd);
}
inline HRESULT SpAddTokenToList(UINT MsgAddString, UINT MsgSetItemData, UINT MsgSetCurSel, HWND hwnd, ISpObjectToken * pToken)
{
CSpDynamicString dstrDesc;
HRESULT hr = SpGetDescription(pToken, &dstrDesc);
if (SUCCEEDED(hr))
{
USES_CONVERSION;
LRESULT i = ::SendMessage(hwnd, MsgAddString, 0, (LPARAM)W2T(dstrDesc));
if (i == CB_ERR || i == CB_ERRSPACE) // Note: CB_ and LB_ errors are identical values...
{
hr = E_OUTOFMEMORY;
}
else
{
::SendMessage(hwnd, MsgSetItemData, i, (LPARAM)pToken);
::SendMessage(hwnd, MsgSetCurSel, i, 0);
pToken->AddRef();
}
}
return hr;
}
inline HRESULT SpAddTokenToComboBox(HWND hwnd, ISpObjectToken * pToken)
{
return SpAddTokenToList(CB_ADDSTRING, CB_SETITEMDATA, CB_SETCURSEL, hwnd, pToken);
}
inline HRESULT SpAddTokenToListBox(HWND hwnd, ISpObjectToken * pToken)
{
return SpAddTokenToList(LB_ADDSTRING, LB_SETITEMDATA, LB_SETCURSEL, hwnd, pToken);
}
inline HRESULT SpDeleteCurSelToken(UINT MsgGetCurSel, UINT MsgSetCurSel, UINT MsgGetItemData, UINT MsgDeleteString, HWND hwnd)
{
HRESULT hr = S_OK;
LRESULT i = ::SendMessage(hwnd, MsgGetCurSel, 0, 0);
if (i == CB_ERR)
{
hr = S_FALSE;
}
else
{
ISpObjectToken * pToken = (ISpObjectToken *)::SendMessage(hwnd, MsgGetItemData, i, 0);
if (pToken)
{
pToken->Release();
}
::SendMessage(hwnd, MsgDeleteString, i, 0);
::SendMessage(hwnd, MsgSetCurSel, i, 0);
}
return hr;
}
inline HRESULT SpDeleteCurSelComboBoxToken(HWND hwnd)
{
return SpDeleteCurSelToken(CB_GETCURSEL, CB_SETCURSEL, CB_GETITEMDATA, CB_DELETESTRING, hwnd);
}
inline HRESULT SpDeleteCurSelListBoxToken(HWND hwnd)
{
return SpDeleteCurSelToken(LB_GETCURSEL, CB_SETCURSEL, LB_GETITEMDATA, LB_DELETESTRING, hwnd);
}
#endif /* #ifndef SPUIHelp_h -- This must be the last line in the file */

Binary file not shown.