Jump to content
Sign in to follow this  
pyscripter

Translation of C headers.

Recommended Posts

In d2d1svg.h (Direct2D) there is the following declaration of the ID2D1SvgElement interface:

/// <summary>
/// Sets an attribute of this element using a POD type. Returns an error if the
/// attribute name is not valid on this element. Returns an error if the attribute
/// cannot be expressed as the specified type.
/// </summary>
STDMETHOD(SetAttributeValue)(
_In_ PCWSTR name,
D2D1_SVG_ATTRIBUTE_POD_TYPE type,
_In_reads_bytes_(valueSizeInBytes) CONST void *value,
UINT32 valueSizeInBytes
) PURE;
 

D2D1_SVG_ATTRIBUTE_POD_TYPE = DWord;

 

I am translating this as 

    function SetAttributeValue(name: LPWSTR;
                               _type: D2D1_SVG_ATTRIBUTE_POD_TYPE;
                               value: Pointer;
                               valueSizeInBytes: UINT32): HResult; overload; stdcall;

But it crashes when it is used.

 

The assembly prolog of SetAttributeValue is

564711F0 6690             nop 
564711F2 55               push ebp
564711F3 8BEC             mov ebp,esp
564711F5 83EC14           sub esp,$14
564711F8 8B4508           mov eax,[ebp+$08]
564711FB 33C9             xor ecx,ecx
564711FD 53               push ebx
564711FE 56               push esi
564711FF 57               push edi
56471200 8D5808           lea ebx,[eax+$08]
56471203 85DB             test ebx,ebx
56471205 6A08             push $08
56471207 0F44C1           cmovz eax,ecx
5647120A 8945F8           mov [ebp-$08],eax
5647120D 5A               pop edx

 

Any idea what I am doing wrong?

Thanks!

 

 

 

Share this post


Link to post

For comparison the following method is GetAttributeValue:

/// <summary>
/// Gets an attribute of this element as a POD type. Returns an error if the
/// attribute is not specified. Returns an error if the attribute name is not valid
/// on this element. Returns an error if the attribute cannot be expressed as the
/// specified POD type.
/// </summary>
STDMETHOD(GetAttributeValue)(
_In_ PCWSTR name,
D2D1_SVG_ATTRIBUTE_POD_TYPE type,
_Out_writes_bytes_(valueSizeInBytes) void *value,
UINT32 valueSizeInBytes
) PURE;
 

which I am successfully using by translating to (same parameters)

    function GetAttributeValue(name: LPWSTR;
                               _type: D2D1_SVG_ATTRIBUTE_POD_TYPE;
                               value: Pointer;
                               valueSizeInBytes: UINT32): HResult; overload; stdcall;

However the prolog of GetAttributeValue is different:

 

564713C0 6690             nop 
564713C2 55               push ebp
564713C3 8BEC             mov ebp,esp
564713C5 83EC24           sub esp,$24
564713C8 8B4D08           mov ecx,[ebp+$08]
564713CB 53               push ebx
564713CC 8BD9             mov ebx,ecx
564713CE 56               push esi
564713CF 8D4108           lea eax,[ecx+$08]
564713D2 33C9             xor ecx,ecx
564713D4 85C0             test eax,eax
564713D6 57               push edi
564713D7 0F44D9           cmovz ebx,ecx
564713DA 6A08             push $08
564713DC 5A               pop edx

 

Share this post


Link to post
Posted (edited)
41 minutes ago, David Heffernan said:

Problem could be how you call the function 

OldColor: TD2D1ColorF;

//works with correct results
if Succeeded(Element.GetAttributeValue('fill', D2D1_SVG_ATTRIBUTE_POD_TYPE_COLOR,
       @OldColor, SizeOf(OldColor)))

// Crashes Access violation
Element.SetAttributeValue('fill', D2D1_SVG_ATTRIBUTE_POD_TYPE_COLOR,
           @OldColor, SizeOf(OldColor));
D2D1_SVG_ATTRIBUTE_POD_TYPE_COLOR = 1

The prolog of the two functions differ.  Doesn't this mean the declaration should be different?  But I am not sure what SetAttributeValue expects

