Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 21 additions & 8 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
cmake_minimum_required (VERSION 3.25)
set(CMAKE_CXX_STANDARD 20)

set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
# Allow runtime library to be set externally; default to dynamic if not set
if(NOT CMAKE_MSVC_RUNTIME_LIBRARY)
Comment on lines +7 to +8
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change modifies the default runtime library from static (MultiThreaded) to dynamic (MultiThreadedDLL), which is unrelated to the UIA feature toggle. This is a breaking change that could affect existing users who depend on static linking and should be documented or split into a separate PR. If this change is intentional and related to UIA compatibility issues, it should be explained in the PR description.

Suggested change
# Allow runtime library to be set externally; default to dynamic if not set
if(NOT CMAKE_MSVC_RUNTIME_LIBRARY)
# Allow runtime library to be set externally; optionally enable dynamic CRT
option(SRAL_USE_DYNAMIC_MSVC_RUNTIME "Use dynamic MSVC runtime library (/MD, /MDd)" OFF)
if(SRAL_USE_DYNAMIC_MSVC_RUNTIME AND NOT CMAKE_MSVC_RUNTIME_LIBRARY)

Copilot uses AI. Check for mistakes.
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
endif()
set(INCLUDES "Include")

# Enable Hot Reload for MSVC compilers if supported.
Expand All @@ -17,6 +20,7 @@ endif()

project ("SRAL")
option (BUILD_SRAL_TEST "Build SRAL examples/tests" ON)
option (SRAL_DISABLE_UIA "Disable UIA (UI Automation) support" OFF)
add_library(${PROJECT_NAME}_obj OBJECT)
target_sources(${PROJECT_NAME}_obj PRIVATE
"SRC/Encoding.h" "SRC/Encoding.cpp"
Expand All @@ -29,8 +33,12 @@ if(WIN32)
target_sources(${PROJECT_NAME}_obj PRIVATE
"SRC/NVDA.h" "SRC/NVDA.cpp" "SRC/SAPI.h" "SRC/SAPI.cpp"
"Dep/blastspeak.h" "Dep/blastspeak.c" "Dep/fsapi.h" "Dep/fsapi.c" "Dep/nvda_control.h" "Dep/nvda_control.c"
"SRC/Jaws.h" "SRC/Jaws.cpp" "SRC/UIA.cpp"
"Dep/UIAProvider.h" "Dep/UIAProvider.cpp" "Dep/wasapi.h" "Dep/wasapi.cpp" "SRC/ZDSR.h" "SRC/ZDSR.cpp")
"SRC/Jaws.h" "SRC/Jaws.cpp"
"Dep/wasapi.h" "Dep/wasapi.cpp" "SRC/ZDSR.h" "SRC/ZDSR.cpp")
if(NOT SRAL_DISABLE_UIA)
target_sources(${PROJECT_NAME}_obj PRIVATE
"SRC/UIA.cpp" "Dep/UIAProvider.h" "Dep/UIAProvider.cpp")
endif()
elseif(APPLE)
target_sources(${PROJECT_NAME}_obj PRIVATE
"SRC/AVSpeech.h" "SRC/AVSpeech.mm" "SRC/VoiceOver.h" "SRC/VoiceOver.mm")
Expand All @@ -43,6 +51,9 @@ set_property(TARGET ${PROJECT_NAME}_obj
PROPERTY POSITION_INDEPENDENT_CODE on)
# TODO: Probably we shouldn't simply suppress these warnings
target_compile_definitions(${PROJECT_NAME}_obj PRIVATE _CRT_SECURE_NO_WARNINGS)
if(SRAL_DISABLE_UIA)
target_compile_definitions(${PROJECT_NAME}_obj PRIVATE SRAL_NO_UIA)
endif()

if(BUILD_SHARED_LIBS)
add_library(${PROJECT_NAME} SHARED
Expand Down Expand Up @@ -81,11 +92,13 @@ if (WIN32)
if (BUILD_SRAL_TEST)
add_executable(${PROJECT_NAME}_NVDAControleExConsole "Examples/C/NVDAControlExConsole.c" "Dep/nvda_control.c")
endif()
set(LIBS "uiautomationcore.lib")
if(BUILD_SHARED_LIBS)
target_link_libraries(${PROJECT_NAME} ${LIBS})
endif()
target_link_libraries(${PROJECT_NAME}_static ${LIBS})
if(NOT SRAL_DISABLE_UIA)
set(LIBS "uiautomationcore.lib")
if(BUILD_SHARED_LIBS)
target_link_libraries(${PROJECT_NAME} ${LIBS})
endif()
target_link_libraries(${PROJECT_NAME}_static ${LIBS})
endif()
elseif (APPLE)
enable_language(OBJCXX)
set(CMAKE_C_COMPILER clang)
Expand Down
10 changes: 7 additions & 3 deletions SRC/SRAL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
#include "ZDSR.h"
#include "SAPI.h"
#include "Jaws.h"
#ifndef SRAL_NO_UIA
#include "UIA.h"
#endif
#include <windows.h>
#include <tlhelp32.h>
#elif defined(__APPLE__)
Expand Down Expand Up @@ -219,7 +221,9 @@ extern "C" SRAL_API bool SRAL_Initialize(int engines_exclude) {
g_engines[SRAL_ENGINE_NVDA] = std::make_unique<Sral::Nvda>();
g_engines[SRAL_ENGINE_JAWS] = std::make_unique<Sral::Jaws>();
g_engines[SRAL_ENGINE_ZDSR] = std::make_unique<Sral::Zdsr>();
#ifndef SRAL_NO_UIA
g_engines[SRAL_ENGINE_UIA] = std::make_unique<Sral::Uia>();
#endif
g_engines[SRAL_ENGINE_SAPI] = std::make_unique<Sral::Sapi>();
#elif defined(__APPLE__)
g_engines[SRAL_ENGINE_VOICE_OVER] = std::make_unique<Sral::VoiceOver>();
Expand Down Expand Up @@ -317,7 +321,7 @@ static BOOL FindProcess(const wchar_t* name) {
#endif
static void speech_engine_update() {
if (!g_currentEngine || !g_currentEngine->GetActive() || g_currentEngine->GetNumber() == SRAL_ENGINE_SAPI || g_currentEngine->GetNumber() == SRAL_ENGINE_UIA || g_currentEngine->GetNumber() == SRAL_ENGINE_AV_SPEECH) {
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When SRAL_NO_UIA is defined, the condition still checks for SRAL_ENGINE_UIA even though the UIA engine is never initialized. This comparison against SRAL_ENGINE_UIA will never be true when UIA is disabled, but the check itself can still execute. Consider wrapping the SRAL_ENGINE_UIA check in the condition with a preprocessor directive to avoid the unnecessary comparison when UIA is disabled.

Copilot uses AI. Check for mistakes.
#ifdef _WIN32
#if defined(_WIN32) && !defined(SRAL_NO_UIA)
if (FindProcess(L"narrator.exe") == TRUE) {
g_currentEngine = get_engine(SRAL_ENGINE_UIA);
return;
Expand All @@ -330,10 +334,10 @@ static void speech_engine_update() {
break;
}
}
#if defined(_WIN32) && !defined(SRAL_NO_UIA)
}
#ifdef _WIN32
}
#endif
}
}

extern "C" SRAL_API bool SRAL_Speak(const char* text, bool interrupt) {
Expand Down