Passing a structure to an external API

We are working with a C API for OpenCV. Most of the current OpenCV function calls don’t take separate width/length parameters, they use an internal structure called Size, which contains width and length as integers. In the C API:

typedef struct CVCSize {
	int width, height;
} CVCSize;

In a Xojo Module I have external methods that match the C API functions, an internal method that calls this external method, and a structure that contains the width and height as integers:

C API:

void CVCresize(CVCMat src, CVCMat dst, CVCSize dsize, double fx, double fy, int interpolation)
{
cv::resize(ConstCVCMatRef(src), CVCMatRef(dst), CVCSizeParam(dsize), fx, fy, interpolation);
}

Xojo Module External Method CVCresize():
src as ptr, dst as ptr, dsize as CVCSize, fx as double, fy as double, interpolation as integer

Xojo Module Internal Method resize():
src as ptr, dst as ptr, dsize as CVCSize, fx as double, fy as double, interpolation as integer

and the code in the resize() method is:
CVCresize(src, dst, dsize, fx, fy, interpolation)

A Xojo structure called CVCSize, which contains width and height as integers

And the code that calls this is:

Var dsize as CVCSize
dsize.width = 640
dsize.height = 480
resize(source.cvmat, smaller.cvmat,  dsize , 0, 0, 0 )

However, when I run this in the debugger, the application simply quits and drops me back in the IDE with no errors. I’ve tried catching exceptions in the resize() method, but I get the same result.

At first I thought I needed to pass the dsize structure as a pointer, so I changed both CVCresize() and resize() to expect pointers instead of type CVCSize, and then passed byref dsize in the call to the resize() function. However, that just resulted in a syntax error.

How do I get this Xojo structure to the API?

(Also, as an aside - why won’t this forum at least display the C code as fixed width if not with syntax coloring? I’ve wrapped the code above with the “</>” tag and it does nothing, so I had to put it in as a quote in order to separate it from the rest of the text).

Try making the external method’s parameter ByRef and then pass the structure instead a of a Ptr:

CVCresize(src as ptr, dst as ptr, ByRef dsize as CVCSize, fx as double, fy as double, interpolation as integer)

I’ll give that a try tomorrow, thanks. I’m pretty sure I did that though, and got an error as well, but can’t remember what it was. I won’t be in the office until morning though, to try it out.

So this fails in the same way: When I run it in the debugger, it simply quits without error.

I should point out that other functions in the C API do work. For example, I’m able to create a CV Mat, which is the structure that holds the image data, and I know that’s working correctly because I can load an image into it and get the image’s size from the CVMat using functions that live in the API.

Windows Event Viewer tells me I’ve got an exception of type 0xc0000409, which is a Stack Buffer Overrun – but of course that doesn’t really tell me much.

It is usually a problem with the datatypes not being the same. Do you know the size of those INTs? For example, could be a 32-bit integer value and if you have a 64 bit app, those Integers will be 64-bit.

Maybe is you use a MemoryBlock of the apropriate size instead of a struct and pass it as a ptr :thinking:

Dim CVCSize As New MemoryBlock (8)
rc.Int32Value (0) = w
rc.Int32Value (4) = h

I’ll give the memory block thing a try.

Here’s what the structure looks like:

I’ve also specified the width and height as int64 and int32, but it fails in the same way

Same result with a memoryblock:

Dim dsize As New MemoryBlock (8)
dsize.Int32Value (0) = 640
dsize.Int32Value (4) = 480

resize(source.cvmat, smaller.cvmat, dsize, 0, 0, 0 )

then from resize() I pass the memory block to CVCresize() which passes it along to the API as a ptr. the exception code in Event Viewer is the same.

In the original OpenCV-Xojo project, Size is a structure (set up exactly as mine is, above). And that structure is passed to OpenCVX (which was the glue between Xojo and OpenCV’s now-deprecated C-API).

Does this indicate that there might be an issue on the C API side?

Maybe the structure alignment is incorrect? Alignment affects size in memory of the structure, which can be greater-than the sum of its members’ sizes. By default Xojo doesn’t align structures (i.e. StructureAlignment=1).

So I’d set StructureAlignment to 0? From the docs:

Structures can be aligned using Attributes. You add the attribute “StructureAlignment” to a structure and use one of the legal values: 0, 1, 2, 4, 8, 16, 32, 64, and 128 as the value. A value of 0 indicates that the compiler should perform a natural alignment, which ensures that the structure will be laid out correctly for a given OS platform’s ABI (app binary interface) rules.