Edited by pyscripter

Share this post


Link to post
45 minutes ago, pyscripter said:

However the prolog of GetAttributeValue is different:

Means nothing, as it depends on different factors, like the local variables initialized or not, the stack protection cookie, stack frame.. etc

So being different help with nothing here.

 

But lets approach this differently, is the value returned in OldColor with GetAttributeValue is right ? if yes then passing it to SetAttributeValue should be OK, i have no idea what POD means ?!, may be try with string type at first then switch to that POD.

"Crashes Access violation" this is not very helpful without the address triggering the AV with the invalid value trying to read, this will help you understand if the message have reading address XXXXX, is your stack in other word belongs to OldColor the pointer itself instead of the memory it pointing to.

 

And last, i would suggest to double check if you landing on the right function SetAttributeValue

https://docs.microsoft.com/en-us/windows/win32/direct2d/id2d1svgelement-setattributevalue-overload

 

 

Share this post


Link to post
Posted (edited)
24 minutes ago, Kas Ob. said:

Means nothing, as it depends on different factors, like the local variables initialized or not, the stack protection cookie, stack frame.. etc

So being different help with nothing here.

 

But lets approach this differently, is the value returned in OldColor with GetAttributeValue is right ? if yes then passing it to SetAttributeValue should be OK, i have no idea what POD means ?!, may be try with string type at first then switch to that POD.

"Crashes Access violation" this is not very helpful without the address triggering the AV with the invalid value trying to read, this will help you understand if the message have reading address XXXXX, is your stack in other word belongs to OldColor the pointer itself instead of the memory it pointing to.

 

And last, i would suggest to double check if you landing on the right function SetAttributeValue

https://docs.microsoft.com/en-us/windows/win32/direct2d/id2d1svgelement-setattributevalue-overload

 

 

The value of OldColor returned by GetAttributeValue is right.  (I have a simple svg file and checked with the contents of the file).  So GetAttributeValue works fine.

 

Access violation at 0x75db8cbx read of address 0x000000001

  D2D1_SVG_ATTRIBUTE_POD_TYPE = DWord;
  {$EXTERNALSYM D2D1_SVG_ATTRIBUTE_POD_TYPE}
const
  // The attribute is a D2D1_COLOR_F.
  D2D1_SVG_ATTRIBUTE_POD_TYPE_COLOR                = D2D1_SVG_ATTRIBUTE_POD_TYPE(1);

 

I did check that the correct overload is called. (looked at the assembly code calliing the function: call dword ptr [eax+$7c] for GetAttributeValue  , dword ptr [eax+$78] for SetAttributeValue  , tripled checked with the C header file order of interface members etc).

MSDN description of SetAttributeValue overload used.

 

I am attaching the project source code in case anyone wants to have a go.   The display of svg files works fine and now without using Vcl.Direct2D.

Svg.zip

d2d1svg.h

Edited by pyscripter

Share this post


Link to post

why don't you debug into the dll?

 "read of address 0x000000001" where "0x000000001" is D2D1_SVG_ATTRIBUTE_POD_TYPE_COLOR

so just my 2 cent's the overloads are mixed up

Share this post


Link to post

The declaration is fine and the value been handled fine inside the function SetAttributeValue, but the exception is been raised from msvcrt.memcpy and that after few functions in d2d1.dll, you can check easily by supplying wrong ( invalid address for OldColor) and see for your self the exception is in different place, so the declaration is OK.

 

The problem is in Element itself in different place, can't figure it out, and can't find a single sample/example in internet on how to use those attributes, should element be retrieved in different way ?

Share this post


Link to post

Thank you for sharing the sample.

 

And here is the thing,

1) in that sample fill, RecolorSubtree is using IsAttributeSpecified and GetAttributeValue then utilizing paint->SetColor to change the color, not using SetAttributeValue.

2) SetAttributeValue is been used after GetAttributeValue for 'display' and not for fill

 

may be that is the case ?

Share this post


Link to post
Posted (edited)
6 minutes ago, Kas Ob. said:

Thank you for sharing the sample.

 

And here is the thing,

