Wrong method sequence in ID2D1SvgElement API.

Tony 96 Reputation points
2020-08-07T12:29:17.143+00:00

Hello,
As we are working on this API, we noticed that the implemented methods ID2D1SvgElement API (d2d1svg.h) are in the wrong sequence.
The right sequence of the methods, leaving out the comment and inline methods should be:

    interface DX_DECLARE_INTERFACE("ac7b67a6-183e-49c1-a823-0ebe40b0db29") ID2D1SvgElement  : public ID2D1Resource
    {

        STDMETHOD_(void, GetDocument)(
            _Outptr_result_maybenull_ ID2D1SvgDocument **document 
            ) PURE;

        STDMETHOD(GetTagName)(
            _Out_writes_(nameCount) PWSTR name,
            UINT32 nameCount 
            ) PURE;

        STDMETHOD_(UINT32, GetTagNameLength)(
            ) PURE;

        STDMETHOD_(BOOL, IsTextContent)(
            ) PURE;

        STDMETHOD_(void, GetParent)(
            _Outptr_result_maybenull_ ID2D1SvgElement **parent 
            ) PURE;

        STDMETHOD_(BOOL, HasChildren)(
            ) PURE;

        STDMETHOD_(void, GetFirstChild)(
            _Outptr_result_maybenull_ ID2D1SvgElement **child 
            ) PURE;

        STDMETHOD_(void, GetLastChild)(
            _Outptr_result_maybenull_ ID2D1SvgElement **child 
            ) PURE;

        STDMETHOD(GetPreviousChild)(
            _In_ ID2D1SvgElement *referenceChild,
            _COM_Outptr_result_maybenull_ ID2D1SvgElement **previousChild 
            ) PURE;

        STDMETHOD(GetNextChild)(
            _In_ ID2D1SvgElement *referenceChild,
            _COM_Outptr_result_maybenull_ ID2D1SvgElement **nextChild 
            ) PURE;

        STDMETHOD(InsertChildBefore)(
            _In_ ID2D1SvgElement *newChild,
            _In_opt_ ID2D1SvgElement *referenceChild = NULL 
            ) PURE;

       STDMETHOD(AppendChild)(
            _In_ ID2D1SvgElement *newChild 
            ) PURE;

        STDMETHOD(ReplaceChild)(
            _In_ ID2D1SvgElement *newChild,
            _In_ ID2D1SvgElement *oldChild 
            ) PURE;

        STDMETHOD(RemoveChild)(
            _In_ ID2D1SvgElement *oldChild 
            ) PURE;

        STDMETHOD(CreateChild)(
            _In_ PCWSTR tagName,
            _COM_Outptr_ ID2D1SvgElement **newChild 
            ) PURE;

        STDMETHOD_(BOOL, IsAttributeSpecified)(
            _In_ PCWSTR name,
            _Out_opt_ BOOL *inherited = NULL 
            ) PURE;

        STDMETHOD_(UINT32, GetSpecifiedAttributeCount)(
            ) PURE;

        STDMETHOD(GetSpecifiedAttributeName)(
            UINT32 index,
            _Out_writes_(nameCount) PWSTR name,
            UINT32 nameCount,
            _Out_opt_ BOOL *inherited = NULL 
            ) PURE;

        STDMETHOD(GetSpecifiedAttributeNameLength)(
            UINT32 index,
            _Out_ UINT32 *nameLength,
            _Out_opt_ BOOL *inherited = NULL 
            ) PURE;

        STDMETHOD(RemoveAttribute)(
            _In_ PCWSTR name 
            ) PURE;

        STDMETHOD(SetTextValue)(
            _In_reads_(nameCount) CONST WCHAR *name,
            UINT32 nameCount 
            ) PURE;

        STDMETHOD(GetTextValue)(
            _Out_writes_(nameCount) PWSTR name,
            UINT32 nameCount 
            ) PURE;

        STDMETHOD_(UINT32, GetTextValueLength)(
            ) PURE;

        /* this section should be in this sequence /*

        STDMETHOD(SetAttributeValue)(
            _In_ PCWSTR name,
            _In_ ID2D1SvgAttribute *value 
            ) PURE;

        STDMETHOD(SetAttributeValue)(
            _In_ PCWSTR name,
            D2D1_SVG_ATTRIBUTE_POD_TYPE type,
            _In_reads_bytes_(valueSizeInBytes) CONST void *value,
            UINT32 valueSizeInBytes 
            ) PURE;

        STDMETHOD(SetAttributeValue)(
            _In_ PCWSTR name,
            D2D1_SVG_ATTRIBUTE_STRING_TYPE type,
            _In_ PCWSTR value 
            ) PURE;

        STDMETHOD(GetAttributeValue)(
            _In_ PCWSTR name,
            _In_ REFIID riid,
            _COM_Outptr_result_maybenull_ void **value 
            ) PURE;

        STDMETHOD(GetAttributeValue)(
            _In_ PCWSTR name,
            D2D1_SVG_ATTRIBUTE_POD_TYPE type,
            _Out_writes_bytes_(valueSizeInBytes) void *value,
            UINT32 valueSizeInBytes 
            ) PURE;

        STDMETHOD(GetAttributeValue)(
            _In_ PCWSTR name,
            D2D1_SVG_ATTRIBUTE_STRING_TYPE type,
            _Out_writes_(valueCount) PWSTR value,
            UINT32 valueCount 
            ) PURE;

        STDMETHOD(GetAttributeValueLength)(
            _In_ PCWSTR name,
            D2D1_SVG_ATTRIBUTE_STRING_TYPE type,
            _Out_ UINT32 *valueLength 
            ) PURE;

    }; // interface ID2D1SvgElement
Windows development Windows API - Win32
{count} votes

Accepted answer
  1. Fei Xue - MSFT 1,111 Reputation points
    2020-08-17T09:33:39.94+00:00

    Here is the code:

      hr = element->GetAttributeValue(L"fill", &paint);
            //DX::ThrowIfFailed(element->GetAttributeValue(L"fill", &paint));
         /*   element->GetAttributeValue(L"fill", D2D1_SVG_ATTRIBUTE_POD_TYPE_COLOR, &color, sizeof(D2D1_COLOR_F));
            element->SetAttributeValue(L"fill", D2D1_SVG_ATTRIBUTE_POD_TYPE_COLOR, &newColor, sizeof(D2D1_COLOR_F));
            element->GetAttributeValue(L"fill", D2D1_SVG_ATTRIBUTE_POD_TYPE_COLOR, &afterSetColor, sizeof(D2D1_COLOR_F));*/
    
            if (SUCCEEDED(hr))
            {
                hr = element->SetAttributeValue(L"fill", D2D1_SVG_ATTRIBUTE_POD_TYPE_COLOR, &newColor, sizeof(D2D1_COLOR_F));
            }
    
            if (SUCCEEDED(hr))
            {
                OutputDebugStringA("SetAttributeValue OK.\n");
    
                hr = element->GetAttributeValue(L"fill", D2D1_SVG_ATTRIBUTE_POD_TYPE_COLOR, &afterSetColor, sizeof(D2D1_COLOR_F));
            }
            else
            {
                OutputDebugStringA("SetAttributeValue failed.\n");
            }
    
            if (SUCCEEDED(hr))
            {
                OutputDebugStringA("GetAttributeValue OK.\n");
            }
            else
                OutputDebugStringA("GetAttributeValue failed.\n");
    
    
            if (FAILED(hr))
            {
                //wprintf_s(L"Failed. 0x%X error.\n", hr);
                DX::ThrowIfFailed(hr);
            }
    

2 additional answers

Sort by: Most helpful
  1. Tony 96 Reputation points
    2020-08-14T00:29:54.103+00:00

    @Fei Xue - MSFT
    Because a reply on your reply doesn't work anymore on this site, I'll reply this way:

    It would be handy to add code the appropiate way like putting it in a codeblock with comments, instead of attaching a screenshot with code that costs me time to figure out from where this code is originated.
    I'll test your suggestion asap.
    Never the less, the interface vtable does not corresponds with the API header.
    As agreed more than a decade ago Microsoft headerfiles should be compatible with other languages that includes correct interface method sequences (vtables), method naming conventions and naming parameters or offer alternatives for semantics.

    Thanks, Tony.

    UPDATE

    I tested D2DSvgImage, and not surprisingly after 2 times calling GetAttributeValue and SetAttributeValue the debugger throws this exception in VS2019:

    Exception thrown at 0x00007FFFC866A719 in D2DSvgImage.exe: Microsoft C++ exception: Platform::InvalidArgumentException ^ at memory location 0x000000C759FFCA08. HRESULT:0x80070057 The parameter is incorrect.

    WinRT information: The parameter is incorrect.

    This is exactly what Delphi is returning when executing this code.

    I altered the code a bit to check return values:

    void D2DSvgImageRenderer::RecolorSubtree(ID2D1SvgElement* element, D2D1_COLOR_F newColor)  
    {  
        // Check if this SVG element has a "fill" element explicitly specified or inherited.  
        if (element->IsAttributeSpecified(L"fill"))  
        {  
            // Retrieve the value of this element's "fill" attribute, as a paint object.  
            ComPtr<ID2D1SvgPaint> paint;  
             
            HRESULT hr = S_OK;  
      
            D2D1_COLOR_F color;  
            D2D1_COLOR_F newColor;  
            D2D1_COLOR_F afterSetColor;  
      
            newColor.r = 50;  
            newColor.g = 100;  
      
            hr = element->GetAttributeValue(L"fill", &paint);          
              
            //DX::ThrowIfFailed(element->GetAttributeValue(L"fill", &paint));  
             
            if (SUCCEEDED(hr))  
            {  
                hr = element->GetAttributeValue(L"fill", D2D1_SVG_ATTRIBUTE_POD_TYPE_COLOR, &color, sizeof(D2D1_COLOR_F));  
                if (SUCCEEDED(hr))  
                {  
                    hr = element->SetAttributeValue(L"fill", D2D1_SVG_ATTRIBUTE_POD_TYPE_COLOR, &newColor, sizeof(D2D1_COLOR_F));  
                }  
      
                if (SUCCEEDED(hr))  
                {  
                    hr = element->GetAttributeValue(L"fill", D2D1_SVG_ATTRIBUTE_POD_TYPE_COLOR, &afterSetColor, sizeof(D2D1_COLOR_F));  
                }  
            }  
      
            if (FAILED(hr))  
            {  
                //wprintf_s(L"Failed. 0x%X error.\n", hr);  
                DX::ThrowIfFailed(hr);  
            }  
      
      
            // Check the type of paint object that was set. There are different types of  
            // paints, such as plain colors, URLs, or the 'none' type. For this app we  
            // only want to modify fills that were set to a specific color.  
            D2D1_SVG_PAINT_TYPE paintType = paint->GetPaintType();  
    

    17660-ss-codesample-001.jpg


  2. Tony 96 Reputation points
    2022-04-25T00:29:13.3+00:00

    So the end conclusion is:

    The definition of the ID2D1SvgElement API (d2d1svg.h) is in wrong sequence.
    The sample to check this, presented in this conversation, shows the same flaw when running the sample multiple times where it throws an exception instead of returning a HResult.
    The flaw still exists in SDK 10.0.22000.0
    Thank you.

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.