Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

391 lines
11 KiB

  1. #include <windows.h>
  2. #include <atlbase.h>
  3. extern CComModule _Module;
  4. #include <atlcom.h>
  5. #include "sapi.h"
  6. #include "sphelper.h"
  7. #include "spddkhlp.h"
  8. #include "spttseng.h"
  9. #include "spttseng_i.c"
  10. #include "ms1033ltsmap.h" // BUGBUG: Move to somewhere... else.
  11. #ifdef _WIN32_WCE
  12. #define GOTO_LRETURN(hres) {RETAILMSG(1, (_T("File: %s Line :%d, hr=%08x\n"),_T(__FILE__),__LINE__, hres)); goto LReturn;}
  13. #define MARK(text) {RETAILMSG(1, (_T("%s Line :%d\n"), text,__LINE__));}
  14. #else
  15. #define GOTO_LRETURN(hres) {wprintf(L"Line :%d, hr=%08x\n",__LINE__, hres); goto LReturn;}
  16. #define MARK(text) {wprintf(L"%s Line :%d\n", text,__LINE__);}
  17. #endif
  18. // This code does not ship
  19. // This code creates the registry entries for the TTS voices. The
  20. // datafiles registered here are the ones checked in the slm source tree. This is not
  21. // done using a reg file because we need to compute the absolute path of the datafiles
  22. // which can be different on different machines because of different root slm directories.
  23. #ifndef _WIN32_WCE
  24. #define DIRS_TO_GO_BACK_VOICE 3 // Back 3 levels to 'Voices" directory
  25. #define DIRS_TO_GO_BACK_LEX 6 // Back 3 levels to Lex Data directory
  26. #else
  27. #define DIRS_TO_GO_BACK_VOICE 1 // Back 3 levels to 'Voices" directory
  28. #define DIRS_TO_GO_BACK_LEX 1 // Back 3 levels to Lex Data directory
  29. #endif
  30. CSpUnicodeSupport g_Unicode;
  31. /*****************************************************************************
  32. * CreateLexSubKey *
  33. *------------------*
  34. * Description:
  35. * Each TTS voice gets installed under one registry sub-key.
  36. * This function installs the single voice from the passed params.
  37. *
  38. ********************************************************************** MC ***/
  39. HRESULT CreateLexSubKey(
  40. ISpObjectToken * pToken,
  41. const WCHAR * pszSubKeyName,
  42. const CLSID * pclsid,
  43. const WCHAR * pszFilePath,
  44. const WCHAR * pszLexName,
  45. const WCHAR * pszPhoneMap)
  46. {
  47. HRESULT hr = S_OK;
  48. //---------------------------------------
  49. // Create the lex sub-key (Lex or LTS)
  50. //---------------------------------------
  51. CComPtr<ISpObjectToken> cpSubToken;
  52. hr = SpGetSubTokenFromToken(pToken, pszSubKeyName, &cpSubToken, TRUE);
  53. if (SUCCEEDED(hr))
  54. {
  55. hr = SpSetCommonTokenData(
  56. cpSubToken,
  57. pclsid,
  58. NULL,
  59. 0,
  60. NULL,
  61. NULL);
  62. }
  63. WCHAR szLexDataPath[MAX_PATH];
  64. if (SUCCEEDED(hr))
  65. {
  66. //--------------------------------
  67. // Lex DATA file location
  68. //--------------------------------
  69. wcscpy(szLexDataPath, pszFilePath);
  70. wcscat(szLexDataPath, pszLexName);
  71. hr = cpSubToken->SetStringValue(L"DataFile", szLexDataPath);
  72. }
  73. if (SUCCEEDED(hr) && pszPhoneMap)
  74. {
  75. CComPtr<ISpObjectToken> cpPhoneToken;
  76. if (SUCCEEDED(hr))
  77. hr = SpGetSubTokenFromToken(cpSubToken, L"PhoneConverter", &cpPhoneToken, TRUE);
  78. if (SUCCEEDED(hr))
  79. hr = SpSetCommonTokenData(cpPhoneToken, &CLSID_SpPhoneConverter, NULL, 0, NULL, NULL);
  80. if (SUCCEEDED(hr))
  81. hr = cpPhoneToken->SetStringValue(L"PhoneMap", pszPhoneMap);
  82. }
  83. return hr;
  84. }
  85. /*****************************************************************************
  86. * CreateUISubKey *
  87. *-----------------*
  88. * Description:
  89. * Creates the UI SubKey under a voice.
  90. *
  91. ********************************************************************** AH ***/
  92. HRESULT CreateUISubKey(
  93. ISpObjectToken * pToken,
  94. const CLSID * pclsid)
  95. {
  96. HRESULT hr = S_OK;
  97. //-----------------------
  98. // Create the UI sub-key
  99. //-----------------------
  100. CComPtr<ISpObjectToken> cpSubToken;
  101. hr = SpGetSubTokenFromToken(pToken, L"UI", &cpSubToken, TRUE);
  102. //--------------------------------------
  103. // Create the EngineProperties sub-key
  104. //--------------------------------------
  105. CComPtr<ISpObjectToken> cpSubSubToken;
  106. if ( SUCCEEDED( hr ) )
  107. {
  108. hr = SpGetSubTokenFromToken( cpSubToken, L"EngineProperties", &cpSubSubToken, TRUE );
  109. }
  110. if (SUCCEEDED(hr))
  111. {
  112. hr = SpSetCommonTokenData(
  113. cpSubSubToken,
  114. pclsid,
  115. NULL,
  116. 0,
  117. NULL,
  118. NULL);
  119. }
  120. return hr;
  121. }
  122. /*****************************************************************************
  123. * CreateVoiceSubKey *
  124. *--------------------*
  125. * Description:
  126. * Each TTS voice gets installed under one registry sub-key.
  127. * This function installs the single voice from the passed params.
  128. *
  129. ********************************************************************** MC ***/
  130. HRESULT CreateVoiceSubKey(
  131. const WCHAR * pszSubKeyName,
  132. const WCHAR * pszDescription,
  133. BOOL fVendorDefault,
  134. const WCHAR * pszGender,
  135. const WCHAR * pszAge,
  136. const WCHAR * pszVoicePath,
  137. const WCHAR * pszVoiceName,
  138. const WCHAR * pszLexPath)
  139. {
  140. HRESULT hr;
  141. CComPtr<ISpObjectToken> cpToken;
  142. CComPtr<ISpDataKey> cpDataKeyAttribs;
  143. hr = SpCreateNewTokenEx(
  144. SPCAT_VOICES,
  145. pszSubKeyName,
  146. &CLSID_MSVoiceData,
  147. pszDescription,
  148. 0x409,
  149. pszDescription,
  150. &cpToken,
  151. &cpDataKeyAttribs);
  152. if (SUCCEEDED(hr))
  153. {
  154. hr = cpDataKeyAttribs->SetStringValue(L"Name", pszSubKeyName);
  155. }
  156. if (SUCCEEDED(hr))
  157. {
  158. hr = cpDataKeyAttribs->SetStringValue(L"Gender", pszGender);
  159. }
  160. if (SUCCEEDED(hr))
  161. {
  162. hr = cpDataKeyAttribs->SetStringValue(L"Age", pszAge);
  163. }
  164. if (SUCCEEDED(hr))
  165. {
  166. hr = cpDataKeyAttribs->SetStringValue(L"Vendor", L"Microsoft");
  167. }
  168. if (SUCCEEDED(hr))
  169. {
  170. hr = cpDataKeyAttribs->SetStringValue(L"Language", L"409");
  171. }
  172. if (SUCCEEDED(hr) && fVendorDefault)
  173. {
  174. hr = cpDataKeyAttribs->SetStringValue(L"VendorPreferred", L"");
  175. }
  176. WCHAR szVoiceDataPath[MAX_PATH];
  177. if (SUCCEEDED(hr))
  178. {
  179. //--------------------------------
  180. // Voice DATA file location
  181. //--------------------------------
  182. wcscpy(szVoiceDataPath, pszVoicePath);
  183. wcscat(szVoiceDataPath, pszVoiceName);
  184. wcscat(szVoiceDataPath, L".vdt");
  185. hr = cpToken->SetStringValue(L"VoiceData", szVoiceDataPath);
  186. }
  187. if (SUCCEEDED(hr))
  188. {
  189. //--------------------------------
  190. // Voice DEF file location
  191. //--------------------------------
  192. wcscpy(szVoiceDataPath, pszVoicePath);
  193. wcscat(szVoiceDataPath, pszVoiceName);
  194. wcscat(szVoiceDataPath, L".vdf");
  195. hr = cpToken->SetStringValue(L"VoiceDef", szVoiceDataPath);
  196. }
  197. //------------------------------------------------
  198. // Register TTS lexicons
  199. //------------------------------------------------
  200. if (SUCCEEDED(hr))
  201. {
  202. hr = CreateLexSubKey(cpToken, L"Lex", &CLSID_SpCompressedLexicon, pszLexPath, L"LTTS1033.LXA", NULL);
  203. }
  204. if (SUCCEEDED(hr))
  205. {
  206. hr = CreateLexSubKey(cpToken, L"LTS", &CLSID_SpLTSLexicon, pszLexPath, L"r1033tts.lxa", pszms1033ltsmap);
  207. }
  208. if ( SUCCEEDED( hr ) )
  209. {
  210. hr = CreateUISubKey( cpToken, &CLSID_SpTtsEngUI );
  211. }
  212. return hr;
  213. }
  214. /*****************************************************************************
  215. * main *
  216. *-------*
  217. * Description:
  218. * Locate the abs path to the Mary, Mike and Sam voices
  219. * and register them in the system registry.
  220. *
  221. ********************************************************************** MC ***/
  222. int wmain()
  223. {
  224. HRESULT hr = S_OK;
  225. CoInitialize(NULL);
  226. //----------------------------------------
  227. // Get the exe's location...
  228. //----------------------------------------
  229. WCHAR szVoiceDataPath[MAX_PATH];
  230. if (!g_Unicode.GetModuleFileName(NULL, szVoiceDataPath, MAX_PATH))
  231. {
  232. hr = HRESULT_FROM_WIN32(::GetLastError());
  233. }
  234. WCHAR szLexDataPath[MAX_PATH];
  235. if (SUCCEEDED(hr))
  236. {
  237. wcscpy(szLexDataPath, szVoiceDataPath);
  238. }
  239. //----------------------------------------
  240. // ...and derive abs path to VOICE data
  241. //----------------------------------------
  242. if (SUCCEEDED(hr))
  243. {
  244. // modulename is "<sapi5>\Src\TTS\msttsdrv\voices\RegVoices\debug_x86\RegVoices.exe"
  245. // Data is at "<sapi5>\Src\TTS\msttsdrv\voices\"
  246. WCHAR * psz;
  247. psz = szVoiceDataPath;
  248. for (int i = 0; i < DIRS_TO_GO_BACK_VOICE; i++)
  249. {
  250. psz = wcsrchr(psz, '\\');
  251. if (!psz)
  252. {
  253. hr = E_FAIL;
  254. break;
  255. }
  256. else
  257. {
  258. *psz = 0;
  259. psz = szVoiceDataPath;
  260. }
  261. }
  262. }
  263. if (SUCCEEDED(hr))
  264. {
  265. wcscat(szVoiceDataPath, L"\\");
  266. }
  267. #ifdef _WIN32_WCE
  268. MARK(szVoiceDataPath);
  269. // if (SUCCEEDED(hr))
  270. // {
  271. // wcscat(szVoiceDataPath, L"voices\\");
  272. // }
  273. // MARK(szVoiceDataPath);
  274. #endif // _WIN32_WCE
  275. //----------------------------------------
  276. // Derive abs path to LEX data
  277. //----------------------------------------
  278. if (SUCCEEDED(hr))
  279. {
  280. // modulename is "<sapi5>\Src\TTS\msttsdrv\voices\RegVoices\debug_x86\RegVoices.exe"
  281. // Data is at "<sapi5>\Src\lexicon\data\"
  282. WCHAR * psz = szLexDataPath;
  283. for (int i = 0; i < DIRS_TO_GO_BACK_LEX; i++)
  284. {
  285. psz = wcsrchr(psz, '\\');
  286. if (!psz)
  287. {
  288. hr = E_FAIL;
  289. break;
  290. }
  291. else
  292. {
  293. *psz = 0;
  294. psz = szLexDataPath;
  295. }
  296. }
  297. }
  298. MARK(szLexDataPath);
  299. if (SUCCEEDED(hr))
  300. {
  301. wcscat(szLexDataPath, L"\\");
  302. }
  303. MARK(szLexDataPath);
  304. //------------------------------------------------
  305. // ...then register the three Microsoft voices..
  306. //------------------------------------------------
  307. if (SUCCEEDED(hr))
  308. {
  309. hr = CreateVoiceSubKey(L"MSMary",
  310. L"MS Mary",
  311. TRUE,
  312. L"Female",
  313. L"Adult",
  314. szVoiceDataPath,
  315. L"Mary",
  316. szLexDataPath);
  317. }
  318. /* if (SUCCEEDED(hr))
  319. {
  320. hr = CreateVoiceSubKey(L"MSMike",
  321. L"MS Mike",
  322. FALSE,
  323. L"Male",
  324. L"Adult",
  325. szVoiceDataPath,
  326. L"Mike",
  327. szLexDataPath);
  328. }
  329. if (SUCCEEDED(hr))
  330. {
  331. hr = CreateVoiceSubKey(L"MSSam",
  332. L"MS Sam",
  333. FALSE,
  334. L"Male",
  335. L"Adult",
  336. szVoiceDataPath,
  337. L"Sam",
  338. szLexDataPath);
  339. }
  340. */
  341. CoUninitialize();
  342. if (FAILED(hr))
  343. return -1;
  344. return 0;
  345. }