1) in that sample fill, RecolorSubtree is using IsAttributeSpecified and GetAttributeValue then utilizing paint->SetColor to change the color, not using SetAttributeValue.

2) SetAttributeValue is been used after GetAttributeValue for 'display' and not for fill

 

may be that is the case ?

I have tried to used the method used in the sample see the commented out code:

 

 Assert(Succeeded(
    Element.GetAttributeValue('fill', IID_ID2D1SvgPaint, Pointer(Paint))
    ));

but that did not work either.  So I then tried to use a different overload to get the color and that worked.  But setting it back produces the crash.

Edited by pyscripter

Share this post


Link to post

looks like I'm being ignored here.

change the order of the last 2 SetAttributeValue()'s in the interface, no AV but I can't see any changes, maybe you would know why and see if it helps.

  • Like 1

Share this post


Link to post

@pyscripter

Quote

I did check that the correct overload is called. (looked at the assembly code calliing the function: call dword ptr [eax+$7c] for GetAttributeValue  , dword ptr [eax+$78] for SetAttributeValue  , tripled checked with the C header file order of interface members etc).

I believe you're wrong on $78 ! its for an overloaded GetAttributeValue function (not SetAttributeValue). So your code is calling an overloaded version of GetAttributeValue instead of SetAttributeValue.

attr.PNG

  • Like 3
  • Thanks 1

Share this post


Link to post
15 minutes ago, Attila Kovacs said:

looks like I'm being ignored here.

change the order of the last 2 SetAttributeValue()'s in the interface, no AV but I can't see any changes, maybe you would know why and see if it helps.

Wow.  I was using the order in the include file.  What exactly is the order that works?  Could you please post the relevant section of the file or the file as a whole?

Share this post


Link to post
Posted (edited)

As I first mentioned the in the AV reading address 0x00000001, the "1" is the parameter D2D1_SVG_ATTRIBUTE_POD_TYPE_COLOR.

Change it to D2D1_SVG_ATTRIBUTE_POD_TYPE_FILL_MODE and you will get AV reading address 0x00000002.

So I thought that the wrong "SetAttributeValue" is called, so I changed the order of the "SetAttributeValue"'s => swapped the last two.

But as I can't see any changes in the image and @Mahdi Safsafi showed in IDA that this is a completely different call, I'm not sure what is going on.

But it's a good start for you to sort it out.

 

Edited by Attila Kovacs
  • Like 1

Share this post


Link to post
19 minutes ago, Mahdi Safsafi said:

I believe you're wrong on $78 ! its for an overloaded GetAttributeValue function (not SetAttributeValue). So your code is calling an overloaded version of GetAttributeValue instead of SetAttributeValue.

Thanks, but this is puzzling.  at $7C is the GetAttributeValue, which I know it works  and  at $78 should be the one before. (right?).  In the include file the function before the GetAttributeValue is the relevant SetAttributeValue.   How can I find the correct order?

Share this post


Link to post
2 minutes ago, Attila Kovacs said:

As I first mentioned the in the AV reading address 0x00000001, the "1" is the parameter D2D1_SVG_ATTRIBUTE_POD_TYPE_COLOR.

Impressive guess work!

Share this post


Link to post

OK, i giving up on this.

 

6 minutes ago, pyscripter said:

I was using the order in the include file.

And that exactly what you should do.

 

I count them 10 times, the count is 30 and when i ran out of fingers and toes, i draw 10 fingers on my table and used them, this should not be happening and i am lost here !

the parent ID2D1Resource does have only one function and it is coming form IUknown, so please when you figure it out i want.., no , i have to know to able to sleep tonight.

  • Thanks 1

Share this post


Link to post
30 minutes ago, Kas Ob. said:

OK, i giving up on this.

Thanks for your efforts...

Share this post


Link to post
46 minutes ago, pyscripter said:

Thanks, but this is puzzling.  at $7C is the GetAttributeValue, which I know it works  and  at $78 should be the one before. (right?).  In the include file the function before the GetAttributeValue is the relevant SetAttributeValue.   How can I find the correct order?

Basically vtable respects the order in which functions are declared. But here the overloading is tweaking. Try to respect both the order and overloading name. The below code should demonstrate what I mean.

