dllcall unexpected behavior when running 64bit Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
Spawnova
Posts: 554
Joined: 08 Jul 2015, 00:12
Contact:

dllcall unexpected behavior when running 64bit

Post by Spawnova » 16 Jun 2022, 04:10

Hello, I'm currently working on a direct2d overlay and it works flawlessly in 32bit, but in 64bit a few functions fail, and they seem to be related so I'll focus on just 1 - DrawLine

c++ code

Code: Select all

STDMETHOD_(void, DrawLine)(
         ID2D1RenderTarget *This,
         D2D1_POINT_2F point0, ;<-- problem is here, my params don't seem to work in 64bit, but work in 32bit
         D2D1_POINT_2F point1,
         __in ID2D1Brush *brush,
         FLOAT strokeWidth,
         __in_opt ID2D1StrokeStyle *strokeStyle 
         ) PURE;
Here's my function for ahk which works fine in 32 bit, x1,y1,x2,y2 are parameters for line coordinates

Code: Select all

		dllcall(this.vTable(this.renderTarget,15)
		,"Ptr",this.renderTarget
		,"float",x1,"float",y1  ;D2D1_POINT_2F point0
		,"float",x2,"float",y2  ;D2D1_POINT_2F point1
		,"ptr",this.brush
		,"float",thickness
		,"ptr",this.stroke)
My understanding is that in this case when calling DrawLine; D2D1_POINT_2F is not a pointer to a structure but simply the structure of arguments, meaning it's the same as using 2 floats as parameters (I obviously could and may be wrong on this)

My problem is that in 64bit specifying the parameters that way causes the call to fail, but when I call it like below, it does indeed draw a line from 50,0 to 150,0 ..... This made me think it was looking for a pointer to a D2D1_POINT_2F structure since the param count seemed to be correct, but creating 2 D2D1_POINT_2F structures and passing the pointers "ptr",&struct1,"ptr",&struct2 did not work

Code: Select all

dllcall(this.vTable(this.renderTarget,15)
		,"Ptr",this.renderTarget
		,"float",50     ;using only 2 floats does draw a line, but without y coordinates
		,"float",150   ;so the line is from 50,0 to 150,0, so it seems like the correct amount of params...
		,"ptr",this.brush
		,"float",thickness
		,"ptr",this.stroke)
I am hoping someone who knows more about this would be able to point out my mistake, I'm no expert at this stuff and it seems I'm lacking crucial knowledge here, I'll continue to tinker on my end but I really hope someone can point me in the right direction :mrgreen:

Emile HasKey
Posts: 27
Joined: 06 Mar 2022, 17:45

Re: dllcall unexpected behavior when running 64bit

Post by Emile HasKey » 16 Jun 2022, 05:29

In the past, I've seen something similar with integers and POINT structs:
DllCall(..., "Int64",x&0xFFFFFFFF|y<<32, ...)

So, maybe you need to do something similar, but with floats:

Code: Select all

VarSetCapacity(point0, 8)
NumPut(x1, &point0, 0, "Float")
NumPut(y1, &point0, 4, "Float")
value := NumGet(&point0, 0, "Int64")
;DllCall(..., "Int64",value, ...)

teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: dllcall unexpected behavior when running 64bit  Topic is solved

Post by teadrinker » 16 Jun 2022, 06:28

Something like this:

Code: Select all

dllcall(this.vTable(this.renderTarget,15)
,"Ptr",this.renderTarget
,"Double",Create_D2D1_POINT_2F(x1, y1, _)
,"Double",Create_D2D1_POINT_2F(x2, y2, __)
,"ptr",this.brush
,"float",thickness
,"ptr",this.stroke)

Create_D2D1_POINT_2F(x, y, ByRef D2D1_POINT_2F) {
   VarSetCapacity(D2D1_POINT_2F, 8, 0)
   NumPut(x, D2D1_POINT_2F, 0, "Float")
   NumPut(y, D2D1_POINT_2F, 4, "Float")
   Return NumGet(D2D1_POINT_2F, "Double")
}

User avatar
Spawnova
Posts: 554
Joined: 08 Jul 2015, 00:12
Contact:

Re: dllcall unexpected behavior when running 64bit

Post by Spawnova » 16 Jun 2022, 06:40

@teadrinker Thank you! I was losing my mind trying to figure this out :lol:

I would have never thought to do it that way, but now I have learned a new tool for the future =)

Thank you very much! I can finally move on and finish this up :D


Emile HasKey
Posts: 27
Joined: 06 Mar 2022, 17:45

Re: dllcall unexpected behavior when running 64bit

Post by Emile HasKey » 02 Jul 2022, 19:27

@Spawnova @teadrinker

In my example, I assigned 2 Floats, then used an Int64 as a go-between.
In his example, teadrinker assigned 2 Floats, then used a Double as a go-between.

In some rare circumstances, if you read 8 bytes as a Double, then write that number as a Double, the value is changed.
That would mean that one or both Floats would have been modified.

Here are 2 examples:

Code: Select all

; reading/writing 8 bytes as a Double can modify the value:
for index, num in [0x7FF7FFFFFFFFFFFF, 0x7FF0000000000001]
{
	VarSetCapacity(buf, 8)
	NumPut(num, &buf, "Int64")
	double := NumGet(&buf, "Double")
	NumPut(double, &buf, "Double")
	num2 := NumGet(&buf, "Int64")
	MsgBox % Clipboard := Format("0x{:X} 0x{:X}", num, num2)
}
return

; results:
; 0x7FF7FFFFFFFFFFFF 0x7FFFFFFFFFFFFFFF
; 0x7FF0000000000001 0x7FF8000000000001

teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: dllcall unexpected behavior when running 64bit

Post by teadrinker » 03 Jul 2022, 05:50

The issue is how floating point numbers are represented in memory.

Code: Select all

num := 0x7FF7FFFFFFFFFFFF
VarSetCapacity(buf, 8)
NumPut(num, buf, "Int64")
double := NumGet(buf, "Double")
MsgBox % num . " " . double

Post Reply

Return to “Ask for Help (v1)”