设为首页 收藏本站
查看: 438|回复: 0

基于Windows Sdk 与visual C++2008 在微软平台上构架自己的语音朗读引擎(适用于windows 2000/xp2003/vista w

[复制链接]

尚未签到

发表于 2015-4-30 11:07:20 | 显示全部楼层 |阅读模式
  本人闲来无事,自行开发了一个小型的语音朗读引擎,搭建起在微软平台上的语音朗读框架服务体系,
  鉴于本人个人力量有限,为了将语音朗读引擎做的功能更加强悍,强大,
  现在将该系统开源,需要源码的请在本人CSDN博客下留下EMail,
  本系统属于系统框架,搭建起一个语音朗读的引擎服务框架,
  在微软平台上畅通无阻,
  
  现在将本系统构架公布一下,
  并贴出相关核心源码,源码体积为27M,编译后为1M,
  适用于windows 2000/xp2003/vista   windows CE /mobile
  
  
  #include "stdafx.h"#include #include int wmain(int argc, __in_ecount(argc) WCHAR* argv[]){static const DWORD dwVersion = { 1 };ULONG ulNumWords = 0;HRESULT hr = S_OK;if( argc != 4 ){printf( "%s", "Usage: > MakeVoice [[in]word list file] [[out]voice file] [voice name]/n" );hr = E_INVALIDARG;}else{::CoInitialize( NULL );FILE *hWordList = NULL, *hVoiceFile = NULL;if ( fopen_s( &hWordList, CW2A(argv[1]), "r" ) != 0 ){hWordList = NULL;hr = E_FAIL;}if ( SUCCEEDED( hr ) && fopen_s( &hVoiceFile, CW2A(argv[2]), "wb" ) != 0 ){hVoiceFile = NULL;hr = E_FAIL;}if( SUCCEEDED( hr ) ){if( !fwrite( &dwVersion, sizeof(dwVersion), 1, hVoiceFile ) ||fseek( hVoiceFile, 4, SEEK_CUR ) ){hr = E_FAIL;}WCHAR WordFileName[MAX_PATH];while( SUCCEEDED( hr ) && fgetws( WordFileName, MAX_PATH, hWordList ) ){ULONG ulTextLen = (ULONG)wcslen( WordFileName );if( WordFileName[ulTextLen-1] == '/n' ){WordFileName[--ulTextLen] = NULL;}ulTextLen = (ulTextLen+1) * sizeof(WCHAR);if( fwrite( &ulTextLen, sizeof(ulTextLen), 1, hVoiceFile ) &&fwrite( WordFileName, ulTextLen, 1, hVoiceFile ) ){++ulNumWords;ISpStream* pStream;wcscat_s( WordFileName, _countof(WordFileName), L".wav" );hr = SPBindToFile( WordFileName, SPFM_OPEN_READONLY, &pStream );if( SUCCEEDED( hr ) ){CSpStreamFormat Fmt;Fmt.AssignFormat(pStream);if( Fmt.ComputeFormatEnum() == SPSF_11kHz16BitMono ){STATSTG Stat;hr = pStream->Stat( &Stat, STATFLAG_NONAME );ULONG ulNumBytes = Stat.cbSize.LowPart;if( ulNumBytes > MAXLONG ){hr = E_OUTOFMEMORY;}if( SUCCEEDED( hr ) &&fwrite( &ulNumBytes, sizeof(ulNumBytes), 1, hVoiceFile ) ){BYTE* Buff = (BYTE*)_malloca( ulNumBytes );if( SUCCEEDED( hr = pStream->Read( Buff, ulNumBytes, NULL ) ) ){if( !fwrite( Buff, 1, ulNumBytes, hVoiceFile ) ){hr = E_FAIL;}}_freea( Buff );}else{hr = E_FAIL;}}else{printf( "Input file: %s has wrong wav format.", (LPSTR)CW2A( WordFileName ) );}pStream->Release();}}else{hr = E_FAIL;}}}else{hr = E_FAIL;}if( SUCCEEDED( hr ) ){if( fseek( hVoiceFile, sizeof(dwVersion), SEEK_SET ) ||!fwrite( &ulNumWords, sizeof(ulNumWords), 1, hVoiceFile ) ){hr = E_FAIL;}}if( SUCCEEDED( hr ) ){CComPtr cpToken;CComPtr cpDataKeyAttribs;hr = SpCreateNewTokenEx(SPCAT_VOICES, argv[3], &CLSID_SampleTTSEngine, L"Sample TTS Voice", 0x409, L"Sample TTS Voice", &cpToken,&cpDataKeyAttribs);if (SUCCEEDED(hr)){hr = cpDataKeyAttribs->SetStringValue(L"Gender", L"Male");if (SUCCEEDED(hr)){hr = cpDataKeyAttribs->SetStringValue(L"Name", L"SampleTTSVoice");}if (SUCCEEDED(hr)){hr = cpDataKeyAttribs->SetStringValue(L"Language", L"409");}if (SUCCEEDED(hr)){hr = cpDataKeyAttribs->SetStringValue(L"Age", L"Adult");}if (SUCCEEDED(hr)){hr = cpDataKeyAttribs->SetStringValue(L"Vendor", L"Microsoft");}CHAR    szFullPath[MAX_PATH * 2];if (SUCCEEDED(hr) && _fullpath(szFullPath, CW2A(argv[2]), sizeof(szFullPath)/sizeof(szFullPath[0])) == NULL){hr = SPERR_NOT_FOUND;}if (SUCCEEDED(hr)){hr = cpToken->SetStringValue(L"VoiceData", CA2W(szFullPath));}}}if( hWordList  ){fclose( hWordList );}if( hVoiceFile ){fclose( hVoiceFile );}::CoUninitialize();}return FAILED( hr );}TTS引擎头文件#ifndef TtsEngObj_h#define TtsEngObj_h#ifndef __SampleTtsEngine_h__#include "SampleTtsEngine.h"#endif#ifndef SPDDKHLP_h#include #endif#ifndef SPCollec_h#include #endif#include "resource.h"class CSentItem{public:CSentItem() { memset( this, 0, sizeof(*this) ); }CSentItem( CSentItem& Other ) { memcpy( this, &Other, sizeof( Other ) ); }const SPVSTATE* pXmlState;LPCWSTR         pItem;ULONG           ulItemLen;ULONG           ulItemSrcOffset;        ULONG           ulItemSrcLen;    };typedef CSPList CItemList;/*** CTTSEngObj COM 接口 *********************************/class ATL_NO_VTABLE CTTSEngObj : public CComObjectRootEx,public CComCoClass,public ISpTTSEngine,public ISpObjectWithToken{public:DECLARE_REGISTRY_RESOURCEID(IDR_SAMPLETTSENGINE)DECLARE_PROTECT_FINAL_CONSTRUCT()BEGIN_COM_MAP(CTTSEngObj)COM_INTERFACE_ENTRY(ISpTTSEngine)COM_INTERFACE_ENTRY(ISpObjectWithToken)END_COM_MAP()public:    HRESULT FinalConstruct();void FinalRelease();public:STDMETHODIMP SetObjectToken( ISpObjectToken * pToken );STDMETHODIMP GetObjectToken( ISpObjectToken ** ppToken ){ return SpGenericGetObjectToken( ppToken, m_cpToken ); }STDMETHOD(Speak)( DWORD dwSpeakFlags,REFGUID rguidFormatId, const WAVEFORMATEX * pWaveFormatEx,const SPVTEXTFRAG* pTextFragList, ISpTTSEngineSite* pOutputSite );STDMETHOD(GetOutputFormat)( const GUID * pTargetFormatId, const WAVEFORMATEX * pTargetWaveFormatEx,GUID * pDesiredFormatId, WAVEFORMATEX ** ppCoMemDesiredWaveFormatEx );private:HRESULT MapFile(const WCHAR * pszTokenValName, HANDLE * phMapping, void ** ppvData );HRESULT GetNextSentence( CItemList& ItemList );BOOL    AddNextSentItem( CItemList& ItemList );HRESULT OutputSentence( CItemList& ItemList, ISpTTSEngineSite* pOutputSite );private:CComPtr m_cpToken;HANDLE                  m_hVoiceData;void*                   m_pVoiceData;VOICEITEM*          m_pWordList;ULONG               m_ulNumWords;const SPVTEXTFRAG*  m_pCurrFrag;const WCHAR*        m_pNextChar;const WCHAR*        m_pEndChar;ULONGLONG           m_ullAudioOff;};#endif TTS资源调用import "oaidl.idl";import "ocidl.idl";import "sapiddk.idl";typedef struct VOICEITEM{LPCWSTR pText;ULONG   ulTextLen;ULONG   ulNumAudioBytes;BYTE*   pAudio;} VOICEITEM;[uuid(7192AA2F-F759-43e9-91E7-226371EF6B2F),version(1.0),helpstring("Sample TTS Engine 1.0 Type Library")]library SAMPLETTSENGLib{importlib("stdole32.tlb");importlib("stdole2.tlb");[uuid(A832755E-9C2A-40b4-89B2-3A92EE705852),helpstring("SampleTTSEngine Class")]coclass SampleTTSEngine{[default] interface ISpTTSEngine;interface ISpObjectWithToken;};};TTS服务框架#include "stdafx.h"#include "resource.h"#include #include "SampleTtsEngine.h"#include "SampleTtsEngine_i.c"#include "TtsEngObj.h"CComModule _Module;BEGIN_OBJECT_MAP(ObjectMap)OBJECT_ENTRY( CLSID_SampleTTSEngine   , CTTSEngObj    )END_OBJECT_MAP()#ifdef _WIN32_WCEextern "C" BOOL WINAPI DllMain(HANDLE hInstance, ULONG dwReason, LPVOID)#elseextern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID #endif{if (dwReason == DLL_PROCESS_ATTACH){_Module.Init(ObjectMap, (HINSTANCE)hInstance, &LIBID_SAMPLETTSENGLib);}else if (dwReason == DLL_PROCESS_DETACH)_Module.Term();return TRUE;    }STDAPI DllCanUnloadNow(void){return (_Module.GetLockCount()==0) ? S_OK : S_FALSE;}STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv){return _Module.GetClassObject(rclsid, riid, ppv);}STDAPI DllRegisterServer(void){return _Module.RegisterServer(TRUE);}STDAPI DllUnregisterServer(void){return _Module.UnregisterServer(TRUE);}TTS预留接口EXPORTSDllCanUnloadNow     PRIVATEDllGetClassObject   PRIVATEDllRegisterServer   PRIVATEDllUnregisterServer PRIVATE/********************************************************************************TTS引擎实现********************************************************************************/#include "stdafx.h"#include "TtsEngObj.h"/******************************************************************************----------------------------* *描述: *构造*****************************************************************************/HRESULT CTTSEngObj::FinalConstruct(){HRESULT hr = S_OK;m_hVoiceData = NULL;m_pVoiceData = NULL;m_pWordList  = NULL;m_ulNumWords = 0;return hr;} void CTTSEngObj::FinalRelease(){delete m_pWordList;if( m_pVoiceData ){::UnmapViewOfFile( (void*)m_pVoiceData );}if( m_hVoiceData ){::CloseHandle( m_hVoiceData );}} HRESULT CTTSEngObj::MapFile( const WCHAR * pszTokenVal,  HANDLE * phMapping,          void ** ppvData )            {HRESULT hr = S_OK;CSpDynamicString dstrFilePath;hr = m_cpToken->GetStringValue( pszTokenVal, &dstrFilePath );if ( SUCCEEDED( hr ) ){bool fWorked = false;*phMapping = NULL;*ppvData = NULL;HANDLE hFile;#ifdef _WIN32_WCEhFile = CreateFileForMapping( dstrFilePath, GENERIC_READ,FILE_SHARE_READ, NULL, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, NULL );#elsehFile = CreateFile( CW2T(dstrFilePath), GENERIC_READ,FILE_SHARE_READ, NULL, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, NULL );#endifif (hFile != INVALID_HANDLE_VALUE){*phMapping = ::CreateFileMapping( hFile, NULL, PAGE_READONLY, 0, 0, NULL );if (*phMapping){*ppvData = ::MapViewOfFile( *phMapping, FILE_MAP_READ, 0, 0, 0 );if (*ppvData){fWorked = true;}}::CloseHandle( hFile );}if (!fWorked){hr = HRESULT_FROM_WIN32(::GetLastError());if (*phMapping){::CloseHandle(*phMapping);*phMapping = NULL;}}}return hr;}STDMETHODIMP CTTSEngObj::SetObjectToken(ISpObjectToken * pToken){HRESULT hr = SpGenericSetObjectToken(pToken, m_cpToken);if( SUCCEEDED( hr ) ){hr = MapFile( L"VoiceData", &m_hVoiceData, &m_pVoiceData );}if( SUCCEEDED( hr ) ){delete m_pWordList;UNALIGNED DWORD* pdwPtr = (UNALIGNED DWORD*)m_pVoiceData;if( *pdwPtr++ != 1 ){hr = E_INVALIDARG;_ASSERT(0);}if( SUCCEEDED( hr ) ){m_ulNumWords = *pdwPtr++;}m_pWordList = new VOICEITEM[m_ulNumWords];if( !m_pWordList ){hr = E_OUTOFMEMORY;}else{for( ULONG i = 0; i < m_ulNumWords; ++i ){ULONG ulTextByteLen = *pdwPtr++;m_pWordList.pText = (UNALIGNED LPCWSTR)pdwPtr;m_pWordList.ulTextLen = (ulTextByteLen / sizeof(WCHAR)) - 1;pdwPtr = (UNALIGNED DWORD*)(((BYTE*)pdwPtr) + ulTextByteLen);m_pWordList.ulNumAudioBytes = *pdwPtr++;m_pWordList.pAudio = (BYTE*)pdwPtr;pdwPtr = (UNALIGNED DWORD*)(((BYTE*)pdwPtr) + m_pWordList.ulNumAudioBytes);}}}return hr;} /****************************************************************************** CTTSEngObj : :说话* *-------------------* *描述: *这是主要的方法的SAPI要求提供的案文。 *------------------------------------------------- ---------------------------- *输入参数 * * pUser *指针当前的用户配置文件对象。这个对象包含 *信息,如哪些语言和正在使用此对象 *还提供获得资源,如掌握词汇的SAPI对象。 * * dwSpeakFlags *这是一套用来控制旗帜的行为 *的SAPI语音对象和相关的发动机。 * * VoiceFmtIndex *零基础的索引指定的输出格式,应 *用于在渲染。 * * pTextFragList *一个链表的文字片段将会作出。有 *每一个片段的XML状态的变化。如果输入文本并 *不包含任何的XML标记,将只有一个单一的片段。 * * pOutputSite *该接口返回的SAPI ,所有输出的音频样本和事件是书面。 * *返回值 * S_OK -这应该是成功的渲染后返回,或者如果 *渲染被打断,因为* pfContinue更改为FALSE 。 * E_INVALIDARG ******************************************************************************/STDMETHODIMP CTTSEngObj::Speak( DWORD dwSpeakFlags,REFGUID rguidFormatId,const WAVEFORMATEX * pWaveFormatEx,const SPVTEXTFRAG* pTextFragList,ISpTTSEngineSite* pOutputSite ){HRESULT hr = S_OK;if( SP_IS_BAD_INTERFACE_PTR( pOutputSite ) ||SP_IS_BAD_READ_PTR( pTextFragList )  ){hr = E_INVALIDARG;}else{m_pCurrFrag   = pTextFragList;m_pNextChar   = m_pCurrFrag->pTextStart;m_pEndChar    = m_pNextChar + m_pCurrFrag->ulTextLen;m_ullAudioOff = 0;CItemList ItemList;while( SUCCEEDED( hr ) && !(pOutputSite->GetActions() & SPVES_ABORT) ){if( pOutputSite->GetActions() & SPVES_SKIP ){long lSkipCnt;SPVSKIPTYPE eType;hr = pOutputSite->GetSkipInfo( &eType, &lSkipCnt );if( SUCCEEDED( hr ) ){hr = pOutputSite->CompleteSkip( 0 );}}if( SUCCEEDED( hr ) && (hr = GetNextSentence( ItemList )) != S_OK ){break;                }if( !(pOutputSite->GetActions() & SPVES_ABORT) ){CSentItem& FirstItem = ItemList.GetHead();CSentItem& LastItem  = ItemList.GetTail();CSpEvent Event;Event.eEventId             = SPEI_SENTENCE_BOUNDARY;Event.elParamType          = SPET_LPARAM_IS_UNDEFINED;Event.ullAudioStreamOffset = m_ullAudioOff;Event.lParam               = (LPARAM)FirstItem.ulItemSrcOffset;Event.wParam               = (WPARAM)LastItem.ulItemSrcOffset +LastItem.ulItemSrcLen -FirstItem.ulItemSrcOffset;hr = pOutputSite->AddEvents( &Event, 1 );if( SUCCEEDED( hr ) ){hr = OutputSentence( ItemList, pOutputSite );}}}if( hr == S_FALSE ){hr = S_OK;}}return hr;}HRESULT CTTSEngObj::OutputSentence( CItemList& ItemList, ISpTTSEngineSite* pOutputSite ){HRESULT hr = S_OK;ULONG WordIndex;SPLISTPOS ListPos = ItemList.GetHeadPosition();while( ListPos && !(pOutputSite->GetActions() & SPVES_ABORT) ){CSentItem& Item = ItemList.GetNext( ListPos );switch( Item.pXmlState->eAction ){case SPVA_Speak:{if( iswalpha( Item.pItem[0] ) || iswdigit( Item.pItem[0] ) ){for( WordIndex = 0; WordIndex < m_ulNumWords; ++WordIndex ){if( ( m_pWordList[WordIndex].ulTextLen == Item.ulItemLen ) &&( !_wcsnicmp( m_pWordList[WordIndex].pText, Item.pItem, Item.ulItemLen )) ){break;}}if( WordIndex == m_ulNumWords ){WordIndex = 0;}CSpEvent Event;Event.eEventId             = SPEI_WORD_BOUNDARY;Event.elParamType          = SPET_LPARAM_IS_UNDEFINED;Event.ullAudioStreamOffset = m_ullAudioOff;Event.lParam               = Item.ulItemSrcOffset;Event.wParam               = Item.ulItemSrcLen;pOutputSite->AddEvents( &Event, 1 );hr = pOutputSite->Write( m_pWordList[WordIndex].pAudio,m_pWordList[WordIndex].ulNumAudioBytes,NULL );m_ullAudioOff += m_pWordList[WordIndex].ulNumAudioBytes;}}break;case SPVA_Silence:{BYTE Buff[1000];memset( Buff, 0, 1000 );ULONG NumSilenceBytes = Item.pXmlState->SilenceMSecs * 22;while( !(pOutputSite->GetActions() & SPVES_ABORT) ){if( NumSilenceBytes > 1000 ){hr = pOutputSite->Write( Buff, 1000, NULL );NumSilenceBytes -= 1000;}else{hr = pOutputSite->Write( Buff, NumSilenceBytes, NULL );break;}}m_ullAudioOff += NumSilenceBytes;}break;case SPVA_Bookmark:{WCHAR * pszBookmark = (WCHAR *)_malloca((Item.ulItemLen + 1) * sizeof(WCHAR));memcpy(pszBookmark, Item.pItem, Item.ulItemLen * sizeof(WCHAR));pszBookmark[Item.ulItemLen] = 0;SPEVENT Event;Event.eEventId             = SPEI_TTS_BOOKMARK;Event.elParamType          = SPET_LPARAM_IS_STRING;Event.ullAudioStreamOffset = m_ullAudioOff;Event.lParam               = (LPARAM)pszBookmark;Event.wParam               = _wtol(pszBookmark);hr = pOutputSite->AddEvents( &Event, 1 );_freea(pszBookmark);}break;case SPVA_Pronounce:break;case SPVA_ParseUnknownTag:break;}}return hr;} /* CTTSEngObj::OutputSentence */STDMETHODIMP CTTSEngObj::GetOutputFormat( const GUID * pTargetFormatId, const WAVEFORMATEX * pTargetWaveFormatEx,GUID * pDesiredFormatId, WAVEFORMATEX ** ppCoMemDesiredWaveFormatEx ){HRESULT hr = S_OK;hr = SpConvertStreamFormatEnum(SPSF_11kHz16BitMono, pDesiredFormatId, ppCoMemDesiredWaveFormatEx);return hr;}HRESULT CTTSEngObj::GetNextSentence( CItemList& ItemList ){HRESULT hr = S_OK;ItemList.RemoveAll();if( m_pCurrFrag == NULL ){hr = S_FALSE;}else{BOOL fSentDone = false;BOOL fGoToNextFrag = false;while( m_pCurrFrag && !fSentDone ){if( m_pCurrFrag->State.eAction == SPVA_Speak ){fSentDone = AddNextSentItem( ItemList );if( m_pNextChar >= m_pEndChar ){fGoToNextFrag = true;}}else{CSentItem Item;Item.pItem           = m_pCurrFrag->pTextStart;Item.ulItemLen       = m_pCurrFrag->ulTextLen;Item.ulItemSrcOffset = m_pCurrFrag->ulTextSrcOffset;Item.ulItemSrcLen    = Item.ulItemLen;Item.pXmlState       = &m_pCurrFrag->State;ItemList.AddTail( Item );fGoToNextFrag = true;}if( fGoToNextFrag ){fGoToNextFrag = false;m_pCurrFrag = m_pCurrFrag->pNext;if( m_pCurrFrag ){m_pNextChar = m_pCurrFrag->pTextStart;m_pEndChar  = m_pNextChar + m_pCurrFrag->ulTextLen;}else{m_pNextChar = NULL;m_pEndChar  = NULL;}}} if( ItemList.IsEmpty() ){hr = S_FALSE;}}return hr;} static BOOL IsSpace( WCHAR wc ){return ( ( wc == 0x20 ) || ( wc == 0x9 ) || ( wc == 0xD  ) || ( wc == 0xA ) );}static const WCHAR* SkipWhiteSpace( const WCHAR* pPos ){while( IsSpace( *pPos ) ) ++pPos;return pPos;}static const WCHAR* FindNextToken( const WCHAR* pStart, const WCHAR* pEnd, const WCHAR*& pNext ){const WCHAR* pPos = SkipWhiteSpace( pStart );pNext = pPos;if( pNext == pEnd ){pPos = NULL;}else{while( *pNext && !IsSpace( *pNext ) ){if( ++pNext == pEnd ){break;}}}return pPos;} BOOL SearchSet( WCHAR wc, const WCHAR* Set, ULONG Count, ULONG* pIndex ){for( ULONG i = 0; i < Count; ++i ){if( wc == Set ){*pIndex = i;return true;}}return false;}BOOL CTTSEngObj::AddNextSentItem( CItemList& ItemList ){ULONG ulIndex;CSentItem Item;Item.pItem = FindNextToken( m_pNextChar, m_pEndChar, m_pNextChar );if( Item.pItem == NULL ){return false;}const WCHAR* pTrailChar = m_pNextChar-1;ULONG TokenLen = (ULONG)(m_pNextChar - Item.pItem);static const WCHAR LeadItems[] = { L'(', L'/"', L'{', L'/'', L'[' };while( TokenLen > 1 ){if( SearchSet( Item.pItem[0], LeadItems, sp_countof(LeadItems), &ulIndex ) ){CSentItem LItem;LItem.pItem           = Item.pItem;LItem.ulItemLen       = 1;LItem.pXmlState       = &m_pCurrFrag->State;LItem.ulItemSrcLen    = LItem.ulItemLen;LItem.ulItemSrcOffset = m_pCurrFrag->ulTextSrcOffset +(ULONG)( LItem.pItem - m_pCurrFrag->pTextStart );ItemList.AddTail( LItem );++Item.pItem;--TokenLen;}else{break;}}SPLISTPOS ItemPos = ItemList.AddTail( Item );static const WCHAR EOSItems[] = { L'.', L'!', L'?' };static const WCHAR TrailItems[] = { L',', L'/"', L';', L':', L')', L'}', L'/'', L']' };BOOL fIsEOS = false;while( TokenLen > 1 ){BOOL fAddTrailItem = false;if( SearchSet( *pTrailChar, EOSItems, sp_countof(EOSItems), &ulIndex ) ){fIsEOS = true;fAddTrailItem = true;}else if( SearchSet( *pTrailChar, TrailItems, sp_countof(TrailItems), &ulIndex ) ){fAddTrailItem = true;}if( fAddTrailItem ){CSentItem TItem;TItem.pItem           = pTrailChar;TItem.ulItemLen       = 1;TItem.pXmlState       = &m_pCurrFrag->State;TItem.ulItemSrcLen    = TItem.ulItemLen;TItem.ulItemSrcOffset = m_pCurrFrag->ulTextSrcOffset +(ULONG)( TItem.pItem - m_pCurrFrag->pTextStart );ItemList.InsertAfter( ItemPos, TItem );--TokenLen;--pTrailChar;}else{break;}}if( *m_pNextChar == NULL ){fIsEOS = true;if( !SearchSet( *(m_pNextChar-1), EOSItems, sp_countof(EOSItems), &ulIndex ) ){static const WCHAR* pPeriod = L".";CSentItem EOSItem;EOSItem.pItem           = pPeriod;EOSItem.ulItemLen       = 1;EOSItem.pXmlState       = &m_pCurrFrag->State;EOSItem.ulItemSrcLen    = EOSItem.ulItemLen;EOSItem.ulItemSrcOffset = m_pCurrFrag->ulTextSrcOffset +(ULONG)( (m_pNextChar-1) - m_pCurrFrag->pTextStart );ItemList.AddTail( EOSItem );}}else if( pTrailChar[1] == L'.' ){}for( ULONG i = 0; i < TokenLen; ++i ){if( Item.pItem == L'/'' ){((WCHAR)Item.pItem) = L'_';}}if( TokenLen > 0 ){Item.ulItemLen       = TokenLen;Item.pXmlState       = &m_pCurrFrag->State;Item.ulItemSrcLen    = Item.ulItemLen;Item.ulItemSrcOffset = m_pCurrFrag->ulTextSrcOffset +(ULONG)( Item.pItem - m_pCurrFrag->pTextStart );ItemList.SetAt( ItemPos, Item );}return fIsEOS;}

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-62216-1-1.html 上篇帖子: [置顶]基于Windows Sdk 与visual C++2008 在微软平台上构架自己的语音朗读引擎(适用于windows 2000/xp2003/vista 下篇帖子: Windows server 2008搭建php运行环境
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表