Page 1 of 3

Passing structure to function

Posted: 29 Dec 2018, 08:42
by malcev
I can not pass structure pointer to function:
https://docs.opencv.org/2.4/modules/cor ... reateimage
CreateImage

Creates an image header and allocates the image data.

C: IplImage* cvCreateImage(CvSize size, int depth, int channels)

Python: cv.CreateImage(size, depth, channels) → image
Parameters:

size – Image width and height
depth – Bit depth of image elements. See IplImage for valid depths.
channels – Number of channels per pixel. See IplImage for details. This function only creates images with interleaved channels.
CvSize structure:
int width
int height
https://docs.opencv.org/ref/2.4/da/dcb/ ... vSize.html

Code: Select all

VarSetCapacity(cvsize, 8, 0)
NumPut(100, cvsize, 0, "int")
NumPut(100, cvsize, 4, "int")
msgbox % DllCall("opencv_core2413.dll\cvCreateImage", "ptr", &cvsize, "int", IPL_DEPTH_8U := 8, "int", channels := 2, "Cdecl Ptr")
msgbox % a_LastError
It can be done if I send copy of structure like this:

Code: Select all

width := 100
height := 100
cvsize := (height << 32) | width
msgbox % DllCall("opencv_core2413.dll\cvCreateImage", "int64", cvsize, "int", IPL_DEPTH_8U := 8, "int", channels := 2, "Cdecl Ptr")
msgbox % a_LastError
or pass elements of structure as parameters:

Code: Select all

width := 100
height := 100
msgbox % DllCall("opencv_core2413.dll\cvCreateImage", "int", width, "int", height, "int", IPL_DEPTH_8U := 8, "int", channels := 2, "Cdecl Ptr")
msgbox % a_LastError
But autoit successfully sends structure:

Code: Select all

Local $cvsize = DllStructCreate("int;int")
DllStructSetData($cvsize, 1, 100)
DllStructSetData($cvsize, 2, 100)
Local $Result = DllCall("opencv_core2413.dll", "ptr:cdecl", "cvCreateImage" , "struct" , $cvsize , "int" , 8, "int" , 2)
MsgBox("","", $Result[0])
32bit dll here:
https://files.fm/u/6ny65dcr

Re: Passing structure to function (bug?)

Posted: 29 Dec 2018, 09:15
by nnnik
What the function expects is not a pointer to the struct but being passed the struct directly.
In this case you have to use the second version or this:

Code: Select all

width := 100
height := 100
msgbox % DllCall("opencv_core2413.dll\cvCreateImage", "int", width, "int", height, "int", IPL_DEPTH_8U := 8, "int", channels := 2, "Cdecl Ptr")
msgbox % a_LastError
Though the order of width and height may be mixed up

Re: Passing structure to function (bug?)

Posted: 29 Dec 2018, 09:51
by swagfag
would

Code: Select all

VarSetCapacity(cvsize, 8, 0)
NumPut(100, cvsize, 0, "int")
NumPut(100, cvsize, 4, "int")
msgbox % DllCall("opencv_core2413.dll\cvCreateImage", "int64", cvsize, "int", IPL_DEPTH_8U := 8, "int", channels := 2, "Cdecl Ptr")
msgbox % a_LastError
work?

Re: Passing structure to function (bug?)

Posted: 29 Dec 2018, 09:57
by just me
It should be mentioned that

Code: Select all

msgbox % DllCall("opencv_core2413.dll\cvCreateImage", "int", width, "int", height, "int", IPL_DEPTH_8U := 8, "int", channels := 2, "Cdecl Ptr")
will most likely work only for a 32-bit DLL.

Re: Passing structure to function (bug?)

Posted: 29 Dec 2018, 10:03
by jeeswg
- @nnnik: Thanks for giving me the clue to what the issue might be.
- @malcev: This is a common issue with the POINT structure affecting Winapi functions such as: AccessibleObjectFromPoint, ChildWindowFromPoint, WindowFromPoint.
- Instead of passing a pointer to a POINT struct, you pass a value.
- You can use bitshift, bitwise-and and bitwise-or to combine the x and y values into one UInt64 value and pass that.
- [EDIT:] Something like: DllCall("WindowFromPoint", UInt64,(vPosX&0xFFFFFFFF)|(vPosY<<32), Ptr)
- Perhaps you could pass the 2 values as separate Int values, as nnnik pointed out, but it may be that that doesn't work in some situations, possibly in 64-bit.

- Here are some related links, search for: FromPoint.
PixelSearch + PostMessage Click - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 07#p161307
script does not work in 64 bit AHK - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 36#p167136
DllCall converter/cleaner (e.g. x32 to x64/x32 two-way compatible) - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 11#p173111
jeeswg's documentation extension tutorial - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 36#p155736
Wish List 2.0 - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 60#p171860

