Skip to content

Commit 8e00326

Browse files
author
leion
committed
feat(installer): Add silent installation mode with configuration support
- Add silent installation functions (SilentInstall and SilentUninstall) to support unattended deployments - Implement command-line parameter parsing for installation configuration - Add support for configurable settings via command-line flags: * Log level configuration (-loglevel) * Voice provider selection (-no-narrator, -enable-narrator, -no-edge, -enable-edge, -no-azure, -enable-azure) * Narrator voice path configuration (-narrator-path) * Azure credentials configuration (-azure-key, -azure-region) * Language settings (-all-languages, -languages) * Architecture selection (-32bit-only, -64bit-only) * Phoneme converter installation control (-no-phoneme-converters) - Add helper functions GetParameterValue and HasParameter for command-line parsing - Add ApplyConfigurationSettings function to write configuration to registry - Update platform toolset to use DefaultPlatformToolset for better build compatibility - Add SILENT_INSTALL.md documentation for silent installation usage - Include <algorithm> header for string processing utilities
1 parent 7194eca commit 8e00326

File tree

4 files changed

+574
-17
lines changed

4 files changed

+574
-17
lines changed

Installer/Install.cpp

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "Installer.h"
22
#include "RegKey.h"
33
#include <system_error>
4+
#include <algorithm>
45

56

67
// Returns the exit code. Throws if failed to launch.
@@ -190,4 +191,230 @@ void CheckPhonemeConverters()
190191
{
191192
ReportError(ex.code().value());
192193
}
194+
}
195+
196+
// Parse command line parameter value
197+
static std::wstring GetParameterValue(int argc, LPWSTR* argv, LPCWSTR paramName)
198+
{
199+
for (int i = 1; i < argc - 1; i++)
200+
{
201+
if (_wcsicmp(argv[i], paramName) == 0)
202+
{
203+
return argv[i + 1];
204+
}
205+
}
206+
return L"";
207+
}
208+
209+
// Check if parameter exists
210+
static bool HasParameter(int argc, LPWSTR* argv, LPCWSTR paramName)
211+
{
212+
for (int i = 1; i < argc; i++)
213+
{
214+
if (_wcsicmp(argv[i], paramName) == 0)
215+
{
216+
return true;
217+
}
218+
}
219+
return false;
220+
}
221+
222+
// Apply configuration settings from command line
223+
static void ApplyConfigurationSettings(int argc, LPWSTR* argv)
224+
{
225+
RegKey configKey, enumKey;
226+
227+
// Create registry keys
228+
configKey.Create(HKEY_CURRENT_USER, L"Software\\NaturalVoiceSAPIAdapter", KEY_SET_VALUE);
229+
enumKey.Create(HKEY_CURRENT_USER, L"Software\\NaturalVoiceSAPIAdapter\\Enumerator", KEY_SET_VALUE);
230+
231+
// Log level (0-6, default 2)
232+
std::wstring logLevel = GetParameterValue(argc, argv, L"-loglevel");
233+
if (!logLevel.empty())
234+
{
235+
DWORD level = _wtoi(logLevel.c_str());
236+
if (level <= 6)
237+
{
238+
configKey.SetDword(L"LogLevel", level);
239+
}
240+
}
241+
242+
// Narrator voices
243+
if (HasParameter(argc, argv, L"-no-narrator"))
244+
{
245+
enumKey.SetDword(L"NoNarratorVoices", 1);
246+
}
247+
else if (HasParameter(argc, argv, L"-enable-narrator"))
248+
{
249+
enumKey.SetDword(L"NoNarratorVoices", 0);
250+
}
251+
252+
// Edge voices
253+
if (HasParameter(argc, argv, L"-no-edge"))
254+
{
255+
enumKey.SetDword(L"NoEdgeVoices", 1);
256+
}
257+
else if (HasParameter(argc, argv, L"-enable-edge"))
258+
{
259+
enumKey.SetDword(L"NoEdgeVoices", 0);
260+
}
261+
262+
// Azure voices
263+
if (HasParameter(argc, argv, L"-no-azure"))
264+
{
265+
enumKey.SetDword(L"NoAzureVoices", 1);
266+
}
267+
else if (HasParameter(argc, argv, L"-enable-azure"))
268+
{
269+
enumKey.SetDword(L"NoAzureVoices", 0);
270+
}
271+
272+
// Narrator voice path
273+
std::wstring narratorPath = GetParameterValue(argc, argv, L"-narrator-path");
274+
if (!narratorPath.empty())
275+
{
276+
enumKey.SetString(L"NarratorVoicePath", narratorPath.c_str());
277+
}
278+
279+
// Azure key and region
280+
std::wstring azureKey = GetParameterValue(argc, argv, L"-azure-key");
281+
std::wstring azureRegion = GetParameterValue(argc, argv, L"-azure-region");
282+
if (!azureKey.empty())
283+
{
284+
enumKey.SetString(L"AzureVoiceKey", azureKey.c_str());
285+
}
286+
if (!azureRegion.empty())
287+
{
288+
enumKey.SetString(L"AzureVoiceRegion", azureRegion.c_str());
289+
}
290+
291+
// Language settings
292+
if (HasParameter(argc, argv, L"-all-languages"))
293+
{
294+
enumKey.SetDword(L"EdgeVoiceAllLanguages", 1);
295+
}
296+
else
297+
{
298+
std::wstring languages = GetParameterValue(argc, argv, L"-languages");
299+
if (!languages.empty())
300+
{
301+
enumKey.SetDword(L"EdgeVoiceAllLanguages", 0);
302+
// Convert comma-separated to null-separated
303+
std::vector<std::wstring> langList;
304+
std::wstring temp;
305+
for (wchar_t c : languages)
306+
{
307+
if (c == L',')
308+
{
309+
if (!temp.empty())
310+
{
311+
langList.push_back(temp);
312+
temp.clear();
313+
}
314+
}
315+
else
316+
{
317+
temp.push_back(c);
318+
}
319+
}
320+
if (!temp.empty())
321+
{
322+
langList.push_back(temp);
323+
}
324+
enumKey.SetMultiStringList(L"EdgeVoiceLanguages", langList);
325+
}
326+
}
327+
}
328+
329+
void SilentInstall(int argc, LPWSTR* argv)
330+
{
331+
// Apply configuration settings first
332+
ApplyConfigurationSettings(argc, argv);
333+
334+
// Determine which architectures to install
335+
bool install32 = true;
336+
bool install64 = Is64BitSystem();
337+
338+
// Check for architecture-specific parameters
339+
if (HasParameter(argc, argv, L"-32bit-only"))
340+
{
341+
install32 = true;
342+
install64 = false;
343+
}
344+
else if (HasParameter(argc, argv, L"-64bit-only"))
345+
{
346+
install32 = false;
347+
install64 = Is64BitSystem();
348+
}
349+
350+
// Install 32-bit version
351+
if (install32)
352+
{
353+
try
354+
{
355+
Register(false);
356+
}
357+
catch (const std::system_error&)
358+
{
359+
// In silent mode, we still throw to let the caller handle it
360+
throw;
361+
}
362+
}
363+
364+
// Install 64-bit version
365+
if (install64)
366+
{
367+
try
368+
{
369+
Register(true);
370+
}
371+
catch (const std::system_error&)
372+
{
373+
// In silent mode, we still throw to let the caller handle it
374+
throw;
375+
}
376+
}
377+
378+
// Check and install phoneme converters if needed
379+
if (!HasParameter(argc, argv, L"-no-phoneme-converters"))
380+
{
381+
HKEY hKey;
382+
bool hasConverters = true;
383+
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Speech\\PhoneConverters\\Tokens\\Universal",
384+
0, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &hKey) == ERROR_SUCCESS)
385+
{
386+
RegCloseKey(hKey);
387+
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Speech\\PhoneConverters\\Tokens\\Universal",
388+
0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &hKey) == ERROR_SUCCESS)
389+
{
390+
RegCloseKey(hKey);
391+
}
392+
else
393+
hasConverters = false;
394+
}
395+
else
396+
hasConverters = false;
397+
398+
if (!hasConverters)
399+
{
400+
try
401+
{
402+
if (Is64BitSystem())
403+
AddToRegistry(L"x64\\PhoneConverters.reg");
404+
else
405+
AddToRegistry(L"x86\\PhoneConverters.reg");
406+
}
407+
catch (const std::system_error&)
408+
{
409+
// Ignore errors in silent mode for phoneme converters
410+
}
411+
}
412+
}
413+
}
414+
415+
void SilentUninstall()
416+
{
417+
Unregister(false);
418+
if (Is64BitSystem())
419+
Unregister(true);
193420
}

