Passing structure to C++ code (64bit)

I’m trying to pass Xojo structure (64bit) to C++ code (64bit) compiled with VS2019, but getting wrong (actually, shifted parameters) values on parameters.
The structure is simple, with two int32 members.
C++ code is accepting the 3 parameters: 1st parameter is the structure, last two are 32 bit integers.

When passing the structure, the last parameter is “jumping” on to the next parameter. (see screenshot)
But when I used to replace the structure with equivalent int64 value (combined two 32bit int), I got right results.

Looks like C++ is getting the three parameters when passing the structure with two members from Xojo despite the structure size is 8 bytes on both sides (Xojo and C++).

Am I doing something wrong when passing the structure to C++ code?

Run Results: (incorrect results in red rectangle box, green rect is correct.
Clipboard01

Here is the App.Code:

#tag Class
Protected Class App
Inherits ConsoleApplication
	#tag Event
		Function Run(args() as String) As Integer
		  Var st As st2int 
		  st.ileft = 44
		  st.iright = 99
	  
		  Var p1 As Integer = 123
		  Var p2 As Integer = 456
		  
		  Print("Initial Parameters....")
		  Print("  Struct iLeft: " + st.ileft.ToString + ", iRight: " + st.iRight.ToString)
		  Print("   p1: " + p1.ToString + ", p2: " + p2.ToString)
		  Print("   sizeof(p1)")
		  Print("   sizeof(st2Int): " + st.Size.ToString)
		  Print("")
		  Print("Call argtest1..")
		  Print("")
		  
		  Var rz1 As Int64 = argtest1(st, p1, p2)
		  
		  Print("")
		  Print (" ---- using single 64bit integer parameter ---- " )
		  Print("")
		  Print("Call argtest2..")
		  Print("")
		  
		  Var max32int As Int64 = 4294967296 
		  Var v64 As Int64 = st.iright * max32int + st.ileft // constant not working here,only variable 
		  Var rz2 As Int64 = argtest2(v64, p1, p2)
		  
		  WaitEnter
		End Function
	#tag EndEvent
	#tag ExternalMethod, Flags = &h0
		Soft Declare Function argtest1 Lib "t:\down\mydll.dll" (sz as st2int, p1 as integer, p2 as integer) As int64
	#tag EndExternalMethod
	#tag ExternalMethod, Flags = &h0
		Soft Declare Function argtest2 Lib "t:\down\mydll.dll" Alias "argtest1" (sz as int64, p1 as integer, p2 as integer) As int64
	#tag EndExternalMethod
	#tag Method, Flags = &h0
		Sub WaitEnter()
		  Print("Press Enter to exit ...")
		  Var s As String = Input
		End Sub
	#tag EndMethod
	#tag Structure, Name = st2int, Flags = &h0
		ileft as int32
		iright as int32
	#tag EndStructure
End Class
#tag EndClass

C++ code

argtest.h

#pragma once

#ifdef ARGTEST_EXPORTS
#define ARGTEST_API __declspec(dllexport)
#else
#define ARGTEST_API __declspec(dllimport)
#endif

struct st2Int
{
	int iLeft;
	int iRight;
};
extern "C" ARGTEST_API int argtest1(st2Int st, int par1, int par2);

dllmain.cpp

#include "pch.h"
#include "argtest.h"
#include <iostream>

BOOL APIENTRY DllMain( HMODULE hModule, DWORD  ul_reason_for_call,LPVOID lpReserved )
{
    switch (ul_reason_for_call)
    {case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;} return TRUE;
}

int argtest1(st2Int st, int p1, int p2)
{
    int sz1 = sizeof(p1);
    int sz2 = sizeof(st2Int);

    std::cout << "**************************************" << std::endl;
    std::cout << "  Struct iLeft: " << st.iLeft << ", iRight: " << st.iRight << std::endl;
    std::cout << "   p1: " << p1 << ", p2: " << p2 << std::endl;
    std::cout << "   sizeof(p1): " << sz1 << std::endl;
    std::cout << "   sizeof(st2Int): " << sz2 << std::endl;
    std::cout << "**************************************" << std::endl;

    int rz = p1 + p2;
    return rz;
}

Probably because you defined both values of the Xojo structure as int32. Use type int64 if you want explicit 64-bit values. If you define them as integer in Xojo it depends on the compilation setting.

Or use int32 instead of int in the C++ code.

1 Like

Thanks for reply. Actually both structures have the same size.
The C++ (64bit) int and __int32 are 4 bytes, i.e. 32bit, so the structures members in Xojo.

I used int64 single parameter instead of two to test the solution, but in reality structure may have different data types or more int32 members.

I’m using an external library from 3rd party tool, so I stuck when I passed the structure data. Given C++ code is simulating the actual problem/statement.

Hello @Aslan_Babakhanov ,

There could be quite a few reasons for this. One that I frequently run into is that the default setting in Xojo is big endian or sometimes middle or little endian.

Maybe check the raw hexadecimal structure of the values in both languages. :wink:

You may also be running into structure alignment issues. See here about ⅔ of the way down the page:

https://docs.xojo.com/Structure

Sorry it’s the old docs, but I could not quickly locate this on the new site.

2 Likes

Sorry to be the bearer of bad news but it looks like another 64bit bug in xojo, it works perfectly in 32bit as you have written it and when the structure is sent ByRef (pointer) it works in both 32bit and 64bit.

However if that isn’t what your 3rd party dll is expecting, the dll is 64bit and the structure if of a more substantial size and you can’t get away with the working example above then you’re out of luck.

1 Like

Thank you Greg - tested with StructureAlignment - it worked for parameters only with attribute of 32, but not for structure.

Yes, its working well with 32bit dll, but it seems there is a bug in 64bit.
Some 3rd party dll’s came with source codes and recompilation will break the dll call chains to existing 64bit dlls. Everything is made for 64 bit only (very specific subs/funcs using Rxx registers using asm inlines in C++ code…).

Unfortunately, I have to switch my project from Xojo to C++ …

Have you tried using a memory block instead of a structure as that would give you more control.

That wouldn’t help because that would be sent via reference, if the receiving dll isnt expecting that it simply wouldn’t work, well it would but you’d end up with garage in the structure as the pointer would take the place of the two int32’s

1 Like

ah - I didn’t see that it needed to be sent by value.

If Aslan has the MBS plugins then he might be able to use MemoryBlock.AddressMBS to retrieve an Int64 memory address to the memory block.

I see the following from the Xojo side:

image

There is no problems with int64 params, but passing the structure with members by ref.
Given example is just a single issue - there are lots of different structures with different number of datatypes.

Probably an alignment issue