Re: Passing structure to function (bug?)

Posted: 29 Dec 2018, 11:10
by malcev
Why Autohotkey can not pass copy of structure directly as it does autoit?
https://www.autoitscript.com/autoit3/do ... llCall.htm
* Add * to the end of another type to pass it by reference. For example "int*" passes a pointer to an "int" type.
May be move this topic to feature request?

Re: Passing structure to function (Feature Request)

Posted: 29 Dec 2018, 11:38
by just me
malcev wrote:Why Autohotkey can not pass copy of structure directly as it does autoit?
That's exactly what

Code: Select all

DllCall("opencv_core2413.dll\cvCreateImage", "int64", cvsize, "int", ...)
does.

cvCreateImage

Re: Passing structure to function (Feature Request)

Posted: 29 Dec 2018, 11:54
by malcev
Therefore the correct variant to send copy of structure is code by swagfag ?

Code: Select all

VarSetCapacity(cvsize, 8, 0)
NumPut(100, cvsize, 0, "int")
NumPut(100, cvsize, 4, "int")
msgbox % DllCall("opencv_core2413.dll\cvCreateImage", "int64", cvsize, "int", IPL_DEPTH_8U := 8, "int", channels := 2, "Cdecl Ptr")
msgbox % a_LastError

Re: Passing structure to function (Feature Request)

Posted: 29 Dec 2018, 11:58
by just me
No! It's

Code: Select all

width := 100
height := 100
cvsize := (height << 32) | width
msgbox % DllCall("opencv_core2413.dll\cvCreateImage", "int64", cvsize, "int", IPL_DEPTH_8U := 8, "int", channels := 2, "Cdecl Ptr")
msgbox % a_LastError
A structure like

Code: Select all

VarSetCapacity(cvsize, 8, 0)
NumPut(100, cvsize, 0, "int")
NumPut(100, cvsize, 4, "int")
can only be passed by pointer.

Re: Passing structure to function

Posted: 29 Dec 2018, 12:02
by malcev
But if I have this structure (4 elements "doubles")?
double d0,
double d1 = 0,
double d2 = 0,
double d3 = 0

Re: Passing structure to function

Posted: 29 Dec 2018, 12:07
by just me
Most likely, the function will require a structure pointer in this case.

Re: Passing structure to function

Posted: 29 Dec 2018, 12:08
by malcev

Re: Passing structure to function

Posted: 29 Dec 2018, 12:25
by malcev
This code does not work:

Code: Select all

width := 100
height := 100
window := "test"

DllCall("LoadLibrary", "Str", "opencv_core2413.dll", "Ptr")
DllCall("LoadLibrary", "Str", "opencv_highgui2413.dll", "Ptr")

VarSetCapacity(cvsize, 8, 0)
NumPut(width, cvsize, 0, "int")
NumPut(height, cvsize, 4, "int")
pimg := DllCall("opencv_core2413.dll\cvCreateImage", "int64", cvsize, "int", IPL_DEPTH_8U := 8, "int", channels := 1, "Cdecl Ptr")

VarSetCapacity(cvScalar, 32, 0)
NumPut(255, cvScalar, 0, "Double")
NumPut(255, cvScalar, 8, "Double")
NumPut(255, cvScalar, 16, "Double")
NumPut(255, cvScalar, 24, "Double")
DllCall("opencv_core2413.dll\cvSet", "ptr", pimg, "int64", cvScalar, "ptr", 0, "Cdecl")

DllCall("opencv_highgui2413.dll\cvShowImage", "AStr", window, "ptr", pimg, "Cdecl")
msgbox ok
But this work:

Code: Select all

width := 100
height := 100
window := "test"

DllCall("LoadLibrary", "Str", "opencv_core2413.dll", "Ptr")
DllCall("LoadLibrary", "Str", "opencv_highgui2413.dll", "Ptr")

pimg := DllCall("opencv_core2413.dll\cvCreateImage", "int", width, "int", height, "int", IPL_DEPTH_8U := 8, "int", channels := 1, "Cdecl Ptr")
DllCall("opencv_core2413.dll\cvSet", "ptr", pimg, "Double", 255, "Double", 255, "Double", 255, "Double", 255, "ptr", 0, "Cdecl") 
DllCall("opencv_highgui2413.dll\cvShowImage", "AStr", window, "ptr", pimg, "Cdecl")
msgbox ok
Therefore question - Is it possible to pass copy of structure to function in autohotkey as it done in autoit?

Re: Passing structure to function