Installer/Installer.vcxproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,29 +29,29 @@
2929
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
3030
<ConfigurationType>Application</ConfigurationType>
3131
<UseDebugLibraries>true</UseDebugLibraries>
32-
<PlatformToolset>v143</PlatformToolset>
32+
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
3333
<CharacterSet>Unicode</CharacterSet>
3434
<YY_Thunks_File>YY_Thunks_for_WinXP.obj</YY_Thunks_File>
3535
</PropertyGroup>
3636
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
3737
<ConfigurationType>Application</ConfigurationType>
3838
<UseDebugLibraries>false</UseDebugLibraries>
39-
<PlatformToolset>v143</PlatformToolset>
39+
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
4040
<WholeProgramOptimization>true</WholeProgramOptimization>
4141
<CharacterSet>Unicode</CharacterSet>
4242
<YY_Thunks_File>YY_Thunks_for_WinXP.obj</YY_Thunks_File>
4343
</PropertyGroup>
4444
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
4545
<ConfigurationType>Application</ConfigurationType>
4646
<UseDebugLibraries>true</UseDebugLibraries>
47-
<PlatformToolset>v143</PlatformToolset>
47+
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
4848
<CharacterSet>Unicode</CharacterSet>
4949
<YY_Thunks_File>YY_Thunks_for_WinXP.obj</YY_Thunks_File>
5050
</PropertyGroup>
5151
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
5252
<ConfigurationType>Application</ConfigurationType>
5353
<UseDebugLibraries>false</UseDebugLibraries>
54-
<PlatformToolset>v143</PlatformToolset>
54+
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
5555
<WholeProgramOptimization>true</WholeProgramOptimization>
5656
<CharacterSet>Unicode</CharacterSet>
5757
<YY_Thunks_File>YY_Thunks_for_WinXP.obj</YY_Thunks_File>

0 commit comments

Comments
 (0)