That doesn’t say what the other values do though. I did try this with values of both 0 and 1, and in both cases it still fails in the same way (just quits).

I’m not sure if it makes any difference, but in the old OpenCV-Xojo project, they didn’t do any alignment for the CvSize struct.

The most common alignments I’ve seen are 1 and 8. Often, but not always, x86 uses 1 and x64 uses 8.

Maybe int means int16 ? Instead of integer. Could also be int32 on 64-bit systems try to make sure you do what you expect.

You should lookup the definition of the “int” datatype in c it could depend on many things as to wht the size of int i means.

So I was away for the weekend, but just to recap, I have now tried the following:

  • Using int16, int32, int64, uint16, uint32, uint64, Integer and Uinteger in the Size struct
  • Setting the StructureAlignment to 0, 1, 2, 4, 8
  • passing the size struct byref to the C API
  • avoiding a Xojo Structure entirely, and passing a memory block as a pointer, with int16, int32, and int64

I’m waiting to hear back from the programmer who made the C API, but since I’ve tried all the variations of int sizes, I don’t think that’s the issue.

Any other ideas?

Can you show me the source of the C part including the source part you created ?

Meaning please show:

Var dsize as CVCSize
dsize.width = 640
dsize.height = 480
resize(source.cvmat, smaller.cvmat,  dsize , 0, 0, 0 )

all of the parameters?

It’s all in the first post, unless you’re looking for something different. …or do you mean the OpenCV C++ code? That’s all here: OpenCV: Geometric Image Transformations

You are forgetting something:

Const CVCMatRef(src), CVCMatRef(dst), CVCSizeParam(dsize), fx, fy, interpolation

Actually puts in the Reference to the structs. You may want to Ptr(src) Ptr(dst) at least convert it to Ptr (pointer).

Or change the external method signature to it should work, please try:

Var src As CVCMat
Var dst As CVCSize 
Var dsize As CVCSize

CVCresize(ByRef src as CVCMat, ByRef dst CVCSize, ByRef dsize as CVCSize, fx as double, fy as double, interpolation as integer)

Not sure but why is the CVCresize sub even there in the code? You could as well call the cv::resize sub directly with it’s parameterers converted correctly ?

void CVCresize(CVCMat src, CVCMat dst, CVCSize dsize, double fx, double fy, int interpolation)
{
    cv::resize(ConstCVCMatRef(src), CVCMatRef(dst), CVCSizeParam(dsize), fx, fy, interpolation);
}

They are:

resize() is a xojo internal method that you’d call from your code. It calls CVCresize()

CVCresize() is an External method in Xojo, and the src and dst CVCMats are passed as pointers to it.

Is that not the same?

CVCresize():
src as ptr, dst as ptr, ...etc

The code you’re referring to above is the C API in turn calling the C++ OpenCV API. That function (in C), CVCResize(), just passes its parameters on to the C++ API it’s interfacing with.

please check the edited post: Passing a structure to an external API - #16 by DerkJ

It looks like that C function is expecting you to pass a class (not a pointer to the class) as the first two parameters.

This is the C API;
void CVCresize(CVCMat src, CVCMat dst, CVCSize dsize, double fx, double fy, int interpolation)

It calls the C++ OpenCV API:
cv::resize(ConstCVCMatRef(src), CVCMatRef(dst), CVCSizeParam(dsize), fx, fy, interpolation);

You can’t call the C++ API directly from Xojo, which is why we had the C API made - to give us an interface to Open CV.

I will try your suggestion above to change the call to CVCresize() to CVCresize(ByRef src as CVCMat, ByRef dst CVCSize, ByRef dsize as CVCSize, fx as double, fy as double, interpolation as integer)

But I should note that other functions we’re calling DO NOT require this setup. For example, OpenCV uses CVMats to hold image data. To create a CVMat we call an external method from our C API called CVCMatCreate(). This returns a pointer to the CVMat, which we can pass to other functions such as CVCMatWidth(), again an external method in our C API, that returns the width. This methodology works fine for anything where you need to pass a Mat (an image, usually) around from one OpenCV function to another. CVCMatWidth(mat as ptr) as int32

See the paragraph above. The CVCMat stuff is not the issue here, it’s just the struct with the width and height integers we need to pass to the C API.