Posted: 29 Dec 2018, 13:02
by teadrinker
malcev wrote:
29 Dec 2018, 12:25
This code does not work:

Code: Select all

width := 100
height := 100
window := "test"

DllCall("LoadLibrary", "Str", "opencv_core2413.dll", "Ptr")
DllCall("LoadLibrary", "Str", "opencv_highgui2413.dll", "Ptr")

VarSetCapacity(cvsize, 8, 0)
NumPut(width, cvsize, 0, "int")
NumPut(height, cvsize, 4, "int")
pimg := DllCall("opencv_core2413.dll\cvCreateImage", "int64", cvsize, "int", IPL_DEPTH_8U := 8, "int", channels := 1, "Cdecl Ptr")
Try

Code: Select all

MsgBox, % pimg := DllCall("opencv_core2413.dll\cvCreateImage", "int64P", cvsize, "int", IPL_DEPTH_8U := 8, "int", channels := 1, "Cdecl Ptr")

Re: Passing structure to function

Posted: 29 Dec 2018, 13:18
by malcev
It does not return error, but result structure is corrupted:
https://docs.opencv.org/2.4/modules/cor ... l#IplImage

Code: Select all

width := 100
height := 100

DllCall("LoadLibrary", "Str", "opencv_core2413.dll", "Ptr")

VarSetCapacity(cvsize, 8, 0)
NumPut(width, cvsize, 0, "int")
NumPut(height, cvsize, 4, "int")
pimg := DllCall("opencv_core2413.dll\cvCreateImage", "int64P", cvsize, "int", IPL_DEPTH_8U := 8, "int", channels := 1, "Cdecl Ptr")
loop 22
   fin .= NumGet(pimg+0, (A_Index-1)*4, "int") "`n"
msgbox % clipboard := fin   ; wrong
fin := ""

pimg := DllCall("opencv_core2413.dll\cvCreateImage", "int", width, "int", height, "int", IPL_DEPTH_8U := 8, "int", channels := 1, "Cdecl Ptr")
loop 22
   fin .= NumGet(pimg+0, (A_Index-1)*4, "int") "`n"
msgbox % clipboard := fin   ; right

Re: Passing structure to function

Posted: 29 Dec 2018, 13:47
by teadrinker
It's strange :)

Re: Passing structure to function

Posted: 29 Dec 2018, 15:28
by Helgef
In c (cdecl), as far as I know, passing a struct by value is done by copying it on to the stack, including padding. Your only option to put something on the stack, is by passing parameters via dllcall. I'd expect stdcall behaves the same.
just me wrote:will most likely work only for a 32-bit DLL.
For x64 calling convention, refer to MSDN,
Structs and unions of size 8, 16, 32, or 64 bits, and __m64 types, are passed as if they were integers of the same size. Structs or unions of other sizes are passed as a pointer to memory allocated by the caller.
So indeed, struct S {int;int;} must be passed as int64 for x64 calling convention, and it can be for cdecl too. But struct S2 {char c1;short s;char c2;} would need to be passed as "ptr", &S2 for x64. But, for cdecl, S2 would be passed as "int64", c1 | (s << 16) | (c2 << 32), you cannot do "char", c1, "short", s, "char", c2. Finally struct d {double; double; ... double;} must be passed as "ptr", &d for x64 and "double", d1, ..., "double", dn for cdecl.

@swagfag, you can do it like this,

Code: Select all

VarSetCapacity(cvsize, 14, 0)
strPut("429496729700", &cvsize)
DllCall("opencv_core2413.dll\cvCreateImage", "int64", cvsize, "int", IPL_DEPTH_8U := 8, "int", channels := 2, "Cdecl Ptr")
;)

Cheers :fireworks: :champagne:.

Re: Passing structure to function

Posted: 30 Dec 2018, 10:21
by malcev
Helgef, may be this information and your examples will be useful here?
https://autohotkey.com/docs/commands/DllCall.htm#struct

Re: Passing structure to function

Posted: 30 Dec 2018, 10:49
by nnnik
malcev wrote:
30 Dec 2018, 10:21
Helgef, may be this information and your examples will be useful here?
https://autohotkey.com/docs/commands/DllCall.htm#struct
Passing structs like this is not considered good practice and does not see common use.
Perhaps there is a better dll that you can use that does show this kind of behavior.

Re: Passing structure to function

Posted: 30 Dec 2018, 16:23
by Helgef
Helgef, may be this information and your examples will be useful here?
If information were to go to the documentation, more research would be needed, we cannot depend on helgef memory in the docs. And as nnnik says, it is not very common. I wouldn't ditch the dll because it passes small structs by value though.

Next year, I will write a function for this.

Happy new year all, cheers.