BOOL CSampleIME::_FindComposingRange(TfEditCookie ec, _In_ ITfContext *pContext, _In_ ITfRange *pSelection, _Outptr_result_maybenull_ ITfRange **ppRange)
{
    if (ppRange == nullptr)
    {
        return FALSE;
    }

    *ppRange = nullptr;

    // find GUID_PROP_COMPOSING
    ITfProperty* pPropComp = nullptr;
    IEnumTfRanges* enumComp = nullptr;

	/* GetProperty(GUID_PROP_COMPOSING, ...) -- nonzero if text is part of a composition */
    HRESULT hr = pContext->GetProperty(GUID_PROP_COMPOSING, &pPropComp);
    if (FAILED(hr) || pPropComp == nullptr)
    {
        return FALSE;
    }

	/* EnumRanges:
		Obtains an enumeration of ranges that contain unique values of the property GUID_PROP_COMPOSING within the given range */
    hr = pPropComp->EnumRanges(ec, &enumComp, pSelection);
    if (FAILED(hr) || enumComp == nullptr)
    {
        pPropComp->Release();
        return FALSE;
    }

    BOOL isCompExist = FALSE;
    VARIANT var;
    ULONG  fetched = 0;

    while (enumComp->Next(1, ppRange, &fetched) == S_OK && fetched == 1)
    {
        hr = pPropComp->GetValue(ec, *ppRange, &var);
        if (hr == S_OK)
        {
            if (var.vt == VT_I4 && var.lVal != 0)
            {
                isCompExist = TRUE;
                break;
            }
        }
        (*ppRange)->Release();
        *ppRange = nullptr;
    }

    pPropComp->Release();
    enumComp->Release();

    return isCompExist;
}
Beispiel #2
0
BOOL CDIME::_FindComposingRange(TfEditCookie ec, _In_ ITfContext *pContext, _In_ ITfRange *pSelection, _Outptr_result_maybenull_ ITfRange **ppRange)
{
	debugPrint(L"CDIME::_FindComposingRange()");

    if (pContext == nullptr || ppRange == nullptr)
    {
		debugPrint(L"CDIME::_FindComposingRange() failed with null pContext or pRange");
        return FALSE;
    }

    *ppRange = nullptr;

    // find GUID_PROP_COMPOSING
    ITfProperty* pPropComp = nullptr;
    IEnumTfRanges* enumComp = nullptr;

    HRESULT hr = pContext->GetProperty(GUID_PROP_COMPOSING, &pPropComp);
    if (FAILED(hr) || pPropComp == nullptr)
    {
		if (FAILED(hr))
			debugPrint(L"CDIME::_FindComposingRange()  pContext->GetProperty() failed");
		else
			debugPrint(L"CDIME::_FindComposingRange() failed with null pPropComp");
        return FALSE;
    }

    hr = pPropComp->EnumRanges(ec, &enumComp, pSelection);
    if (FAILED(hr) || enumComp == nullptr)
    {
		if (FAILED(hr))
			debugPrint(L"CDIME::_FindComposingRange()  pPropComp->EnumRanges failed");
		else
			debugPrint(L"CDIME::_FindComposingRange() failed with null enumComp");
        pPropComp->Release();
        return FALSE;
    }

    BOOL isCompExist = FALSE;
    VARIANT var;
    ULONG  fetched = 0;

    while (enumComp->Next(1, ppRange, &fetched) == S_OK && fetched == 1)
    {
		debugPrint(L"CDIME::_FindComposingRange() enumComp->Next() ");
        hr = pPropComp->GetValue(ec, *ppRange, &var);
        if (hr == S_OK)
        {
            if (var.vt == VT_I4 && var.lVal != 0)
            {
				WCHAR rangeText[4096];
				rangeText[0] = NULL;
				fetched = 0;
				hr = (*ppRange)->GetText(ec, 0, rangeText, 4096, &fetched);
				if (SUCCEEDED(hr))
				{
					if (lastReadingString.GetLength() > 0) // The last reading string is null when composing is just started and the range should be empty.
					{
						debugPrint(L"CDIME::_FindComposingRange() text in range = %s with %d character, last reading string = %s with %d characters",
							rangeText, fetched, lastReadingString.Get(), lastReadingString.GetLength());
						UINT cmpCount = (int)lastReadingString.GetLength();
						BOOL rangeMatchReadingString = FALSE;
						if (fetched > 0 && fetched > cmpCount)
						{
							LONG shifted = 0;
							// range contains other characters than last reading string, and these characters should be skipped with shifting the start anchor
							(*ppRange)->ShiftStart(ec, fetched - cmpCount, &shifted, NULL);
							debugPrint(L"CDIME::_FindComposingRange() shift start anchor with %d characters", shifted);
							rangeText[0] = NULL;
							hr = (*ppRange)->GetText(ec, 0, rangeText, 4096, &fetched);
							if (SUCCEEDED(hr))
								debugPrint(L"CDIME::_FindComposingRange() text in range with shited anchor = %s with %d character", rangeText, fetched);
						}
						// The range we are composing should always matched with the last reading string.
						rangeMatchReadingString = CompareString(GetLocale(), 0, rangeText, cmpCount, lastReadingString.Get(), cmpCount) == CSTR_EQUAL;
				
						if (rangeMatchReadingString)
						{
							isCompExist = TRUE;
							debugPrint(L"CDIME::_FindComposingRange() text in this range mathced with last reading string. isCompExist = TRUE");
							break;
						}
					}
					
				}
				else
				{
					debugPrint(L"CDIME::_FindComposingRange() cannot getText from range isCompExist = TRUE");
				}
            }
        }
		debugPrint(L"CDIME::_FindComposingRange() release *ppRange");
        if(*ppRange)
			(*ppRange)->Release();
        *ppRange = nullptr;
    }

    pPropComp->Release();
    enumComp->Release();

    return isCompExist;
}
void CTSFEditWnd::_Save(IStream *pStream)
{
    if(pStream)
    {
        HRESULT hr;
        
        //write the plain UNICODE text into the stream
        LPWSTR          pwsz;
        LONG            cch;
        ULONG           uWritten;
        LARGE_INTEGER   li;
        ULONG           uSize;

        //set the stream pointer to the start of the stream
        li.QuadPart = 0;
        pStream->Seek(li, STREAM_SEEK_SET, NULL);
        
        //get the text
        if(SUCCEEDED(_GetText(&pwsz, &cch)))
        {
            TF_PERSISTENT_PROPERTY_HEADER_ACP   PropHeader;

            //write the size, in BYTES, of the text
            uSize = cch * sizeof(WCHAR);
            hr = pStream->Write(&uSize, sizeof(ULONG), &uWritten);

            //write the text, including the NULL_terminator, into the stream
            hr = pStream->Write(pwsz, uSize, &uWritten);

            //free the memory allocated by _GetText
            GlobalFree(pwsz);

            //enumerate the properties in the context
            IEnumTfProperties   *pEnumProps;
            hr = m_pContext->EnumProperties(&pEnumProps);
            if(SUCCEEDED(hr))
            {
                ITfProperty *pProp;
                ULONG       uFetched;

                while(SUCCEEDED(pEnumProps->Next(1, &pProp, &uFetched)) && uFetched)
                {
                    //enumerate all the ranges that contain the property
                    IEnumTfRanges   *pEnumRanges;
                    hr = pProp->EnumRanges(m_EditCookie, &pEnumRanges, NULL);
                    if(SUCCEEDED(hr))
                    {
                        IStream *pTempStream;

                        //create a temporary stream to write the property data to
                        hr = CreateStreamOnHGlobal(NULL, TRUE, &pTempStream);
                        if(SUCCEEDED(hr))
                        {
                            ITfRange    *pRange;

                            while(SUCCEEDED(pEnumRanges->Next(1, &pRange, &uFetched)) && uFetched)
                            {
                                //reset the temporary stream's pointer
                                li.QuadPart = 0;
                                pTempStream->Seek(li, STREAM_SEEK_SET, NULL);
                                
                                //get the property header and data for the range
                                hr = m_pServices->Serialize(pProp, pRange, &PropHeader, pTempStream);

                                /*
                                Write the property header into the primary stream. 
                                The header also contains the size of the property 
                                data.
                                */
                                hr = pStream->Write(&PropHeader, sizeof(TF_PERSISTENT_PROPERTY_HEADER_ACP), &uWritten);

                                //reset the temporary stream's pointer
                                li.QuadPart = 0;
                                pTempStream->Seek(li, STREAM_SEEK_SET, NULL);

                                //copy the property data from the temporary stream into the primary stream
                                ULARGE_INTEGER  uli;
                                uli.QuadPart = PropHeader.cb;

                                hr = pTempStream->CopyTo(pStream, uli, NULL, NULL);

                                pRange->Release();
                            }
                            
                            pTempStream->Release();
                        }
                        
                        pEnumRanges->Release();
                    }
                    
                    pProp->Release();
                }
                
                pEnumProps->Release();
            }

            //write a property header with zero size and guid into the stream as a terminator
            ZeroMemory(&PropHeader, sizeof(TF_PERSISTENT_PROPERTY_HEADER_ACP));
            hr = pStream->Write(&PropHeader, sizeof(TF_PERSISTENT_PROPERTY_HEADER_ACP), &uWritten);
        }
    }
}