// SetAttributeValue declared first ... we put it first
function SetAttributeValue(name: LPWSTR; _type: D2D1_SVG_ATTRIBUTE_STRING_TYPE; value: LPWSTR): HResult; overload; stdcall;
// then we put all overloaded methods SetAttributeValue but in the order they were declared:
function SetAttributeValue(name: LPWSTR; _type: D2D1_SVG_ATTRIBUTE_POD_TYPE; value: Pointer; valueSizeInBytes: UINT32): HResult; overload; stdcall; // SetAttributeValue2
function SetAttributeValue(name: LPWSTR; value: ID2D1SvgAttribute): HResult; overload; stdcall; // SetAttributeValue3
// GetAttributeValue comes after  SetAttributeValue:
function GetAttributeValue(name: LPWSTR; _type: D2D1_SVG_ATTRIBUTE_STRING_TYPE; out value: PWideChar; valueCount: UINT32): HResult; overload; stdcall; 
// overloaded2 first and then overloaded3
function GetAttributeValue(name: LPWSTR; _type: D2D1_SVG_ATTRIBUTE_POD_TYPE; value: Pointer; valueSizeInBytes: UINT32): HResult; overload; stdcall; // overloaded2
function GetAttributeValue(name: LPWSTR; const riid: TGUID; var value: Pointer): HResult; overload; stdcall;  // overloaded3

PS: I got the smile SVG 🙂 

  • Like 1
  • Thanks 1

Share this post


Link to post
Posted (edited)

@Mahdi Safsafi Amazing stuff.

Questions: 

  1. There are many more overloads in the include file implemented as inline functions.   Do those interfere with the above?
  2. After the first set of Set/GetAttributeValue there is a GetAttributeValueLength function.  Does this comes last?

It was just by accident that my GetAttributeCall was picking the correct overload!!  That really confused me.

Edited by pyscripter

Share this post


Link to post

Thank you @Mahdi Safsafi

 

The new to me fact on how that interface is declared and how its method allocated disturbs me, i didn't know that, i was decompiling and try to make sense of all of that without success.

 

Now the question is : How many of those overloaded are in Delphi libraries ? and is this documented behaviour ?

 

If you create COM object with overloaded methods with Delphi , then you can't use it from different platform, right? and the worse question if you went ahead and used CBuilder is the interface usable ?

 

Too many questions !

Share this post


Link to post
Posted (edited)
28 minutes ago, Mahdi Safsafi said:

function GetAttributeValue(name: LPWSTR; const riid: TGUID; var value: Pointer😞 HResult; overload; stdcall; // overloaded3

This is the one I was getting before at $78 I think.

Also when I call it using the commented code it does not succeed.

 

    Assert(Succeeded(
      Element.GetAttributeValue('fill', IID_ID2D1SvgPaint, Pointer(Paint))
    ))

fails.
 

It does not appear to be in the right order now.  

 

Do you get the recoloring to work.

Edited by pyscripter

Share this post


Link to post
11 minutes ago, pyscripter said:
  1. There are many more overloads in the include file implemented as inline functions.   Do those interfere with the above?

Those are not stored inside vtable ... you need to skip them(don't declare them).

Quote
  1.  After the first set of Set/GetAttributeValue there is a GetAttributeValueLength function.  Does this comes last?

Exactly! 

That's my bad man ... I'm a little bit bad at explaining since I'm not a native English speaker.

First step, add all methods in the order they declared(skip all overloaded versions but keep the original). second step for each added method "A" add just after it "A" all its overloaded versions in the order they declared too.

Here is how your vtable looks like.

 

vtbl.PNG

  • Like 2

Share this post


Link to post
28 minutes ago, Kas Ob. said:

Now the question is : How many of those overloaded are in Delphi libraries ? and is this documented behaviour ?
 

I really don't know.

Quote

If you create COM object with overloaded methods with Delphi , then you can't use it from different platform, right? and the worse question if you went ahead and used CBuilder is the interface usable ?

Well I never tried to consume Delphi stuff from c/c++ mostly because c/c++ has a much native frameworks than Delphi ... However I do consume c/c++ stuff from Delphi.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×